From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- dbaccess/source/core/api/BookmarkSet.cxx | 204 ++ dbaccess/source/core/api/BookmarkSet.hxx | 57 + dbaccess/source/core/api/CIndexes.cxx | 87 + dbaccess/source/core/api/CIndexes.hxx | 48 + dbaccess/source/core/api/CRowSetColumn.cxx | 92 + dbaccess/source/core/api/CRowSetColumn.hxx | 49 + dbaccess/source/core/api/CRowSetDataColumn.cxx | 237 ++ dbaccess/source/core/api/CRowSetDataColumn.hxx | 99 + dbaccess/source/core/api/CacheSet.cxx | 580 +++ dbaccess/source/core/api/CacheSet.hxx | 172 + dbaccess/source/core/api/FilteredContainer.cxx | 459 +++ dbaccess/source/core/api/HelperCollections.cxx | 107 + dbaccess/source/core/api/HelperCollections.hxx | 106 + dbaccess/source/core/api/KeySet.cxx | 1467 ++++++++ dbaccess/source/core/api/KeySet.hxx | 217 ++ dbaccess/source/core/api/OptimisticSet.cxx | 588 +++ dbaccess/source/core/api/OptimisticSet.hxx | 76 + dbaccess/source/core/api/PrivateRow.cxx | 133 + dbaccess/source/core/api/PrivateRow.hxx | 58 + dbaccess/source/core/api/RowSet.cxx | 2941 +++++++++++++++ dbaccess/source/core/api/RowSet.hxx | 519 +++ dbaccess/source/core/api/RowSetBase.cxx | 1425 ++++++++ dbaccess/source/core/api/RowSetBase.hxx | 400 ++ dbaccess/source/core/api/RowSetCache.cxx | 1713 +++++++++ dbaccess/source/core/api/RowSetCache.hxx | 190 + dbaccess/source/core/api/RowSetCacheIterator.cxx | 91 + dbaccess/source/core/api/RowSetCacheIterator.hxx | 73 + dbaccess/source/core/api/RowSetRow.hxx | 53 + .../source/core/api/SingleSelectQueryComposer.cxx | 1922 ++++++++++ dbaccess/source/core/api/StaticSet.cxx | 280 ++ dbaccess/source/core/api/StaticSet.hxx | 75 + dbaccess/source/core/api/TableDeco.cxx | 634 ++++ dbaccess/source/core/api/View.cxx | 120 + dbaccess/source/core/api/WrappedResultSet.cxx | 184 + dbaccess/source/core/api/WrappedResultSet.hxx | 60 + dbaccess/source/core/api/callablestatement.cxx | 250 ++ dbaccess/source/core/api/column.cxx | 412 +++ dbaccess/source/core/api/columnsettings.cxx | 150 + dbaccess/source/core/api/datacolumn.cxx | 396 ++ dbaccess/source/core/api/datacolumn.hxx | 107 + dbaccess/source/core/api/datasettings.cxx | 191 + dbaccess/source/core/api/definitioncolumn.cxx | 611 ++++ dbaccess/source/core/api/preparedstatement.cxx | 412 +++ dbaccess/source/core/api/query.cxx | 383 ++ dbaccess/source/core/api/query.hxx | 147 + dbaccess/source/core/api/querycomposer.cxx | 265 ++ dbaccess/source/core/api/querycontainer.cxx | 430 +++ dbaccess/source/core/api/querydescriptor.cxx | 253 ++ dbaccess/source/core/api/querydescriptor.hxx | 135 + dbaccess/source/core/api/resultcolumn.cxx | 296 ++ dbaccess/source/core/api/resultcolumn.hxx | 87 + dbaccess/source/core/api/resultset.cxx | 994 +++++ dbaccess/source/core/api/resultset.hxx | 221 ++ dbaccess/source/core/api/statement.cxx | 591 +++ dbaccess/source/core/api/table.cxx | 340 ++ dbaccess/source/core/api/tablecontainer.cxx | 456 +++ dbaccess/source/core/api/viewcontainer.cxx | 254 ++ .../source/core/dataaccess/ComponentDefinition.cxx | 285 ++ .../source/core/dataaccess/ComponentDefinition.hxx | 159 + dbaccess/source/core/dataaccess/ContentHelper.cxx | 604 ++++ dbaccess/source/core/dataaccess/ModelImpl.cxx | 1428 ++++++++ .../source/core/dataaccess/SharedConnection.cxx | 154 + .../source/core/dataaccess/SharedConnection.hxx | 117 + .../source/core/dataaccess/bookmarkcontainer.cxx | 301 ++ .../source/core/dataaccess/commandcontainer.cxx | 100 + .../source/core/dataaccess/commandcontainer.hxx | 72 + .../source/core/dataaccess/commanddefinition.cxx | 153 + .../source/core/dataaccess/commanddefinition.hxx | 125 + dbaccess/source/core/dataaccess/connection.cxx | 808 +++++ dbaccess/source/core/dataaccess/connection.hxx | 229 ++ .../core/dataaccess/dataaccessdescriptor.cxx | 229 ++ .../source/core/dataaccess/databasecontext.cxx | 736 ++++ .../source/core/dataaccess/databasedocument.cxx | 2200 +++++++++++ .../source/core/dataaccess/databasedocument.hxx | 748 ++++ .../core/dataaccess/databaseregistrations.cxx | 369 ++ .../core/dataaccess/databaseregistrations.hxx | 32 + dbaccess/source/core/dataaccess/datasource.cxx | 1369 +++++++ dbaccess/source/core/dataaccess/datasource.hxx | 220 ++ .../source/core/dataaccess/definitioncontainer.cxx | 679 ++++ .../source/core/dataaccess/documentcontainer.cxx | 770 ++++ .../source/core/dataaccess/documentcontainer.hxx | 137 + .../source/core/dataaccess/documentdefinition.cxx | 2099 +++++++++++ .../source/core/dataaccess/documentdefinition.hxx | 356 ++ .../core/dataaccess/documenteventexecutor.cxx | 189 + .../core/dataaccess/documenteventexecutor.hxx | 58 + .../core/dataaccess/documenteventnotifier.cxx | 290 ++ .../core/dataaccess/documenteventnotifier.hxx | 128 + dbaccess/source/core/dataaccess/documentevents.cxx | 199 + dbaccess/source/core/dataaccess/intercept.cxx | 363 ++ dbaccess/source/core/dataaccess/intercept.hxx | 113 + .../source/core/dataaccess/myucp_datasupplier.cxx | 286 ++ .../source/core/dataaccess/myucp_datasupplier.hxx | 75 + .../source/core/dataaccess/myucp_resultset.cxx | 76 + .../source/core/dataaccess/myucp_resultset.hxx | 49 + dbaccess/source/core/inc/ContainerMediator.hxx | 79 + dbaccess/source/core/inc/ContentHelper.hxx | 177 + dbaccess/source/core/inc/DatabaseDataProvider.hxx | 262 ++ dbaccess/source/core/inc/FilteredContainer.hxx | 136 + dbaccess/source/core/inc/ModelImpl.hxx | 606 ++++ dbaccess/source/core/inc/PropertyForward.hxx | 69 + dbaccess/source/core/inc/RefreshListener.hxx | 42 + .../source/core/inc/SingleSelectQueryComposer.hxx | 264 ++ dbaccess/source/core/inc/TableDeco.hxx | 164 + dbaccess/source/core/inc/View.hxx | 71 + dbaccess/source/core/inc/bookmarkcontainer.hxx | 148 + dbaccess/source/core/inc/callablestatement.hxx | 80 + dbaccess/source/core/inc/column.hxx | 217 ++ dbaccess/source/core/inc/columnsettings.hxx | 88 + dbaccess/source/core/inc/commandbase.hxx | 50 + dbaccess/source/core/inc/composertools.hxx | 121 + dbaccess/source/core/inc/containerapprove.hxx | 57 + dbaccess/source/core/inc/databasecontext.hxx | 171 + dbaccess/source/core/inc/datasettings.hxx | 77 + dbaccess/source/core/inc/definitioncolumn.hxx | 291 ++ dbaccess/source/core/inc/definitioncontainer.hxx | 323 ++ dbaccess/source/core/inc/documentevents.hxx | 73 + dbaccess/source/core/inc/migrwarndlg.hxx | 24 + dbaccess/source/core/inc/objectnameapproval.hxx | 75 + dbaccess/source/core/inc/preparedstatement.hxx | 105 + dbaccess/source/core/inc/querycomposer.hxx | 91 + dbaccess/source/core/inc/querycontainer.hxx | 165 + .../source/core/inc/recovery/dbdocrecovery.hxx | 69 + dbaccess/source/core/inc/sdbcoretools.hxx | 55 + dbaccess/source/core/inc/statement.hxx | 179 + dbaccess/source/core/inc/table.hxx | 136 + dbaccess/source/core/inc/tablecontainer.hxx | 96 + dbaccess/source/core/inc/veto.hxx | 55 + dbaccess/source/core/inc/viewcontainer.hxx | 94 + dbaccess/source/core/misc/ContainerMediator.cxx | 231 ++ dbaccess/source/core/misc/DatabaseDataProvider.cxx | 1067 ++++++ dbaccess/source/core/misc/PropertyForward.cxx | 147 + dbaccess/source/core/misc/apitools.cxx | 91 + dbaccess/source/core/misc/dsntypes.cxx | 573 +++ dbaccess/source/core/misc/migrwarndlg.cxx | 22 + dbaccess/source/core/misc/objectnameapproval.cxx | 62 + dbaccess/source/core/misc/sdbcoretools.cxx | 142 + dbaccess/source/core/misc/veto.cxx | 50 + dbaccess/source/core/recovery/dbdocrecovery.cxx | 337 ++ dbaccess/source/core/recovery/settingsimport.cxx | 216 ++ dbaccess/source/core/recovery/settingsimport.hxx | 163 + dbaccess/source/core/recovery/storagestream.cxx | 54 + dbaccess/source/core/recovery/storagestream.hxx | 51 + .../source/core/recovery/storagetextstream.cxx | 63 + .../source/core/recovery/storagetextstream.hxx | 51 + dbaccess/source/core/recovery/storagexmlstream.cxx | 139 + dbaccess/source/core/recovery/storagexmlstream.hxx | 89 + .../source/core/recovery/subcomponentloader.cxx | 124 + .../source/core/recovery/subcomponentloader.hxx | 71 + .../source/core/recovery/subcomponentrecovery.cxx | 626 ++++ .../source/core/recovery/subcomponentrecovery.hxx | 115 + dbaccess/source/core/recovery/subcomponents.hxx | 61 + dbaccess/source/core/resource/core_resource.cxx | 41 + dbaccess/source/filter/hsqldb/alterparser.cxx | 56 + dbaccess/source/filter/hsqldb/alterparser.hxx | 52 + dbaccess/source/filter/hsqldb/columndef.cxx | 45 + dbaccess/source/filter/hsqldb/columndef.hxx | 47 + dbaccess/source/filter/hsqldb/createparser.cxx | 298 ++ dbaccess/source/filter/hsqldb/createparser.hxx | 68 + dbaccess/source/filter/hsqldb/fbalterparser.cxx | 51 + dbaccess/source/filter/hsqldb/fbalterparser.hxx | 30 + dbaccess/source/filter/hsqldb/fbcreateparser.cxx | 207 ++ dbaccess/source/filter/hsqldb/fbcreateparser.hxx | 37 + dbaccess/source/filter/hsqldb/hsqlbinarynode.cxx | 58 + dbaccess/source/filter/hsqldb/hsqlbinarynode.hxx | 63 + dbaccess/source/filter/hsqldb/hsqlimport.cxx | 384 ++ dbaccess/source/filter/hsqldb/hsqlimport.hxx | 60 + dbaccess/source/filter/hsqldb/parseschema.cxx | 205 ++ dbaccess/source/filter/hsqldb/parseschema.hxx | 84 + dbaccess/source/filter/hsqldb/rowinputbinary.cxx | 399 ++ dbaccess/source/filter/hsqldb/rowinputbinary.hxx | 52 + dbaccess/source/filter/hsqldb/utils.cxx | 147 + dbaccess/source/filter/hsqldb/utils.hxx | 27 + dbaccess/source/filter/xml/dbaxml.component | 46 + dbaccess/source/filter/xml/dbloader2.cxx | 533 +++ dbaccess/source/filter/xml/xmlAutoStyle.cxx | 82 + dbaccess/source/filter/xml/xmlAutoStyle.hxx | 45 + dbaccess/source/filter/xml/xmlColumn.cxx | 162 + dbaccess/source/filter/xml/xmlColumn.hxx | 53 + dbaccess/source/filter/xml/xmlComponent.cxx | 99 + dbaccess/source/filter/xml/xmlComponent.hxx | 40 + dbaccess/source/filter/xml/xmlConnectionData.cxx | 93 + dbaccess/source/filter/xml/xmlConnectionData.hxx | 41 + .../source/filter/xml/xmlConnectionResource.cxx | 88 + .../source/filter/xml/xmlConnectionResource.hxx | 36 + dbaccess/source/filter/xml/xmlDataSource.cxx | 251 ++ dbaccess/source/filter/xml/xmlDataSource.hxx | 47 + dbaccess/source/filter/xml/xmlDataSourceInfo.cxx | 119 + dbaccess/source/filter/xml/xmlDataSourceInfo.hxx | 37 + .../source/filter/xml/xmlDataSourceSetting.cxx | 215 ++ .../source/filter/xml/xmlDataSourceSetting.hxx | 60 + .../source/filter/xml/xmlDataSourceSettings.cxx | 66 + .../source/filter/xml/xmlDataSourceSettings.hxx | 39 + dbaccess/source/filter/xml/xmlDatabase.cxx | 135 + dbaccess/source/filter/xml/xmlDatabase.hxx | 41 + .../source/filter/xml/xmlDatabaseDescription.cxx | 79 + .../source/filter/xml/xmlDatabaseDescription.hxx | 41 + dbaccess/source/filter/xml/xmlDocuments.cxx | 100 + dbaccess/source/filter/xml/xmlDocuments.hxx | 56 + dbaccess/source/filter/xml/xmlEnums.hxx | 23 + dbaccess/source/filter/xml/xmlExport.cxx | 1343 +++++++ dbaccess/source/filter/xml/xmlExport.hxx | 179 + .../source/filter/xml/xmlFileBasedDatabase.cxx | 113 + .../source/filter/xml/xmlFileBasedDatabase.hxx | 36 + dbaccess/source/filter/xml/xmlHelper.cxx | 157 + dbaccess/source/filter/xml/xmlHelper.hxx | 57 + .../source/filter/xml/xmlHierarchyCollection.cxx | 132 + .../source/filter/xml/xmlHierarchyCollection.hxx | 55 + dbaccess/source/filter/xml/xmlLogin.cxx | 111 + dbaccess/source/filter/xml/xmlLogin.hxx | 37 + dbaccess/source/filter/xml/xmlQuery.cxx | 117 + dbaccess/source/filter/xml/xmlQuery.hxx | 46 + dbaccess/source/filter/xml/xmlServerDatabase.cxx | 136 + dbaccess/source/filter/xml/xmlServerDatabase.hxx | 36 + dbaccess/source/filter/xml/xmlStyleImport.cxx | 263 ++ dbaccess/source/filter/xml/xmlStyleImport.hxx | 99 + dbaccess/source/filter/xml/xmlTable.cxx | 227 ++ dbaccess/source/filter/xml/xmlTable.hxx | 67 + dbaccess/source/filter/xml/xmlTableFilterList.cxx | 95 + dbaccess/source/filter/xml/xmlTableFilterList.hxx | 64 + .../source/filter/xml/xmlTableFilterPattern.cxx | 59 + .../source/filter/xml/xmlTableFilterPattern.hxx | 44 + dbaccess/source/filter/xml/xmlfilter.cxx | 617 ++++ dbaccess/source/filter/xml/xmlfilter.hxx | 121 + .../source/inc/OAuthenticationContinuation.hxx | 67 + dbaccess/source/inc/apitools.hxx | 48 + dbaccess/source/inc/dsntypes.hxx | 221 ++ dbaccess/source/inc/stringconstants.hxx | 171 + .../source/sdbtools/connection/connectiontools.cxx | 132 + .../sdbtools/connection/datasourcemetadata.cxx | 51 + .../sdbtools/connection/datasourcemetadata.hxx | 69 + .../source/sdbtools/connection/objectnames.cxx | 421 +++ .../source/sdbtools/connection/objectnames.hxx | 74 + dbaccess/source/sdbtools/connection/tablename.cxx | 220 ++ dbaccess/source/sdbtools/connection/tablename.hxx | 84 + .../source/sdbtools/inc/connectiondependent.hxx | 136 + dbaccess/source/sdbtools/inc/connectiontools.hxx | 77 + dbaccess/source/ui/app/AppController.cxx | 2837 +++++++++++++++ dbaccess/source/ui/app/AppController.hxx | 540 +++ dbaccess/source/ui/app/AppControllerDnD.cxx | 869 +++++ dbaccess/source/ui/app/AppControllerGen.cxx | 736 ++++ dbaccess/source/ui/app/AppDetailPageHelper.cxx | 1221 +++++++ dbaccess/source/ui/app/AppDetailPageHelper.hxx | 349 ++ dbaccess/source/ui/app/AppDetailView.cxx | 510 +++ dbaccess/source/ui/app/AppDetailView.hxx | 318 ++ dbaccess/source/ui/app/AppIconControl.cxx | 238 ++ dbaccess/source/ui/app/AppIconControl.hxx | 67 + dbaccess/source/ui/app/AppSwapWindow.cxx | 133 + dbaccess/source/ui/app/AppSwapWindow.hxx | 88 + dbaccess/source/ui/app/AppTitleWindow.cxx | 65 + dbaccess/source/ui/app/AppTitleWindow.hxx | 67 + dbaccess/source/ui/app/AppView.cxx | 473 +++ dbaccess/source/ui/app/AppView.hxx | 302 ++ dbaccess/source/ui/app/ChildWindow.cxx | 25 + dbaccess/source/ui/app/DocumentInfoPreview.cxx | 164 + dbaccess/source/ui/app/DocumentInfoPreview.hxx | 59 + dbaccess/source/ui/app/subcomponentmanager.cxx | 552 +++ dbaccess/source/ui/app/subcomponentmanager.hxx | 120 + dbaccess/source/ui/app/templwin.cxx | 35 + dbaccess/source/ui/app/templwin.hxx | 28 + dbaccess/source/ui/app/window_layout.txt | 49 + dbaccess/source/ui/browser/AsynchronousLink.cxx | 81 + dbaccess/source/ui/browser/brwctrlr.cxx | 2616 ++++++++++++++ dbaccess/source/ui/browser/brwview.cxx | 333 ++ dbaccess/source/ui/browser/dataview.cxx | 154 + dbaccess/source/ui/browser/dbexchange.cxx | 251 ++ dbaccess/source/ui/browser/dbloader.cxx | 268 ++ dbaccess/source/ui/browser/dbtreemodel.cxx | 33 + dbaccess/source/ui/browser/dbtreemodel.hxx | 54 + dbaccess/source/ui/browser/dsEntriesNoExp.cxx | 154 + dbaccess/source/ui/browser/dsbrowserDnD.cxx | 258 ++ dbaccess/source/ui/browser/exsrcbrw.cxx | 413 +++ dbaccess/source/ui/browser/formadapter.cxx | 1879 ++++++++++ dbaccess/source/ui/browser/genericcontroller.cxx | 1176 ++++++ dbaccess/source/ui/browser/sbagrid.cxx | 1367 +++++++ dbaccess/source/ui/browser/sbamultiplex.cxx | 528 +++ dbaccess/source/ui/browser/unodatbr.cxx | 3819 ++++++++++++++++++++ dbaccess/source/ui/control/ColumnControlWindow.cxx | 182 + dbaccess/source/ui/control/FieldControls.cxx | 60 + dbaccess/source/ui/control/FieldDescControl.cxx | 1385 +++++++ dbaccess/source/ui/control/RelationControl.cxx | 695 ++++ dbaccess/source/ui/control/SqlNameEdit.cxx | 85 + dbaccess/source/ui/control/TableGrantCtrl.cxx | 476 +++ dbaccess/source/ui/control/charsetlistbox.cxx | 69 + dbaccess/source/ui/control/curledit.cxx | 89 + dbaccess/source/ui/control/dbtreelistbox.cxx | 513 +++ dbaccess/source/ui/control/opendoccontrols.cxx | 194 + dbaccess/source/ui/control/sqledit.cxx | 515 +++ dbaccess/source/ui/control/tabletree.cxx | 707 ++++ dbaccess/source/ui/control/undosqledit.cxx | 34 + dbaccess/source/ui/dlg/CollectionView.cxx | 317 ++ dbaccess/source/ui/dlg/ConnectionHelper.cxx | 720 ++++ dbaccess/source/ui/dlg/ConnectionHelper.hxx | 103 + dbaccess/source/ui/dlg/ConnectionPage.cxx | 284 ++ dbaccess/source/ui/dlg/ConnectionPage.hxx | 72 + dbaccess/source/ui/dlg/ConnectionPageSetup.cxx | 153 + dbaccess/source/ui/dlg/ConnectionPageSetup.hxx | 63 + dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx | 912 +++++ dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx | 308 ++ dbaccess/source/ui/dlg/DbAdminImpl.cxx | 1110 ++++++ dbaccess/source/ui/dlg/DbAdminImpl.hxx | 167 + dbaccess/source/ui/dlg/DriverSettings.hxx | 78 + dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx | 60 + dbaccess/source/ui/dlg/RelationDlg.cxx | 215 ++ dbaccess/source/ui/dlg/TablesSingleDlg.cxx | 105 + dbaccess/source/ui/dlg/TextConnectionHelper.cxx | 397 ++ dbaccess/source/ui/dlg/TextConnectionHelper.hxx | 89 + dbaccess/source/ui/dlg/UserAdmin.cxx | 316 ++ dbaccess/source/ui/dlg/UserAdmin.hxx | 72 + dbaccess/source/ui/dlg/UserAdminDlg.cxx | 162 + dbaccess/source/ui/dlg/admincontrols.cxx | 201 ++ dbaccess/source/ui/dlg/admincontrols.hxx | 65 + dbaccess/source/ui/dlg/adminpages.cxx | 278 ++ dbaccess/source/ui/dlg/adminpages.hxx | 236 ++ dbaccess/source/ui/dlg/adodatalinks.cxx | 141 + dbaccess/source/ui/dlg/adodatalinks.hxx | 26 + dbaccess/source/ui/dlg/adtabdlg.cxx | 466 +++ dbaccess/source/ui/dlg/advancedsettings.cxx | 470 +++ dbaccess/source/ui/dlg/advancedsettings.hxx | 114 + dbaccess/source/ui/dlg/dbadmin.cxx | 436 +++ dbaccess/source/ui/dlg/dbfindex.cxx | 428 +++ dbaccess/source/ui/dlg/dbfindex.hxx | 111 + dbaccess/source/ui/dlg/dbwiz.cxx | 336 ++ dbaccess/source/ui/dlg/dbwizsetup.cxx | 1004 +++++ dbaccess/source/ui/dlg/detailpages.cxx | 717 ++++ dbaccess/source/ui/dlg/detailpages.hxx | 247 ++ dbaccess/source/ui/dlg/directsql.cxx | 456 +++ dbaccess/source/ui/dlg/dlgattr.cxx | 60 + dbaccess/source/ui/dlg/dlgsave.cxx | 289 ++ dbaccess/source/ui/dlg/dlgsize.cxx | 83 + dbaccess/source/ui/dlg/dsnItem.hxx | 48 + dbaccess/source/ui/dlg/dsselect.cxx | 130 + dbaccess/source/ui/dlg/dsselect.hxx | 58 + dbaccess/source/ui/dlg/finteraction.cxx | 59 + dbaccess/source/ui/dlg/finteraction.hxx | 54 + dbaccess/source/ui/dlg/generalpage.cxx | 700 ++++ dbaccess/source/ui/dlg/generalpage.hxx | 188 + dbaccess/source/ui/dlg/indexdialog.cxx | 707 ++++ dbaccess/source/ui/dlg/indexfieldscontrol.cxx | 447 +++ dbaccess/source/ui/dlg/odbcconfig.cxx | 325 ++ dbaccess/source/ui/dlg/odbcconfig.hxx | 106 + dbaccess/source/ui/dlg/optionalboolitem.cxx | 44 + dbaccess/source/ui/dlg/optionalboolitem.hxx | 51 + dbaccess/source/ui/dlg/paramdialog.cxx | 334 ++ dbaccess/source/ui/dlg/queryfilter.cxx | 748 ++++ dbaccess/source/ui/dlg/queryorder.cxx | 218 ++ dbaccess/source/ui/dlg/sqlmessage.cxx | 604 ++++ dbaccess/source/ui/dlg/tablespage.cxx | 488 +++ dbaccess/source/ui/dlg/tablespage.hxx | 81 + dbaccess/source/ui/dlg/textconnectionsettings.cxx | 69 + dbaccess/source/ui/inc/AppElementType.hxx | 53 + dbaccess/source/ui/inc/ChildWindow.hxx | 38 + dbaccess/source/ui/inc/CollectionView.hxx | 65 + dbaccess/source/ui/inc/ColumnControlWindow.hxx | 82 + dbaccess/source/ui/inc/ConnectionLine.hxx | 71 + dbaccess/source/ui/inc/ConnectionLineAccess.hxx | 76 + dbaccess/source/ui/inc/ConnectionLineData.hxx | 80 + dbaccess/source/ui/inc/DExport.hxx | 162 + dbaccess/source/ui/inc/FieldControls.hxx | 120 + dbaccess/source/ui/inc/FieldDescControl.hxx | 201 ++ dbaccess/source/ui/inc/FieldDescriptions.hxx | 111 + dbaccess/source/ui/inc/GeneralUndo.hxx | 40 + dbaccess/source/ui/inc/HtmlReader.hxx | 68 + dbaccess/source/ui/inc/IClipBoardTest.hxx | 40 + dbaccess/source/ui/inc/IItemSetHelper.hxx | 72 + dbaccess/source/ui/inc/IUpdateHelper.hxx | 44 + dbaccess/source/ui/inc/JAccess.hxx | 64 + dbaccess/source/ui/inc/JoinController.hxx | 154 + dbaccess/source/ui/inc/JoinDesignView.hxx | 68 + dbaccess/source/ui/inc/JoinExchange.hxx | 62 + dbaccess/source/ui/inc/JoinTableView.hxx | 325 ++ dbaccess/source/ui/inc/QEnumTypes.hxx | 79 + dbaccess/source/ui/inc/QueryDesignView.hxx | 154 + dbaccess/source/ui/inc/QueryPropertiesDialog.hxx | 45 + dbaccess/source/ui/inc/QueryTableView.hxx | 116 + dbaccess/source/ui/inc/QueryTextView.hxx | 69 + dbaccess/source/ui/inc/QueryViewSwitch.hxx | 94 + dbaccess/source/ui/inc/RTableConnectionData.hxx | 79 + dbaccess/source/ui/inc/RelControliFace.hxx | 40 + dbaccess/source/ui/inc/RelationControl.hxx | 91 + dbaccess/source/ui/inc/RelationController.hxx | 79 + dbaccess/source/ui/inc/RelationDesignView.hxx | 45 + dbaccess/source/ui/inc/RelationDlg.hxx | 74 + dbaccess/source/ui/inc/RelationTableView.hxx | 74 + dbaccess/source/ui/inc/RtfReader.hxx | 59 + dbaccess/source/ui/inc/SqlNameEdit.hxx | 122 + dbaccess/source/ui/inc/TableConnection.hxx | 98 + dbaccess/source/ui/inc/TableConnectionData.hxx | 101 + dbaccess/source/ui/inc/TableController.hxx | 129 + dbaccess/source/ui/inc/TableCopyHelper.hxx | 188 + dbaccess/source/ui/inc/TableDesignControl.hxx | 78 + dbaccess/source/ui/inc/TableDesignHelpBar.hxx | 59 + dbaccess/source/ui/inc/TableDesignView.hxx | 112 + dbaccess/source/ui/inc/TableFieldDescription.hxx | 150 + dbaccess/source/ui/inc/TableGrantCtrl.hxx | 104 + dbaccess/source/ui/inc/TableRow.hxx | 76 + dbaccess/source/ui/inc/TableRowExchange.hxx | 40 + dbaccess/source/ui/inc/TableWindow.hxx | 183 + dbaccess/source/ui/inc/TableWindowAccess.hxx | 79 + dbaccess/source/ui/inc/TableWindowData.hxx | 95 + dbaccess/source/ui/inc/TableWindowListBox.hxx | 121 + dbaccess/source/ui/inc/TableWindowTitle.hxx | 44 + dbaccess/source/ui/inc/TablesSingleDlg.hxx | 71 + dbaccess/source/ui/inc/TokenWriter.hxx | 206 ++ dbaccess/source/ui/inc/TypeInfo.hxx | 121 + dbaccess/source/ui/inc/UITools.hxx | 396 ++ dbaccess/source/ui/inc/UserAdminDlg.hxx | 76 + dbaccess/source/ui/inc/WCPage.hxx | 78 + dbaccess/source/ui/inc/WColumnSelect.hxx | 82 + dbaccess/source/ui/inc/WCopyTable.hxx | 413 +++ dbaccess/source/ui/inc/WExtendPages.hxx | 69 + dbaccess/source/ui/inc/WNameMatch.hxx | 63 + dbaccess/source/ui/inc/WTabPage.hxx | 46 + dbaccess/source/ui/inc/WTypeSelect.hxx | 138 + dbaccess/source/ui/inc/adtabdlg.hxx | 98 + dbaccess/source/ui/inc/advancedsettingsdlg.hxx | 70 + dbaccess/source/ui/inc/asyncmodaldialog.hxx | 47 + dbaccess/source/ui/inc/browserids.hxx | 98 + dbaccess/source/ui/inc/brwctrlr.hxx | 332 ++ dbaccess/source/ui/inc/brwview.hxx | 96 + dbaccess/source/ui/inc/callbacks.hxx | 123 + dbaccess/source/ui/inc/charsetlistbox.hxx | 50 + dbaccess/source/ui/inc/charsets.hxx | 105 + dbaccess/source/ui/inc/commontypes.hxx | 39 + dbaccess/source/ui/inc/curledit.hxx | 102 + dbaccess/source/ui/inc/databaseobjectview.hxx | 230 ++ dbaccess/source/ui/inc/datasourceconnector.hxx | 76 + dbaccess/source/ui/inc/dbadmin.hxx | 114 + dbaccess/source/ui/inc/dbexchange.hxx | 83 + dbaccess/source/ui/inc/dbtreelistbox.hxx | 164 + dbaccess/source/ui/inc/dbu_dlg.hxx | 24 + dbaccess/source/ui/inc/dbwiz.hxx | 100 + dbaccess/source/ui/inc/dbwizsetup.hxx | 170 + dbaccess/source/ui/inc/defaultobjectnamecheck.hxx | 121 + dbaccess/source/ui/inc/directsql.hxx | 113 + dbaccess/source/ui/inc/dlgattr.hxx | 41 + dbaccess/source/ui/inc/dlgsave.hxx | 100 + dbaccess/source/ui/inc/dlgsize.hxx | 44 + dbaccess/source/ui/inc/dsitems.hxx | 102 + dbaccess/source/ui/inc/dsmeta.hxx | 124 + dbaccess/source/ui/inc/exsrcbrw.hxx | 96 + dbaccess/source/ui/inc/formadapter.hxx | 436 +++ dbaccess/source/ui/inc/imageprovider.hxx | 107 + dbaccess/source/ui/inc/indexcollection.hxx | 93 + dbaccess/source/ui/inc/indexdialog.hxx | 103 + dbaccess/source/ui/inc/indexes.hxx | 81 + dbaccess/source/ui/inc/indexfieldscontrol.hxx | 91 + dbaccess/source/ui/inc/linkeddocuments.hxx | 108 + dbaccess/source/ui/inc/objectnamecheck.hxx | 57 + dbaccess/source/ui/inc/opendoccontrols.hxx | 78 + dbaccess/source/ui/inc/paramdialog.hxx | 103 + dbaccess/source/ui/inc/propertystorage.hxx | 54 + dbaccess/source/ui/inc/querycontainerwindow.hxx | 104 + dbaccess/source/ui/inc/querycontroller.hxx | 217 ++ dbaccess/source/ui/inc/queryfilter.hxx | 109 + dbaccess/source/ui/inc/queryorder.hxx | 81 + dbaccess/source/ui/inc/sbagrid.hrc | 37 + dbaccess/source/ui/inc/sbagrid.hxx | 291 ++ dbaccess/source/ui/inc/sbamultiplex.hxx | 305 ++ dbaccess/source/ui/inc/singledoccontroller.hxx | 78 + dbaccess/source/ui/inc/sqledit.hxx | 100 + dbaccess/source/ui/inc/sqlmessage.hxx | 145 + dbaccess/source/ui/inc/stringlistitem.hxx | 48 + dbaccess/source/ui/inc/tabletree.hxx | 155 + dbaccess/source/ui/inc/textconnectionsettings.hxx | 59 + dbaccess/source/ui/inc/undosqledit.hxx | 45 + dbaccess/source/ui/inc/unoadmin.hxx | 59 + dbaccess/source/ui/inc/unodatbr.hxx | 448 +++ dbaccess/source/ui/inc/unosqlmessage.hxx | 68 + dbaccess/source/ui/misc/DExport.cxx | 839 +++++ dbaccess/source/ui/misc/HtmlReader.cxx | 481 +++ dbaccess/source/ui/misc/RowSetDrop.cxx | 247 ++ dbaccess/source/ui/misc/RtfReader.cxx | 309 ++ dbaccess/source/ui/misc/TableCopyHelper.cxx | 306 ++ dbaccess/source/ui/misc/TokenWriter.cxx | 967 +++++ dbaccess/source/ui/misc/UITools.cxx | 1371 +++++++ dbaccess/source/ui/misc/UpdateHelperImpl.hxx | 74 + dbaccess/source/ui/misc/WCPage.cxx | 325 ++ dbaccess/source/ui/misc/WColumnSelect.cxx | 403 +++ dbaccess/source/ui/misc/WCopyTable.cxx | 1553 ++++++++ dbaccess/source/ui/misc/WExtendPages.cxx | 62 + dbaccess/source/ui/misc/WNameMatch.cxx | 330 ++ dbaccess/source/ui/misc/WTypeSelect.cxx | 416 +++ dbaccess/source/ui/misc/asyncmodaldialog.cxx | 91 + dbaccess/source/ui/misc/charsets.cxx | 131 + dbaccess/source/ui/misc/controllerframe.cxx | 389 ++ dbaccess/source/ui/misc/databaseobjectview.cxx | 281 ++ dbaccess/source/ui/misc/datasourceconnector.cxx | 199 + dbaccess/source/ui/misc/dbaundomanager.cxx | 324 ++ .../source/ui/misc/dbsubcomponentcontroller.cxx | 605 ++++ dbaccess/source/ui/misc/defaultobjectnamecheck.cxx | 140 + dbaccess/source/ui/misc/dsmeta.cxx | 165 + dbaccess/source/ui/misc/imageprovider.cxx | 192 + dbaccess/source/ui/misc/indexcollection.cxx | 328 ++ dbaccess/source/ui/misc/linkeddocuments.cxx | 350 ++ dbaccess/source/ui/misc/propertystorage.cxx | 106 + dbaccess/source/ui/misc/singledoccontroller.cxx | 172 + dbaccess/source/ui/misc/stringlistitem.cxx | 62 + dbaccess/source/ui/querydesign/ConnectionLine.cxx | 357 ++ .../source/ui/querydesign/ConnectionLineAccess.cxx | 177 + .../source/ui/querydesign/ConnectionLineData.cxx | 77 + dbaccess/source/ui/querydesign/JAccess.cxx | 87 + dbaccess/source/ui/querydesign/JoinController.cxx | 406 +++ dbaccess/source/ui/querydesign/JoinDesignView.cxx | 100 + dbaccess/source/ui/querydesign/JoinExchange.cxx | 114 + dbaccess/source/ui/querydesign/JoinTableView.cxx | 1567 ++++++++ .../source/ui/querydesign/QTableConnection.cxx | 73 + .../source/ui/querydesign/QTableConnection.hxx | 46 + .../source/ui/querydesign/QTableConnectionData.cxx | 112 + .../source/ui/querydesign/QTableConnectionData.hxx | 67 + dbaccess/source/ui/querydesign/QTableWindow.cxx | 175 + dbaccess/source/ui/querydesign/QTableWindow.hxx | 76 + .../source/ui/querydesign/QTableWindowData.cxx | 34 + .../source/ui/querydesign/QTableWindowData.hxx | 38 + .../ui/querydesign/QueryAddTabConnUndoAction.hxx | 49 + .../ui/querydesign/QueryDesignFieldUndoAct.hxx | 138 + .../ui/querydesign/QueryDesignUndoAction.hxx | 39 + dbaccess/source/ui/querydesign/QueryDesignView.cxx | 3433 ++++++++++++++++++ .../ui/querydesign/QueryMoveTabWinUndoAct.cxx | 40 + .../ui/querydesign/QueryMoveTabWinUndoAct.hxx | 54 + .../ui/querydesign/QuerySizeTabWinUndoAct.hxx | 70 + .../ui/querydesign/QueryTabConnUndoAction.cxx | 117 + .../ui/querydesign/QueryTabConnUndoAction.hxx | 50 + .../ui/querydesign/QueryTabWinShowUndoAct.hxx | 51 + .../source/ui/querydesign/QueryTabWinUndoAct.cxx | 112 + .../source/ui/querydesign/QueryTabWinUndoAct.hxx | 61 + dbaccess/source/ui/querydesign/QueryTableView.cxx | 885 +++++ dbaccess/source/ui/querydesign/QueryTextView.cxx | 177 + dbaccess/source/ui/querydesign/QueryViewSwitch.cxx | 292 ++ .../source/ui/querydesign/SelectionBrowseBox.cxx | 2720 ++++++++++++++ .../source/ui/querydesign/SelectionBrowseBox.hxx | 324 ++ dbaccess/source/ui/querydesign/TableConnection.cxx | 191 + .../source/ui/querydesign/TableConnectionData.cxx | 148 + .../ui/querydesign/TableFieldDescription.cxx | 196 + dbaccess/source/ui/querydesign/TableFieldInfo.cxx | 30 + dbaccess/source/ui/querydesign/TableFieldInfo.hxx | 43 + dbaccess/source/ui/querydesign/TableWindow.cxx | 717 ++++ .../source/ui/querydesign/TableWindowAccess.cxx | 240 ++ dbaccess/source/ui/querydesign/TableWindowData.cxx | 136 + .../source/ui/querydesign/TableWindowListBox.cxx | 292 ++ .../source/ui/querydesign/TableWindowTitle.cxx | 97 + dbaccess/source/ui/querydesign/class.jpg | Bin 0 -> 224242 bytes .../source/ui/querydesign/limitboxcontroller.cxx | 301 ++ .../source/ui/querydesign/limitboxcontroller.hxx | 60 + .../source/ui/querydesign/querycontainerwindow.cxx | 222 ++ dbaccess/source/ui/querydesign/querycontroller.cxx | 1790 +++++++++ dbaccess/source/ui/querydesign/querydlg.cxx | 309 ++ dbaccess/source/ui/querydesign/querydlg.hxx | 77 + .../source/ui/relationdesign/RTableConnection.cxx | 117 + .../source/ui/relationdesign/RTableConnection.hxx | 40 + .../ui/relationdesign/RTableConnectionData.cxx | 396 ++ dbaccess/source/ui/relationdesign/RTableWindow.hxx | 40 + .../ui/relationdesign/RelationController.cxx | 548 +++ .../ui/relationdesign/RelationDesignView.cxx | 74 + .../source/ui/relationdesign/RelationTableView.cxx | 410 +++ .../source/ui/tabledesign/FieldDescriptions.cxx | 642 ++++ dbaccess/source/ui/tabledesign/TEditControl.cxx | 1693 +++++++++ dbaccess/source/ui/tabledesign/TEditControl.hxx | 204 ++ dbaccess/source/ui/tabledesign/TableController.cxx | 1491 ++++++++ .../source/ui/tabledesign/TableDesignControl.cxx | 172 + .../source/ui/tabledesign/TableDesignHelpBar.cxx | 62 + dbaccess/source/ui/tabledesign/TableDesignView.cxx | 259 ++ .../source/ui/tabledesign/TableFieldControl.cxx | 154 + .../source/ui/tabledesign/TableFieldControl.hxx | 66 + .../source/ui/tabledesign/TableFieldDescWin.cxx | 140 + .../source/ui/tabledesign/TableFieldDescWin.hxx | 91 + dbaccess/source/ui/tabledesign/TableRow.cxx | 183 + .../source/ui/tabledesign/TableRowExchange.cxx | 67 + dbaccess/source/ui/tabledesign/TableUndo.cxx | 353 ++ dbaccess/source/ui/tabledesign/TableUndo.hxx | 136 + dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx | 117 + dbaccess/source/ui/uno/ColumnControl.cxx | 146 + dbaccess/source/ui/uno/ColumnControl.hxx | 46 + dbaccess/source/ui/uno/ColumnModel.cxx | 180 + dbaccess/source/ui/uno/ColumnModel.hxx | 97 + dbaccess/source/ui/uno/ColumnPeer.cxx | 148 + dbaccess/source/ui/uno/ColumnPeer.hxx | 47 + dbaccess/source/ui/uno/DBTypeWizDlg.cxx | 85 + dbaccess/source/ui/uno/DBTypeWizDlg.hxx | 56 + dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx | 104 + dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx | 59 + dbaccess/source/ui/uno/TableFilterDlg.cxx | 85 + dbaccess/source/ui/uno/TableFilterDlg.hxx | 57 + dbaccess/source/ui/uno/UserSettingsDlg.cxx | 85 + dbaccess/source/ui/uno/UserSettingsDlg.hxx | 57 + dbaccess/source/ui/uno/admindlg.cxx | 92 + dbaccess/source/ui/uno/admindlg.hxx | 56 + dbaccess/source/ui/uno/composerdialogs.cxx | 270 ++ dbaccess/source/ui/uno/composerdialogs.hxx | 123 + dbaccess/source/ui/uno/copytablewizard.cxx | 1576 ++++++++ dbaccess/source/ui/uno/dbinteraction.cxx | 387 ++ dbaccess/source/ui/uno/dbinteraction.hxx | 168 + .../source/ui/uno/textconnectionsettings_uno.cxx | 268 ++ dbaccess/source/ui/uno/unoDirectSql.cxx | 149 + dbaccess/source/ui/uno/unoDirectSql.hxx | 61 + dbaccess/source/ui/uno/unoadmin.cxx | 71 + dbaccess/source/ui/uno/unosqlmessage.cxx | 144 + 596 files changed, 158447 insertions(+) create mode 100644 dbaccess/source/core/api/BookmarkSet.cxx create mode 100644 dbaccess/source/core/api/BookmarkSet.hxx create mode 100644 dbaccess/source/core/api/CIndexes.cxx create mode 100644 dbaccess/source/core/api/CIndexes.hxx create mode 100644 dbaccess/source/core/api/CRowSetColumn.cxx create mode 100644 dbaccess/source/core/api/CRowSetColumn.hxx create mode 100644 dbaccess/source/core/api/CRowSetDataColumn.cxx create mode 100644 dbaccess/source/core/api/CRowSetDataColumn.hxx create mode 100644 dbaccess/source/core/api/CacheSet.cxx create mode 100644 dbaccess/source/core/api/CacheSet.hxx create mode 100644 dbaccess/source/core/api/FilteredContainer.cxx create mode 100644 dbaccess/source/core/api/HelperCollections.cxx create mode 100644 dbaccess/source/core/api/HelperCollections.hxx create mode 100644 dbaccess/source/core/api/KeySet.cxx create mode 100644 dbaccess/source/core/api/KeySet.hxx create mode 100644 dbaccess/source/core/api/OptimisticSet.cxx create mode 100644 dbaccess/source/core/api/OptimisticSet.hxx create mode 100644 dbaccess/source/core/api/PrivateRow.cxx create mode 100644 dbaccess/source/core/api/PrivateRow.hxx create mode 100644 dbaccess/source/core/api/RowSet.cxx create mode 100644 dbaccess/source/core/api/RowSet.hxx create mode 100644 dbaccess/source/core/api/RowSetBase.cxx create mode 100644 dbaccess/source/core/api/RowSetBase.hxx create mode 100644 dbaccess/source/core/api/RowSetCache.cxx create mode 100644 dbaccess/source/core/api/RowSetCache.hxx create mode 100644 dbaccess/source/core/api/RowSetCacheIterator.cxx create mode 100644 dbaccess/source/core/api/RowSetCacheIterator.hxx create mode 100644 dbaccess/source/core/api/RowSetRow.hxx create mode 100644 dbaccess/source/core/api/SingleSelectQueryComposer.cxx create mode 100644 dbaccess/source/core/api/StaticSet.cxx create mode 100644 dbaccess/source/core/api/StaticSet.hxx create mode 100644 dbaccess/source/core/api/TableDeco.cxx create mode 100644 dbaccess/source/core/api/View.cxx create mode 100644 dbaccess/source/core/api/WrappedResultSet.cxx create mode 100644 dbaccess/source/core/api/WrappedResultSet.hxx create mode 100644 dbaccess/source/core/api/callablestatement.cxx create mode 100644 dbaccess/source/core/api/column.cxx create mode 100644 dbaccess/source/core/api/columnsettings.cxx create mode 100644 dbaccess/source/core/api/datacolumn.cxx create mode 100644 dbaccess/source/core/api/datacolumn.hxx create mode 100644 dbaccess/source/core/api/datasettings.cxx create mode 100644 dbaccess/source/core/api/definitioncolumn.cxx create mode 100644 dbaccess/source/core/api/preparedstatement.cxx create mode 100644 dbaccess/source/core/api/query.cxx create mode 100644 dbaccess/source/core/api/query.hxx create mode 100644 dbaccess/source/core/api/querycomposer.cxx create mode 100644 dbaccess/source/core/api/querycontainer.cxx create mode 100644 dbaccess/source/core/api/querydescriptor.cxx create mode 100644 dbaccess/source/core/api/querydescriptor.hxx create mode 100644 dbaccess/source/core/api/resultcolumn.cxx create mode 100644 dbaccess/source/core/api/resultcolumn.hxx create mode 100644 dbaccess/source/core/api/resultset.cxx create mode 100644 dbaccess/source/core/api/resultset.hxx create mode 100644 dbaccess/source/core/api/statement.cxx create mode 100644 dbaccess/source/core/api/table.cxx create mode 100644 dbaccess/source/core/api/tablecontainer.cxx create mode 100644 dbaccess/source/core/api/viewcontainer.cxx create mode 100644 dbaccess/source/core/dataaccess/ComponentDefinition.cxx create mode 100644 dbaccess/source/core/dataaccess/ComponentDefinition.hxx create mode 100644 dbaccess/source/core/dataaccess/ContentHelper.cxx create mode 100644 dbaccess/source/core/dataaccess/ModelImpl.cxx create mode 100644 dbaccess/source/core/dataaccess/SharedConnection.cxx create mode 100644 dbaccess/source/core/dataaccess/SharedConnection.hxx create mode 100644 dbaccess/source/core/dataaccess/bookmarkcontainer.cxx create mode 100644 dbaccess/source/core/dataaccess/commandcontainer.cxx create mode 100644 dbaccess/source/core/dataaccess/commandcontainer.hxx create mode 100644 dbaccess/source/core/dataaccess/commanddefinition.cxx create mode 100644 dbaccess/source/core/dataaccess/commanddefinition.hxx create mode 100644 dbaccess/source/core/dataaccess/connection.cxx create mode 100644 dbaccess/source/core/dataaccess/connection.hxx create mode 100644 dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx create mode 100644 dbaccess/source/core/dataaccess/databasecontext.cxx create mode 100644 dbaccess/source/core/dataaccess/databasedocument.cxx create mode 100644 dbaccess/source/core/dataaccess/databasedocument.hxx create mode 100644 dbaccess/source/core/dataaccess/databaseregistrations.cxx create mode 100644 dbaccess/source/core/dataaccess/databaseregistrations.hxx create mode 100644 dbaccess/source/core/dataaccess/datasource.cxx create mode 100644 dbaccess/source/core/dataaccess/datasource.hxx create mode 100644 dbaccess/source/core/dataaccess/definitioncontainer.cxx create mode 100644 dbaccess/source/core/dataaccess/documentcontainer.cxx create mode 100644 dbaccess/source/core/dataaccess/documentcontainer.hxx create mode 100644 dbaccess/source/core/dataaccess/documentdefinition.cxx create mode 100644 dbaccess/source/core/dataaccess/documentdefinition.hxx create mode 100644 dbaccess/source/core/dataaccess/documenteventexecutor.cxx create mode 100644 dbaccess/source/core/dataaccess/documenteventexecutor.hxx create mode 100644 dbaccess/source/core/dataaccess/documenteventnotifier.cxx create mode 100644 dbaccess/source/core/dataaccess/documenteventnotifier.hxx create mode 100644 dbaccess/source/core/dataaccess/documentevents.cxx create mode 100644 dbaccess/source/core/dataaccess/intercept.cxx create mode 100644 dbaccess/source/core/dataaccess/intercept.hxx create mode 100644 dbaccess/source/core/dataaccess/myucp_datasupplier.cxx create mode 100644 dbaccess/source/core/dataaccess/myucp_datasupplier.hxx create mode 100644 dbaccess/source/core/dataaccess/myucp_resultset.cxx create mode 100644 dbaccess/source/core/dataaccess/myucp_resultset.hxx create mode 100644 dbaccess/source/core/inc/ContainerMediator.hxx create mode 100644 dbaccess/source/core/inc/ContentHelper.hxx create mode 100644 dbaccess/source/core/inc/DatabaseDataProvider.hxx create mode 100644 dbaccess/source/core/inc/FilteredContainer.hxx create mode 100644 dbaccess/source/core/inc/ModelImpl.hxx create mode 100644 dbaccess/source/core/inc/PropertyForward.hxx create mode 100644 dbaccess/source/core/inc/RefreshListener.hxx create mode 100644 dbaccess/source/core/inc/SingleSelectQueryComposer.hxx create mode 100644 dbaccess/source/core/inc/TableDeco.hxx create mode 100644 dbaccess/source/core/inc/View.hxx create mode 100644 dbaccess/source/core/inc/bookmarkcontainer.hxx create mode 100644 dbaccess/source/core/inc/callablestatement.hxx create mode 100644 dbaccess/source/core/inc/column.hxx create mode 100644 dbaccess/source/core/inc/columnsettings.hxx create mode 100644 dbaccess/source/core/inc/commandbase.hxx create mode 100644 dbaccess/source/core/inc/composertools.hxx create mode 100644 dbaccess/source/core/inc/containerapprove.hxx create mode 100644 dbaccess/source/core/inc/databasecontext.hxx create mode 100644 dbaccess/source/core/inc/datasettings.hxx create mode 100644 dbaccess/source/core/inc/definitioncolumn.hxx create mode 100644 dbaccess/source/core/inc/definitioncontainer.hxx create mode 100644 dbaccess/source/core/inc/documentevents.hxx create mode 100644 dbaccess/source/core/inc/migrwarndlg.hxx create mode 100644 dbaccess/source/core/inc/objectnameapproval.hxx create mode 100644 dbaccess/source/core/inc/preparedstatement.hxx create mode 100644 dbaccess/source/core/inc/querycomposer.hxx create mode 100644 dbaccess/source/core/inc/querycontainer.hxx create mode 100644 dbaccess/source/core/inc/recovery/dbdocrecovery.hxx create mode 100644 dbaccess/source/core/inc/sdbcoretools.hxx create mode 100644 dbaccess/source/core/inc/statement.hxx create mode 100644 dbaccess/source/core/inc/table.hxx create mode 100644 dbaccess/source/core/inc/tablecontainer.hxx create mode 100644 dbaccess/source/core/inc/veto.hxx create mode 100644 dbaccess/source/core/inc/viewcontainer.hxx create mode 100644 dbaccess/source/core/misc/ContainerMediator.cxx create mode 100644 dbaccess/source/core/misc/DatabaseDataProvider.cxx create mode 100644 dbaccess/source/core/misc/PropertyForward.cxx create mode 100644 dbaccess/source/core/misc/apitools.cxx create mode 100644 dbaccess/source/core/misc/dsntypes.cxx create mode 100644 dbaccess/source/core/misc/migrwarndlg.cxx create mode 100644 dbaccess/source/core/misc/objectnameapproval.cxx create mode 100644 dbaccess/source/core/misc/sdbcoretools.cxx create mode 100644 dbaccess/source/core/misc/veto.cxx create mode 100644 dbaccess/source/core/recovery/dbdocrecovery.cxx create mode 100644 dbaccess/source/core/recovery/settingsimport.cxx create mode 100644 dbaccess/source/core/recovery/settingsimport.hxx create mode 100644 dbaccess/source/core/recovery/storagestream.cxx create mode 100644 dbaccess/source/core/recovery/storagestream.hxx create mode 100644 dbaccess/source/core/recovery/storagetextstream.cxx create mode 100644 dbaccess/source/core/recovery/storagetextstream.hxx create mode 100644 dbaccess/source/core/recovery/storagexmlstream.cxx create mode 100644 dbaccess/source/core/recovery/storagexmlstream.hxx create mode 100644 dbaccess/source/core/recovery/subcomponentloader.cxx create mode 100644 dbaccess/source/core/recovery/subcomponentloader.hxx create mode 100644 dbaccess/source/core/recovery/subcomponentrecovery.cxx create mode 100644 dbaccess/source/core/recovery/subcomponentrecovery.hxx create mode 100644 dbaccess/source/core/recovery/subcomponents.hxx create mode 100644 dbaccess/source/core/resource/core_resource.cxx create mode 100644 dbaccess/source/filter/hsqldb/alterparser.cxx create mode 100644 dbaccess/source/filter/hsqldb/alterparser.hxx create mode 100644 dbaccess/source/filter/hsqldb/columndef.cxx create mode 100644 dbaccess/source/filter/hsqldb/columndef.hxx create mode 100644 dbaccess/source/filter/hsqldb/createparser.cxx create mode 100644 dbaccess/source/filter/hsqldb/createparser.hxx create mode 100644 dbaccess/source/filter/hsqldb/fbalterparser.cxx create mode 100644 dbaccess/source/filter/hsqldb/fbalterparser.hxx create mode 100644 dbaccess/source/filter/hsqldb/fbcreateparser.cxx create mode 100644 dbaccess/source/filter/hsqldb/fbcreateparser.hxx create mode 100644 dbaccess/source/filter/hsqldb/hsqlbinarynode.cxx create mode 100644 dbaccess/source/filter/hsqldb/hsqlbinarynode.hxx create mode 100644 dbaccess/source/filter/hsqldb/hsqlimport.cxx create mode 100644 dbaccess/source/filter/hsqldb/hsqlimport.hxx create mode 100644 dbaccess/source/filter/hsqldb/parseschema.cxx create mode 100644 dbaccess/source/filter/hsqldb/parseschema.hxx create mode 100644 dbaccess/source/filter/hsqldb/rowinputbinary.cxx create mode 100644 dbaccess/source/filter/hsqldb/rowinputbinary.hxx create mode 100644 dbaccess/source/filter/hsqldb/utils.cxx create mode 100644 dbaccess/source/filter/hsqldb/utils.hxx create mode 100644 dbaccess/source/filter/xml/dbaxml.component create mode 100644 dbaccess/source/filter/xml/dbloader2.cxx create mode 100644 dbaccess/source/filter/xml/xmlAutoStyle.cxx create mode 100644 dbaccess/source/filter/xml/xmlAutoStyle.hxx create mode 100644 dbaccess/source/filter/xml/xmlColumn.cxx create mode 100644 dbaccess/source/filter/xml/xmlColumn.hxx create mode 100644 dbaccess/source/filter/xml/xmlComponent.cxx create mode 100644 dbaccess/source/filter/xml/xmlComponent.hxx create mode 100644 dbaccess/source/filter/xml/xmlConnectionData.cxx create mode 100644 dbaccess/source/filter/xml/xmlConnectionData.hxx create mode 100644 dbaccess/source/filter/xml/xmlConnectionResource.cxx create mode 100644 dbaccess/source/filter/xml/xmlConnectionResource.hxx create mode 100644 dbaccess/source/filter/xml/xmlDataSource.cxx create mode 100644 dbaccess/source/filter/xml/xmlDataSource.hxx create mode 100644 dbaccess/source/filter/xml/xmlDataSourceInfo.cxx create mode 100644 dbaccess/source/filter/xml/xmlDataSourceInfo.hxx create mode 100644 dbaccess/source/filter/xml/xmlDataSourceSetting.cxx create mode 100644 dbaccess/source/filter/xml/xmlDataSourceSetting.hxx create mode 100644 dbaccess/source/filter/xml/xmlDataSourceSettings.cxx create mode 100644 dbaccess/source/filter/xml/xmlDataSourceSettings.hxx create mode 100644 dbaccess/source/filter/xml/xmlDatabase.cxx create mode 100644 dbaccess/source/filter/xml/xmlDatabase.hxx create mode 100644 dbaccess/source/filter/xml/xmlDatabaseDescription.cxx create mode 100644 dbaccess/source/filter/xml/xmlDatabaseDescription.hxx create mode 100644 dbaccess/source/filter/xml/xmlDocuments.cxx create mode 100644 dbaccess/source/filter/xml/xmlDocuments.hxx create mode 100644 dbaccess/source/filter/xml/xmlEnums.hxx create mode 100644 dbaccess/source/filter/xml/xmlExport.cxx create mode 100644 dbaccess/source/filter/xml/xmlExport.hxx create mode 100644 dbaccess/source/filter/xml/xmlFileBasedDatabase.cxx create mode 100644 dbaccess/source/filter/xml/xmlFileBasedDatabase.hxx create mode 100644 dbaccess/source/filter/xml/xmlHelper.cxx create mode 100644 dbaccess/source/filter/xml/xmlHelper.hxx create mode 100644 dbaccess/source/filter/xml/xmlHierarchyCollection.cxx create mode 100644 dbaccess/source/filter/xml/xmlHierarchyCollection.hxx create mode 100644 dbaccess/source/filter/xml/xmlLogin.cxx create mode 100644 dbaccess/source/filter/xml/xmlLogin.hxx create mode 100644 dbaccess/source/filter/xml/xmlQuery.cxx create mode 100644 dbaccess/source/filter/xml/xmlQuery.hxx create mode 100644 dbaccess/source/filter/xml/xmlServerDatabase.cxx create mode 100644 dbaccess/source/filter/xml/xmlServerDatabase.hxx create mode 100644 dbaccess/source/filter/xml/xmlStyleImport.cxx create mode 100644 dbaccess/source/filter/xml/xmlStyleImport.hxx create mode 100644 dbaccess/source/filter/xml/xmlTable.cxx create mode 100644 dbaccess/source/filter/xml/xmlTable.hxx create mode 100644 dbaccess/source/filter/xml/xmlTableFilterList.cxx create mode 100644 dbaccess/source/filter/xml/xmlTableFilterList.hxx create mode 100644 dbaccess/source/filter/xml/xmlTableFilterPattern.cxx create mode 100644 dbaccess/source/filter/xml/xmlTableFilterPattern.hxx create mode 100644 dbaccess/source/filter/xml/xmlfilter.cxx create mode 100644 dbaccess/source/filter/xml/xmlfilter.hxx create mode 100644 dbaccess/source/inc/OAuthenticationContinuation.hxx create mode 100644 dbaccess/source/inc/apitools.hxx create mode 100644 dbaccess/source/inc/dsntypes.hxx create mode 100644 dbaccess/source/inc/stringconstants.hxx create mode 100644 dbaccess/source/sdbtools/connection/connectiontools.cxx create mode 100644 dbaccess/source/sdbtools/connection/datasourcemetadata.cxx create mode 100644 dbaccess/source/sdbtools/connection/datasourcemetadata.hxx create mode 100644 dbaccess/source/sdbtools/connection/objectnames.cxx create mode 100644 dbaccess/source/sdbtools/connection/objectnames.hxx create mode 100644 dbaccess/source/sdbtools/connection/tablename.cxx create mode 100644 dbaccess/source/sdbtools/connection/tablename.hxx create mode 100644 dbaccess/source/sdbtools/inc/connectiondependent.hxx create mode 100644 dbaccess/source/sdbtools/inc/connectiontools.hxx create mode 100644 dbaccess/source/ui/app/AppController.cxx create mode 100644 dbaccess/source/ui/app/AppController.hxx create mode 100644 dbaccess/source/ui/app/AppControllerDnD.cxx create mode 100644 dbaccess/source/ui/app/AppControllerGen.cxx create mode 100644 dbaccess/source/ui/app/AppDetailPageHelper.cxx create mode 100644 dbaccess/source/ui/app/AppDetailPageHelper.hxx create mode 100644 dbaccess/source/ui/app/AppDetailView.cxx create mode 100644 dbaccess/source/ui/app/AppDetailView.hxx create mode 100644 dbaccess/source/ui/app/AppIconControl.cxx create mode 100644 dbaccess/source/ui/app/AppIconControl.hxx create mode 100644 dbaccess/source/ui/app/AppSwapWindow.cxx create mode 100644 dbaccess/source/ui/app/AppSwapWindow.hxx create mode 100644 dbaccess/source/ui/app/AppTitleWindow.cxx create mode 100644 dbaccess/source/ui/app/AppTitleWindow.hxx create mode 100644 dbaccess/source/ui/app/AppView.cxx create mode 100644 dbaccess/source/ui/app/AppView.hxx create mode 100644 dbaccess/source/ui/app/ChildWindow.cxx create mode 100644 dbaccess/source/ui/app/DocumentInfoPreview.cxx create mode 100644 dbaccess/source/ui/app/DocumentInfoPreview.hxx create mode 100644 dbaccess/source/ui/app/subcomponentmanager.cxx create mode 100644 dbaccess/source/ui/app/subcomponentmanager.hxx create mode 100644 dbaccess/source/ui/app/templwin.cxx create mode 100644 dbaccess/source/ui/app/templwin.hxx create mode 100644 dbaccess/source/ui/app/window_layout.txt create mode 100644 dbaccess/source/ui/browser/AsynchronousLink.cxx create mode 100644 dbaccess/source/ui/browser/brwctrlr.cxx create mode 100644 dbaccess/source/ui/browser/brwview.cxx create mode 100644 dbaccess/source/ui/browser/dataview.cxx create mode 100644 dbaccess/source/ui/browser/dbexchange.cxx create mode 100644 dbaccess/source/ui/browser/dbloader.cxx create mode 100644 dbaccess/source/ui/browser/dbtreemodel.cxx create mode 100644 dbaccess/source/ui/browser/dbtreemodel.hxx create mode 100644 dbaccess/source/ui/browser/dsEntriesNoExp.cxx create mode 100644 dbaccess/source/ui/browser/dsbrowserDnD.cxx create mode 100644 dbaccess/source/ui/browser/exsrcbrw.cxx create mode 100644 dbaccess/source/ui/browser/formadapter.cxx create mode 100644 dbaccess/source/ui/browser/genericcontroller.cxx create mode 100644 dbaccess/source/ui/browser/sbagrid.cxx create mode 100644 dbaccess/source/ui/browser/sbamultiplex.cxx create mode 100644 dbaccess/source/ui/browser/unodatbr.cxx create mode 100644 dbaccess/source/ui/control/ColumnControlWindow.cxx create mode 100644 dbaccess/source/ui/control/FieldControls.cxx create mode 100644 dbaccess/source/ui/control/FieldDescControl.cxx create mode 100644 dbaccess/source/ui/control/RelationControl.cxx create mode 100644 dbaccess/source/ui/control/SqlNameEdit.cxx create mode 100644 dbaccess/source/ui/control/TableGrantCtrl.cxx create mode 100644 dbaccess/source/ui/control/charsetlistbox.cxx create mode 100644 dbaccess/source/ui/control/curledit.cxx create mode 100644 dbaccess/source/ui/control/dbtreelistbox.cxx create mode 100644 dbaccess/source/ui/control/opendoccontrols.cxx create mode 100644 dbaccess/source/ui/control/sqledit.cxx create mode 100644 dbaccess/source/ui/control/tabletree.cxx create mode 100644 dbaccess/source/ui/control/undosqledit.cxx create mode 100644 dbaccess/source/ui/dlg/CollectionView.cxx create mode 100644 dbaccess/source/ui/dlg/ConnectionHelper.cxx create mode 100644 dbaccess/source/ui/dlg/ConnectionHelper.hxx create mode 100644 dbaccess/source/ui/dlg/ConnectionPage.cxx create mode 100644 dbaccess/source/ui/dlg/ConnectionPage.hxx create mode 100644 dbaccess/source/ui/dlg/ConnectionPageSetup.cxx create mode 100644 dbaccess/source/ui/dlg/ConnectionPageSetup.hxx create mode 100644 dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx create mode 100644 dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx create mode 100644 dbaccess/source/ui/dlg/DbAdminImpl.cxx create mode 100644 dbaccess/source/ui/dlg/DbAdminImpl.hxx create mode 100644 dbaccess/source/ui/dlg/DriverSettings.hxx create mode 100644 dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx create mode 100644 dbaccess/source/ui/dlg/RelationDlg.cxx create mode 100644 dbaccess/source/ui/dlg/TablesSingleDlg.cxx create mode 100644 dbaccess/source/ui/dlg/TextConnectionHelper.cxx create mode 100644 dbaccess/source/ui/dlg/TextConnectionHelper.hxx create mode 100644 dbaccess/source/ui/dlg/UserAdmin.cxx create mode 100644 dbaccess/source/ui/dlg/UserAdmin.hxx create mode 100644 dbaccess/source/ui/dlg/UserAdminDlg.cxx create mode 100644 dbaccess/source/ui/dlg/admincontrols.cxx create mode 100644 dbaccess/source/ui/dlg/admincontrols.hxx create mode 100644 dbaccess/source/ui/dlg/adminpages.cxx create mode 100644 dbaccess/source/ui/dlg/adminpages.hxx create mode 100644 dbaccess/source/ui/dlg/adodatalinks.cxx create mode 100644 dbaccess/source/ui/dlg/adodatalinks.hxx create mode 100644 dbaccess/source/ui/dlg/adtabdlg.cxx create mode 100644 dbaccess/source/ui/dlg/advancedsettings.cxx create mode 100644 dbaccess/source/ui/dlg/advancedsettings.hxx create mode 100644 dbaccess/source/ui/dlg/dbadmin.cxx create mode 100644 dbaccess/source/ui/dlg/dbfindex.cxx create mode 100644 dbaccess/source/ui/dlg/dbfindex.hxx create mode 100644 dbaccess/source/ui/dlg/dbwiz.cxx create mode 100644 dbaccess/source/ui/dlg/dbwizsetup.cxx create mode 100644 dbaccess/source/ui/dlg/detailpages.cxx create mode 100644 dbaccess/source/ui/dlg/detailpages.hxx create mode 100644 dbaccess/source/ui/dlg/directsql.cxx create mode 100644 dbaccess/source/ui/dlg/dlgattr.cxx create mode 100644 dbaccess/source/ui/dlg/dlgsave.cxx create mode 100644 dbaccess/source/ui/dlg/dlgsize.cxx create mode 100644 dbaccess/source/ui/dlg/dsnItem.hxx create mode 100644 dbaccess/source/ui/dlg/dsselect.cxx create mode 100644 dbaccess/source/ui/dlg/dsselect.hxx create mode 100644 dbaccess/source/ui/dlg/finteraction.cxx create mode 100644 dbaccess/source/ui/dlg/finteraction.hxx create mode 100644 dbaccess/source/ui/dlg/generalpage.cxx create mode 100644 dbaccess/source/ui/dlg/generalpage.hxx create mode 100644 dbaccess/source/ui/dlg/indexdialog.cxx create mode 100644 dbaccess/source/ui/dlg/indexfieldscontrol.cxx create mode 100644 dbaccess/source/ui/dlg/odbcconfig.cxx create mode 100644 dbaccess/source/ui/dlg/odbcconfig.hxx create mode 100644 dbaccess/source/ui/dlg/optionalboolitem.cxx create mode 100644 dbaccess/source/ui/dlg/optionalboolitem.hxx create mode 100644 dbaccess/source/ui/dlg/paramdialog.cxx create mode 100644 dbaccess/source/ui/dlg/queryfilter.cxx create mode 100644 dbaccess/source/ui/dlg/queryorder.cxx create mode 100644 dbaccess/source/ui/dlg/sqlmessage.cxx create mode 100644 dbaccess/source/ui/dlg/tablespage.cxx create mode 100644 dbaccess/source/ui/dlg/tablespage.hxx create mode 100644 dbaccess/source/ui/dlg/textconnectionsettings.cxx create mode 100644 dbaccess/source/ui/inc/AppElementType.hxx create mode 100644 dbaccess/source/ui/inc/ChildWindow.hxx create mode 100644 dbaccess/source/ui/inc/CollectionView.hxx create mode 100644 dbaccess/source/ui/inc/ColumnControlWindow.hxx create mode 100644 dbaccess/source/ui/inc/ConnectionLine.hxx create mode 100644 dbaccess/source/ui/inc/ConnectionLineAccess.hxx create mode 100644 dbaccess/source/ui/inc/ConnectionLineData.hxx create mode 100644 dbaccess/source/ui/inc/DExport.hxx create mode 100644 dbaccess/source/ui/inc/FieldControls.hxx create mode 100644 dbaccess/source/ui/inc/FieldDescControl.hxx create mode 100644 dbaccess/source/ui/inc/FieldDescriptions.hxx create mode 100644 dbaccess/source/ui/inc/GeneralUndo.hxx create mode 100644 dbaccess/source/ui/inc/HtmlReader.hxx create mode 100644 dbaccess/source/ui/inc/IClipBoardTest.hxx create mode 100644 dbaccess/source/ui/inc/IItemSetHelper.hxx create mode 100644 dbaccess/source/ui/inc/IUpdateHelper.hxx create mode 100644 dbaccess/source/ui/inc/JAccess.hxx create mode 100644 dbaccess/source/ui/inc/JoinController.hxx create mode 100644 dbaccess/source/ui/inc/JoinDesignView.hxx create mode 100644 dbaccess/source/ui/inc/JoinExchange.hxx create mode 100644 dbaccess/source/ui/inc/JoinTableView.hxx create mode 100644 dbaccess/source/ui/inc/QEnumTypes.hxx create mode 100644 dbaccess/source/ui/inc/QueryDesignView.hxx create mode 100644 dbaccess/source/ui/inc/QueryPropertiesDialog.hxx create mode 100644 dbaccess/source/ui/inc/QueryTableView.hxx create mode 100644 dbaccess/source/ui/inc/QueryTextView.hxx create mode 100644 dbaccess/source/ui/inc/QueryViewSwitch.hxx create mode 100644 dbaccess/source/ui/inc/RTableConnectionData.hxx create mode 100644 dbaccess/source/ui/inc/RelControliFace.hxx create mode 100644 dbaccess/source/ui/inc/RelationControl.hxx create mode 100644 dbaccess/source/ui/inc/RelationController.hxx create mode 100644 dbaccess/source/ui/inc/RelationDesignView.hxx create mode 100644 dbaccess/source/ui/inc/RelationDlg.hxx create mode 100644 dbaccess/source/ui/inc/RelationTableView.hxx create mode 100644 dbaccess/source/ui/inc/RtfReader.hxx create mode 100644 dbaccess/source/ui/inc/SqlNameEdit.hxx create mode 100644 dbaccess/source/ui/inc/TableConnection.hxx create mode 100644 dbaccess/source/ui/inc/TableConnectionData.hxx create mode 100644 dbaccess/source/ui/inc/TableController.hxx create mode 100644 dbaccess/source/ui/inc/TableCopyHelper.hxx create mode 100644 dbaccess/source/ui/inc/TableDesignControl.hxx create mode 100644 dbaccess/source/ui/inc/TableDesignHelpBar.hxx create mode 100644 dbaccess/source/ui/inc/TableDesignView.hxx create mode 100644 dbaccess/source/ui/inc/TableFieldDescription.hxx create mode 100644 dbaccess/source/ui/inc/TableGrantCtrl.hxx create mode 100644 dbaccess/source/ui/inc/TableRow.hxx create mode 100644 dbaccess/source/ui/inc/TableRowExchange.hxx create mode 100644 dbaccess/source/ui/inc/TableWindow.hxx create mode 100644 dbaccess/source/ui/inc/TableWindowAccess.hxx create mode 100644 dbaccess/source/ui/inc/TableWindowData.hxx create mode 100644 dbaccess/source/ui/inc/TableWindowListBox.hxx create mode 100644 dbaccess/source/ui/inc/TableWindowTitle.hxx create mode 100644 dbaccess/source/ui/inc/TablesSingleDlg.hxx create mode 100644 dbaccess/source/ui/inc/TokenWriter.hxx create mode 100644 dbaccess/source/ui/inc/TypeInfo.hxx create mode 100644 dbaccess/source/ui/inc/UITools.hxx create mode 100644 dbaccess/source/ui/inc/UserAdminDlg.hxx create mode 100644 dbaccess/source/ui/inc/WCPage.hxx create mode 100644 dbaccess/source/ui/inc/WColumnSelect.hxx create mode 100644 dbaccess/source/ui/inc/WCopyTable.hxx create mode 100644 dbaccess/source/ui/inc/WExtendPages.hxx create mode 100644 dbaccess/source/ui/inc/WNameMatch.hxx create mode 100644 dbaccess/source/ui/inc/WTabPage.hxx create mode 100644 dbaccess/source/ui/inc/WTypeSelect.hxx create mode 100644 dbaccess/source/ui/inc/adtabdlg.hxx create mode 100644 dbaccess/source/ui/inc/advancedsettingsdlg.hxx create mode 100644 dbaccess/source/ui/inc/asyncmodaldialog.hxx create mode 100644 dbaccess/source/ui/inc/browserids.hxx create mode 100644 dbaccess/source/ui/inc/brwctrlr.hxx create mode 100644 dbaccess/source/ui/inc/brwview.hxx create mode 100644 dbaccess/source/ui/inc/callbacks.hxx create mode 100644 dbaccess/source/ui/inc/charsetlistbox.hxx create mode 100644 dbaccess/source/ui/inc/charsets.hxx create mode 100644 dbaccess/source/ui/inc/commontypes.hxx create mode 100644 dbaccess/source/ui/inc/curledit.hxx create mode 100644 dbaccess/source/ui/inc/databaseobjectview.hxx create mode 100644 dbaccess/source/ui/inc/datasourceconnector.hxx create mode 100644 dbaccess/source/ui/inc/dbadmin.hxx create mode 100644 dbaccess/source/ui/inc/dbexchange.hxx create mode 100644 dbaccess/source/ui/inc/dbtreelistbox.hxx create mode 100644 dbaccess/source/ui/inc/dbu_dlg.hxx create mode 100644 dbaccess/source/ui/inc/dbwiz.hxx create mode 100644 dbaccess/source/ui/inc/dbwizsetup.hxx create mode 100644 dbaccess/source/ui/inc/defaultobjectnamecheck.hxx create mode 100644 dbaccess/source/ui/inc/directsql.hxx create mode 100644 dbaccess/source/ui/inc/dlgattr.hxx create mode 100644 dbaccess/source/ui/inc/dlgsave.hxx create mode 100644 dbaccess/source/ui/inc/dlgsize.hxx create mode 100644 dbaccess/source/ui/inc/dsitems.hxx create mode 100644 dbaccess/source/ui/inc/dsmeta.hxx create mode 100644 dbaccess/source/ui/inc/exsrcbrw.hxx create mode 100644 dbaccess/source/ui/inc/formadapter.hxx create mode 100644 dbaccess/source/ui/inc/imageprovider.hxx create mode 100644 dbaccess/source/ui/inc/indexcollection.hxx create mode 100644 dbaccess/source/ui/inc/indexdialog.hxx create mode 100644 dbaccess/source/ui/inc/indexes.hxx create mode 100644 dbaccess/source/ui/inc/indexfieldscontrol.hxx create mode 100644 dbaccess/source/ui/inc/linkeddocuments.hxx create mode 100644 dbaccess/source/ui/inc/objectnamecheck.hxx create mode 100644 dbaccess/source/ui/inc/opendoccontrols.hxx create mode 100644 dbaccess/source/ui/inc/paramdialog.hxx create mode 100644 dbaccess/source/ui/inc/propertystorage.hxx create mode 100644 dbaccess/source/ui/inc/querycontainerwindow.hxx create mode 100644 dbaccess/source/ui/inc/querycontroller.hxx create mode 100644 dbaccess/source/ui/inc/queryfilter.hxx create mode 100644 dbaccess/source/ui/inc/queryorder.hxx create mode 100644 dbaccess/source/ui/inc/sbagrid.hrc create mode 100644 dbaccess/source/ui/inc/sbagrid.hxx create mode 100644 dbaccess/source/ui/inc/sbamultiplex.hxx create mode 100644 dbaccess/source/ui/inc/singledoccontroller.hxx create mode 100644 dbaccess/source/ui/inc/sqledit.hxx create mode 100644 dbaccess/source/ui/inc/sqlmessage.hxx create mode 100644 dbaccess/source/ui/inc/stringlistitem.hxx create mode 100644 dbaccess/source/ui/inc/tabletree.hxx create mode 100644 dbaccess/source/ui/inc/textconnectionsettings.hxx create mode 100644 dbaccess/source/ui/inc/undosqledit.hxx create mode 100644 dbaccess/source/ui/inc/unoadmin.hxx create mode 100644 dbaccess/source/ui/inc/unodatbr.hxx create mode 100644 dbaccess/source/ui/inc/unosqlmessage.hxx create mode 100644 dbaccess/source/ui/misc/DExport.cxx create mode 100644 dbaccess/source/ui/misc/HtmlReader.cxx create mode 100644 dbaccess/source/ui/misc/RowSetDrop.cxx create mode 100644 dbaccess/source/ui/misc/RtfReader.cxx create mode 100644 dbaccess/source/ui/misc/TableCopyHelper.cxx create mode 100644 dbaccess/source/ui/misc/TokenWriter.cxx create mode 100644 dbaccess/source/ui/misc/UITools.cxx create mode 100644 dbaccess/source/ui/misc/UpdateHelperImpl.hxx create mode 100644 dbaccess/source/ui/misc/WCPage.cxx create mode 100644 dbaccess/source/ui/misc/WColumnSelect.cxx create mode 100644 dbaccess/source/ui/misc/WCopyTable.cxx create mode 100644 dbaccess/source/ui/misc/WExtendPages.cxx create mode 100644 dbaccess/source/ui/misc/WNameMatch.cxx create mode 100644 dbaccess/source/ui/misc/WTypeSelect.cxx create mode 100644 dbaccess/source/ui/misc/asyncmodaldialog.cxx create mode 100644 dbaccess/source/ui/misc/charsets.cxx create mode 100644 dbaccess/source/ui/misc/controllerframe.cxx create mode 100644 dbaccess/source/ui/misc/databaseobjectview.cxx create mode 100644 dbaccess/source/ui/misc/datasourceconnector.cxx create mode 100644 dbaccess/source/ui/misc/dbaundomanager.cxx create mode 100644 dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx create mode 100644 dbaccess/source/ui/misc/defaultobjectnamecheck.cxx create mode 100644 dbaccess/source/ui/misc/dsmeta.cxx create mode 100644 dbaccess/source/ui/misc/imageprovider.cxx create mode 100644 dbaccess/source/ui/misc/indexcollection.cxx create mode 100644 dbaccess/source/ui/misc/linkeddocuments.cxx create mode 100644 dbaccess/source/ui/misc/propertystorage.cxx create mode 100644 dbaccess/source/ui/misc/singledoccontroller.cxx create mode 100644 dbaccess/source/ui/misc/stringlistitem.cxx create mode 100644 dbaccess/source/ui/querydesign/ConnectionLine.cxx create mode 100644 dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx create mode 100644 dbaccess/source/ui/querydesign/ConnectionLineData.cxx create mode 100644 dbaccess/source/ui/querydesign/JAccess.cxx create mode 100644 dbaccess/source/ui/querydesign/JoinController.cxx create mode 100644 dbaccess/source/ui/querydesign/JoinDesignView.cxx create mode 100644 dbaccess/source/ui/querydesign/JoinExchange.cxx create mode 100644 dbaccess/source/ui/querydesign/JoinTableView.cxx create mode 100644 dbaccess/source/ui/querydesign/QTableConnection.cxx create mode 100644 dbaccess/source/ui/querydesign/QTableConnection.hxx create mode 100644 dbaccess/source/ui/querydesign/QTableConnectionData.cxx create mode 100644 dbaccess/source/ui/querydesign/QTableConnectionData.hxx create mode 100644 dbaccess/source/ui/querydesign/QTableWindow.cxx create mode 100644 dbaccess/source/ui/querydesign/QTableWindow.hxx create mode 100644 dbaccess/source/ui/querydesign/QTableWindowData.cxx create mode 100644 dbaccess/source/ui/querydesign/QTableWindowData.hxx create mode 100644 dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx create mode 100644 dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx create mode 100644 dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx create mode 100644 dbaccess/source/ui/querydesign/QueryDesignView.cxx create mode 100644 dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.cxx create mode 100644 dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.hxx create mode 100644 dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx create mode 100644 dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx create mode 100644 dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx create mode 100644 dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx create mode 100644 dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx create mode 100644 dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx create mode 100644 dbaccess/source/ui/querydesign/QueryTableView.cxx create mode 100644 dbaccess/source/ui/querydesign/QueryTextView.cxx create mode 100644 dbaccess/source/ui/querydesign/QueryViewSwitch.cxx create mode 100644 dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx create mode 100644 dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx create mode 100644 dbaccess/source/ui/querydesign/TableConnection.cxx create mode 100644 dbaccess/source/ui/querydesign/TableConnectionData.cxx create mode 100644 dbaccess/source/ui/querydesign/TableFieldDescription.cxx create mode 100644 dbaccess/source/ui/querydesign/TableFieldInfo.cxx create mode 100644 dbaccess/source/ui/querydesign/TableFieldInfo.hxx create mode 100644 dbaccess/source/ui/querydesign/TableWindow.cxx create mode 100644 dbaccess/source/ui/querydesign/TableWindowAccess.cxx create mode 100644 dbaccess/source/ui/querydesign/TableWindowData.cxx create mode 100644 dbaccess/source/ui/querydesign/TableWindowListBox.cxx create mode 100644 dbaccess/source/ui/querydesign/TableWindowTitle.cxx create mode 100644 dbaccess/source/ui/querydesign/class.jpg create mode 100644 dbaccess/source/ui/querydesign/limitboxcontroller.cxx create mode 100644 dbaccess/source/ui/querydesign/limitboxcontroller.hxx create mode 100644 dbaccess/source/ui/querydesign/querycontainerwindow.cxx create mode 100644 dbaccess/source/ui/querydesign/querycontroller.cxx create mode 100644 dbaccess/source/ui/querydesign/querydlg.cxx create mode 100644 dbaccess/source/ui/querydesign/querydlg.hxx create mode 100644 dbaccess/source/ui/relationdesign/RTableConnection.cxx create mode 100644 dbaccess/source/ui/relationdesign/RTableConnection.hxx create mode 100644 dbaccess/source/ui/relationdesign/RTableConnectionData.cxx create mode 100644 dbaccess/source/ui/relationdesign/RTableWindow.hxx create mode 100644 dbaccess/source/ui/relationdesign/RelationController.cxx create mode 100644 dbaccess/source/ui/relationdesign/RelationDesignView.cxx create mode 100644 dbaccess/source/ui/relationdesign/RelationTableView.cxx create mode 100644 dbaccess/source/ui/tabledesign/FieldDescriptions.cxx create mode 100644 dbaccess/source/ui/tabledesign/TEditControl.cxx create mode 100644 dbaccess/source/ui/tabledesign/TEditControl.hxx create mode 100644 dbaccess/source/ui/tabledesign/TableController.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableDesignControl.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableDesignView.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableFieldControl.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableFieldControl.hxx create mode 100644 dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx create mode 100644 dbaccess/source/ui/tabledesign/TableRow.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableRowExchange.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableUndo.cxx create mode 100644 dbaccess/source/ui/tabledesign/TableUndo.hxx create mode 100644 dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx create mode 100644 dbaccess/source/ui/uno/ColumnControl.cxx create mode 100644 dbaccess/source/ui/uno/ColumnControl.hxx create mode 100644 dbaccess/source/ui/uno/ColumnModel.cxx create mode 100644 dbaccess/source/ui/uno/ColumnModel.hxx create mode 100644 dbaccess/source/ui/uno/ColumnPeer.cxx create mode 100644 dbaccess/source/ui/uno/ColumnPeer.hxx create mode 100644 dbaccess/source/ui/uno/DBTypeWizDlg.cxx create mode 100644 dbaccess/source/ui/uno/DBTypeWizDlg.hxx create mode 100644 dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx create mode 100644 dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx create mode 100644 dbaccess/source/ui/uno/TableFilterDlg.cxx create mode 100644 dbaccess/source/ui/uno/TableFilterDlg.hxx create mode 100644 dbaccess/source/ui/uno/UserSettingsDlg.cxx create mode 100644 dbaccess/source/ui/uno/UserSettingsDlg.hxx create mode 100644 dbaccess/source/ui/uno/admindlg.cxx create mode 100644 dbaccess/source/ui/uno/admindlg.hxx create mode 100644 dbaccess/source/ui/uno/composerdialogs.cxx create mode 100644 dbaccess/source/ui/uno/composerdialogs.hxx create mode 100644 dbaccess/source/ui/uno/copytablewizard.cxx create mode 100644 dbaccess/source/ui/uno/dbinteraction.cxx create mode 100644 dbaccess/source/ui/uno/dbinteraction.hxx create mode 100644 dbaccess/source/ui/uno/textconnectionsettings_uno.cxx create mode 100644 dbaccess/source/ui/uno/unoDirectSql.cxx create mode 100644 dbaccess/source/ui/uno/unoDirectSql.hxx create mode 100644 dbaccess/source/ui/uno/unoadmin.cxx create mode 100644 dbaccess/source/ui/uno/unosqlmessage.cxx (limited to 'dbaccess/source') diff --git a/dbaccess/source/core/api/BookmarkSet.cxx b/dbaccess/source/core/api/BookmarkSet.cxx new file mode 100644 index 0000000000..75dfc24f58 --- /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 +#include +#include +#include + +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 xUpdRow(m_xRowLocate,UNO_QUERY); + if(!xUpdRow.is()) + ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_XROWUPDATE ), StandardSQLState::GENERAL_ERROR, *this ); + + Reference 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 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 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 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 0000000000..9863a80ecb --- /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 +#include + +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 0000000000..409d877288 --- /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 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 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 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 0000000000..d8dbeb82a8 --- /dev/null +++ b/dbaccess/source/core/api/CIndexes.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 +#include + +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, + css::uno::Reference< css::container::XNameAccess > _rxIndexes + ) : connectivity::OIndexesHelper(_pTable,_rMutex,_rVector) + ,m_xIndexes(std::move(_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 0000000000..98435b7c44 --- /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 +#include +#include "CRowSetColumn.hxx" + +#include + +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 &_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::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_DISPLAYSIZE, PROPERTY_ID_DISPLAYSIZE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISCASESENSITIVE, PROPERTY_ID_ISCASESENSITIVE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISDEFINITELYWRITABLE, PROPERTY_ID_ISDEFINITELYWRITABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND }, + { PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISSEARCHABLE, PROPERTY_ID_ISSEARCHABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISSIGNED, PROPERTY_ID_ISSIGNED, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISWRITABLE, PROPERTY_ID_ISWRITABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SERVICENAME, PROPERTY_ID_SERVICENAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_VALUE, PROPERTY_ID_VALUE, cppu::UnoType::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 0000000000..bc0ae7eedf --- /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 +#include +#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 &_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 0000000000..be5c70b938 --- /dev/null +++ b/dbaccess/source/core/api/CRowSetDataColumn.cxx @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include +#include +#include + +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, + OUString i_sDescription, + OUString i_sLabel, + std::function _getValue) + :ODataColumn(_xMetaData,_xRow,_xRowUpdate,_nPos,_rxDBMeta) + ,m_pGetValue(std::move(_getValue)) + ,m_sLabel(std::move(i_sLabel)) + ,m_aDescription(std::move(i_sDescription)) +{ + OColumnSettings::registerProperties( *this ); + registerProperty( PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, PropertyAttribute::READONLY, &m_aDescription, cppu::UnoType::get() ); +} + +ORowSetDataColumn::~ORowSetDataColumn() +{ +} + +// comphelper::OPropertyArrayUsageHelper +::cppu::IPropertyArrayHelper* ORowSetDataColumn::createArrayHelper( ) const +{ + css::uno::Sequence< css::beans::Property> aDescriptor + { + { PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_DISPLAYSIZE, PROPERTY_ID_DISPLAYSIZE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISCASESENSITIVE, PROPERTY_ID_ISCASESENSITIVE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISDEFINITELYWRITABLE, PROPERTY_ID_ISDEFINITELYWRITABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND }, + { PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISSEARCHABLE, PROPERTY_ID_ISSEARCHABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISSIGNED, PROPERTY_ID_ISSIGNED, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISWRITABLE, PROPERTY_ID_ISWRITABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SERVICENAME, PROPERTY_ID_SERVICENAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_VALUE, PROPERTY_ID_VALUE, cppu::UnoType::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(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(); +} + +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, + ::rtl::Reference< ::connectivity::OSQLColumns> _xColumns, + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector + ) : connectivity::sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector) + ,m_aColumns(std::move(_xColumns)) +{ +} + +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 0000000000..a19aad8497 --- /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 + +#include +#include + +#include + +namespace dbaccess +{ + class ORowSetDataColumn; + typedef ::comphelper::OPropertyArrayUsageHelper ORowSetDataColumn_PROP; + + class ORowSetDataColumn : public ODataColumn, + public OColumnSettings, + public ORowSetDataColumn_PROP + { + protected: + const std::function 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, + OUString i_sDescription, + OUString i_sLabel, + std::function _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, + ::rtl::Reference< ::connectivity::OSQLColumns> _xColumns, + ::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 0000000000..15fe62f291 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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(_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& _xTable) +{ + OSL_ENSURE(_xTable.is(),"OCacheSet::fillTableName: PropertySet is empty!"); + if(m_aComposedTableName.isEmpty() && _xTable.is() ) + { + Reference 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 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 xSet(_xTable,UNO_QUERY); + const Reference xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xSet); + // second the indexes + Reference xIndexSup(_xTable,UNO_QUERY); + Reference xIndexes; + if(xIndexSup.is()) + xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY); + + Reference xIndexColsSup; + std::vector< Reference > aAllIndexColumns; + if(xIndexes.is()) + { + for(sal_Int32 j=0;jgetCount();++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(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 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 xSet(_xTable,UNO_QUERY); + fillTableName(xSet); + + OUStringBuffer aSql("DELETE FROM " + m_aComposedTableName + " WHERE "); + + // use keys and indexes for exact positioning + Reference xIndexSup(_xTable,UNO_QUERY); + Reference xIndexes; + if(xIndexSup.is()) + xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY); + + // Reference + Reference xIndexColsSup; + std::vector< Reference > aAllIndexColumns; + if(xIndexes.is()) + { + for(sal_Int32 j=0;jgetCount();++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(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& 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& /*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 0000000000..1006b9662f --- /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 +#include +#include +#include +#include +#include "RowSetRow.hxx" +#include + +#include + +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 m_aNullable; + std::vector m_aSignedFlags; + std::vector 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& 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& 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 0000000000..c39c3c2c10 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& _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 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 OUString sAll = u"%"_ustr; + 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 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 constexpr OUString sAll( u"%"_ustr ); + static constexpr OUString sView( u"VIEW"_ustr ); + static constexpr OUString sTable( u"TABLE"_ustr ); + + 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 0000000000..5eb0db967e --- /dev/null +++ b/dbaccess/source/core/api/HelperCollections.cxx @@ -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 . + */ + +#include "HelperCollections.hxx" + +#include +#include + +#include + +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(::rtl::Reference< ::connectivity::OSQLColumns> _xColumns, + bool _bCase, + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector, + bool _bUseAsIndex + ) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector,_bUseAsIndex) + ,m_aColumns(std::move(_xColumns)) + { + } + + std::unique_ptr 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(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 0000000000..b7f69b8bac --- /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 +#include +#include + +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(::rtl::Reference< ::connectivity::OSQLColumns> _xColumns, + 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 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( 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 0000000000..cfbec6afec --- /dev/null +++ b/dbaccess/source/core/api/KeySet.cxx @@ -0,0 +1,1467 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include "KeySet.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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& _xIndexes, std::vector< Reference >& _rAllIndexColumns) + { + if ( !_xIndexes.is() ) + return; + + Reference 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(xIndexColsSup,UNO_QUERY_THROW)->getColumns()); + } + } + + template < typename T > void tryDispose( Reference &r ) + { + try + { + ::comphelper::disposeComponent(r); + } + catch(const Exception&) + { + r = nullptr; + } + catch(...) + { + SAL_WARN("dbaccess", "Unknown Exception occurred"); + } + } +} + + +OKeySet::OKeySet(connectivity::OSQLTable _xTable, + OUString _sUpdateTableName, // 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(std::move(_xTable)) + ,m_xComposer(_xComposer) + ,m_sUpdateTableName(std::move(_sUpdateTableName)) + ,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 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& i_xMeta, + const Reference& i_xQueryColumns, + std::unique_ptr const & o_pKeyColumnNames) +{ + // first ask the database itself for the best columns which can be used + Sequence< OUString> aBestColumnNames; + Reference xKeyColumns = getPrimaryKeyColumns_throw(i_aTable); + if ( xKeyColumns.is() ) + aBestColumnNames = xKeyColumns->getElementNames(); + + const Reference xTblColSup(i_aTable,UNO_QUERY_THROW); + const Reference xTblColumns = xTblColSup->getColumns(); + // locate parameter in select columns + Reference xParaSup(m_xComposer,UNO_QUERY); + Reference 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 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 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 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 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 xMeta = m_xConnection->getMetaData(); + Reference xQueryColSup(m_xComposer, UNO_QUERY); + const Reference 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 xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY); + xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery()); + Reference xTabSup(xAnalyzer,uno::UNO_QUERY); + Reference 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 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 >(0,Reference())); + 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 >(0,Reference())); + 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 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 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& 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 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 OUString aAnd(u" AND "_ustr); + OUString sIsNull(" IS NULL"); + OUString sParam(" = ?"); + + // use keys and indexes for exact positioning + Reference xIndexSup(_xTable,UNO_QUERY); + Reference xIndexes; + if ( xIndexSup.is() ) + xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY); + + std::vector< Reference > aAllIndexColumns; + lcl_fillIndexColumns(xIndexes,aAllIndexColumns); + + OUStringBuffer sKeyCondition,sIndexCondition; + std::vector 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& _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; + 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); + assert(m_aKeyIter != m_aKeyMap.end()); + 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 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 = m_xConnection->createStatement(); + Reference xRes = xStatement->executeQuery(sStmt); + Reference 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 >(1,Reference())) ).first; + // now we set the bookmark for this row + (*_rInsertRow)[0] = Any(static_cast(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 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 xIndexSup(_xTable,UNO_QUERY); + Reference xIndexes; + if ( xIndexSup.is() ) + xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY); + + // Reference + std::vector< Reference > aAllIndexColumns; + lcl_fillIndexColumns(xIndexes,aAllIndexColumns); + + OUStringBuffer sIndexCondition; + std::vector 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()); + const auto iter = m_aKeyMap.find(nBookmark); + assert(iter != m_aKeyMap.end()); + if(m_aKeyIter == iter && 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(std::distance(m_aKeyMap.begin(), m_aKeyIter))); + m_aKeyIter = std::prev(m_aKeyIter, row); + } + else + { + if(row >= static_cast(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 >(0,Reference())) ).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& _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 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 0000000000..bd30f3960e --- /dev/null +++ b/dbaccess/source/core/api/KeySet.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 "CacheSet.hxx" + +#include +#include +#include +#include + +#include +#include +#include + +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, OUString _sDefaultValue ) + :sDefaultValue(std::move( _sDefaultValue )) + ,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 > > OKeySetValue; + typedef std::map OKeySetMatrix; + typedef std::map > 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 m_aParameterValueForCache; + std::unique_ptr m_pKeyColumnNames; // contains all key column names + std::unique_ptr m_pColumnNames; // contains all column names + std::unique_ptr m_pParameterNames; // contains all parameter names + std::unique_ptr 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, + 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 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& _aIndexColumnPositions = std::vector()); + 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(connectivity::OSQLTable _aTable, + OUString _sUpdateTableName, + 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 0000000000..2a89974794 --- /dev/null +++ b/dbaccess/source/core/api/OptimisticSet.cxx @@ -0,0 +1,588 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "OptimisticSet.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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& _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(_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 xMeta = m_xConnection->getMetaData(); + bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(); + Reference xQueryColSup(m_xComposer,UNO_QUERY); + const Reference xQueryColumns = xQueryColSup->getColumns(); + const Reference xTabSup(m_xComposer,UNO_QUERY); + const Reference 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 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 >(0,Reference())); + 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 xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY); + OUString sQuery = xSourceComposer->getQuery(); + xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery()); + // check for joins + OUString aErrorMsg; + std::unique_ptr 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 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::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 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::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 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 xRes = xPrep->executeQuery(); + Reference 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 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()); + const auto iter = m_aKeyMap.find(nBookmark); + assert(iter != m_aKeyMap.end()); + if(m_aKeyIter == iter && 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& o_aChangedColumns) +{ + o_aChangedColumns.push_back(i_nColumnIndex); + std::map::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& 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 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 xRes = xPrep->executeQuery(); + Reference 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 0000000000..bf5e3a8037 --- /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 +#include + +#include + +namespace dbaccess +{ + // is used when the source supports keys + class OptimisticSet : public OKeySet + { + ::connectivity::OSQLParser m_aSqlParser; + ::connectivity::OSQLParseTreeIterator m_aSqlIterator; + + std::map m_aJoinedColumns; + std::map 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& 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& i_aChangedColumns) override; + virtual void fillMissingValues(ORowSetValueVector::Vector& io_aRow) const override; + + bool isReadOnly() const { return m_aJoinedKeyColumns.empty(); } + const std::map& 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 0000000000..9bf2709606 --- /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 0000000000..c5ce74f15f --- /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 +#include +#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 0000000000..44709a2a5a --- /dev/null +++ b/dbaccess/source/core/api/RowSet.cxx @@ -0,0 +1,2941 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include + +#include "RowSet.hxx" +#include +#include +#include +#include "CRowSetColumn.hxx" +#include "CRowSetDataColumn.hxx" +#include "RowSetCache.hxx" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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::get()); + registerProperty(PROPERTY_DATASOURCENAME, PROPERTY_ID_DATASOURCENAME, PropertyAttribute::BOUND, &m_aDataSourceName, ::cppu::UnoType::get()); + registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND, &m_aCommand, ::cppu::UnoType::get()); + registerProperty(PROPERTY_COMMAND_TYPE, PROPERTY_ID_COMMAND_TYPE, PropertyAttribute::BOUND, &m_nCommandType, ::cppu::UnoType::get()); + registerProperty(PROPERTY_ACTIVECOMMAND, PROPERTY_ID_ACTIVECOMMAND, nRBT, &m_aActiveCommand, ::cppu::UnoType::get()); + registerProperty(PROPERTY_IGNORERESULT, PROPERTY_ID_IGNORERESULT, PropertyAttribute::BOUND, &m_bIgnoreResult, cppu::UnoType::get()); + registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND, &m_aFilter, ::cppu::UnoType::get()); + registerProperty(PROPERTY_HAVING_CLAUSE, PROPERTY_ID_HAVING_CLAUSE, PropertyAttribute::BOUND, &m_aHavingClause, ::cppu::UnoType::get()); + registerProperty(PROPERTY_GROUP_BY, PROPERTY_ID_GROUP_BY, PropertyAttribute::BOUND, &m_aGroupBy, ::cppu::UnoType::get()); + registerProperty(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, PropertyAttribute::BOUND, &m_bApplyFilter, cppu::UnoType::get()); + registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND, &m_aOrder, ::cppu::UnoType::get()); + registerProperty(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, nRT, &m_nPrivileges, ::cppu::UnoType::get()); + registerProperty(PROPERTY_ISMODIFIED, PROPERTY_ID_ISMODIFIED, nBT, &m_bModified, cppu::UnoType::get()); + registerProperty(PROPERTY_ISNEW, PROPERTY_ID_ISNEW, nRBT, &m_bNew, cppu::UnoType::get()); + registerProperty(PROPERTY_SINGLESELECTQUERYCOMPOSER,PROPERTY_ID_SINGLESELECTQUERYCOMPOSER, nRT, &m_xComposer, cppu::UnoType::get()); + + // sdbcx.ResultSet Properties + registerProperty(PROPERTY_ISBOOKMARKABLE, PROPERTY_ID_ISBOOKMARKABLE, nRT, &m_bIsBookmarkable, cppu::UnoType::get()); + registerProperty(PROPERTY_CANUPDATEINSERTEDROWS,PROPERTY_ID_CANUPDATEINSERTEDROWS, nRT, &m_bCanUpdateInsertedRows, cppu::UnoType::get()); + // sdbc.ResultSet Properties + registerProperty(PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::TRANSIENT, &m_nResultSetConcurrency,::cppu::UnoType::get()); + registerProperty(PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::TRANSIENT, &m_nResultSetType, ::cppu::UnoType::get()); + registerProperty(PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, PropertyAttribute::TRANSIENT, &m_nFetchDirection, ::cppu::UnoType::get()); + registerProperty(PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, PropertyAttribute::TRANSIENT, &m_nFetchSize, ::cppu::UnoType::get()); + + // sdbc.RowSet Properties + registerProperty(PROPERTY_URL, PROPERTY_ID_URL, 0, &m_aURL, ::cppu::UnoType::get()); + registerProperty(PROPERTY_TRANSACTIONISOLATION, PROPERTY_ID_TRANSACTIONISOLATION, PropertyAttribute::TRANSIENT, &m_nTransactionIsolation,::cppu::UnoType::get()); + registerMayBeVoidProperty(PROPERTY_TYPEMAP, PROPERTY_ID_TYPEMAP, PropertyAttribute::MAYBEVOID|PropertyAttribute::TRANSIENT, &m_aTypeMap, cppu::UnoType::get()); + registerProperty(PROPERTY_ESCAPE_PROCESSING,PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, &m_bUseEscapeProcessing,cppu::UnoType::get() ); + registerProperty(PROPERTY_QUERYTIMEOUT, PROPERTY_ID_QUERYTIMEOUT, PropertyAttribute::TRANSIENT, &m_nQueryTimeOut, ::cppu::UnoType::get()); + registerProperty(PROPERTY_MAXFIELDSIZE, PROPERTY_ID_MAXFIELDSIZE, PropertyAttribute::TRANSIENT, &m_nMaxFieldSize, ::cppu::UnoType::get()); + registerProperty(PROPERTY_MAXROWS, PROPERTY_ID_MAXROWS, 0, &m_nMaxRows, ::cppu::UnoType::get() ); + registerProperty(PROPERTY_USER, PROPERTY_ID_USER, PropertyAttribute::TRANSIENT, &m_aUser, ::cppu::UnoType::get()); + registerProperty(PROPERTY_PASSWORD, PROPERTY_ID_PASSWORD, PropertyAttribute::TRANSIENT, &m_aPassword, ::cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND, &m_aUpdateCatalogName, ::cppu::UnoType::get()); + registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND, &m_aUpdateSchemaName, ::cppu::UnoType::get()); + registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND, &m_aUpdateTableName, ::cppu::UnoType::get()); + + // ??? + registerProperty(PROPERTY_CHANGE_NOTIFICATION_ENABLED, PROPERTY_ID_PROPCHANGE_NOTIFY, PropertyAttribute::BOUND, &m_bPropChangeNotifyEnabled, cppu::UnoType::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(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::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + ::comphelper::concatSequences(ORowSet_BASE1::getTypes(),ORowSetBase::getTypes())); + return aTypes.getTypes(); +} + +Sequence< sal_Int8 > SAL_CALL ORowSet::getImplementationId() +{ + return css::uno::Sequence(); +} + +// 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::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 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().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 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 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 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); + } + // additional 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::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(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 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 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 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 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( CursorMoveDirection::Current ); + 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 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( CursorMoveDirection::Current ); + + 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(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& rxItem) { + try + { + return static_cast(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& rxItem) { + try + { + return static_cast(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( CursorMoveDirection::Forward ); + m_pCache->next(); + setCurrentRow( true, false, aOldValues, aGuard); + } + else + positionCache( CursorMoveDirection::Current ); + + // 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 >::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( CursorMoveDirection::CurrentRefresh ); + + 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 xParameters(xComposer, UNO_QUERY); + + Reference xParamsAsIndicies = xParameters.is() ? xParameters->getParameters() : Reference(); + 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(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(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[] = { + PROPERTY_ALIGN, PROPERTY_RELATIVEPOSITION, PROPERTY_WIDTH, PROPERTY_HIDDEN, PROPERTY_CONTROLMODEL, + PROPERTY_HELPTEXT, 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& rKeyColumns = m_pCache->getKeyColumns(); + if(!m_xColumns.is()) + { + SAL_INFO("dbaccess", "ORowSet::execute_NoApprove_NoNewConn::creating columns" ); + // use the meta data + Reference xMetaSup(m_xStatement,UNO_QUERY); + try + { + Reference 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 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 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(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 xInfo = xColumn.is() ? xColumn->getPropertySetInfo() : Reference(); + 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 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 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 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 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) + { + rtl::Reference pClone = dynamic_cast(elem.get().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) + { + rtl::Reference pClone = dynamic_cast(clone.get().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 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 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; isize() ); + m_aPrematureParamValues->resize( nParamCount ); + for ( size_t i=0; idispose(); + 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(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 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 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(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(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& _rContext, ORowSet& rParent, ::osl::Mutex* _pMutex ) + :OSubComponent(m_aMutex, rParent) + ,ORowSetBase( _rContext, WeakComponentImplHelper::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 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 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 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::get()); + registerProperty(PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::READONLY, &m_nResultSetConcurrency,::cppu::UnoType::get()); + registerProperty(PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY, &m_nResultSetType, ::cppu::UnoType::get()); + registerProperty(PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, PropertyAttribute::TRANSIENT, &m_nFetchDirection, ::cppu::UnoType::get()); + registerProperty(PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, PropertyAttribute::TRANSIENT, &m_nFetchSize, ::cppu::UnoType::get()); + registerProperty(PROPERTY_ISBOOKMARKABLE, PROPERTY_ID_ISBOOKMARKABLE, nRT, &m_bIsBookmarkable, cppu::UnoType::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 (WeakComponentImplHelper::rBHelper.bDisposed) + return; + } + 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::getArrayHelper(); +} + +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 0000000000..3cf6fe6901 --- /dev/null +++ b/dbaccess/source/core/api/RowSet.hxx @@ -0,0 +1,519 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include +#include + +#include +#include "RowSetBase.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 + { + 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 m_aPrematureParamValues; + rtl::Reference m_aParameterValueForCache; + std::vector m_aParametersSet; + std::vector m_aReadOnlyDataColumns; + + ::comphelper::OInterfaceContainerHelper3 m_aRowsetListeners; + ::comphelper::OInterfaceContainerHelper3 m_aApproveListeners; + ::comphelper::OInterfaceContainerHelper3 m_aRowsChangeListener; + + ::dbtools::WarningsContainer m_aWarnings; + + // no Reference! see OCollection::acquire + std::unique_ptr 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 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 , this one will returned. + Else, m_pTables will be constructed and returned. + + @precond m_xActiveConnection is not + @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 + */ + 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 , *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::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::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 execute, 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

+ @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& _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(); + } + + // 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::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 0000000000..753c857eec --- /dev/null +++ b/dbaccess/source/core/api/RowSetBase.cxx @@ -0,0 +1,1425 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include "RowSetCache.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& _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::get(), css::uno::Any(sal_Int32(0)) ); + registerPropertyNoMember( PROPERTY_ISROWCOUNTFINAL, PROPERTY_ID_ISROWCOUNTFINAL, nRBT, cppu::UnoType::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( CursorMoveDirection::Current ); + 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(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( CursorMoveDirection::Current ); + 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( CursorMoveDirection::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( CursorMoveDirection::Current ); + 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( CursorMoveDirection::Current ); + 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 const & _aCheckFunctor, + std::function 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( CursorMoveDirection::Current ); + 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 ? CursorMoveDirection::Forward : CursorMoveDirection::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( CursorMoveDirection::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( CursorMoveDirection::Current ); + 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(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 == CursorMoveDirection::CurrentRefresh || + (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 CursorMoveDirection::Forward: + if ( m_nDeletedPosition > 1 ) + bSuccess = m_pCache->absolute( m_nDeletedPosition - 1 ); + else + { + m_pCache->beforeFirst(); + bSuccess = true; + } + break; + + case CursorMoveDirection::Backward: + if ( m_pCache->m_bRowCountFinal && ( m_nDeletedPosition == impl_getRowCount() ) ) + { + m_pCache->afterLast(); + bSuccess = true; + } + else + bSuccess = m_pCache->absolute( m_nDeletedPosition ); + break; + + case CursorMoveDirection::Current: + case CursorMoveDirection::CurrentRefresh: + 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( CursorMoveDirection::Current ); + 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; +} + + +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_pRowSet( _pRowSet ) + ,m_bWasNew( false ) + ,m_bWasModified( false ) +{ + OSL_ENSURE( m_pRowSet, "ORowSetNotifier::ORowSetNotifier: invalid row set. This will crash." ); + 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& ORowSetNotifier::getChangedColumns() +{ + return aChangedColumns; +} + +void ORowSetNotifier::firePropertyChange() +{ + for (auto const& changedColumn : aChangedColumns) + { + m_pRowSet->firePropertyChange(changedColumn-1, aRow[changedColumn-1], ORowSetBase::GrantNotifierAccess()); + } + if ( !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 0000000000..13d6464cdd --- /dev/null +++ b/dbaccess/source/core/api/RowSetBase.hxx @@ -0,0 +1,400 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "RowSetRow.hxx" +#include "RowSetCacheIterator.hxx" + +#include + +namespace com::sun::star { + namespace sdb { struct RowChangeEvent; } + namespace lang { struct Locale; } +} + +namespace dbaccess +{ + class OEmptyCollection; + + typedef ::cppu::ImplHelper9< 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> ORowSetBase_BASE; + + class ORowSetCache; + class ORowSetDataColumns; + class ORowSetCacheIterator; + class ORowSetDataColumn; + class ORowSetBase : public ORowSetBase_BASE, + public ::comphelper::OPropertyStateContainer, + public ::comphelper::OPropertyArrayUsageHelper // this class hold the static property info + { + protected: + typedef std::vector 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 m_pCache; // the cache is used by the rowset and his clone (shared) + std::unique_ptr 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 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& _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 if and only if we're using the insert row (means: we're updating _or_ inserting) + virtual bool isModification( ) = 0; + // return if and only if the current row is modified + // TODO: isn't this the same as isModification? + virtual bool isModified( ) = 0; + // return if and only if the current row is the insert row + virtual bool isNew( ) = 0; + // return 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 class CursorMoveDirection + { + /// denotes a cursor move forward + Forward, + /// denotes a cursor move backwards + Backward, + /// denotes no cursor move at all, but move cache to current row (if it is not there already) + Current, + /// denotes no cursor move at all, but force the cache to move to current row (and refresh the row) + CurrentRefresh + }; + /** 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.
+ If, however, we're currently on a deleted row, this is used to properly position the cache + using m_nDeletedPosition.
+ 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 when we already stand on the row we want to. + @param _aMovementFunctor + The method used to move. + @return + if movement was successful. + */ + bool SAL_CALL move( std::function const & _aCheckFunctor, + std::function const & _aMovementFunctor); + + /** same meaning as isFirst. Only need by mem_fun + @return + if so. + */ + bool isOnFirst(); + /** same meaning as isLast. Only need by mem_fun + @return + 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 + +

The class can only be used on the stack, within a method of ORowSetBase (or derivees)

+ */ + class ORowSetNotifier + { + private: + std::vector aChangedColumns; + ORowSetValueVector::Vector aRow; + 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. fire has to be called before. + ~ORowSetNotifier( ); + + /** notifies the insertion + +

This has not been put into the destructor by intention!
+ + 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.

+ + @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 index of the changed column values + */ + std::vector& getChangedColumns(); + + }; + +} // 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 0000000000..25952429d0 --- /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 +#include "BookmarkSet.hxx" +#include "KeySet.hxx" +#include "OptimisticSet.hxx" +#include "RowSetBase.hxx" +#include "RowSetCache.hxx" +#include "StaticSet.hxx" +#include "WrappedResultSet.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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& _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 xTabSup(_xAnalyzer,UNO_QUERY); + OSL_ENSURE(xTabSup.is(),"ORowSet::execute composer isn't a tablesupplier!"); + Reference 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 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(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 xSet(m_aUpdateTable,UNO_QUERY); + const Reference xPrimaryKeyColumns = dbtools::getPrimaryKeyColumns_throw(xSet); + if ( xPrimaryKeyColumns.is() ) + { + Reference xColSup(_xAnalyzer,UNO_QUERY); + if ( xColSup.is() ) + { + Reference xSelColumns = xColSup->getColumns(); + Reference 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(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it + { + Reference 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 xMeta = xConnection->getMetaData(); + SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()); + Reference xColSup(_xAnalyzer,UNO_QUERY); + Reference xSelColumns = xColSup->getColumns(); + Reference 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 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 pKeySet = new OKeySet(m_aUpdateTable, aUpdateTableName ,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount); + try + { + m_xCacheSet = pKeySet; + pKeySet->construct(_xRs,i_sRowSetFilter); + + if(Reference(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it + { + Reference 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 aPositions; + std::map 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::const_iterator aIter = aPositions.begin(); + ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin(); + for(const auto& rPosChange : aCacheIterToChange) + { + if ( rPosChange.second ) + { + OSL_ENSURE((*aIter >= static_cast(0)) && (*aIter < static_cast(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& 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& 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& o_ChangedColumns + ) +{ + checkUpdateConditions(columnIndex); + + Sequence 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& 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& 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(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(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(0)) && + ((nDist + nStartPosOffset) < static_cast(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(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(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(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(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(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(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((*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(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 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 0000000000..01ed6394dc --- /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 +#include +#include +#include +#include +#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 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 m_xCacheSet; // is a bookmarkable, keyset or static resultset + + std::unique_ptr 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 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& o_ChangedColumns + ); + + void impl_updateRowFromCache_throw(ORowSetValueVector::Vector& io_aRow + ,std::vector 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& o_ChangedColumns + ); + void updateObject( sal_Int32 columnIndex, const css::uno::Any& x,ORowSetValueVector::Vector& io_aRow ,std::vector& o_ChangedColumns); + void updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, ORowSetValueVector::Vector& io_aRow ,std::vector& o_ChangedColumns); + void updateNull(sal_Int32 columnIndex + ,ORowSetValueVector::Vector& io_aRow + ,std::vector& 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& 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 0000000000..7df7bae6b9 --- /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 0000000000..f5d5e6783b --- /dev/null +++ b/dbaccess/source/core/api/RowSetCacheIterator.hxx @@ -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 . + */ +#pragma once + +#include + +#include +#include + +#include "RowSetRow.hxx" + +namespace dbaccess +{ + class ORowSetBase; + struct ORowSetCacheIterator_Helper + { + ORowSetMatrix::iterator aIterator; + ORowSetBase* pRowSet; + }; + + typedef std::map ORowSetCacheMap; + + class ORowSetCache; + class ORowSetCacheIterator final + { + friend class ORowSetCache; + ORowSetCacheMap::iterator m_aIter; + ORowSetCache* m_pCache; + ORowSetBase* m_pRowSet; + + ORowSetCacheIterator(ORowSetCacheMap::iterator _aIter, ORowSetCache* _pCache,ORowSetBase* _pRowSet) + : m_aIter(std::move(_aIter)) + ,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 0000000000..a847399dd1 --- /dev/null +++ b/dbaccess/source/core/api/RowSetRow.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 +#include +#include +#include +#include + +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(ORowSetRow _aRow) + : m_aRow(std::move(_aRow)) + {} + + 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 0000000000..f6dffbd131 --- /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 +#include +#include +#include +#include +#include +#include +#include "HelperCollections.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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 OUString STR_WHERE = u" WHERE "_ustr; +constexpr OUStringLiteral STR_GROUP_BY = u" GROUP BY "; +constexpr OUStringLiteral STR_HAVING = u" HAVING "; +constexpr OUStringLiteral STR_ORDER_BY = u" ORDER BY "; +constexpr OUString STR_AND = u" AND "_ustr; +constexpr OUString STR_OR = u" OR "_ustr; +constexpr OUStringLiteral STR_LIKE = u" LIKE "; +constexpr OUString L_BRACKET = u"("_ustr; +constexpr OUString R_BRACKET = u")"_ustr; +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 parseStatement_throwError( OSQLParser& _rParser, const OUString& _rStatement, const Reference< XInterface >& _rxContext ) + { + OUString aErrorMsg; + std::unique_ptr 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 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& _rContext ) + :OSubComponent(m_aMutex,_xConnection) + ,OPropertyContainer(m_aBHelper) + ,m_aSqlParser( _rContext, &m_aParseContext, &m_aNeutralContext ) + ,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::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 xDs = dbaccess::getDataSource(_xConnection); + if ( dbtools::getDataSourceSetting(xDs,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 OSingleSelectQueryComposer::getImplementationId() +{ + return css::uno::Sequence(); +} + +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 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 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 aCatalog,aSchema,aTable; + ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatalog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation); + sTableName = ::dbtools::composeTableName( m_xMetaData, aCatalog, 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 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(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 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(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 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(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 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 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, std::u16string_view rQuoteString) + { + const size_t nQuoteLength = rQuoteString.size(); + 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 ( static_cast(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, + std::u16string_view 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 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 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 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 aCatalog,aSchema,aTable; + ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatalog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation); + sTableName = ::dbtools::composeTableName( m_xMetaData, aCatalog, 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(nLength)) + "'"); + } + } + else + { + aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) ); + } + } + break; + case DataType::VARBINARY: + case DataType::BINARY: + case DataType::LONGVARBINARY: + { + Sequence 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(*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::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 pSqlParseNode( m_aSqlParser.parseTree(aErrorMsg,aSql)); + if (pSqlParseNode) + { + m_aAdditiveIterator.setParseTree(pSqlParseNode.get()); + // normalize the filter + OSQLParseNode* pWhereNode = const_cast(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* 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 0000000000..97226b466d --- /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 +#include +#include +#include +#include +#include + +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(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 0000000000..9f765996b8 --- /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 0000000000..92821750f9 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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(); +} + +// 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::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 xProp(m_xTable,UNO_QUERY); + xProp->setPropertyValue(PROPERTY_CATALOGNAME,_rValue); + } + break; + case PROPERTY_ID_SCHEMANAME: + { + Reference xProp(m_xTable,UNO_QUERY); + xProp->setPropertyValue(PROPERTY_SCHEMANAME,_rValue); + } + break; + case PROPERTY_ID_NAME: + { + Reference xProp(m_xTable,UNO_QUERY); + xProp->setPropertyValue(PROPERTY_NAME,_rValue); + } + break; + case PROPERTY_ID_DESCRIPTION: + { + Reference xProp(m_xTable,UNO_QUERY); + xProp->setPropertyValue(PROPERTY_DESCRIPTION,_rValue); + } + break; + case PROPERTY_ID_TYPE: + { + Reference 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 xProp(m_xTable,UNO_QUERY); + Reference 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 xProp(m_xTable,UNO_QUERY); + _rValue = xProp->getPropertyValue(PROPERTY_CATALOGNAME); + } + break; + case PROPERTY_ID_SCHEMANAME: + { + Reference xProp(m_xTable,UNO_QUERY); + _rValue = xProp->getPropertyValue(PROPERTY_SCHEMANAME); + } + break; + case PROPERTY_ID_NAME: + { + Reference xProp(m_xTable,UNO_QUERY); + _rValue = xProp->getPropertyValue(PROPERTY_NAME); + } + break; + case PROPERTY_ID_DESCRIPTION: + { + Reference xProp(m_xTable,UNO_QUERY); + _rValue = xProp->getPropertyValue(PROPERTY_DESCRIPTION); + } + break; + case PROPERTY_ID_TYPE: + { + Reference 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 xProp(m_xTable,UNO_QUERY); + if ( xProp.is() ) + { + Reference xInfo = xProp->getPropertySetInfo(); + bNotFound = !xInfo->hasPropertyByName(PROPERTY_PRIVILEGES); + } + if ( bNotFound ) + registerProperty(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, PropertyAttribute::BOUND | PropertyAttribute::READONLY, + &m_nPrivileges, ::cppu::UnoType::get()); +} + +::cppu::IPropertyArrayHelper* ODBTableDecorator::createArrayHelper(sal_Int32 /*_nId*/) const +{ + Reference xProp(m_xTable,UNO_QUERY); + Reference 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 xProp(m_xTable,UNO_QUERY); + + Reference 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 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(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 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 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 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(rId)) + return comphelper::getSomething_cast(this); + + sal_Int64 nRet = 0; + Reference 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 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 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 pMediator = new OContainerMediator( pCol, m_xColumnDefinitions ); + m_xColumnMediator = pMediator; + pCol->setMediator( pMediator.get() ); + m_pColumns.reset(pCol); + } + else + m_pColumns->reFill(aVector); +} + +rtl::Reference ODBTableDecorator::createColumn(const OUString& _rName) const +{ + rtl::Reference pReturn; + + Reference xNames; + if ( m_xTable.is() ) + { + xNames = m_xTable->getColumns(); + + if ( xNames.is() && xNames->hasByName(_rName) ) + { + Reference xProp(xNames->getByName(_rName),UNO_QUERY); + + Reference 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(m_xColumnDefinitions,UNO_QUERY); + if ( xDrop.is() && m_xColumnDefinitions->hasByName(_sName) ) + xDrop->dropByName(_sName); +} + +Reference< XPropertySet > ODBTableDecorator::createColumnDescriptor() +{ + Reference 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 0000000000..ce813b29ee --- /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 +#include + +#include + +#include + +#include + +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 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::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::get(); + + Sequence< Type > aTypes( ::comphelper::concatSequences(View_Base::getTypes(),View_IBASE::getTypes()) ); + std::vector 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(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 0000000000..09d70826bd --- /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 + +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 0000000000..58b2d70410 --- /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 +#include +#include + +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 0000000000..59615c4cd2 --- /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 +#include +#include +#include + +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::get(), + cppu::UnoType::get(), + OPreparedStatement::getTypes() ); + + return aTypes.getTypes(); +} + +Sequence< sal_Int8 > OCallableStatement::getImplementationId() +{ + return css::uno::Sequence(); +} + +// 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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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 0000000000..661624c2e5 --- /dev/null +++ b/dbaccess/source/core/api/column.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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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::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, + css::uno::Reference< css::container::XNameAccess > _xDrvColumns, + 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(std::move(_xDrvColumns)) + ,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(xRet,UNO_QUERY); + if ( xChild.is() ) + xChild->setParent(static_cast(static_cast(this))); + } + + Reference xDest(xRet,UNO_QUERY); + if ( m_pMediator && xDest.is() ) + m_pMediator->notifyElementCreated(_rName,xDest); + + return xRet; +} + +Reference< XPropertySet > OColumns::createDescriptor() +{ + if ( m_pColFactoryImpl ) + { + Reference xRet = m_pColFactoryImpl->createColumnDescriptor(); + Reference xChild(xRet,UNO_QUERY); + if ( xChild.is() ) + xChild->setParent(static_cast(static_cast(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::get()) + return Any(); + if(!m_bDropColumn && rType == cppu::UnoType::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::get(); + Type aDropType = cppu::UnoType::get(); + if(m_xDrvColumns.is()) + { + Reference 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(static_cast(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(static_cast(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 0000000000..505e0d36b9 --- /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 +#include +#include + +#include + +#include +#include + +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::get(); + const Type& rStringType = ::cppu::UnoType::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::get() ); + _rPropertyContainer.registerProperty( PROPERTY_HIDDEN, PROPERTY_ID_HIDDEN, nBoundAttr, &m_bHidden, cppu::UnoType::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[] = + { + { PROPERTY_ALIGN, PROPERTY_ID_ALIGN }, + { PROPERTY_NUMBERFORMAT, PROPERTY_ID_NUMBERFORMAT }, + { PROPERTY_RELATIVEPOSITION, PROPERTY_ID_RELATIVEPOSITION }, + { PROPERTY_WIDTH, PROPERTY_ID_WIDTH }, + { PROPERTY_HELPTEXT, PROPERTY_ID_HELPTEXT }, + { PROPERTY_CONTROLDEFAULT, PROPERTY_ID_CONTROLDEFAULT }, + { PROPERTY_CONTROLMODEL, PROPERTY_ID_CONTROLMODEL }, + { 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 0000000000..c597a40649 --- /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 +#include +#include + +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::get(), + cppu::UnoType::get(), + OColumn::getTypes()); + return aTypes.getTypes(); +} + +Sequence< sal_Int8 > ODataColumn::getImplementationId() +{ + return css::uno::Sequence(); +} + +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 0000000000..46512d9455 --- /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 +#include +#include +#include +#include +#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 0000000000..e845f11350 --- /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 +#include +#include +#include +#include +#include +#include + +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::UnoTypem_sHavingClause)>::get()); + + registerProperty(PROPERTY_GROUP_BY, PROPERTY_ID_GROUP_BY, PropertyAttribute::BOUND, + &_pItem->m_sGroupBy, cppu::UnoTypem_sGroupBy)>::get()); + } + + registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND, + &_pItem->m_sFilter, cppu::UnoTypem_sFilter)>::get()); + + registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND, + &_pItem->m_sOrder, cppu::UnoTypem_sOrder)>::get()); + + registerProperty(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, PropertyAttribute::BOUND, + &_pItem->m_bApplyFilter, cppu::UnoType::get()); + + registerProperty(PROPERTY_FONT, PROPERTY_ID_FONT, PropertyAttribute::BOUND, + &_pItem->m_aFont, cppu::UnoTypem_aFont)>::get()); + + registerMayBeVoidProperty(PROPERTY_ROW_HEIGHT, PROPERTY_ID_ROW_HEIGHT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID, + &_pItem->m_aRowHeight, ::cppu::UnoType::get()); + + registerProperty(PROPERTY_AUTOGROW, PROPERTY_ID_AUTOGROW, PropertyAttribute::BOUND, + &_pItem->m_bAutoGrow, cppu::UnoType::get()); + + registerMayBeVoidProperty(PROPERTY_TEXTCOLOR, PROPERTY_ID_TEXTCOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID, + &_pItem->m_aTextColor, ::cppu::UnoType::get()); + + registerMayBeVoidProperty(PROPERTY_TEXTLINECOLOR, PROPERTY_ID_TEXTLINECOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID, + &_pItem->m_aTextLineColor, ::cppu::UnoType::get()); + + registerProperty(PROPERTY_TEXTEMPHASIS, PROPERTY_ID_TEXTEMPHASIS, PropertyAttribute::BOUND, + &_pItem->m_nFontEmphasis, cppu::UnoTypem_nFontEmphasis)>::get()); + + registerProperty(PROPERTY_TEXTRELIEF, PROPERTY_ID_TEXTRELIEF, PropertyAttribute::BOUND,&_pItem->m_nFontRelief, cppu::UnoTypem_nFontRelief)>::get()); + + registerProperty(PROPERTY_FONTNAME, PROPERTY_ID_FONTNAME, PropertyAttribute::BOUND,&_pItem->m_aFont.Name, cppu::UnoTypem_aFont.Name)>::get()); + registerProperty(PROPERTY_FONTHEIGHT, PROPERTY_ID_FONTHEIGHT, PropertyAttribute::BOUND,&_pItem->m_aFont.Height, cppu::UnoTypem_aFont.Height)>::get()); + registerProperty(PROPERTY_FONTWIDTH, PROPERTY_ID_FONTWIDTH, PropertyAttribute::BOUND,&_pItem->m_aFont.Width, cppu::UnoTypem_aFont.Width)>::get()); + registerProperty(PROPERTY_FONTSTYLENAME, PROPERTY_ID_FONTSTYLENAME, PropertyAttribute::BOUND,&_pItem->m_aFont.StyleName, cppu::UnoTypem_aFont.StyleName)>::get()); + registerProperty(PROPERTY_FONTFAMILY, PROPERTY_ID_FONTFAMILY, PropertyAttribute::BOUND,&_pItem->m_aFont.Family, cppu::UnoTypem_aFont.Family)>::get()); + registerProperty(PROPERTY_FONTCHARSET, PROPERTY_ID_FONTCHARSET, PropertyAttribute::BOUND,&_pItem->m_aFont.CharSet, cppu::UnoTypem_aFont.CharSet)>::get()); + registerProperty(PROPERTY_FONTPITCH, PROPERTY_ID_FONTPITCH, PropertyAttribute::BOUND,&_pItem->m_aFont.Pitch, cppu::UnoTypem_aFont.Pitch)>::get()); + registerProperty(PROPERTY_FONTCHARWIDTH, PROPERTY_ID_FONTCHARWIDTH, PropertyAttribute::BOUND,&_pItem->m_aFont.CharacterWidth, cppu::UnoTypem_aFont.CharacterWidth)>::get()); + registerProperty(PROPERTY_FONTWEIGHT, PROPERTY_ID_FONTWEIGHT, PropertyAttribute::BOUND,&_pItem->m_aFont.Weight, cppu::UnoTypem_aFont.Weight)>::get()); + registerProperty(PROPERTY_FONTSLANT, PROPERTY_ID_FONTSLANT, PropertyAttribute::BOUND,&_pItem->m_aFont.Slant, cppu::UnoTypem_aFont.Slant)>::get()); + registerProperty(PROPERTY_FONTUNDERLINE, PROPERTY_ID_FONTUNDERLINE, PropertyAttribute::BOUND,&_pItem->m_aFont.Underline, cppu::UnoTypem_aFont.Underline)>::get()); + registerProperty(PROPERTY_FONTSTRIKEOUT, PROPERTY_ID_FONTSTRIKEOUT, PropertyAttribute::BOUND,&_pItem->m_aFont.Strikeout, cppu::UnoTypem_aFont.Strikeout)>::get()); + registerProperty(PROPERTY_FONTORIENTATION, PROPERTY_ID_FONTORIENTATION, PropertyAttribute::BOUND,&_pItem->m_aFont.Orientation, cppu::UnoTypem_aFont.Orientation)>::get()); + registerProperty(PROPERTY_FONTKERNING, PROPERTY_ID_FONTKERNING, PropertyAttribute::BOUND,&_pItem->m_aFont.Kerning, cppu::UnoTypem_aFont.Kerning)>::get()); + registerProperty(PROPERTY_FONTWORDLINEMODE, PROPERTY_ID_FONTWORDLINEMODE,PropertyAttribute::BOUND,&_pItem->m_aFont.WordLineMode, cppu::UnoTypem_aFont.WordLineMode)>::get()); + registerProperty(PROPERTY_FONTTYPE, PROPERTY_ID_FONTTYPE, PropertyAttribute::BOUND,&_pItem->m_aFont.Type, cppu::UnoTypem_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 0000000000..82b3fc02c5 --- /dev/null +++ b/dbaccess/source/core/api/definitioncolumn.cxx @@ -0,0 +1,611 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +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::get() ); + registerProperty( PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, nDefaultAttr, &m_aDescription, cppu::UnoType::get() ); + registerProperty( PROPERTY_DEFAULTVALUE, PROPERTY_ID_DEFAULTVALUE, nDefaultAttr, &m_aDefaultValue, cppu::UnoType::get() ); + + if ( m_bActAsDescriptor ) + registerProperty( PROPERTY_AUTOINCREMENTCREATION, PROPERTY_ID_AUTOINCREMENTCREATION, nDefaultAttr, &m_aAutoIncrementValue, cppu::UnoType::get() ); + + registerProperty( PROPERTY_TYPE, PROPERTY_ID_TYPE, nDefaultAttr, &m_nType, cppu::UnoType::get() ); + registerProperty( PROPERTY_PRECISION, PROPERTY_ID_PRECISION, nDefaultAttr, &m_nPrecision, cppu::UnoType::get() ); + registerProperty( PROPERTY_SCALE, PROPERTY_ID_SCALE, nDefaultAttr, &m_nScale, cppu::UnoType::get() ); + registerProperty( PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, nDefaultAttr, &m_nIsNullable, cppu::UnoType::get() ); + registerProperty( PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, nDefaultAttr, &m_bAutoIncrement, cppu::UnoType::get() ); + registerProperty( PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, nDefaultAttr, &m_bRowVersion, cppu::UnoType::get() ); + registerProperty( PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, nDefaultAttr, &m_bCurrency, cppu::UnoType::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? SERVICE_SDBCX_COLUMNDESCRIPTOR : 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, OUString i_sLabel ) + :OTableColumnDescriptor( false /* do not act as descriptor */ ) + ,m_sLabel(std::move(i_sLabel)) +{ + const sal_Int32 nPropAttr = PropertyAttribute::READONLY; + registerProperty( PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, nPropAttr, &m_sCatalogName, cppu::UnoType::get() ); + registerProperty( PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, nPropAttr, &m_sSchemaName, cppu::UnoType::get() ); + registerProperty( PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, nPropAttr, &m_sTableName, cppu::UnoType::get() ); + registerProperty( PROPERTY_REALNAME, PROPERTY_ID_REALNAME, nPropAttr, &m_sRealName, cppu::UnoType::get() ); + registerProperty( PROPERTY_LABEL, PROPERTY_ID_LABEL, nPropAttr, &m_sLabel, cppu::UnoType::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[] = + { + { PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME }, + { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME }, + { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME }, + { 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 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::get(), 0); + pDesc[nPos++] = css::beans::Property(PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType::get(), 0); + pDesc[nPos++] = css::beans::Property(PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType::get(), 0); + pDesc[nPos++] = css::beans::Property(PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType::get(), 0); + pDesc[nPos++] = css::beans::Property(PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType::get(), 0); + pDesc[nPos++] = css::beans::Property(PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType::get(), 0); + pDesc[nPos++] = css::beans::Property(PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType::get(), 0); + + if ( nId & HAS_AUTOINCREMENT_CREATION ) + { + pDesc[nPos++] = css::beans::Property(PROPERTY_AUTOINCREMENTCREATION, PROPERTY_ID_AUTOINCREMENTCREATION, cppu::UnoType::get(), css::beans::PropertyAttribute::MAYBEVOID ); + } + if ( nId & HAS_DEFAULTVALUE ) + { + pDesc[nPos++] = css::beans::Property(PROPERTY_DEFAULTVALUE, PROPERTY_ID_DEFAULTVALUE, cppu::UnoType::get(), 0); + } + if ( nId & HAS_DESCRIPTION ) + { + pDesc[nPos++] = css::beans::Property(PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, cppu::UnoType::get(), 0); + } + if ( nId & HAS_ROWVERSION ) + { + pDesc[nPos++] = css::beans::Property(PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType::get(), 0); + } + if ( nId & HAS_CATALOGNAME ) + { + pDesc[nPos++] = css::beans::Property(PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType::get(), 0); + } + if ( nId & HAS_SCHEMANAME ) + { + pDesc[nPos++] = css::beans::Property(PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType::get(), 0); + } + if ( nId & HAS_TABLENAME ) + { + pDesc[nPos++] = css::beans::Property(PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType::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 0000000000..32c3ff1777 --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "resultcolumn.hxx" +#include "resultset.hxx" +#include + +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 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::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + OStatementBase::getTypes() ); + + return aTypes.getTypes(); +} + +Sequence< sal_Int8 > OPreparedStatement::getImplementationId() +{ + return css::uno::Sequence(); +} + +// 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_PREPAREDSTATEMENT }; +} + +// 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(WeakComponentImplHelper::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 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(WeakComponentImplHelper::rBHelper.bDisposed); + return Reference< XResultSetMetaDataSupplier >( m_xAggregateAsSet, UNO_QUERY_THROW )->getMetaData(); +} + +// XPreparedStatement +Reference< XResultSet > OPreparedStatement::executeQuery() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::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(WeakComponentImplHelper::rBHelper.bDisposed); + + disposeResultSet(); + + return Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->executeUpdate(); +} + +sal_Bool OPreparedStatement::execute() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setBoolean(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setByte(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setShort(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setInt(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setLong(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setFloat(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setDouble(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setArray(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::clearParameters( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::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 0000000000..eceedb03b9 --- /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 +#include +#include +#include +#include "HelperCollections.hxx" +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +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()) + ,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 OQuery::getImplementationId() +{ + return css::uno::Sequence(); +} + +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 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 aColNames = xColumns->getElementNames(); + for ( const OUString& rName : aColNames ) + { + Reference xSource(xColumns->getByName( rName ),UNO_QUERY); + OUString sLabel = rName; + if ( xColumnDefinitions.is() && xColumnDefinitions->hasByName(rName) ) + { + Reference xCommandColumn(xColumnDefinitions->getByName( rName ),UNO_QUERY); + xCommandColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel; + } + rtl::Reference 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 OQuery::createColumn(const OUString& /*_rName*/) const +{ + return nullptr; +} + +void SAL_CALL OQuery::rename( const OUString& newName ) +{ + MutexGuard aGuard(m_aMutex); + Reference 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::get()); + + registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND, + &m_sCommand, cppu::UnoType::get()); + + registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, + &m_bEscapeProcessing, cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND, + &m_sUpdateTableName, cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND, + &m_sUpdateSchemaName, cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND, + &m_sUpdateCatalogName, cppu::UnoType::get()); + + registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND, + &m_aLayoutInformation, cppu::UnoType::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 0000000000..fefcb94b47 --- /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 +#include +#include +#include +#include +#include +#include + +#include + +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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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 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 0000000000..8bab871870 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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(); +} + +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 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(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(m_xComposer,UNO_QUERY_THROW)->getColumns(); +} + +Reference< XIndexAccess > SAL_CALL OQueryComposer::getParameters( ) +{ + ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed); + + ::osl::MutexGuard aGuard( m_aMutex ); + return Reference(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 0000000000..583cab373b --- /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 +#include "query.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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()) + ,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( m_xConnection, ObjectNameApproval::TypeQuery ) ); +} + +rtl::Reference 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(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 xProp(Reference(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 xContainer(_rxCommandDesc,UNO_QUERY); + Reference< XContent > xReturn; + if ( xContainer .is() ) + { + xReturn = create( xContainer, m_xConnection, m_aContext, m_pWarnings ). + get(); + } + else + { + rtl::Reference 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(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 0000000000..d9cbbc634c --- /dev/null +++ b/dbaccess/source/core/api/querydescriptor.cxx @@ -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 . + */ + +#include "querydescriptor.hxx" +#include +#include +#include +#include +#include + +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 OQueryDescriptor::getImplementationId() +{ + return css::uno::Sequence(); +} + +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::get()); + + registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND, + &m_sCommand, cppu::UnoType::get()); + + registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, + &m_bEscapeProcessing, cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND, + &m_sUpdateTableName, cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND, + &m_sUpdateSchemaName, cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND, + &m_sUpdateCatalogName, cppu::UnoType::get()); + + registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND, + &m_aLayoutInformation, cppu::UnoType::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(); +} + +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 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 0000000000..181b8e4d43 --- /dev/null +++ b/dbaccess/source/core/api/querydescriptor.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 +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace dbaccess +{ + +// OQueryDescriptor_Base - a query descriptor (as the name suggests :) +typedef ::cppu::ImplHelper2< + css::sdbcx::XColumnsSupplier, + 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 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::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 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 NOT 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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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 0000000000..8662317696 --- /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 +#include +#include +#include +#include +#include +#include +#include + +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(); +} + +// 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::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_DISPLAYSIZE, PROPERTY_ID_DISPLAYSIZE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISCASESENSITIVE, PROPERTY_ID_ISCASESENSITIVE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISDEFINITELYWRITABLE, PROPERTY_ID_ISDEFINITELYWRITABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISSEARCHABLE, PROPERTY_ID_ISSEARCHABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISSIGNED, PROPERTY_ID_ISSIGNED, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_ISWRITABLE, PROPERTY_ID_ISWRITABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_NAME, PROPERTY_ID_NAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SERVICENAME, PROPERTY_ID_SERVICENAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType::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 0000000000..53803bac8c --- /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 +#include +#include +#include +#include +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 0000000000..cc6a6fe018 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "datacolumn.hxx" +#include +#include + + +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 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::get(), + OResultSetBase::getTypes()); + + return aTypes.getTypes(); +} + +Sequence< sal_Int8 > OResultSet::getImplementationId() +{ + return css::uno::Sequence(); +} + +// 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::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, cppu::UnoType::get(), 0 }, + { PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, cppu::UnoType::get(), 0 }, + { PROPERTY_ISBOOKMARKABLE, PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, cppu::UnoType::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(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 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 0000000000..b2da0f2483 --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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 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 0000000000..1a20823ab9 --- /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 +#include "resultset.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(WeakComponentImplHelper::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::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + OSubComponent::getTypes() ); + Reference< XGeneratedResultSet > xGRes(m_xAggregateAsSet, UNO_QUERY); + if ( xGRes.is() ) + aTypes = OTypeCollection(cppu::UnoType::get(),aTypes.getTypes()); + Reference< XPreparedBatchExecution > xPreparedBatchExecution(m_xAggregateAsSet, UNO_QUERY); + if ( xPreparedBatchExecution.is() ) + aTypes = OTypeCollection(cppu::UnoType::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::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::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(WeakComponentImplHelper::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::get(), 0 }, + { PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, cppu::UnoType::get(), 0 }, + { PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, cppu::UnoType::get(), 0 }, + { PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, cppu::UnoType::get(), 0 }, + { PROPERTY_MAXFIELDSIZE, PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType::get(), 0 }, + { PROPERTY_MAXROWS, PROPERTY_ID_MAXROWS, cppu::UnoType::get(), 0 }, + { PROPERTY_QUERYTIMEOUT, PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType::get(), 0 }, + { PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType::get(), 0 }, + { PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, cppu::UnoType::get(), 0 }, + { PROPERTY_USEBOOKMARKS, PROPERTY_ID_USEBOOKMARKS, cppu::UnoType::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(WeakComponentImplHelper::rBHelper.bDisposed); + + return Reference< XWarningsSupplier >(m_xAggregateAsSet, UNO_QUERY_THROW)->getWarnings(); +} + +void OStatementBase::clearWarnings() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(WeakComponentImplHelper::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(WeakComponentImplHelper::rBHelper.bDisposed); + + // first check the meta data + Reference 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(WeakComponentImplHelper::rBHelper.bDisposed); + + // first check the meta data + Reference 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(WeakComponentImplHelper::rBHelper.bDisposed); + + // first check the meta data + Reference 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(WeakComponentImplHelper::rBHelper.bDisposed); + + // first check the meta data + Reference 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(WeakComponentImplHelper::rBHelper.bDisposed); + + // first check the meta data + Reference 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(WeakComponentImplHelper::rBHelper.bDisposed); + + // first check the meta data + Reference 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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::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(WeakComponentImplHelper::rBHelper.bDisposed); + + // first check the meta data + Reference 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(WeakComponentImplHelper::rBHelper.bDisposed); + // first check the meta data + Reference 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(WeakComponentImplHelper::rBHelper.bDisposed); + // first check the meta data + Reference 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 0000000000..32c7afdf92 --- /dev/null +++ b/dbaccess/source/core/api/table.cxx @@ -0,0 +1,340 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include "CIndexes.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +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 ODBTable::createColumn(const OUString& _rName) const +{ + Reference xProp; + if ( m_xDriverColumns.is() && m_xDriverColumns->hasByName(_rName) ) + { + xProp.set(m_xDriverColumns->getByName(_rName),UNO_QUERY); + } + else + { + OColumns* pColumns = static_cast(m_xColumns.get()); + xProp.set(pColumns->createBaseObject(_rName),UNO_QUERY); + } + + Reference 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(m_xColumnDefinitions,UNO_QUERY); + if ( xDrop.is() && m_xColumnDefinitions->hasByName(_sName) ) + { + xDrop->dropByName(_sName); + } +} + +Sequence< sal_Int8 > ODBTable::getImplementationId() +{ + return css::uno::Sequence(); +} + +// 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(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::get()); + + registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND, + &m_sOrder, cppu::UnoType::get()); + + registerProperty(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, PropertyAttribute::BOUND, + &m_bApplyFilter, cppu::UnoType::get()); + + registerProperty(PROPERTY_FONT, PROPERTY_ID_FONT, PropertyAttribute::BOUND, + &m_aFont, cppu::UnoType::get()); + + registerMayBeVoidProperty(PROPERTY_ROW_HEIGHT, PROPERTY_ID_ROW_HEIGHT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID, + &m_aRowHeight, cppu::UnoType::get()); + + registerProperty(PROPERTY_AUTOGROW, PROPERTY_ID_AUTOGROW, PropertyAttribute::BOUND, + &m_bAutoGrow, cppu::UnoType::get()); + + registerMayBeVoidProperty(PROPERTY_TEXTCOLOR, PROPERTY_ID_TEXTCOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID, + &m_aTextColor, cppu::UnoType::get()); + + registerProperty(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, PropertyAttribute::BOUND | PropertyAttribute::READONLY, + &m_nPrivileges, cppu::UnoType::get()); + + registerMayBeVoidProperty(PROPERTY_TEXTLINECOLOR, PROPERTY_ID_TEXTLINECOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID, + &m_aTextLineColor, cppu::UnoType::get()); + + registerProperty(PROPERTY_TEXTEMPHASIS, PROPERTY_ID_TEXTEMPHASIS, PropertyAttribute::BOUND, + &m_nFontEmphasis, cppu::UnoType::get()); + + registerProperty(PROPERTY_TEXTRELIEF, PROPERTY_ID_TEXTRELIEF, PropertyAttribute::BOUND, + &m_nFontRelief, cppu::UnoType::get()); + + registerProperty(PROPERTY_FONTNAME, PROPERTY_ID_FONTNAME, PropertyAttribute::BOUND,&m_aFont.Name, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTHEIGHT, PROPERTY_ID_FONTHEIGHT, PropertyAttribute::BOUND,&m_aFont.Height, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTWIDTH, PROPERTY_ID_FONTWIDTH, PropertyAttribute::BOUND,&m_aFont.Width, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTSTYLENAME, PROPERTY_ID_FONTSTYLENAME, PropertyAttribute::BOUND,&m_aFont.StyleName, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTFAMILY, PROPERTY_ID_FONTFAMILY, PropertyAttribute::BOUND,&m_aFont.Family, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTCHARSET, PROPERTY_ID_FONTCHARSET, PropertyAttribute::BOUND,&m_aFont.CharSet, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTPITCH, PROPERTY_ID_FONTPITCH, PropertyAttribute::BOUND,&m_aFont.Pitch, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTCHARWIDTH, PROPERTY_ID_FONTCHARWIDTH, PropertyAttribute::BOUND,&m_aFont.CharacterWidth, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTWEIGHT, PROPERTY_ID_FONTWEIGHT, PropertyAttribute::BOUND,&m_aFont.Weight, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTSLANT, PROPERTY_ID_FONTSLANT, PropertyAttribute::BOUND,&m_aFont.Slant, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTUNDERLINE, PROPERTY_ID_FONTUNDERLINE, PropertyAttribute::BOUND,&m_aFont.Underline, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTSTRIKEOUT, PROPERTY_ID_FONTSTRIKEOUT, PropertyAttribute::BOUND,&m_aFont.Strikeout, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTORIENTATION, PROPERTY_ID_FONTORIENTATION, PropertyAttribute::BOUND,&m_aFont.Orientation, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTKERNING, PROPERTY_ID_FONTKERNING, PropertyAttribute::BOUND,&m_aFont.Kerning, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTWORDLINEMODE, PROPERTY_ID_FONTWORDLINEMODE,PropertyAttribute::BOUND,&m_aFont.WordLineMode, cppu::UnoType::get()); + registerProperty(PROPERTY_FONTTYPE, PROPERTY_ID_FONTTYPE, PropertyAttribute::BOUND,&m_aFont.Type, cppu::UnoType::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::get()&& !getRenameService().is() ) + return Any(); + if(rType == cppu::UnoType::get()&& !getAlterService().is() ) + return Any(); + return OTable_Base::queryInterface( rType); +} + +Sequence< Type > SAL_CALL ODBTable::getTypes( ) +{ + Type aRenameType = cppu::UnoType::get(); + Type aAlterType = cppu::UnoType::get(); + + Sequence< Type > aTypes(OTable_Base::getTypes()); + std::vector 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 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 xTable(this); + getAlterService()->alterColumnByName(xTable,_rName,_rxDescriptor); + m_xColumns->refresh(); +} + +Reference< XPropertySet > ODBTable::createColumnDescriptor() +{ + return new OTableColumnDescriptor( true ); +} + +sdbcx::OCollection* ODBTable::createColumns(const ::std::vector< OUString>& _rNames) +{ + Reference 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(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 0000000000..06ae7603c6 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& _xProp) + { + Reference 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& _nInAppend) + :OFilteredContainer(_rParent,_rMutex,_xCon,_bCase,_pRefreshListener,_nInAppend) + ,m_xTableDefinitions(_xTableDefinitions) +{ +} + +OTableContainer::~OTableContainer() +{ +} + +void OTableContainer::removeMasterContainerListener() +{ + try + { + Reference 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& _xTableDefinition + ,Reference& _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(_xTableDefinition,UNO_QUERY); + if ( xColumnsSupplier.is() ) + _xColumnDefinitions = xColumnsSupplier->getColumns(); +} + +} + +connectivity::sdbcx::ObjectType OTableContainer::createObject(const OUString& _rName) +{ + Reference 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 xTableDefinition; + Reference xColumnDefinitions; + lcl_createDefinitionObject(_rName,m_xTableDefinitions,xTableDefinition,xColumnDefinitions); + + if ( xSup.is() ) + { + rtl::Reference 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 pTable = new ODBTable(this + ,m_xConnection + ,sCatalog + ,sSchema + ,sTable + ,sType + ,sDescription + ,xColumnDefinitions); + xRet = pTable; + pTable->construct(); + } + Reference 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 xMasterColumnsSup; + Reference xDataFactory(m_xMasterContainer,UNO_QUERY); + if ( xDataFactory.is() && m_xMetaData.is() ) + { + xMasterColumnsSup.set( xDataFactory->createDataDescriptor(), UNO_QUERY ); + rtl::Reference pTable = new ODBTableDecorator( m_xConnection, xMasterColumnsSup, ::dbtools::getNumberFormats( m_xConnection ) ,nullptr); + xRet = pTable; + pTable->construct(); + } + else + { + rtl::Reference 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(static_cast(this)),SQLSTATE_GENERAL,1000,Any()); + } + + Reference< XConnection > xConnection( m_xConnection.get(), UNO_QUERY ); + PContainerApprove pApprove = std::make_shared( xConnection, ObjectNameApproval::TypeTable ); + pApprove->approveElement( aName ); + + { + EnsureReset aReset(m_nInAppend); + Reference xAppend(m_xMasterContainer,UNO_QUERY); + if(xAppend.is()) + { + xAppend->appendByDescriptor(descriptor); + } + else + { + OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor,m_xConnection); + + Reference 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 xTableDefinition; + Reference xColumnDefinitions; + lcl_createDefinitionObject(getNameForObject(descriptor),m_xTableDefinitions,xTableDefinition,xColumnDefinitions); + Reference xSup(descriptor,UNO_QUERY); + Reference xFac(xColumnDefinitions,UNO_QUERY); + Reference xAppend(xColumnDefinitions,UNO_QUERY); + bool bModified = false; + if ( xSup.is() && xColumnDefinitions.is() && xFac.is() && xAppend.is() ) + { + Reference xNames = xSup->getColumns(); + if ( xNames.is() ) + { + Reference 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 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 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(static_cast(this))); + + OUString aSql("DROP "); + + if ( bIsView ) // here we have a view + aSql += "VIEW "; + else + aSql += "TABLE "; + aSql += sComposedName; + Reference 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(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 0000000000..462a3b1d00 --- /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 +#include +#include + +#include +#include +#include + +#include +#include + +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& _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 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(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(static_cast(this))); + + OUString sCommand; + descriptor->getPropertyValue(PROPERTY_COMMAND) >>= sCommand; + + OUString aSQL = "CREATE VIEW " + sComposedName + " AS " + sCommand; + + Reference 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 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(static_cast(this))); + + OUString aSql = "DROP VIEW " + sComposedName; + Reference 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 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 0000000000..a3a6459824 --- /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 +#include + +#include +#include +//#include +#include +#include +#include + +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 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::get()); + + if ( m_bTable ) + { + registerProperty(PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, PropertyAttribute::BOUND, + &rDefinition.m_sSchemaName, cppu::UnoType::get()); + + registerProperty(PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, PropertyAttribute::BOUND, + &rDefinition.m_sCatalogName, cppu::UnoType::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 OComponentDefinition::getImplementationId() +{ + return css::uno::Sequence(); +} + +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 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 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 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 const &) +{ + return cppu::acquire(new dbaccess::OComponentDefinition( + context, nullptr, std::make_shared())); +} + +/* 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 0000000000..4c10a5354b --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +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 m_pColumns; + rtl::Reference 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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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 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 0000000000..d7a8f63efd --- /dev/null +++ b/dbaccess/source/core/dataaccess/ContentHelper.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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 + ,TContentPtr _pImpl) + : OContentHelper_COMPBASE(m_aMutex) + ,m_aContentListeners(m_aMutex) + ,m_aPropertyChangeListeners(m_aMutex) + ,m_xParentContainer( _xParentContainer ) + ,m_aContext( _xORB ) + ,m_pImpl(std::move(_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" }; +} + + +css::uno::Sequence OContentHelper::getImplementationId() +{ + return css::uno::Sequence(); +} + +// 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 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 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::get(), + PropertyAttribute::BOUND + | PropertyAttribute::READONLY ), + getContentType() ); + xRow->appendString ( + Property( "Title", -1, + cppu::UnoType::get(), + PropertyAttribute::BOUND ), + m_pImpl->m_aProps.aTitle ); + xRow->appendBoolean( + Property( "IsDocument", -1, + cppu::UnoType::get(), + PropertyAttribute::BOUND + | PropertyAttribute::READONLY ), + m_pImpl->m_aProps.bIsDocument ); + xRow->appendBoolean( + Property( "IsFolder", -1, + cppu::UnoType::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* 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* 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 ); + } +} + +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 aChanges{ + { /* Source */ static_cast(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 0000000000..2144a1793e --- /dev/null +++ b/dbaccess/source/core/dataaccess/ModelImpl.cxx @@ -0,0 +1,1428 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "databasedocument.hxx" +#include "datasource.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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() + ,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_nControllerLockCount(0) +{ + // some kind of default + m_sConnectURL = "jdbc:"; + m_aTableFilter = { "%" }; + impl_construct_nothrow(); +} + +ODatabaseModelImpl::ODatabaseModelImpl( + OUString _sRegistrationName, + const Reference< XComponentContext >& _rxContext, + ODatabaseContext& _rDBContext + ) + :m_aContainer() + ,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(std::move(_sRegistrationName)) + ,m_nLoginTimeout(0) + ,m_bReadOnly(false) + ,m_bPasswordRequired(false) + ,m_bSuppressVersionColumns(true) + ,m_bModified(false) + ,m_bDocumentReadOnly(false) + ,m_bMacroCallsSeenWhileLoading(false) + ,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::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType>::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::ObjectType::Form: pAsciiName = "forms"; break; + case ODatabaseModelImpl::ObjectType::Report: pAsciiName = "reports"; break; + case ODatabaseModelImpl::ObjectType::Query: pAsciiName = "queries"; break; + case ODatabaseModelImpl::ObjectType::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; + for (auto & i : m_aContainer) + i.reset(); + + if ( m_pStorageAccess.is() ) + { + m_pStorageAccess->dispose(); + m_pStorageAccess.clear(); + } +} + +void ODatabaseModelImpl::disposing( const css::lang::EventObject& Source ) +{ + Reference 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_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(); + m_xModel = WeakReference< XModel >(); + + for (auto const& elem : m_aContainer) + { + if ( elem ) + elem->m_pDataSource = nullptr; + } + for (auto & i : m_aContainer) + i.reset(); + + 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::TempFileNamed 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 xDDSigns; + try + { + xDDSigns = security::DocumentDigitalSignatures::createWithVersion( + comphelper::getProcessComponentContext(), aODFVersion); + + const OUString aScriptSignName + = xDDSigns->getScriptingContentSignatureDefaultStreamName(); + + if (!aScriptSignName.isEmpty()) + { + Reference xReadOrig + = comphelper::OStorageHelper::GetStorageOfFormatFromURL( + ZIP_STORAGE_FORMAT_STRING, sTmpFileUrl, ElementModes::READ); + if (!xReadOrig.is()) + throw uno::RuntimeException("Could not read " + sTmpFileUrl); + uno::Reference xMetaInf + = xReadOrig->openStorageElement("META-INF", embed::ElementModes::READ); + + uno::Reference xTargetMetaInf + = _rxStorage->openStorageElement("META-INF", embed::ElementModes::READWRITE); + if (xMetaInf.is() && xTargetMetaInf.is() && xMetaInf->hasByName(aScriptSignName)) + { + xMetaInf->copyElementTo(aScriptSignName, xTargetMetaInf, aScriptSignName); + + uno::Reference xTransact(xTargetMetaInf, + uno::UNO_QUERY); + if (xTransact.is()) + xTransact->commit(); + + xTargetMetaInf->dispose(); + + // now check the copied signature + uno::Sequence aInfos + = xDDSigns->verifyScriptingContentSignatures( + _rxStorage, uno::Reference()); + 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 ODatabaseModelImpl::getOrCreateDataSource() +{ + Reference 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 ) +{ + TContentPtr& rContentPtr = m_aContainer[ _eType ]; + + if ( !rContentPtr ) + { + rContentPtr = std::make_shared(); + 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 ); + const bool bHasMacros = m_aMacroMode.hasMacros(); + return m_aMacroMode.checkMacrosOnLoading(xInteraction, false /*HasValidContentSignature*/, bHasMacros); +} + +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 = EmbeddedMacros::DocumentWide; + } + else if ( lcl_hasObjectsWithMacros_nothrow( *this, ObjectType::Form ) + || lcl_hasObjectsWithMacros_nothrow( *this, ObjectType::Report ) + ) + { + m_aEmbeddedMacros = EmbeddedMacros::SubDocument; + } + else + { + m_aEmbeddedMacros = EmbeddedMacros::NONE; + } + } + return *m_aEmbeddedMacros; +} + +bool ODatabaseModelImpl::documentStorageHasMacros() const +{ + const_cast< ODatabaseModelImpl* >( this )->determineEmbeddedMacros(); + return ( *m_aEmbeddedMacros != EmbeddedMacros::NONE ); +} + +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( + const css::uno::Reference& _rxInteraction) +{ + 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 = comphelper::OStorageHelper::GetStorageOfFormatFromURL( + ZIP_STORAGE_FORMAT_STRING, m_sDocFileLocation, ElementModes::READ); + + OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(getOrCreateRootStorage())); + uno::Reference xSigner( + security::DocumentDigitalSignatures::createWithVersion( + comphelper::getProcessComponentContext(), aODFVersion)); + const uno::Sequence aInfo + = xSigner->verifyScriptingContentSignatures(xStorage, + uno::Reference()); + + 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 && _rxInteraction) + { + task::DocumentMacroConfirmationRequest aRequest; + aRequest.DocumentURL = m_sDocFileLocation; + aRequest.DocumentStorage = xStorage; + aRequest.DocumentSignatureInformation = aInfo; + aRequest.DocumentVersion = aODFVersion; + aRequest.Classification = task::InteractionClassification_QUERY; + bResult = SfxMedium::CallApproveHandler(_rxInteraction, uno::Any(aRequest), true); + } + } + catch (uno::Exception&) + { + } + + return bResult; +} + +void ODatabaseModelImpl::storageIsModified() +{ + setModified( true ); +} + +ModelDependentComponent::ModelDependentComponent( ::rtl::Reference< ODatabaseModelImpl > _model ) + :m_pImpl(std::move( _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 0000000000..d893a8e298 --- /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 + +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& _rxProxyConnection) + : OSharedConnection_BASE(m_aMutex) +{ + setDelegation(_rxProxyConnection, m_refCount); +} + +OSharedConnection::~OSharedConnection() {} + +void SAL_CALL OSharedConnection::disposing() +{ + OConnectionWrapper::disposing(); + OSharedConnection_BASE::disposing(); +} + +Reference SAL_CALL OSharedConnection::createStatement() +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->createStatement(); +} + +Reference SAL_CALL OSharedConnection::prepareStatement(const OUString& sql) +{ + ::osl::MutexGuard aGuard(m_aMutex); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->prepareStatement(sql); +} + +Reference 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 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 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 0000000000..2c88e58fd5 --- /dev/null +++ b/dbaccess/source/core/dataaccess/SharedConnection.hxx @@ -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 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +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; + + class OSharedConnection : public ::cppu::BaseMutex + , public OSharedConnection_BASE + , public ::connectivity::OConnectionWrapper + { + 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(), + ::connectivity::OConnectionWrapper::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 = ::connectivity::OConnectionWrapper::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 0000000000..a03caea57e --- /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 + +#include +#include +#include +#include +#include +#include + +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::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(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 0000000000..8afb81520e --- /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 +#include + +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 OCommandContainer::getImplementationId() +{ + return css::uno::Sequence(); +} + +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 0000000000..3ea36f6480 --- /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 + +#include + +#include + +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.
+ */ + 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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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 0000000000..f04c472285 --- /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 +#include + +#include +#include + + +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::get()); + + registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, + &rCommandDefinition.m_bEscapeProcessing, cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND, + &rCommandDefinition.m_sUpdateTableName, cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND, + &rCommandDefinition.m_sUpdateSchemaName, cppu::UnoType::get()); + + registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND, + &rCommandDefinition.m_sUpdateCatalogName, cppu::UnoType::get()); + registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND, + &rCommandDefinition.m_aLayoutInformation, cppu::UnoType::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 OCommandDefinition::getImplementationId() +{ + return css::uno::Sequence(); +} + +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 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 const &) +{ + return cppu::acquire(new dbaccess::OCommandDefinition( + context, nullptr, std::make_shared() )); +} + +/* 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 0000000000..ed348a8899 --- /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 +#include +#include +#include +#include +#include +#include +#include "ComponentDefinition.hxx" + +#include +#include +#include + +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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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& p2) override + { OComponentDefinition::addPropertyChangeListener(p1, p2); } + virtual void SAL_CALL removePropertyChangeListener(const OUString& p1, const css::uno::Reference& p2) override + { OComponentDefinition::removePropertyChangeListener(p1, p2); } + virtual void SAL_CALL addVetoableChangeListener(const OUString& p1, const css::uno::Reference& p2) override + { OComponentDefinition::addVetoableChangeListener(p1, p2); } + virtual void SAL_CALL removeVetoableChangeListener(const OUString& p1, const css::uno::Reference& p2) override + { OComponentDefinition::removeVetoableChangeListener(p1, p2); } + virtual css::uno::Reference 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& p1) override + { OComponentDefinition::addContentEventListener(p1); } + virtual void SAL_CALL removeContentEventListener(const css::uno::Reference& p1) override + { OComponentDefinition::removeContentEventListener(p1); } + virtual void SAL_CALL dispose() override + { OComponentDefinition::dispose(); } + virtual void SAL_CALL addEventListener(const css::uno::Reference& p1) override + { OComponentDefinition::addEventListener(p1); } + virtual void SAL_CALL removeEventListener(const css::uno::Reference& p1) override + { OComponentDefinition::removeEventListener(p1); } + + // OPropertySetHelper + virtual css::uno::Reference 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 0000000000..144b393663 --- /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 + +#include + +#include "connection.hxx" +#include "datasource.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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 xRes = xMeta->getTableTypes(); + if(xRes.is()) + { + Reference 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::get() ); + if ( !m_bSupportsUsers ) + aNormalizedTypes.erase( cppu::UnoType::get() ); + if ( !m_bSupportsGroups ) + aNormalizedTypes.erase( cppu::UnoType::get() ); + + return comphelper::containerToSequence(aNormalizedTypes); +} + +Sequence< sal_Int8 > OConnection::getImplementationId() +{ + return css::uno::Sequence(); +} + +// css::uno::XInterface +Any OConnection::queryInterface( const Type & rType ) +{ + if ( !m_bSupportsViews && rType.equals( cppu::UnoType::get() ) ) + return Any(); + else if ( !m_bSupportsUsers && rType.equals( cppu::UnoType::get() ) ) + return Any(); + else if ( !m_bSupportsGroups && rType.equals( cppu::UnoType::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 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 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 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 xMy(this); + Sequence 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(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 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 xUsr(getMasterTables(),UNO_QUERY); + return xUsr.is() ? xUsr->getUsers() : Reference< XNameAccess >(); +} + +// XGroupsSupplier +Reference< XNameAccess > SAL_CALL OConnection::getGroups( ) +{ + MutexGuard aGuard(m_aMutex); + checkDisposed(); + Reference 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 0000000000..4ecfa7d709 --- /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 + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 m_pTables; + std::unique_ptr m_pViews; + ::dbtools::WarningsContainer m_aWarnings; + std::atomic 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 + */ + 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 0000000000..ef5239a679 --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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: + // + 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; + // + }; + + 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::get()); + registerProperty(PROPERTY_DATABASE_LOCATION, PROPERTY_ID_DATABASE_LOCATION, PropertyAttribute::BOUND, &m_sDatabaseLocation , cppu::UnoType::get()); + registerProperty(PROPERTY_CONNECTION_RESOURCE, PROPERTY_ID_CONNECTION_RESOURCE, PropertyAttribute::BOUND, &m_sConnectionResource , cppu::UnoType::get()); + registerProperty(PROPERTY_CONNECTION_INFO, PROPERTY_ID_CONNECTION_INFO, PropertyAttribute::BOUND, &m_aConnectionInfo , cppu::UnoType::get()); + registerProperty(PROPERTY_ACTIVE_CONNECTION, PROPERTY_ID_ACTIVE_CONNECTION, PropertyAttribute::BOUND, &m_xActiveConnection , cppu::UnoType::get()); + registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND, &m_sCommand , cppu::UnoType::get()); + registerProperty(PROPERTY_COMMAND_TYPE, PROPERTY_ID_COMMAND_TYPE, PropertyAttribute::BOUND, &m_nCommandType , cppu::UnoType::get()); + registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND, &m_sFilter , cppu::UnoType::get()); + registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND, &m_sOrder , cppu::UnoType::get()); + registerProperty(PROPERTY_HAVING_CLAUSE, PROPERTY_ID_HAVING_CLAUSE, PropertyAttribute::BOUND, &m_sHavingClause , cppu::UnoType::get()); + registerProperty(PROPERTY_GROUP_BY, PROPERTY_ID_GROUP_BY, PropertyAttribute::BOUND, &m_sGroupBy , cppu::UnoType::get()); + registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, &m_bEscapeProcessing , cppu::UnoType::get()); + registerProperty(PROPERTY_RESULT_SET, PROPERTY_ID_RESULT_SET, PropertyAttribute::BOUND, &m_xResultSet , cppu::UnoType::get()); + registerProperty(PROPERTY_SELECTION, PROPERTY_ID_SELECTION, PropertyAttribute::BOUND, &m_aSelection , cppu::UnoType::get()); + registerProperty(PROPERTY_BOOKMARK_SELECTION, PROPERTY_ID_BOOKMARK_SELECTION, PropertyAttribute::BOUND, &m_bBookmarkSelection , cppu::UnoType::get()); + registerProperty(PROPERTY_COLUMN_NAME, PROPERTY_ID_COLUMN_NAME, PropertyAttribute::BOUND, &m_sColumnName , cppu::UnoType::get()); + registerProperty(PROPERTY_COLUMN, PROPERTY_ID_COLUMN, PropertyAttribute::BOUND, &m_xColumn , cppu::UnoType::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 + { + 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 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 0000000000..a94560f1b0 --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasecontext.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 + +#include +#include +#include +#include +#include "databaseregistrations.hxx" +#include "datasource.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 & 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 & 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_xDatabaseRegistrations = createDataSourceRegistrations( m_aContext ); + osl_atomic_decrement( &m_refCount ); +} + +ODatabaseContext::~ODatabaseContext() +{ +#if HAVE_FEATURE_SCRIPTING + ::basic::BasicManagerRepository::revokeCreationListener( *this ); +#endif + + m_xDatabaseDocumentLoader.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(sErrorMessage.replaceAll( + "$file$", aTransformer.get(::svt::OFileNotation::N_SYSTEM)), + {}, {}, 0, {}); + + 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(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::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(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 ); +} + +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 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 0000000000..204bad556e --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasedocument.cxx @@ -0,0 +1,2200 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include "databasedocument.hxx" +#include "documenteventexecutor.hxx" +#include +#include "documentcontainer.hxx" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +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& _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::get() ) + || _rType.equals( cppu::UnoType::get() ) + ) + ) + return Any(); + + return ODatabaseDocument_OfficeDocument::queryInterface(_rType); +} + +Sequence< Type > SAL_CALL ODatabaseDocument::getTypes( ) +{ + Sequence< Type > aTypes = ODatabaseDocument_OfficeDocument::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::get() || + t == cppu::UnoType::get();} ); + aTypes.realloc( std::distance(begin, newEnd) ); + } + + return aTypes; +} + +Sequence< sal_Int8 > SAL_CALL ODatabaseDocument::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +// 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 ) + { + if ( _rURL.isEmpty() ) + return _rDescriptor.getPropertyValues(); + + ::comphelper::NamedValueCollection aMutableDescriptor( _rDescriptor ); + aMutableDescriptor.put( "FileName", _rURL ); + aMutableDescriptor.put( "URL", _rURL ); + return aMutableDescriptor.getPropertyValues(); + } +} + +constexpr OUString sPictures = u"Pictures"_ustr; + +// 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& rxContext ) +{ + const Sequence< OUString > sLibraries = xDlgCont->getElementNames(); + Reference< XStorage > xTmpPic = xStorage->openStorageElement( "tempPictures", ElementModes::READWRITE ); + + std::vector> 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 xGraphicStorageHandler; + xGraphicStorageHandler.set(GraphicStorageHandler::createWithStorage(rxContext, xTmpPic)); + if (xGraphicStorageHandler.is()) + { + for (uno::Reference 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::get(), beans::PropertyAttribute::MAYBEVOID, 0 }, + { OUString("StreamName"), 0, ::cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0 }, + { OUString("UsePrettyPrinting"), 0, ::cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0}, + { OUString("TargetStorage"), 0, cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0}, + { OUString("StreamRelPath"), 0, cppu::UnoType::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 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::EmbeddedMacros::SubDocument ); + + _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 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& /* 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 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 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 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 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 xTargetStorage(impl_GetStorageOrCreateFor_throw(aArguments, _rURL)); + + // extend media descriptor with URL + Sequence 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::ObjectType::Form ) && ( _eType != ODatabaseModelImpl::ObjectType::Report ) ) + throw IllegalArgumentException(); + + bool bFormsContainer = _eType == ODatabaseModelImpl::ObjectType::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 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 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(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::ObjectType::Form ); +} + +Reference< XNameAccess > SAL_CALL ODatabaseDocument::getReportDocuments( ) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit ); + return impl_getDocumentContainer_throw( ODatabaseModelImpl::ObjectType::Report ); +} + +void ODatabaseDocument::WriteThroughComponent( const Reference< XComponent >& xComponent, const char* pStreamName, + const char* pServiceName, const Sequence< Any >& _rArguments, const Sequence< PropertyValue >& rMediaDesc, + const Reference& _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 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( 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 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(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 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 xModuleInterface(m_xModuleManager); + aKeepAlive.push_back(xModuleInterface); + } + m_xModuleManager.clear(); + + { + uno::Reference 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(); + m_xTitleHelper.clear(); + m_xModuleManager.clear(); + m_pEventExecutor.clear(); + m_xCurrentController.clear(); + m_xUIConfigurationManager.clear(); +} + +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::get(), beans::PropertyAttribute::MAYBEVOID, 0}, + {OUString("StreamName"), 0, cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0}, + {OUString("SourceStorage"), 0, cppu::UnoType::get(), beans::PropertyAttribute::MAYBEVOID, 0}, +}; +} + +void SAL_CALL ODatabaseDocument::loadFromStorage(const Reference& xStorage, const Sequence& rMediaDescriptor) +{ + DocumentGuard aGuard(*this, DocumentGuard::InitMethod); + + uno::Reference 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 aFilterCreationArgs{ Any(xInfoSet) }; + + uno::Reference xImporter(m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.comp.sdb.DBFilter", aFilterCreationArgs, m_pImpl->m_aContext), uno::UNO_QUERY_THROW); + + uno::Reference xComponent(*this, uno::UNO_QUERY_THROW); + xImporter->setTargetDocument(xComponent); + + uno::Reference xFilter(xImporter, uno::UNO_QUERY_THROW); + uno::Sequence 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& 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 const &) +{ + Reference xDBContextTunnel(DatabaseContext::create(context), UNO_QUERY_THROW); + rtl::Reference pContext + = dynamic_cast(xDBContextTunnel.get()); + assert(pContext); + + rtl::Reference pImpl( + new dbaccess::ODatabaseModelImpl(context, *pContext)); + css::uno::Reference 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 0000000000..6278aa039a --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasedocument.hxx @@ -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 . + */ +#pragma once + +#include + +#include +#include + +#include +#include "documenteventnotifier.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 + 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 + 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 + , css::frame::XTitle + , css::frame::XTitleChangeBroadcaster + , css::frame::XUntitledNumbers + > ODatabaseDocument_OfficeDocument; + +class ODatabaseDocument :public ModelDependentComponent // ModelDependentComponent must be first! + ,public ODatabaseDocument_OfficeDocument +{ + 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 m_aModifyListeners; + ::comphelper::OInterfaceContainerHelper3 m_aCloseListener; + ::comphelper::OInterfaceContainerHelper3 m_aStorageListeners; + + std::unique_ptr 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 , 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& _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 createDatabaseDocument( const ::rtl::Reference& _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; + + // 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& 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 _eType 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 + */ + 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 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 . + + @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 0000000000..9e53a8429e --- /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 + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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::WeakImplHelper< XDatabaseRegistrations + > DatabaseRegistrations_Base; + + namespace { + + class DatabaseRegistrations :public ::cppu::BaseMutex + ,public DatabaseRegistrations_Base + { + public: + explicit DatabaseRegistrations( const Reference& _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 m_aContext; + ::utl::OConfigurationTreeRoot m_aConfigurationRoot; + ::comphelper::OInterfaceContainerHelper3 m_aRegistrationListeners; + }; + + } + + // DatabaseRegistrations - implementation + DatabaseRegistrations::DatabaseRegistrations( const Reference & _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< XDatabaseRegistrations > createDataSourceRegistrations( const Reference & _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 0000000000..52def1de5a --- /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 +#include + +namespace dbaccess +{ +css::uno::Reference +createDataSourceRegistrations(const css::uno::Reference& _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 0000000000..180ecff777 --- /dev/null +++ b/dbaccess/source/core/dataaccess/datasource.cxx @@ -0,0 +1,1369 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include "connection.hxx" +#include "SharedConnection.hxx" +#include "databasedocument.hxx" +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +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!"); +} + +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(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 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 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& _rxConnection, TConnectionMap::iterator const & _rIter) +{ + Reference 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& _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::get(), + cppu::UnoType::get(), + cppu::UnoType::get()); + + return ::comphelper::concatSequences( + ODatabaseSource_Base::getTypes(), + aPropertyHelperTypes.getTypes() + ); +} + +Sequence< sal_Int8 > ODatabaseSource::getImplementationId() +{ + return css::uno::Sequence(); +} + +// 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(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 = getModel_noCreate(); + if (!xModel.is()) + return nullptr; + Reference xController(xModel->getCurrentController()); + if (!xController.is()) + return nullptr; + Reference xFrame(xController->getFrame()); + if (!xFrame.is()) + return nullptr; + Reference 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 const xRootStorage = m_pImpl->getOrCreateRootStorage(); + OUString sMigrEnvVal; + osl_getEnvironment(OUString("DBACCESS_HSQL_MIGRATION").pData, + &sMigrEnvVal.pData); + if(!sMigrEnvVal.isEmpty()) + bNeedMigration = true; + else + { + Reference 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 OUString BACKUP_XML_NAME = u"content_before_migration.xml"_ustr; + 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( + DBA_RES(RID_STR_CONNECTION_REQUEST).replaceFirst("$name$", m_pImpl->m_sConnectURL), + {}, {}, 0, {}, {}); + + 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 + { + { + // a change here means a change should also been done in OApplicationController::disposing() + { PROPERTY_INFO, PROPERTY_ID_INFO, cppu::UnoType>::get(), css::beans::PropertyAttribute::BOUND }, + { PROPERTY_ISPASSWORDREQUIRED, PROPERTY_ID_ISPASSWORDREQUIRED, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND }, + { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, cppu::UnoType>::get(), css::beans::PropertyAttribute::BOUND }, + { PROPERTY_NAME, PROPERTY_ID_NAME, cppu::UnoType::get(), css::beans::PropertyAttribute::READONLY }, + { PROPERTY_NUMBERFORMATSSUPPLIER, PROPERTY_ID_NUMBERFORMATSSUPPLIER, cppu::UnoType::get(), + css::beans::PropertyAttribute::READONLY | css::beans::PropertyAttribute::TRANSIENT }, + { PROPERTY_PASSWORD, PROPERTY_ID_PASSWORD, cppu::UnoType::get(), css::beans::PropertyAttribute::TRANSIENT }, + { PROPERTY_SETTINGS, PROPERTY_ID_SETTINGS, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY }, + { PROPERTY_SUPPRESSVERSIONCL, PROPERTY_ID_SUPPRESSVERSIONCL, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND }, + { PROPERTY_TABLEFILTER, PROPERTY_ID_TABLEFILTER, cppu::UnoType>::get(), css::beans::PropertyAttribute::BOUND }, + { PROPERTY_TABLETYPEFILTER, PROPERTY_ID_TABLETYPEFILTER, cppu::UnoType>::get(), css::beans::PropertyAttribute::BOUND }, + { PROPERTY_URL, PROPERTY_ID_URL, cppu::UnoType::get(), css::beans::PropertyAttribute::BOUND }, + { PROPERTY_USER, PROPERTY_ID_USER, cppu::UnoType::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 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 +
  • removed from the bag, if it's a removable property
  • +
  • orreset to its default value, if it's not a removable property
  • +
. + + @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 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 pAbort = new OInteractionAbort; + rtl::Reference 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 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() ) + { + m_pImpl->m_xSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext ); + } + xConn = m_pImpl->m_xSharedConnectionManager->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(&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 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::ObjectType::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::ObjectType::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 const &) +{ + css::uno::Reference 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 0000000000..5b5985eacd --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 0000000000..807dc5ec98 --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 ODefinitionContainer::getImplementationId() +{ + return css::uno::Sequence(); +} + +// 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(), 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::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(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 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(_rxNewObject,UNO_QUERY); + if ( xChild.is() ) + xChild->setParent(static_cast(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 = dynamic_cast( _rxNewObject.get() ); + 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( dynamic_cast( _rxObject.get() ) ); + 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( 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 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 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 0000000000..f9a063c86e --- /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 +#include "documentdefinition.hxx" +#include +#include +#include +#include +#include "myucp_resultset.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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::UnoTypem_aProps.aTitle)>::get()); + + setElementApproval( std::make_shared() ); +} + +ODocumentContainer::~ODocumentContainer() +{ + + if ( !OContentHelper::rBHelper.bInDispose && !OContentHelper::rBHelper.bDisposed ) + { + acquire(); + dispose(); + } +} + +IMPLEMENT_FORWARD_XINTERFACE3( ODocumentContainer,ODefinitionContainer,ODocumentContainer_Base,OPropertyStateContainer) + +css::uno::Sequence ODocumentContainer::getImplementationId() +{ + return css::uno::Sequence(); +} + +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 ? SERVICE_NAME_FORM_COLLECTION : 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 xElements = getContainerStorage(); + if ( xElements.is() ) + sPersistentName = ::dbtools::createUniqueName(xElements,sPersistentName); + + const bool bNeedClassID = !aClassID.hasElements() && sURL.isEmpty() ; + if ( xCopyFrom.is() ) + { + Sequence aIni{ Any(getContainerStorage()), Any(sPersistentName) }; + Command aCommand; + aCommand.Name = "copyTo"; + aCommand.Argument <<= aIni; + + xCopyFrom->execute(aCommand,-1,Reference< XCommandEnvironment >()); + Reference 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(); + 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 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 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(); + 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 xObjectToCopy; + + Reference xORB(xContent,UNO_QUERY); + OSL_ENSURE(xORB.is(),"No service factory given"); + if ( xORB.is() ) + { + for(;elements != elementsEnd;++elements) + { + xCopyFrom->getByName(*elements) >>= xObjectToCopy; + Sequence 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 xNew(xORB->createInstanceWithArguments(sServiceName,aArguments),UNO_QUERY); + Reference 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 ODocumentContainer::getContent(const OUString& _sName) const +{ + ::rtl::Reference pContent; + try + { + pContent = dynamic_cast(const_cast(this)->implGetByName( _sName, true ).get()); + } + 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 xTrans(elem.second.get(),UNO_QUERY); + if ( xTrans.is() ) + xTrans->commit(); + } + Reference 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 xTrans(elem.second.get(),UNO_QUERY); + if ( xTrans.is() ) + xTrans->revert(); + } + Reference 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::ObjectType::Form : ODatabaseModelImpl::ObjectType::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 0000000000..d47709e80a --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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.
+ */ + 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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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 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 0000000000..227bde4cde --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentdefinition.cxx @@ -0,0 +1,2099 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "intercept.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 ::comphelper::WeakComponentImplHelper< embed::XStateChangeListener > TEmbedObjectHolder; + + namespace { + + class OEmbedObjectHolder : public TEmbedObjectHolder + { + Reference< XEmbeddedObject > m_xBroadCaster; + ODocumentDefinition* m_pDefinition; + bool m_bInStateChange; + protected: + virtual void disposing(std::unique_lock& rGuard) override; + public: + OEmbedObjectHolder(const Reference< XEmbeddedObject >& _xBroadCaster,ODocumentDefinition* _pDefinition) + : 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 OEmbedObjectHolder::disposing(std::unique_lock& /*rGuard*/) + { + 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 xHoldAlive(static_cast< ::cppu::OWeakObject* >(m_pDefinition),UNO_QUERY); + { + Reference 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 + { + 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 disposing 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 m_xParentContainer; + + public: + ODocumentSaveContinuation() { } + + const Reference& getContent() const { return m_xParentContainer; } + const OUString& getName() const { return m_sName; } + + // XInteractionDocumentSave + virtual void SAL_CALL setName( const OUString& _sName,const Reference& _xParent) override; + }; + + } + + void SAL_CALL ODocumentSaveContinuation::setName( const OUString& _sName,const Reference& _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 xCloseable(m_pImpl->m_pDataSource->getModel_noCreate(),UNO_QUERY); + if ( xCloseable.is() ) + xCloseable->removeCloseListener(this); + } +} + +css::uno::Sequence ODocumentDefinition::getImplementationId() +{ + return css::uno::Sequence(); +} + +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::UnoTypem_aProps.aTitle)>::get()); + + registerProperty(PROPERTY_AS_TEMPLATE, PROPERTY_ID_AS_TEMPLATE, PropertyAttribute::READONLY, &m_pImpl->m_aProps.bAsTemplate, + cppu::UnoTypem_aProps.bAsTemplate)>::get()); + + registerProperty(PROPERTY_PERSISTENT_NAME, PROPERTY_ID_PERSISTENT_NAME, PropertyAttribute::READONLY, &m_pImpl->m_aProps.sPersistentName, + cppu::UnoTypem_aProps.sPersistentName)>::get()); + + registerProperty(PROPERTY_IS_FORM, PROPERTY_ID_IS_FORM, PropertyAttribute::READONLY, &m_bForm, cppu::UnoType::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::ObjectType::Form : ODatabaseModelImpl::ObjectType::Report ) + + "/" + m_pImpl->m_aProps.sPersistentName; + } + o_rValue <<= sPersistentPath; + return; + } + + OPropertyStateContainer::getFastPropertyValue( o_rValue, i_nHandle ); +} + +Reference< XPropertySetInfo > SAL_CALL ODocumentDefinition::getPropertySetInfo( ) +{ + Reference 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::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 & _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::EmbeddedMacros::NONE ) + { + // 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 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 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 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 aEmpty; + Sequence 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 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& 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 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 pRequest = new OInteractionRequest(Any(aRequest)); + // some knittings + // two continuations allowed: OK and Cancel + rtl::Reference pDocuSave; + + if ( m_pImpl->m_aProps.aTitle.isEmpty() ) + { + pDocuSave = new ODocumentSaveContinuation; + pRequest->addContinuation(pDocuSave); + } + if ( _bApprove ) + { + rtl::Reference> pApprove = new OInteraction< XInteractionApprove >; + pRequest->addContinuation(pApprove); + } + + rtl::Reference> pDisApprove = new OInteraction< XInteractionDisapprove >; + pRequest->addContinuation(pDisApprove); + + rtl::Reference pAbort = new OInteractionAbort; + pRequest->addContinuation(pAbort); + + Reference xDialogParent(rDialogParent, UNO_QUERY); + + // create the handler, let it handle the request + Reference xHandler(InteractionHandler::createWithParent(m_aContext, xDialogParent)); + xHandler->handle(pRequest); + + if ( pAbort->wasSelected() ) + return false; + if ( pDisApprove->wasSelected() ) + return true; + if ( pDocuSave && pDocuSave->wasSelected() ) + { + Reference 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 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()); // (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 pRequest = new OInteractionRequest(Any(aRequest)); + // some knittings + // two continuations allowed: OK and Cancel + rtl::Reference pDocuSave = new ODocumentSaveContinuation; + pRequest->addContinuation(pDocuSave); + rtl::Reference> pDisApprove = new OInteraction< XInteractionDisapprove >; + pRequest->addContinuation(pDisApprove); + rtl::Reference 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 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 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 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.has_value() ) + { + 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.has_value() ) + _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::EmbeddedMacros::SubDocument ); + + // 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 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 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() ) + { + throw css::io::WrongFormatException(DBA_RES(RID_STR_MISSING_EXTENSION)); + } + } + 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 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 xTransfer(getComponent(),UNO_QUERY); + if ( xTransfer.is() ) + { + DataFlavor aFlavor; + aFlavor.MimeType = "image/png"; + aFlavor.HumanPresentableName = "Portable Network Graphics"; + aFlavor.DataType = cppu::UnoType>::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 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(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 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::ObjectType::Form : ODatabaseModelImpl::ObjectType::Report ) + : Reference< XStorage>(); +} + +bool ODocumentDefinition::isModified() +{ + osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex); + bool bRet = false; + if ( m_xEmbeddedObject.is() ) + { + Reference 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; + if ( xFrame.is() ) + { + xTopWindow = Reference(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 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 0000000000..5569276d4a --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 m_pInterceptor; + bool m_bForm; // if it is a form + bool m_bOpenInDesign; + bool m_bInExecute; + bool m_bRemoveListener; + rtl::Reference 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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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& 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 + 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 o_rDocumentLoadArgs and o_rEmbeddedObjectDescriptor + will be overwritten by values from i_rOpenCommandArguments, 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 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 0000000000..e1cb9f3f4e --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventexecutor.cxx @@ -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 . + */ + +#include "documenteventexecutor.hxx" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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; + + namespace + { + void lcl_dispatchScriptURL_throw( + css::uno::WeakReference< css::document::XEventsSupplier > const & xWeakDocument, + css::uno::Reference< css::util::XURLTransformer > const & xURLTransformer, + const OUString& _rScriptURL, const DocumentEvent& _rTrigger ) + { + Reference< XModel > xDocument( xWeakDocument.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 ( xURLTransformer.is() ) + 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 & _rContext, + const Reference< XEventsSupplier >& _rxDocument ) + :mxDocument( _rxDocument ) + { + Reference< XDocumentEventBroadcaster > xBroadcaster( _rxDocument, UNO_QUERY_THROW ); + + osl_atomic_increment( &m_refCount ); + { + xBroadcaster->addDocumentEventListener( this ); + } + osl_atomic_decrement( &m_refCount ); + + try + { + mxURLTransformer = URLTransformer::create(_rContext); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + DocumentEventExecutor::~DocumentEventExecutor() + { + } + + void SAL_CALL DocumentEventExecutor::documentEventOccured( const DocumentEvent& Event ) + { + Reference< XEventsSupplier > xEventsSupplier( mxDocument.get(), UNO_QUERY ); + if ( !xEventsSupplier ) + { + 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( mxDocument, mxURLTransformer, 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 0000000000..58aee4bcd5 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventexecutor.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 +#include + +#include +#include + +namespace com::sun::star::uno { class XComponentContext; } +namespace com::sun::star::util { class XURLTransformer; } + +namespace dbaccess +{ + // 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: + css::uno::WeakReference< css::document::XEventsSupplier > mxDocument; + css::uno::Reference< css::util::XURLTransformer > mxURLTransformer; + }; + +} // 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 0000000000..475b16c0b5 --- /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 + +#include +#include +#include +#include +#include + +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 m_aLegacyEventListeners; + ::comphelper::OInterfaceContainerHelper3 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 0000000000..6f3bffc4cf --- /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 +#include + +#include + +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 0000000000..6dbe9ad596 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentevents.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 + +#include + +#include +#include +#include +#include + +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; + + 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 ) + :mrParent(_rParent), mrMutex(_rMutex), mrEventsData(_rEventsData) + { + const DocumentEventData* pEventData = lcl_getDocumentEventData(); + while ( pEventData->pAsciiEventName ) + { + OUString sEventName = OUString::createFromAscii( pEventData->pAsciiEventName ); + DocumentEventsData::const_iterator existingPos = mrEventsData.find( sEventName ); + if ( existingPos == mrEventsData.end() ) + mrEventsData[ sEventName ] = Sequence< PropertyValue >(); + ++pEventData; + } + } + + DocumentEvents::~DocumentEvents() + { + } + + void SAL_CALL DocumentEvents::acquire() noexcept + { + mrParent.acquire(); + } + + void SAL_CALL DocumentEvents::release() noexcept + { + mrParent.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( mrMutex ); + + DocumentEventsData::iterator elementPos = mrEventsData.find( Name ); + if ( elementPos == mrEventsData.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( mrMutex ); + + DocumentEventsData::const_iterator elementPos = mrEventsData.find( Name ); + if ( elementPos == mrEventsData.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( mrMutex ); + + return comphelper::mapKeysToSequence( mrEventsData ); + } + + sal_Bool SAL_CALL DocumentEvents::hasByName( const OUString& Name ) + { + ::osl::MutexGuard aGuard( mrMutex ); + + return mrEventsData.find( Name ) != mrEventsData.end(); + } + + Type SAL_CALL DocumentEvents::getElementType( ) + { + return ::cppu::UnoType< Sequence< PropertyValue > >::get(); + } + + sal_Bool SAL_CALL DocumentEvents::hasElements( ) + { + ::osl::MutexGuard aGuard( mrMutex ); + return !mrEventsData.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 0000000000..89ff572f67 --- /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 + +#include + +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 aArguments; +}; + +} + +//XDispatch +void SAL_CALL OInterceptor::dispatch( const URL& URL,const Sequence& Arguments ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_pContentHolder ) + return; + + if ( URL.Complete == m_aInterceptedURL[ DISPATCH_SAVE ] ) + { + m_pContentHolder->save(false, css::uno::Reference()); + 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 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(this); + } + + if(m_xSlaveDispatchProvider.is()) + return m_xSlaveDispatchProvider->queryDispatch(URL,TargetFrameName,SearchFlags); + else + return Reference(); +} + +Sequence< Reference< XDispatch > > SAL_CALL OInterceptor::queryDispatches( const Sequence& Requests ) +{ + osl::MutexGuard aGuard(m_aMutex); + typedef Sequence> 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(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 0000000000..7ce53752f1 --- /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 +#include +#include +#include +#include +#include +#include "documentdefinition.hxx" +#include + +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 + StatusListenerContainer; + std::unique_ptr 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 0000000000..04a64e0205 --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx @@ -0,0 +1,286 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include "myucp_datasupplier.hxx" +#include +#include + +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; + + +DataSupplier::DataSupplier( const rtl::Reference< ODocumentContainer >& rContent ) +: m_xContent( rContent ) +{ +} + +DataSupplier::~DataSupplier() +{ +} + +OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( static_cast(nIndex) < m_aResults.size() ) + { + OUString aId = m_aResults[ nIndex ]->aId; + if ( !aId.isEmpty() ) + { + // Already cached. + return aId; + } + } + + if ( getResult( nIndex ) ) + { + OUString aId = m_xContent->getIdentifier()->getContentIdentifier(); + + if ( !aId.isEmpty() ) + aId += "/"; + + aId += m_aResults[ nIndex ]->rData.aTitle; + + m_aResults[ nIndex ]->aId = aId; + return aId; + } + return OUString(); +} + +Reference< XContentIdentifier > +DataSupplier::queryContentIdentifier( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( static_cast(nIndex) < m_aResults.size() ) + { + Reference< XContentIdentifier > xId = 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_aResults[ nIndex ]->xId = xId; + return xId; + } + return Reference< XContentIdentifier >(); +} + +Reference< XContent > +DataSupplier::queryContent( sal_uInt32 _nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( static_cast(_nIndex) < m_aResults.size() ) + { + Reference< XContent > xContent = 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_aResults[ _nIndex ]->xContent = m_xContent->getContent(sName); + + xContent = m_aResults[ _nIndex ]->xContent.get(); + return xContent; + + } + catch ( IllegalIdentifierException& ) + { + } + } + return Reference< XContent >(); +} + +bool DataSupplier::getResult( sal_uInt32 nIndex ) +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); + + if ( static_cast(nIndex) < m_aResults.size() ) + { + // Result already present. + return true; + } + + // Result not (yet) present. + + if ( m_bCountFinal ) + return false; + + // Try to obtain result... + + sal_uInt32 nOldCount = m_aResults.size(); + bool bFound = false; + sal_uInt32 nPos = nOldCount; + + // @@@ Obtain data and put it into result list... + Sequence< OUString> aSeq = 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_aResults.emplace_back( + new ResultListEntry( m_xContent->getContent(*pIter)->getContentProperties() ) ); + + if ( nPos == nIndex ) + { + // Result obtained. + bFound = true; + break; + } + } + } + + if ( !bFound ) + m_bCountFinal = true; + + rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet(); + if ( xResultSet.is() ) + { + // Callbacks follow! + aGuard.clear(); + + if ( static_cast(nOldCount) < m_aResults.size() ) + xResultSet->rowCountChanged( nOldCount, m_aResults.size() ); + + if ( m_bCountFinal ) + xResultSet->rowCountFinal(); + } + + return bFound; +} + +sal_uInt32 DataSupplier::totalCount() +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex ); + + if ( m_bCountFinal ) + return m_aResults.size(); + + sal_uInt32 nOldCount = m_aResults.size(); + + // @@@ Obtain data and put it into result list... + Sequence< OUString> aSeq = m_xContent->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + m_aResults.emplace_back( + new ResultListEntry( m_xContent->getContent(*pIter)->getContentProperties() ) ); + + m_bCountFinal = true; + + rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet(); + if ( xResultSet.is() ) + { + // Callbacks follow! + aGuard.clear(); + + if ( static_cast(nOldCount) < m_aResults.size() ) + xResultSet->rowCountChanged( nOldCount, m_aResults.size() ); + + xResultSet->rowCountFinal(); + } + + return m_aResults.size(); +} + +sal_uInt32 DataSupplier::currentCount() +{ + return m_aResults.size(); +} + +bool DataSupplier::isCountFinal() +{ + return m_bCountFinal; +} + +Reference< XRow > +DataSupplier::queryPropertyValues( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( static_cast(nIndex) < m_aResults.size() ) + { + Reference< XRow > xRow = m_aResults[ nIndex ]->xRow; + if ( xRow.is() ) + { + // Already cached. + return xRow; + } + } + + if ( getResult( nIndex ) ) + { + if ( !m_aResults[ nIndex ]->xContent.is() ) + queryContent(nIndex); + + Reference< XRow > xRow = m_aResults[ nIndex ]->xContent->getPropertyValues(getResultSet()->getProperties()); + m_aResults[ nIndex ]->xRow = xRow; + return xRow; + } + + return Reference< XRow >(); +} + +void DataSupplier::releasePropertyValues( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_aMutex ); + + if ( static_cast(nIndex) < m_aResults.size() ) + 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 0000000000..65a45ad7fe --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.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 +#include +#include +#include "documentcontainer.hxx" +#include + +namespace dbaccess +{ +struct ResultListEntry +{ + OUString aId; + css::uno::Reference xId; + ::rtl::Reference xContent; + css::uno::Reference xRow; + const ContentProperties& rData; + + explicit ResultListEntry(const ContentProperties& rEntry) + : rData(rEntry) + { + } +}; + +class DataSupplier : public ucbhelper::ResultSetDataSupplier +{ + osl::Mutex m_aMutex; + std::vector> m_aResults; + rtl::Reference m_xContent; + bool m_bCountFinal = false; + +public: + explicit DataSupplier(const rtl::Reference& rxContent); + virtual ~DataSupplier() override; + + virtual OUString queryContentIdentifierString(sal_uInt32 nIndex) override; + virtual css::uno::Reference + queryContentIdentifier(sal_uInt32 nIndex) override; + virtual css::uno::Reference 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 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 0000000000..4067eae381 --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_resultset.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 . + */ + +/************************************************************************** + TODO + ************************************************************************** + + - This implementation is not a dynamic result set!!! It only implements + the necessary interfaces, but never recognizes/notifies changes!!! + + *************************************************************************/ + +#include + +#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, + rtl::Reference< ODocumentContainer > xContent, + const OpenCommandArgument2& rCommand, + const Reference< XCommandEnvironment >& rxEnv ) + :ResultSetImplHelper( rxContext, rCommand ) + ,m_xContent(std::move(xContent)) + ,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 0000000000..220bdf0a70 --- /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 +#include +#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, + rtl::Reference< ODocumentContainer > xContent, + 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 0000000000..37bfc0ebac --- /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 +#include +#include +#include + +#include +#include +#include + +#include + +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 + */ + 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 0000000000..d60521a432 --- /dev/null +++ b/dbaccess/source/core/inc/ContentHelper.hxx @@ -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 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 TContentPtr; + + typedef comphelper::OMultiTypeInterfaceContainerHelperVar3 + PropertyChangeListenerContainer; + typedef ::cppu::WeakComponentImplHelper< css::ucb::XContent + , css::ucb::XCommandProcessor + , css::lang::XServiceInfo + , css::beans::XPropertiesChangeNotifier + , css::beans::XPropertyContainer + , css::lang::XInitialization + , 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 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 + ,TContentPtr _pImpl + ); + + // css::lang::XTypeProvider + virtual css::uno::Sequence 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::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 0000000000..8c2029634b --- /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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +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 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 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 0000000000..968f3a1d62 --- /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 + +#include +#include + +#include +#include + +#include + +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& 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.
+ After using this method the object may be reconstructed by calling one of the construct methods. + */ + virtual void disposing() override; + + class EnsureReset + { + public: + EnsureReset( std::atomic& _rValueLocation) + :m_rValue( _rValueLocation ) + { + ++m_rValue; + } + + ~EnsureReset() + { + --m_rValue; + } + + private: + std::atomic& m_rValue; + }; + + /** retrieve a table type filter to pass to XDatabaseMetaData::getTables, + 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 XConnection + interface.
+ @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& _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 0000000000..2fc19830ca --- /dev/null +++ b/dbaccess/source/core/inc/ModelImpl.hxx @@ -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 . + */ + +#pragma once + +#include "ContentHelper.hxx" +#include "documentevents.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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::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!" ); + } +}; + +// ODatabaseModelImpl +typedef ::utl::SharedUNOComponent< css::embed::XStorage > SharedStorage; + +class ODatabaseContext; +class DocumentStorageAccess; +class ODatabaseSource; + + +/** 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< css::lang::XEventListener > +{ + // contains the currently used master connections + struct TConnectionHolder + { + css::uno::Reference< css::sdbc::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< css::uno::Reference< css::sdbc::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 + css::uno::Reference< css::reflection::XProxyFactory > m_xProxyFactory; + +protected: + virtual ~OSharedConnectionManager() override; + +public: + explicit OSharedConnectionManager(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + css::uno::Reference< css::sdbc::XConnection > getConnection( const OUString& url, + const OUString& user, + const OUString& password, + const css::uno::Sequence< css::beans::PropertyValue >& _aInfo, + ODatabaseSource* _pDataSource); + void addEventListener(const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, TConnectionMap::iterator const & _rIter); +}; + + +class ODatabaseModelImpl :public ::sfx2::IMacroDocumentAccess + ,public ::sfx2::IModifiableDocument +{ +public: + + enum class ObjectType + { + Form = 0, + Report = 1, + Query = 2, + Table = 3, + LAST = Table + }; + + enum class EmbeddedMacros + { + // the database document (storage) itself contains macros + DocumentWide, + // there are sub document( storage)s containing macros + SubDocument, + // there are no known macro( storage)s + NONE + }; + +private: + css::uno::WeakReference< css::frame::XModel > m_xModel; + css::uno::WeakReference< css::sdbc::XDataSource > m_xDataSource; + + rtl::Reference m_pStorageAccess; + o3tl::enumarray< ObjectType, 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; + rtl::Reference< OSharedConnectionManager > m_xSharedConnectionManager; + css::uno::Reference + 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 here, committing the root storage is prevented for this particular + call. + @return if the storage could be committed, otherwise + */ + 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( + OUString _sRegistrationName, + 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 . + + @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 + @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( + const css::uno::Reference& _rxInteraction) 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( ::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 0000000000..daf31758d0 --- /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 +#include +#include +#include +#include +#include + +#include + +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, + 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 0000000000..03836c308f --- /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 + +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 0000000000..fdde2d451d --- /dev/null +++ b/dbaccess/source/core/inc/SingleSelectQueryComposer.hxx @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(1 + static_cast(e)); } + enum EColumnType + { + SelectColumns = 0, + GroupByColumns = 1, + OrderColumns = 2, + ParameterColumns = 3 + }; + typedef std::function + TGetParseNode; + ::svxform::OSystemParseContext m_aParseContext; + ::svxform::ONeutralParseContext m_aNeutralContext; + ::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> + m_aColumnsCollection; // used for columns and parameters of old queries + std::vector> + 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> m_aCurrentColumns; + std::unique_ptr 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; + + // + OUString m_sOriginal; + // + + + 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 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 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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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 0000000000..93a974dac4 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "datasettings.hxx" +#include "column.hxx" + +#include +#include +#include + +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; + 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; + + // + mutable sal_Int32 m_nPrivileges; + // + // note: this thing uses the ref-count of "this", see OCollection::acquire()! + std::unique_ptr<::connectivity::sdbcx::OCollection> m_pColumns; + + protected: + // IColumnFactory + virtual rtl::Reference 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 + @param _rxTable + the table from the driver can be + @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 0000000000..d3889ff56d --- /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 + +#include +#include + +#include +#include + +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 0000000000..4641925424 --- /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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 MapString2String; + typedef std::vector 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 + m_aContainerListeners; + ::osl::Mutex& m_rMutex; + +public: + /** constructs the container.
+ after the construction of the object the creator has to call initialize. + @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 0000000000..58e21189aa --- /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 +#include +#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 0000000000..eae96fba3f --- /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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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: + // + OUString m_sName; + // + + 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 + 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; + + // 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; + + protected: + 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, + css::uno::Reference< css::container::XNameAccess > _xDrvColumns, + 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 0000000000..6b6c5d4c16 --- /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 + +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 + { + // + 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; + // + + 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 0000000000..1a0bd91d83 --- /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 +#include + +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 +// + 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; +// + +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 0000000000..3370647573 --- /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 +#include + +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 0000000000..f780e224af --- /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 + +#include + +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 0000000000..d94df018d1 --- /dev/null +++ b/dbaccess/source/core/inc/databasecontext.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 + +#include + +#include + +#include + +#include "ModelImpl.hxx" + +#include +#include +#include +#include + +#if HAVE_FEATURE_SCRIPTING +#include +#endif + +#include +#include + +// 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 + > 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 + + ::osl::Mutex m_aMutex; + css::uno::Reference< css::uno::XComponentContext > + m_aContext; + + css::uno::Reference< css::sdb::XDatabaseRegistrations > + m_xDatabaseRegistrations; + + typedef std::map 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 m_aContainerListeners; + rtl::Reference 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; + + 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 0000000000..8e24ebb714 --- /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 +#include +#include + +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: +// + 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; +// + +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
this
+ */ + 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 0000000000..b4c0a5c081 --- /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 +#include +#include +#include + +#include +#include +#include +#include + +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: + // + 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; + // + + 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 + { + // + OUString m_sCatalogName; + OUString m_sSchemaName; + OUString m_sTableName; + OUString m_sRealName; + OUString m_sLabel; + // + + 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, + 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 0000000000..9c871601ad --- /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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ContentHelper.hxx" +#include "containerapprove.hxx" +#include +#include + +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 + 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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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.
+ @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.
+ 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.
+ Additionally the node for the given object will be removed from the registry (including all sub nodes).
+ 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.
+ 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.
+ 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 0000000000..224fc407d2 --- /dev/null +++ b/dbaccess/source/core/inc/documentevents.hxx @@ -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 . + */ + +#pragma once + +#include +#include + +#include + +#include + +namespace dbaccess +{ + + typedef std::map< OUString, css::uno::Sequence< css::beans::PropertyValue > > + DocumentEventsData; + + 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: + ::cppu::OWeakObject& mrParent; + ::osl::Mutex& mrMutex; + DocumentEventsData& mrEventsData; + }; + +} // 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 0000000000..24bacf3001 --- /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 + +namespace dbaccess +{ +class MigrationWarnDialog : public weld::MessageDialogController +{ + std::unique_ptr m_xLater; + +public: + MigrationWarnDialog(weld::Window* pParent); +}; +} + +/* 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 0000000000..e503c347ea --- /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 +#include "containerapprove.hxx" +#include +#include + +namespace dbaccess +{ + + // ObjectNameApproval + /** 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 + { + css::uno::WeakReference< css::sdbc::XConnection > mxConnection; + sal_Int32 mnCommandType; + + 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 0000000000..cea06d79a8 --- /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 +#include +#include +#include +#include +#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 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 0000000000..c5d764d98c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 0000000000..a04a1ddf3d --- /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 +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 XConnection + interface.
+ + @param _pWarnings + specifies a warnings container (May be ) + + 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.

+

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 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.
+ 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 0000000000..4f0f68d306 --- /dev/null +++ b/dbaccess/source/core/inc/recovery/dbdocrecovery.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 +#include +#include + +#include + +namespace dbaccess +{ + + // DatabaseDocumentRecovery + 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: + css::uno::Reference mxContext; + }; + +} // 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 0000000000..5b100dcf17 --- /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 +#include + +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 0000000000..f437040682 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// 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 0000000000..6c71e74476 --- /dev/null +++ b/dbaccess/source/core/inc/table.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 + +#include "datasettings.hxx" +#include "column.hxx" +#include +#include +#include + +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; + + css::uno::Reference< css::container::XNameAccess > m_xColumnDefinitions; + css::uno::Reference< css::container::XNameAccess > m_xDriverColumns; + + // + sal_Int32 m_nPrivileges; + // + + protected: + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // IColumnFactory + virtual rtl::Reference 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.
+ @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; + + // 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; + + 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 0000000000..44358e4e20 --- /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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#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 XConnection + interface.
+ @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& _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 0000000000..ec44172f70 --- /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 + +#include + +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( css::uno::Any _aDetails ); + + 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 0000000000..2f7f48cec1 --- /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 + +#include +#include + +#include + +#include +#include + +#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 XConnection + interface.
+ @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& _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 0000000000..084c42e7e9 --- /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 +#include + +#include +#include +#include +#include +#include +#include + +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( 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( m_xSettings, UNO_QUERY_THROW ); + if ( xNameContainer.is() && m_xSettings->hasByName( sElementName ) ) + { + Reference 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 0000000000..d2aa735fa8 --- /dev/null +++ b/dbaccess/source/core/misc/DatabaseDataProvider.cxx @@ -0,0 +1,1067 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// 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 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 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 xProp(xData,uno::UNO_QUERY); + static constexpr OUString s_sNumberFormatKey = u"NumberFormatKey"_ustr; + if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(s_sNumberFormatKey) ) + { + xProp->setPropertyValue(s_sNumberFormatKey,impl_getNumberFormatKey_nothrow(_sRangeRepresentation)); + } + return xData; +} + +uno::Reference +SAL_CALL DatabaseDataProvider::createDataSequenceByValueArray( + const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/, const OUString& /*aRoleQualifier*/ ) +{ + return uno::Reference(); +} + +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(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(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( OUString i_sName ) + :sName(std::move( i_sName )) + ,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::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 = std::size(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& x, sal_Int32 length) +{ + m_aParameterManager.setBinaryStream(parameterIndex, x, length); +} + +void SAL_CALL DatabaseDataProvider::setCharacterStream(sal_Int32 parameterIndex, const uno::Reference& 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& x) +{ + m_aParameterManager.setRef(parameterIndex, x); +} + +void SAL_CALL DatabaseDataProvider::setBlob(sal_Int32 parameterIndex, const uno::Reference& x) +{ + m_aParameterManager.setBlob(parameterIndex, x); +} + +void SAL_CALL DatabaseDataProvider::setClob(sal_Int32 parameterIndex, const uno::Reference& x) +{ + m_aParameterManager.setClob(parameterIndex, x); +} + +void SAL_CALL DatabaseDataProvider::setArray(sal_Int32 parameterIndex, const Reference& 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& _rListener) +{ + if (m_xRowSet.is()) + m_xRowSet->addRowSetListener(_rListener); +} + +void SAL_CALL DatabaseDataProvider::removeRowSetListener(const uno::Reference& _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 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 0000000000..07e1068f69 --- /dev/null +++ b/dbaccess/source/core/misc/PropertyForward.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 + +#include +#include +#include + +#include +#include +#include + +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, + OUString _sName, const std::vector< OUString>& _aPropertyList ) + :m_xSource( _xSource, UNO_SET_THROW ) + ,m_xDestContainer( _xDestContainer, UNO_SET_THROW ) + ,m_sName(std::move( _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 0000000000..384d5962bd --- /dev/null +++ b/dbaccess/source/core/misc/apitools.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 +#include +#include + +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) + :WeakComponentImplHelper(_rMutex) + ,m_xParent(xParent) +{ + +} + +OSubComponent::~OSubComponent() +{ + m_xParent = nullptr; + +} + +// XInterface + +void OSubComponent::release() noexcept +{ + 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 WeakComponentImplHelper we use the ... + OWeakObject::release(); +} + +/* 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 0000000000..c67ac1646a --- /dev/null +++ b/dbaccess/source/core/misc/dsntypes.cxx @@ -0,0 +1,573 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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) ) + { + // 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() <= static_cast(_sURL.size()), "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 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; + + if (sDsn.startsWithIgnoreAsciiCase("sdbc:embedded:")) + return DST_EMBEDDED_UNKNOWN; + + // 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( OUString _s, const DATASOURCE_TYPE _t, const bool _m ) + :sPrefix(std::move( _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& _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_POSTGRES: + _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_POSTGRES); + 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: + case DST_EMBEDDED_UNKNOWN: + 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(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(m_pContainer)->m_nLivingIterators; +#endif +} + +ODsnTypeCollection::TypeIterator::~TypeIterator() +{ +#if OSL_DEBUG_LEVEL > 0 + --const_cast(m_pContainer)->m_nLivingIterators; +#endif +} + +OUString const & ODsnTypeCollection::TypeIterator::getDisplayName() const +{ + OSL_ENSURE(m_nPosition < static_cast(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(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(m_pContainer->m_aDsnTypesDisplayNames.size()), "ODsnTypeCollection::TypeIterator::operator++ : invalid position!"); + if (m_nPosition < static_cast(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 0000000000..d1712fba3f --- /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 + +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 0000000000..fa03e81e3d --- /dev/null +++ b/dbaccess/source/core/misc/objectnameapproval.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 + +#include +#include +#include + +namespace dbaccess +{ + + using ::com::sun::star::sdbc::XConnection; + 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; + + namespace CommandType = com::sun::star::sdb::CommandType; + + // ObjectNameApproval + ObjectNameApproval::ObjectNameApproval( const Reference< XConnection >& _rxConnection, ObjectType _eType ) + { + mxConnection = _rxConnection; + mnCommandType = _eType == TypeQuery ? CommandType::QUERY : CommandType::TABLE; + } + + ObjectNameApproval::~ObjectNameApproval() + { + } + + void ObjectNameApproval::approveElement( const OUString& _rName ) + { + Reference< XConnection > xConnection( mxConnection ); + if ( !xConnection.is() ) + throw DisposedException(); + + Reference< XConnectionTools > xConnectionTools( xConnection, UNO_QUERY_THROW ); + Reference< XObjectNames > xObjectNames( xConnectionTools->getObjectNames(), css::uno::UNO_SET_THROW ); + xObjectNames->checkNameForCreate( mnCommandType, _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 0000000000..a65cc30054 --- /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 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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(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(xParent,UNO_QUERY); + xParent.set(xChild.is() ? xChild->getParent() : Reference< XInterface >(),UNO_QUERY); + } + return xReturn; + } + + OUString extractExceptionMessage( const Reference & _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 0000000000..07aa9567ec --- /dev/null +++ b/dbaccess/source/core/misc/veto.cxx @@ -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 . + */ + +#include +#include + +namespace dbaccess +{ + + using ::com::sun::star::uno::Any; + + // Veto + Veto::Veto( Any _aDetails ) + :m_aDetails(std::move( _aDetails )) + { + } + + 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 0000000000..eead0c2c79 --- /dev/null +++ b/dbaccess/source/core/recovery/dbdocrecovery.cxx @@ -0,0 +1,337 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include "storagetextstream.hxx" +#include "subcomponentrecovery.hxx" +#include "subcomponents.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include + +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( std::u16string_view i_rIniLine, OUString& o_rStorName, SubComponentDescriptor& o_rCompDesc ) + { + const size_t nEqualSignPos = i_rIniLine.find( '=' ); + if ( nEqualSignPos == 0 || nEqualSignPos == std::u16string_view::npos ) + { + OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of '='" ); + return false; + } + o_rStorName = i_rIniLine.substr( 0, nEqualSignPos ); + + const size_t nCommaPos = i_rIniLine.rfind( ',' ); + if ( nCommaPos != i_rIniLine.size() - 2 ) + { + OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of ','" ); + return false; + } + o_rCompDesc.sName = i_rIniLine.substr( nEqualSignPos + 1, nCommaPos - nEqualSignPos - 1 ); + o_rCompDesc.bForEditing = ( i_rIniLine[ nCommaPos + 1 ] == '1' ); + return true; + } + + constexpr OUString sRecoveryDataSubStorageName = u"recovery"_ustr; + + constexpr OUString sObjectMapStreamName = u"storage-component-map.ini"_ustr; + + void lcl_writeObjectMap_throw( const Reference & 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( std::u16string_view i_rIniLine, OUString& o_rSectionName ) + { + const size_t nLen = i_rIniLine.size(); + if ( o3tl::starts_with(i_rIniLine, u"[") && o3tl::ends_with(i_rIniLine, u"]") ) + { + o_rSectionName = i_rIniLine.substr( 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 & 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 + DatabaseDocumentRecovery::DatabaseDocumentRecovery( const Reference & i_rContext ) + : mxContext( 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( mxContext, 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( mxContext, 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( mxContext, 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( mxContext, 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 0000000000..00db4ddf3b --- /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 +#include +#include +#include + +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 0000000000..bc29bd727b --- /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 + +#include +#include +#include +#include + +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 0000000000..613bfb7299 --- /dev/null +++ b/dbaccess/source/core/recovery/storagestream.cxx @@ -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 . + */ + +#include "storagestream.hxx" + +#include + +#include + +namespace dbaccess +{ + + using ::com::sun::star::uno::Reference; + 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 0000000000..64c7e369dd --- /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 + +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 0000000000..a60890fa85 --- /dev/null +++ b/dbaccess/source/core/recovery/storagetextstream.cxx @@ -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 . + */ + +#include "storagetextstream.hxx" + +#include + +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; + + constexpr OUString sLineFeed = u"\n"_ustr; + + // StorageTextOutputStream + StorageTextOutputStream::StorageTextOutputStream( const Reference& i_rContext, + const Reference< XStorage >& i_rParentStorage, + const OUString& i_rStreamName + ) + :StorageOutputStream( i_rParentStorage, i_rStreamName ) + { + mxTextOutput = TextOutputStream::create( i_rContext ); + mxTextOutput->setEncoding( "UTF-8" ); + mxTextOutput->setOutputStream( getOutputStream() ); + } + + StorageTextOutputStream::~StorageTextOutputStream() + { + } + + void StorageTextOutputStream::writeLine( const OUString& i_rLine ) + { + mxTextOutput->writeString( i_rLine ); + mxTextOutput->writeString( sLineFeed ); + } + + void StorageTextOutputStream::writeLine() + { + mxTextOutput->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 0000000000..31bef3d83b --- /dev/null +++ b/dbaccess/source/core/recovery/storagetextstream.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 "storagestream.hxx" + +#include + +namespace com::sun::star::io { class XTextOutputStream2; } + +namespace dbaccess +{ + + // StorageTextStream + 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: + css::uno::Reference< css::io::XTextOutputStream2 > mxTextOutput; + }; + +} // 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 0000000000..e828ac73d3 --- /dev/null +++ b/dbaccess/source/core/recovery/storagexmlstream.cxx @@ -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 . + */ + +#include "storagexmlstream.hxx" + +#include +#include +#include +#include + +#include +#include + +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 + StorageXMLOutputStream::StorageXMLOutputStream( const Reference& i_rContext, + const Reference< XStorage >& i_rParentStorage, + const OUString& i_rStreamName ) + :StorageOutputStream( i_rParentStorage, i_rStreamName ) + { + const Reference< XWriter > xSaxWriter = Writer::create( i_rContext ); + xSaxWriter->setOutputStream( getOutputStream() ); + + mxHandler.set( xSaxWriter, UNO_QUERY_THROW ); + mxHandler->startDocument(); + + mxAttributes = new comphelper::AttributeList; + } + + StorageXMLOutputStream::~StorageXMLOutputStream() + { + } + + void StorageXMLOutputStream::close() + { + ENSURE_OR_RETURN_VOID( mxHandler.is(), "illegal document handler" ); + mxHandler->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 + { + mxAttributes->AddAttribute( i_rName, i_rValue ); + } + + void StorageXMLOutputStream::startElement( const OUString& i_rElementName ) + { + ENSURE_OR_RETURN_VOID( mxHandler.is(), "no document handler" ); + + mxHandler->startElement( i_rElementName, mxAttributes ); + mxAttributes = new comphelper::AttributeList; + maElements.push( i_rElementName ); + } + + void StorageXMLOutputStream::endElement() + { + ENSURE_OR_RETURN_VOID( mxHandler.is(), "no document handler" ); + ENSURE_OR_RETURN_VOID( !maElements.empty(), "no element on the stack" ); + + const OUString sElementName( maElements.top() ); + mxHandler->endElement( sElementName ); + maElements.pop(); + } + + void StorageXMLOutputStream::ignorableWhitespace( const OUString& i_rWhitespace ) const + { + ENSURE_OR_RETURN_VOID( mxHandler.is(), "no document handler" ); + + mxHandler->ignorableWhitespace( i_rWhitespace ); + } + + void StorageXMLOutputStream::characters( const OUString& i_rCharacters ) const + { + ENSURE_OR_RETURN_VOID( mxHandler.is(), "no document handler" ); + + mxHandler->characters( i_rCharacters ); + } + + // StorageXMLInputStream + StorageXMLInputStream::StorageXMLInputStream( const Reference& 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 0000000000..8a340b6fea --- /dev/null +++ b/dbaccess/source/core/recovery/storagexmlstream.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 "storagestream.hxx" + +#include +#include +#include +#include +#include +#include +#include + +namespace dbaccess +{ + + 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 ); + void endElement(); + + 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: + css::uno::Reference< css::xml::sax::XDocumentHandler > mxHandler; + std::stack< OUString > maElements; + ::rtl::Reference mxAttributes; + }; + + 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 0000000000..a416b997fa --- /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 +#include + +#include + +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 0000000000..4ab8678809 --- /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 +#include +#include +#include + +#include + +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 0000000000..3a7a30d016 --- /dev/null +++ b/dbaccess/source/core/recovery/subcomponentrecovery.cxx @@ -0,0 +1,626 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include "storagexmlstream.hxx" +#include "subcomponentloader.hxx" +#include "settingsimport.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +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::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 OUString sSettingsStreamName = u"settings.xml"_ustr; + constexpr OUString sCurrentQueryDesignName = u"ooo:current-query-design"_ustr; + } + + namespace { + + // SettingsExportContext + class SettingsExportContext : public ::xmloff::XMLSettingsExportContext + { + public: + SettingsExportContext( const Reference& i_rContext, 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& m_rContext; + 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 constexpr OUString sWhitespace( u" "_ustr ); + + 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 0000000000..ee41a32dfc --- /dev/null +++ b/dbaccess/source/core/recovery/subcomponentrecovery.hxx @@ -0,0 +1,115 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in 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 +#include +#include +#include + +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, + css::uno::Reference< css::lang::XComponent > i_xComponent ) + :m_rContext( i_rContext ) + ,m_xDocumentUI( i_rController, css::uno::UNO_SET_THROW ) + ,m_xComponent(std::move( i_xComponent )) + ,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 0000000000..5e41736050 --- /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 + +#include + +#include +#include + +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 0000000000..fdef07e1f8 --- /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 + +#include + +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 0000000000..1dd770b1fc --- /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 +#include +#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 0000000000..813ca7b0be --- /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 + +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 0000000000..af10a2e8dd --- /dev/null +++ b/dbaccess/source/filter/hsqldb/columndef.cxx @@ -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 . + */ + +#include "columndef.hxx" +#include +#include + +namespace dbahsql +{ +using namespace css::sdbc; + +ColumnDefinition::ColumnDefinition(OUString sName, sal_Int32 eType, + std::vector&& aParams, bool bPrimary, + sal_Int32 nAutoIncr, bool bNullable, bool bCaseInsensitive, + OUString sDefault) + : m_sName(std::move(sName)) + , m_eType(eType) + , m_aParams(std::move(aParams)) + , m_bPrimaryKey(bPrimary) + , m_nAutoIncrement(nAutoIncr) + , m_bNullable(bNullable) + , m_bCaseInsensitive(bCaseInsensitive) + , m_sDefaultValue(std::move(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 0000000000..4ac3532a34 --- /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 +#include + +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 m_aParams; + bool m_bPrimaryKey; + sal_Int32 m_nAutoIncrement; + bool m_bNullable; + bool m_bCaseInsensitive; + OUString m_sDefaultValue; + +public: + ColumnDefinition(OUString sName, sal_Int32 eType, std::vector&& aParams, + bool bPrimary = false, sal_Int32 nAutoIncr = -1, bool bNullable = true, + bool bCaseInsensitive = false, 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& 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 0000000000..360741ce0b --- /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 +#include +#include +#include "createparser.hxx" +#include "utils.hxx" +#include + +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 lcl_splitColumnPart(std::u16string_view sColumnPart) +{ + std::vector sParts = string::split(sColumnPart, sal_Unicode(u',')); + std::vector 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& 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 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 0000000000..a92f745860 --- /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 +#include "columndef.hxx" + +namespace dbahsql +{ +class SAL_DLLPUBLIC_EXPORT CreateStmtParser +{ +private: + std::vector m_aColumns; + std::vector m_aForeignParts; + std::vector 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 const& getPrimaryKeys() const { return m_PrimaryKeys; } + + /** + * @return a vector of column descriptors, representing the columns of the + * parsed statement. + */ + const std::vector& getColumnDef() const { return m_aColumns; } + + /** + * @return a vector of words. + */ + const std::vector& 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 0000000000..a8948069e4 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/fbalterparser.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 "fbalterparser.hxx" +#include +#include + +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 " + getTableName()); + + if (getActionType() == AlterAction::IDENTITY_RESTART) + { + sSql.append(" ALTER COLUMN "); + } + sSql.append(getColumnName() + " 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 0000000000..cd48d94d5d --- /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 0000000000..5d4244f808 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/fbcreateparser.cxx @@ -0,0 +1,207 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +#include + +using namespace css::sdbc; + +namespace +{ +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& sPrimaryKeys = getPrimaryKeys(); + if (sPrimaryKeys.empty()) + return; // no primary key specified + + 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& rColumns = getColumnDef(); + for (const auto& col : rColumns) + utils::ensureFirebirdTableLength(col.getName()); +} + +OUString FbCreateStmtParser::compose() const +{ + ensureProperTableLengths(); + OUStringBuffer sSql(128); + sSql.append("CREATE TABLE " + getTableName() + " ("); // column declaration + + auto& rColumns = getColumnDef(); + auto columnIter = rColumns.cbegin(); + while (columnIter != rColumns.end()) + { + sSql.append(" " + columnIter->getName() + " " + + lcl_DataTypetoFbTypeName(columnIter->getDataType())); + + std::vector 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()) + sSql.append(" " + sModifier); + + if (columnIter->isAutoIncremental()) + { + // start with 0: + // HSQLDB: first value will be 0. + // Firebird: first value will be 1. + sSql.append(" GENERATED BY DEFAULT AS IDENTITY (START WITH " + + OUString::number(columnIter->getStartValue() - 1) + ")"); + } + else if (!columnIter->isNullable()) + sSql.append(" NOT NULL"); + + if (columnIter->isCaseInsensitive()) + sSql.append(" COLLATE UNICODE_CI"); + + const OUString& sDefaultVal = columnIter->getDefault(); + if (!sDefaultVal.isEmpty()) + { + sSql.append(" DEFAULT "); + if (sDefaultVal.equalsIgnoreAsciiCase("NOW")) + sSql.append("'NOW'"); // Fb likes it single quoted + else + sSql.append(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 0000000000..6706c05bea --- /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 0000000000..c02da2c4b4 --- /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 HsqlBinaryNode::readRow(HsqlRowInputStream& input, + const std::vector& 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 0000000000..97777e7d14 --- /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 + +#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 readRow(HsqlRowInputStream& rInput, + const std::vector& 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 0000000000..918397da62 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/hsqlimport.cxx @@ -0,0 +1,384 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#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& row, Reference const& xParam, + const std::vector& 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 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 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& rColTypes) +{ + assert(rColTypes.size() > 0); + OUStringBuffer sql(OUString::Concat("INSERT INTO ") + sTableName + " ("); + + // 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(") 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& rConnection, const Reference& rStorage) + : m_rConnection(rConnection) +{ + m_xStorage.set(rStorage); +} + +void HsqlImporter::insertRow(const std::vector& xRows, + std::u16string_view sTableName, + const std::vector& rColTypes) +{ + OUString sStatement = lcl_createInsertStatement(sTableName, rColTypes); + Reference xStatement = m_rConnection->prepareStatement(sStatement); + + Reference 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& 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 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: + * + * Where Node is a 20 byte data, representing the rows in a binary tree: + * + * + * Size is the size of ; + * Balance: ? + * Left/Right/Parent: File position of the Left/Right/Parent child + */ +void HsqlImporter::parseTableRows(const std::vector& rIndexes, + const std::vector& rColTypes, + const OUString& sTableName) +{ + static constexpr OUString BINARY_FILENAME = u"data"_ustr; + + 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 xStream( + m_xStorage->openStreamElement(BINARY_FILENAME, ElementModes::READ)); + + HsqlRowInputStream rowInput; + Reference 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 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 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 aColTypes = parser.getTableColumnTypes(tableIndex.first); + parseTableRows(tableIndex.second, aColTypes, tableIndex.first); + } + catch (const std::out_of_range& e) + { + std::unique_ptr 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 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 0000000000..7bab53c24b --- /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 +#include + +#include "rowinputbinary.hxx" +#include "hsqlbinarynode.hxx" +#include "columndef.hxx" + +namespace weld +{ +class Window; +} + +namespace dbahsql +{ +class SAL_DLLPUBLIC_EXPORT HsqlImporter +{ +private: + css::uno::Reference& m_rConnection; + css::uno::Reference m_xStorage; + +protected: + void insertRow(const std::vector& xRows, std::u16string_view sTable, + const std::vector& rColTypes); + void processTree(HsqlBinaryNode& rNode, HsqlRowInputStream& rStream, + const std::vector& rColTypes, const OUString& sTableName, + sal_Int32 nIndexCount); + void parseTableRows(const std::vector& rIndexes, + const std::vector& 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& rConnection, + const css::uno::Reference& 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 0000000000..5e512f0679 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/parseschema.cxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "parseschema.hxx" +#include "fbcreateparser.hxx" +#include "fbalterparser.hxx" +#include "utils.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ +using namespace ::comphelper; + +using IndexVector = std::vector; + +class IndexStmtParser +{ +private: + OUString m_sql; + +public: + IndexStmtParser(OUString sSql) + : m_sql(std::move(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 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 or SET TABLE "" + 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& rStorage) + : m_rStorage(rStorage) +{ +} + +void SchemaParser::parseSchema() +{ + assert(m_rStorage); + + static constexpr OUString SCHEMA_FILENAME = u"script"_ustr; + if (!m_rStorage->hasByName(SCHEMA_FILENAME)) + { + SAL_WARN("dbaccess", "script file does not exist in storage during hsqldb import"); + return; + } + + Reference xStream(m_rStorage->openStreamElement(SCHEMA_FILENAME, ElementModes::READ)); + + Reference rContext = comphelper::getProcessComponentContext(); + Reference 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 SchemaParser::getTableColumnTypes(const OUString& sTableName) const +{ + if (m_ColumnTypes.count(sTableName) < 1) + { + static constexpr OUString NOT_EXIST + = u"Internal error while getting column information of table"_ustr; + SAL_WARN("dbaccess", NOT_EXIST << ". Table name is: " << sTableName); + dbtools::throwGenericSQLException(NOT_EXIST, ::comphelper::getProcessComponentContext()); + } + return m_ColumnTypes.at(sTableName); +} + +const std::map>& SchemaParser::getTableIndexes() const +{ + return m_Indexes; +} + +const std::map>& 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 0000000000..04a8e09050 --- /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 +#include +#include + +#include "columndef.hxx" + +namespace dbahsql +{ +using SqlStatementVector = std::vector; + +class SchemaParser +{ +private: + css::uno::Reference& m_rStorage; + + // column type for each table. It is filled after parsing schema. + std::map> m_ColumnTypes; + + // root element's position of data for each table + std::map> m_Indexes; + + // primary keys of each table + std::map> m_PrimaryKeys; + + SqlStatementVector m_sCreateStatements; + SqlStatementVector m_sAlterStatements; + +public: + explicit SchemaParser(css::uno::Reference& 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 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>& getTableIndexes() const; + + /** + * Returns a vector of column names for each table. These columns are the + * primary keys of the table. + */ + const std::map>& 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 0000000000..b72ccfd8d7 --- /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 + +#include + +#include "rowinputbinary.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +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& bytes) +{ + size_t nbits = 8 * bytes.size(); // length of array in bits + size_t nscratch = nbits / 2; // length of scratch in bytes + std::vector 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&& 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(std::u16string_view sNum, sal_Int32 nScale) +{ + // e.g. sNum = "0", nScale = 2 -> "0.00" + OUStringBuffer sBuf{ sNum }; + sal_Int32 nNullsToAppend = nScale - sNum.size() + 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 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 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 HsqlRowInputStream::readOneRow(const std::vector& nColTypes) +{ + auto nLen = nColTypes.size(); + std::vector 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 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 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(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 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 0000000000..f81fa446f7 --- /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 +#include + +#include + +#include "columndef.hxx" + +namespace dbahsql +{ +class HsqlRowInputStream +{ +private: + std::unique_ptr 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 readOneRow(const std::vector& colTypes); + + /** + * Sets the file-pointer offset, measured from the beginning of the file + */ + void seek(sal_Int32 nPos); + + void setInputStream(css::uno::Reference 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 0000000000..d8addd3362 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/utils.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 +#include +#include +#include + +#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 (nAposEnd == std::u16string_view::npos) + { + SAL_WARN("dbaccess", "no matching \""); + return OUString(); + } + 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(std::u16string_view sName) +{ + if (sName.size() > 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 0000000000..ed5fb8a1e3 --- /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 + +#include + +#include + +namespace dbahsql::utils +{ +OUString convertToUTF8(std::string_view original); + +OUString getTableNameFromStmt(std::u16string_view sSql); + +void ensureFirebirdTableLength(std::u16string_view 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 0000000000..4842eb4ad3 --- /dev/null +++ b/dbaccess/source/filter/xml/dbaxml.component @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/source/filter/xml/dbloader2.cxx b/dbaccess/source/filter/xml/dbloader2.cxx new file mode 100644 index 0000000000..7b10bf2b52 --- /dev/null +++ b/dbaccess/source/filter/xml/dbloader2.cxx @@ -0,0 +1,533 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 & _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 & _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 = 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 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 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 ); + + // introduce model/view/controller to each other + utl::ConnectFrameControllerModel(rFrame, xController, xModel); + + 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 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 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 0000000000..f55e620ec1 --- /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 +namespace dbaxml +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::xml::sax; + +void OXMLAutoStylePoolP::exportStyleAttributes( + comphelper::AttributeList& 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 0000000000..d358b50f72 --- /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 +#include + +namespace dbaxml +{ + class ODBExport; + class OXMLAutoStylePoolP : public SvXMLAutoStylePoolP + { + ODBExport& rODBExport; + + virtual void exportStyleAttributes( + comphelper::AttributeList& 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 0000000000..1afbf9f0f4 --- /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 +#include +#include +#include +#include "xmlStyleImport.hxx" +#include + +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 xFac(m_xParentContainer,UNO_QUERY); + if ( xFac.is() && !m_sName.isEmpty() ) + { + Reference 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(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( + 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(dynamic_cast(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(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(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 0000000000..8deca87c7c --- /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 +#include +#include + +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 0000000000..0198422591 --- /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 +#include +#include +#include +#include +#include +#include + +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 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 0000000000..136d5b6854 --- /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 +#include + +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 0000000000..2213585374 --- /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 +#include +#include "xmlEnums.hxx" +#include "xmlDatabaseDescription.hxx" +#include "xmlConnectionResource.hxx" +#include + +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(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 0000000000..466c047888 --- /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 + +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 0000000000..6e4a006be2 --- /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 +#include +#include +#include + +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 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 0000000000..357bbe1e11 --- /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 + +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 0000000000..9939a197b1 --- /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 +#include +#include "xmlEnums.hxx" +#include +#include +#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 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(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 0000000000..5b78ff4fe4 --- /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 + +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 0000000000..eefc08e419 --- /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 +#include +#include + +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 0000000000..e29d37a7d3 --- /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 + +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 0000000000..9402bb399d --- /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 +#include + +#include + +#include "xmlDataSourceSetting.hxx" +#include +#include "xmlfilter.hxx" +#include +#include +#include "xmlEnums.hxx" +#include + +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::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::get(); + // Not a copy paste error, see comment xmloff/source/forms/propertyimport.cxx lines 244-248 + tmp[GetXMLToken( XML_FLOAT)] = ::cppu::UnoType::get(); + tmp[GetXMLToken( XML_DOUBLE)] = ::cppu::UnoType::get(); + tmp[GetXMLToken( XML_STRING)] = ::cppu::UnoType::get(); + tmp[GetXMLToken( XML_INT)] = ::cppu::UnoType::get(); + tmp[GetXMLToken( XML_SHORT)] = ::cppu::UnoType::get(); + tmp[GetXMLToken( XML_VOID)] = cppu::UnoType::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(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(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 0000000000..3ed92f80e7 --- /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 +#include +#include + +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 0000000000..49847ef541 --- /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 +#include +#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(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 0000000000..50fea5c000 --- /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 + +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 0000000000..2f629caff3 --- /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 +#include +#include "xmlDataSource.hxx" +#include "xmlDocuments.hxx" +#include "xmlEnums.hxx" +#include +#include +#include +#include +#include +#include +#include + +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 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 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 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 xSup(GetOwnImport().getDataSource(),UNO_QUERY); + if ( xSup.is() ) + pContext = new OXMLDocuments( GetOwnImport(), xSup->getTables()); + } + break; + } + + return pContext; +} + +ODBFilter& OXMLDatabase::GetOwnImport() +{ + return static_cast(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 0000000000..0dab56c51c --- /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 + +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 0000000000..a8168e1295 --- /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 +#include +#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(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 0000000000..146ecb4017 --- /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 + +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 0000000000..fa763614c3 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDocuments.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 "xmlDocuments.hxx" +#include "xmlfilter.hxx" +#include +#include +#include +#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 + ,OUString _sCollectionServiceName + ,OUString _sComponentServiceName) : + SvXMLImportContext( rImport ) + ,m_xContainer(_xContainer) + ,m_sCollectionServiceName(std::move(_sCollectionServiceName)) + ,m_sComponentServiceName(std::move(_sComponentServiceName)) +{ + +} + +OXMLDocuments::OXMLDocuments( ODBFilter& rImport + ,const Reference< XNameAccess >& _xContainer + ,OUString _sCollectionServiceName + ) : + SvXMLImportContext( rImport ) + ,m_xContainer(_xContainer) + ,m_sCollectionServiceName(std::move(_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(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 0000000000..49c6346aa8 --- /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 +#include + +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 + ,OUString _sCollectionServiceName + ,OUString _sComponentServiceName); + + // for queries + OXMLDocuments( ODBFilter& rImport + ,const css::uno::Reference< css::container::XNameAccess >& _xContainer + ,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 0000000000..552f7eb24f --- /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 0000000000..cee5e04a04 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlExport.cxx @@ -0,0 +1,1343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "xmlHelper.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 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 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( + comphelper::AttributeList& /*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, + XML_STYLE_FAMILY_TABLE_TABLE_STYLES_NAME, + m_xExportHelper.get(), + XML_STYLE_FAMILY_TABLE_TABLE_STYLES_PREFIX); + + GetAutoStylePool()->AddFamily( + XmlStyleFamily::TABLE_COLUMN, + XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME, + m_xColumnExportHelper.get(), + XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX); + + GetAutoStylePool()->AddFamily( + XmlStyleFamily::TABLE_CELL, + XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME, + m_xCellExportHelper.get(), + XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX); + + GetAutoStylePool()->AddFamily( + XmlStyleFamily::TABLE_ROW, + XML_STYLE_FAMILY_TABLE_ROW_STYLES_NAME, + m_xRowExportHelper.get(), + XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX); +} + +void ODBExport::exportDataSource() +{ + try + { + Reference 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( OUString _sPropertyName, const XMLTokenEnum _eToken ) + :sPropertyName(std::move( _sPropertyName )) + ,eAttributeToken( _eToken ) + ,aXMLDefault() + { + } + + PropertyMap( OUString _sPropertyName, const XMLTokenEnum _eToken, const OUString& _rDefault ) + :sPropertyName(std::move( _sPropertyName )) + ,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_oAutoIncrement = 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 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 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 constexpr OUString sPropertyName = u"LocalSocket"_ustr; + 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 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 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_oAutoIncrement) + { + AddAttribute(XML_NAMESPACE_DB, XML_ADDITIONAL_COLUMN_STATEMENT,m_oAutoIncrement->second); + AddAttribute(XML_NAMESPACE_DB, XML_ROW_RETRIEVING_STATEMENT,m_oAutoIncrement->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 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& _aMemFunc + ) +{ + if ( !_xCollection.is() ) + return; + + std::unique_ptr 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 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 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 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,comphelper::AttributeList& _rAtt) +{ + Reference 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& _xProp,comphelper::AttributeList& _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 ? PROPERTY_UPDATE_TABLENAME : PROPERTY_NAME) >>= sValue; + if ( sValue.isEmpty() ) + return; + + AddAttribute(XML_NAMESPACE_DB, XML_NAME,sValue); + _xProp->getPropertyValue(_bUpdate ? PROPERTY_UPDATE_SCHEMANAME : PROPERTY_SCHEMANAME) >>= sValue; + if ( !sValue.isEmpty() ) + AddAttribute(XML_NAMESPACE_DB, XML_SCHEMA_NAME,sValue); + _xProp->getPropertyValue(_bUpdate ? PROPERTY_UPDATE_CATALOGNAME : 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& _xColSup) +{ + OSL_PRECOND( _xColSup.is(), "ODBExport::exportColumns: invalid columns supplier!" ); + if ( !_xColSup.is() ) + return; + + try + { + Reference 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 pAtt = new comphelper::AttributeList; + 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 xProp(xNameAccess->getByName(*pIter),UNO_QUERY); + if ( xProp.is() ) + { + rtl::Reference pAtt = new comphelper::AttributeList; + 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 xSup(GetModel(),UNO_QUERY); + if ( xSup.is() ) + { + Reference< XNameAccess > xCollection = xSup->getFormDocuments(); + if ( xCollection.is() && xCollection->hasElements() ) + { + ::comphelper::mem_fun1_t 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 xSup(GetModel(),UNO_QUERY); + if ( xSup.is() ) + { + Reference< XNameAccess > xCollection = xSup->getReportDocuments(); + if ( xCollection.is() && xCollection->hasElements() ) + { + ::comphelper::mem_fun1_t 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 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 > pMemFunc; + if ( _bExportContext ) + pMemFunc.reset( new ::comphelper::mem_fun1_t(&ODBExport::exportQuery) ); + else + pMemFunc.reset( new ::comphelper::mem_fun1_t(&ODBExport::exportAutoStyle) ); + + exportCollection(xCollection,XML_QUERIES,XML_QUERY_COLLECTION,_bExportContext,*pMemFunc); + } +} + +void ODBExport::exportTables(bool _bExportContext) +{ + Reference 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 > pMemFunc; + if ( _bExportContext ) + pMemFunc.reset( new ::comphelper::mem_fun1_t(&ODBExport::exportTable) ); + else + pMemFunc.reset( new ::comphelper::mem_fun1_t(&ODBExport::exportAutoStyle) ); + exportCollection(xCollection,XML_TABLE_REPRESENTATIONS,XML_TOKEN_INVALID,_bExportContext,*pMemFunc); + } +} + +void ODBExport::exportAutoStyle(XPropertySet* _xProp) +{ + typedef std::pair TEnumMapperPair; + typedef std::pair< rtl::Reference < SvXMLExportPropertyMapper> , TEnumMapperPair> TExportPropMapperPair; + Reference 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(aFont.Family), + static_cast(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 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& aProps) +{ + Reference 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 aQueries(aSeq.getLength()); + auto aQueriesRange = asNonConstRange(aQueries); + for(sal_Int32 i = 0;pIter != pEnd;++pIter,++i) + { + Reference 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& aProps) +{ + Reference 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 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 0000000000..4dbd3f1652 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlExport.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 +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +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 ,OUString > TPropertyStyleMap; + typedef std::map< Reference ,Reference > TTableColumnMap; + + struct TypedPropertyValue + { + OUString Name; + css::uno::Type Type; + css::uno::Any Value; + + TypedPropertyValue( OUString _name, const css::uno::Type& _type, css::uno::Any _value ) + :Name(std::move( _name )) + ,Type( _type ) + ,Value(std::move( _value )) + { + } + }; + + std::optional< TStringPair > m_oAutoIncrement; + 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 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,comphelper::AttributeList& _rAtt); + void exportStyleName(const ::xmloff::token::XMLTokenEnum _eToken,const Reference& _xProp,comphelper::AttributeList& _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& _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& _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& aProps) override; + virtual void GetConfigurationSettings(css::uno::Sequence& 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& 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 0000000000..c54acdd652 --- /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 +#include +#include +#include +#include +#include +#include +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 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 0000000000..3720e1da35 --- /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 + +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 0000000000..546c67abf5 --- /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 +#include +#include +#include +#include +#include + +#include +#include +#include + +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 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 } + }; + 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 } + }; + 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 }, + { PROPERTY_CHAR_STRIKEOUT, 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 }, + { PROPERTY_CHAR_STRIKEOUT, 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 }, + { PROPERTY_CHAR_STRIKEOUT, 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 }, + { PROPERTY_CHAR_STRIKEOUT, 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 }, + { PROPERTY_CHAR_UNDERLINE, 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 }, + { PROPERTY_CHAR_UNDERLINE, 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 }, + { PROPERTY_CHAR_UNDERLINE, 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 }, + { PROPERTY_CHAR_UNDERLINE_COLOR, 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_CHAR_UNDERLINE_HAS_COLOR, 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 } + }; + 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 } + }; + 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 0000000000..a65cef9b35 --- /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 +#include +#include + +#include + +#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 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 0000000000..74a5b5e3f1 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlHierarchyCollection.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 "xmlHierarchyCollection.hxx" +#include "xmlComponent.hxx" +#include "xmlColumn.hxx" +#include "xmlfilter.hxx" +#include +#include +#include +#include "xmlEnums.hxx" +#include +#include +#include +#include + +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 + ,OUString _sComponentServiceName) : + SvXMLImportContext( rImport ) + ,m_sCollectionServiceName(_sCollectionServiceName) + ,m_sComponentServiceName(std::move(_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 xORB(_xParentContainer,UNO_QUERY); + if ( xORB.is() ) + { + Sequence aArguments(comphelper::InitAnyPropertySequence( + { + {"Name", Any(sName)}, // set as folder + {"Parent", Any(_xParentContainer)}, + })); + m_xContainer.set(xORB->createInstanceWithArguments(_sCollectionServiceName,aArguments),UNO_QUERY); + Reference 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(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 0000000000..91f0aae869 --- /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 +#include +#include + +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 + ,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 0000000000..a4519b26e7 --- /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 +#include +#include +#include + +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 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 0000000000..adb25c739b --- /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 + +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 0000000000..a707e87345 --- /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 +#include +#include "xmlEnums.hxx" +#include +#include + +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 0000000000..d3e01193c4 --- /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 0000000000..a1db053092 --- /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 +#include +#include +#include + +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 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 0000000000..ec3401fff7 --- /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 + +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 0000000000..4196860031 --- /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 +#include +#include +#include +#include +#include +#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, + OTableStylesContext& 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(dynamic_cast< const SvXMLNumFormatContext* >(pStyles->FindStyleChildContext( + XmlStyleFamily::DATA_STYLE, m_sDataStyleName, true))); + if ( !pStyle ) + { + OTableStylesContext* pMyStyles = dynamic_cast(GetOwnImport().GetAutoStyles()); + if ( pMyStyles ) + pStyle = const_cast(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(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(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(this)->GetOwnImport().GetTableStylesPropertySetMapper(), const_cast(GetImport()) ); + xMapper = m_xTableImpPropMapper; + } + break; + case XmlStyleFamily::TABLE_COLUMN: + { + if ( !m_xColumnImpPropMapper.is() ) + m_xColumnImpPropMapper = new SvXMLImportPropertyMapper( const_cast(this)->GetOwnImport().GetColumnStylesPropertySetMapper(), const_cast(GetImport()) ); + xMapper = m_xColumnImpPropMapper; + } + break; + case XmlStyleFamily::TABLE_CELL: + { + if ( !m_xCellImpPropMapper.is() ) + m_xCellImpPropMapper = new SvXMLImportPropertyMapper( const_cast(this)->GetOwnImport().GetCellStylesPropertySetMapper(), const_cast(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(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 0000000000..7f6c9932da --- /dev/null +++ b/dbaccess/source/filter/xml/xmlStyleImport.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 +#include +#include +#include + +namespace dbaxml +{ + class ODBFilter; + class OTableStylesContext; + + class OTableStyleContext : public XMLPropStyleContext + { + OUString m_sDataStyleName; + OUString sPageStyle; + OTableStylesContext* pStyles; + sal_Int32 m_nNumberFormat; + + ODBFilter& GetOwnImport(); + + protected: + + virtual void SetAttribute( sal_Int32 nElement, + const OUString& rValue ) override; + + public: + + + OTableStyleContext( ODBFilter& rImport, + OTableStylesContext& 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 0000000000..dd7df81c80 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlTable.cxx @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include "xmlEnums.hxx" +#include "xmlStyleImport.hxx" +#include "xmlHierarchyCollection.hxx" +#include +#include +#include +#include +#include +#include + +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 + ,uno::Reference< css::container::XNameAccess > _xParentContainer + ,const OUString& _sServiceName + ) + :SvXMLImportContext( _rImport ) + ,m_xParentContainer(std::move(_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 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(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(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(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 0000000000..9be9feaa02 --- /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 +#include +#include + +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 + ,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 0000000000..a6541684ac --- /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 +#include +#include +#include +#include +#include +#include +#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(GetImport()); +} + +void OXMLTableFilterList::endFastElement(sal_Int32 ) +{ + Reference 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 0000000000..1988bdd29c --- /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 +#include + +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 0000000000..0c4b2892d2 --- /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 0000000000..8f0b64f37a --- /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 +#include + +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 0000000000..9750446232 --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xmlfilter.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xmlDatabase.hxx" +#include "xmlEnums.hxx" +#include +#include +#include "xmlStyleImport.hxx" +#include +#include "xmlHelper.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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, + const uno::Reference& xModelComponent, + const uno::Reference & 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& xModelComponent, + const char* pStreamName, + const uno::Reference & 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 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 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 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 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 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(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(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(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& 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& aConfigProps) +{ + const PropertyValue *pIter = aConfigProps.getConstArray(); + const PropertyValue *pEnd = pIter + aConfigProps.getLength(); + for (; pIter != pEnd; ++pIter) + { + if ( pIter->Name == "layout-settings" ) + { + Sequence aWindows; + pIter->Value >>= aWindows; + uno::Reference xProp(getDataSource()); + if ( xProp.is() ) + xProp->setPropertyValue(PROPERTY_LAYOUTINFORMATION,Any(aWindows)); + } + } +} + + +void ODBFilter::fillPropertyMap(const Any& _rValue,TPropertyNameMap& _rMap) +{ + Sequence aWindows; + _rValue >>= aWindows; + const PropertyValue *pIter = aWindows.getConstArray(); + const PropertyValue *pEnd = pIter + aWindows.getLength(); + for (; pIter != pEnd; ++pIter) + { + Sequence 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(pContext)); + else + SetStyles(static_cast(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 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 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 0000000000..ec776cd75f --- /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 +#include +#include +#include +#include +#include +#include + +#include +#include + + +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 > 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 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& aViewProps) override; + virtual void SetConfigurationSettings(const css::uno::Sequence& aConfigProps) override; + + const Reference& 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 0000000000..d1eac7b54a --- /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 + +#include +#include +#include + +#include +#include + +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 0000000000..0f4f2c9bec --- /dev/null +++ b/dbaccess/source/inc/apitools.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 + +#include +#include + +// 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::WeakComponentImplHelper<> +{ +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::uno::XInterface + virtual void SAL_CALL release() noexcept override; + + operator css::uno::Reference< css::uno::XInterface > () const + { return static_cast(const_cast(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 0000000000..00ea9844e1 --- /dev/null +++ b/dbaccess/source/inc/dsntypes.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 + +#include +#include + +#include +#include + +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_EMBEDDED_UNKNOWN = 30, /// for all embedded addons driver + + + 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 +#define PAGE_DBSETUPWIZARD_POSTGRES 19 + +// ODsnTypeCollection +class OOO_DLLPUBLIC_DBA ODsnTypeCollection final +{ + + std::vector m_aDsnTypesDisplayNames; /// user readable names for the datasource types + std::vector 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(std::u16string_view _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& _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 0000000000..1f20962a78 --- /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 0000000000..5dd408bac8 --- /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 +#include "tablename.hxx" +#include "objectnames.hxx" +#include "datasourcemetadata.hxx" + +#include +#include +#include +#include + +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& _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 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 0000000000..a446885b8b --- /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 + +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& _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 0000000000..232f97f601 --- /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 + +#include + +#include + +#include + +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 . + @throws css::lang::NullPointerException + if _rxConnection is + */ + 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 0000000000..e36092e30b --- /dev/null +++ b/dbaccess/source/sdbtools/connection/objectnames.cxx @@ -0,0 +1,421 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +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(PNameValidation _pPrimary, PNameValidation _pSecondary) + :m_pPrimary(std::move( _pPrimary )) + ,m_pSecondary(std::move( _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( _rxConnection, xTables ); + PNameValidation pQueryCheck = std::make_shared( _rxConnection, xQueries ); + PNameValidation pReturn; + + if ( aMeta.supportsSubqueriesInFrom() ) + pReturn = std::make_shared( 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( _rxConnection ); + return std::make_shared( _rxConnection ); + } + + // ObjectNames + ObjectNames::ObjectNames( const Reference& _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 0000000000..439db09671 --- /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 + +#include + +#include + +#include + +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 . + + @throws css::lang::NullPointerException + if _rxConnection is + */ + 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 0000000000..f6a77dd3e9 --- /dev/null +++ b/dbaccess/source/sdbtools/connection/tablename.cxx @@ -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 . + */ + +#include "tablename.hxx" +#include +#include +#include + +#include +#include + +#include +#include + +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 + TableName::TableName( const Reference& _rContext, const Reference< XConnection >& _rxConnection ) + :ConnectionDependentComponent( _rContext ) + { + setWeakConnection( _rxConnection ); + } + + TableName::~TableName() + { + } + + OUString SAL_CALL TableName::getCatalogName() + { + EntryGuard aGuard( *this ); + return msCatalog; + } + + void SAL_CALL TableName::setCatalogName( const OUString& _catalogName ) + { + EntryGuard aGuard( *this ); + msCatalog = _catalogName; + } + + OUString SAL_CALL TableName::getSchemaName() + { + EntryGuard aGuard( *this ); + return msSchema; + } + + void SAL_CALL TableName::setSchemaName( const OUString& _schemaName ) + { + EntryGuard aGuard( *this ); + msSchema = _schemaName; + } + + OUString SAL_CALL TableName::getTableName() + { + EntryGuard aGuard( *this ); + return msName; + } + + void SAL_CALL TableName::setTableName( const OUString& _tableName ) + { + EntryGuard aGuard( *this ); + msName = _tableName; + } + + OUString SAL_CALL TableName::getNameForSelect() + { + EntryGuard aGuard( *this ); + return composeTableNameForSelect( getConnection(), msCatalog, msSchema, msName ); + } + + 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 ) >>= msCatalog ); + OSL_VERIFY( _table->getPropertyValue( PROPERTY_SCHEMANAME ) >>= msSchema ); + OSL_VERIFY( _table->getPropertyValue( PROPERTY_NAME ) >>= msName ); + } + 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 } + }; + + auto const found = std::find_if(std::begin(TypeTable), std::end(TypeTable) + , [_nType](auto const & type){ return type.nCompositionType == _nType; }); + if (found == std::end(TypeTable)) + throw IllegalArgumentException( + DBA_RES( STR_INVALID_COMPOSITION_TYPE ), + nullptr, + 0 + ); + + return found->eComposeRule; + } + } + + OUString SAL_CALL TableName::getComposedName( ::sal_Int32 Type, sal_Bool Quote ) + { + EntryGuard aGuard( *this ); + + return composeTableName( + getConnection()->getMetaData(), + msCatalog, msSchema, msName, Quote, + lcl_translateCompositionType_throw( Type ) ); + } + + void SAL_CALL TableName::setComposedName( const OUString& ComposedName, ::sal_Int32 Type ) + { + EntryGuard aGuard( *this ); + + qualifiedNameComponents( + getConnection()->getMetaData(), + ComposedName, + msCatalog, msSchema, msName, + 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 0000000000..74abc3025f --- /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 + +#include + +#include + +#include + +namespace sdbtools +{ + + // TableName + typedef ::cppu::WeakImplHelper< css::sdb::tools::XTableName + > TableName_Base; + /** default implementation for XTableName + */ + class TableName :public TableName_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 . + + @throws css::lang::NullPointerException + if _rxConnection is + */ + 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; + + OUString msCatalog; + OUString msSchema; + OUString msName; + }; + +} // 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 0000000000..9f424256c6 --- /dev/null +++ b/dbaccess/source/sdbtools/inc/connectiondependent.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 +#include +#include + +#include +#include +#include + +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( css::uno::Reference< css::uno::XComponentContext > _xContext ) + :m_aContext(std::move( _xContext )) + { + } + + /** 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: +

  • It ensures multi-threading safety by guarding the component's mutex + as long as it lives.
  • +
  • It ensures that the component's connection is alive. The constructor + throws a DisposedException if no hard reference to the connection can + be obtained.
  • +
+ */ + 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 0000000000..876f713afa --- /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 +#include +#include +#include + +#include + +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 0000000000..9d548a1381 --- /dev/null +++ b/dbaccess/source/ui/app/AppController.cxx @@ -0,0 +1,2837 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "AppController.hxx" +#include +#include +#include +#include +#include "subcomponentmanager.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include "AppView.hxx" +#include +#include +#include +#include +#include +#include "AppDetailView.hxx" +#include +#include +#include +#include +#include + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OApplicationController_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence 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 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(PreviewMode::NONE) + ,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() ) + { + // Should correspond to ODatabaseSource::createArrayHelper in dbaccess/source/core/dataaccess/datasource.cxx + m_xDataSource->removePropertyChangeListener(OUString(), this); + m_xDataSource->removePropertyChangeListener(PROPERTY_INFO, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_ISPASSWORDREQUIRED, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_ISREADONLY, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_LAYOUTINFORMATION, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_NAME, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_NUMBERFORMATSSUPPLIER, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_PASSWORD, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_SETTINGS, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_SUPPRESSVERSIONCL, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_TABLEFILTER, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_TABLETYPEFILTER, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_URL, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_USER, this); + m_xDataSource = nullptr; + } + + Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY ); + if ( xBroadcaster.is() ) + xBroadcaster->removeModifyListener(static_cast(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 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::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 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( _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 xModi(m_xModel,UNO_QUERY); + Reference 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()); + 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 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 xViewSup( getConnection(), UNO_QUERY ); + aReturn.bEnabled = xViewSup.is() && Reference(xViewSup->getViews(),UNO_QUERY).is(); + } + } + break; + case SID_DB_APP_DISABLE_PREVIEW: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer()->getPreviewMode() == PreviewMode::NONE; + break; + case SID_DB_APP_VIEW_DOCINFO_PREVIEW: + { + ElementType eType = getContainer()->getElementType(); + aReturn.bEnabled = (E_REPORT == eType || E_FORM == eType); + aReturn.bChecked = getContainer()->getPreviewMode() == PreviewMode::DocumentInfo; + } + break; + case SID_DB_APP_VIEW_DOC_PREVIEW: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer()->getPreviewMode() == PreviewMode::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 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 pDlg(pFact->CreatePasteDialog(getFrameWeld())); + std::vector 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_uInt32 nTmp; + if ( pIter->Value >>= nTmp ) + pasteFormat(static_cast(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 pFilter = getStandardDatabaseFilter(); + if ( pFilter ) + { + aFileDlg.AddFilter(pFilter->GetUIName(),pFilter->GetDefaultExtension()); + aFileDlg.SetCurrentFilter(pFilter->GetUIName()); + } + + if ( aFileDlg.Execute() != ERRCODE_NONE ) + break; + + Reference 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, ElementOpenMode::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, ElementOpenMode::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, ElementOpenMode::Normal ); + break; + case SID_DB_APP_CONVERTTOVIEW: + doAction( _nId, ElementOpenMode::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, ElementOpenMode::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, ElementOpenMode::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 = PreviewMode::NONE; + getContainer()->switchPreview(m_ePreviewMode); + break; + case SID_DB_APP_VIEW_DOCINFO_PREVIEW: + m_ePreviewMode = PreviewMode::DocumentInfo; + getContainer()->switchPreview(m_ePreviewMode); + break; + case SID_DB_APP_VIEW_DOC_PREVIEW: + m_ePreviewMode = PreviewMode::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, ElementOpenMode::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(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 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(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 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 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(), + ElementOpenMode::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 == ElementOpenMode::Design ) + { + // https://bz.apache.org/ooo/show_bug.cgi?id=30382 + getContainer()->showPreview(nullptr); + } + + bool isStandaloneDocument = false; + switch ( _eType ) + { + case E_REPORT: + if ( _eOpenMode != ElementOpenMode::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 == ElementOpenMode::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(reinterpret_cast< sal_IntPtr >( _pType )); + if (getContainer()) + getContainer()->selectContainer(eType); +} + +IMPL_LINK( OApplicationController, OnCreateWithPilot, void*, _pType, void ) +{ + ElementType eType = static_cast(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 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 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 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, ElementOpenMode::Design, xComponent, o_rDocumentDefinition ); + + return xComponent; +} + +void OApplicationController::addContainerListener(const Reference& _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 xDialog; + + Reference xRename; + const ElementType eType = getContainer()->getElementType(); + switch( eType ) + { + case E_FORM: + case E_REPORT: + { + Reference 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(xRename,UNO_QUERY); + if ( xChild.is() ) + { + Reference xParent(xChild->getParent(),UNO_QUERY); + if ( xParent.is() ) + { + xHNames = xParent; + Reference(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(xRename,UNO_QUERY); + if ( xContent.is() ) + { + sOldName = xContent->getIdentifier()->getContentIdentifier(); + } + } + + xRename->rename(sNewName); + + if ( eType == E_TABLE ) + { + Reference 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 == PreviewMode::NONE ) + 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()); +} + +void OApplicationController::onPasteEntry() +{ + Execute(ID_BROWSER_PASTE,Sequence()); +} + +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()); +} + +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(pTreeListBox->GetDataTransfer()); + bSuccess = copySQLObject(rExchange); + } + else + { + svx::OComponentTransferable& rExchange = static_cast(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; + 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(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 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; + + SQLException aDetail(DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS_DETAIL), {}, {}, 0, {}); + SQLWarning aWarning(DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS), {}, {}, 0, css::uno::Any(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[] = + { + PROPERTY_URL, 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 0000000000..b7579c0cf1 --- /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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +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 + 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, will be returned. + @return + if read only or doesn't exist, otherwise + */ + 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 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 + */ + std::unique_ptr 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 the name of the content must be inserted without any change, otherwise not. + @return + if the paste operations was successful, otherwise . + */ + 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 if the clipboard supports a table format, otherwise . + 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& _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 the name of the content must be inserted without any change, otherwise not. + @return + if the insert operations was successful, otherwise . + */ + 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 then the delete command should be checked. + @return + 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 _pErrorInfo, + or, if _pErrorInfo is , 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 + 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 + if the container could be changed otherwise + */ + 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 0000000000..76525cf8f8 --- /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 +#include "AppController.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AppView.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "subcomponentmanager.hxx" +#include + +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 xSup(xConnection,UNO_QUERY); + OSL_ENSURE(xSup.is(),"OApplicationController::deleteTable: no XTablesSupplier!"); + if ( !xSup.is() ) + return; + + Reference xTables = xSup->getTables(); + Reference 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 xViewsSup(xConnection,UNO_QUERY); + + Reference 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 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 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 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 OApplicationController::copyObject() +{ + try + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + ElementType eType = getContainer()->getElementType(); + switch( eType ) + { + case E_TABLE: + case E_QUERY: + { + rtl::Reference xExchange(new ODataClipboard); + if (copySQLObject(*xExchange)) + return xExchange; + break; + } + case E_FORM: + case E_REPORT: + { + rtl::Reference 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 xSrcColSup(xQuery,UNO_QUERY); + Reference xDstColSup(xNewQuery,UNO_QUERY); + if ( xSrcColSup.is() && xDstColSup.is() ) + { + Reference xSrcNameAccess = xSrcColSup->getColumns(); + Reference xDstNameAccess = xDstColSup->getColumns(); + Reference xFac(xDstNameAccess,UNO_QUERY); + Reference xAppend(xFac,UNO_QUERY); + if ( xSrcNameAccess.is() && xDstNameAccess.is() && xSrcNameAccess->hasElements() && xAppend.is() ) + { + Reference xDstProp(xFac->createDataDescriptor()); + + Sequence< OUString> aSeq = xSrcNameAccess->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for( ; pIter != pEnd ; ++pIter) + { + Reference 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; + _rPasteData[DataAccessDescriptorProperty::Component] >>= xContent; + return insertHierarchyElement(_eType,_sParentFolder,Reference(xContent,UNO_QUERY).is(),xContent,_bMove); + } + } + catch(const SQLException&) { showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return false; +} + +Reference OApplicationController::getQueryDefinitions() const +{ + Reference xSet(m_xDataSource,UNO_QUERY); + Reference xNames; + if ( xSet.is() ) + { + xNames.set(xSet->getQueryDefinitions(),UNO_QUERY); + } + return xNames; +} + +void OApplicationController::getSupportedFormats(ElementType _eType,std::vector& _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; + 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 0000000000..8712f63868 --- /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 +#include +#include +#include +#include +#include +#include +#include "subcomponentmanager.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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(evt.Source,UNO_QUERY); + if ( xChild.is() ) + { + Reference 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 ? ElementOpenMode::Design : ElementOpenMode::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 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, bool _bMove) +{ + Reference 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(this)->getElements(eType); + bEnabled = (xContainer.is() && xContainer->hasByName(*aList.begin())); + if ( bEnabled ) + bEnabled = Reference(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 OUString s_sStatusbar = u"private:resource/statusbar/statusbar"_ustr; + _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 && ElementOpenMode::Mail == _eOpenMode ) + { + aArguments.put("Hidden",true); + eOpenMode = ElementOpenMode::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 != ElementOpenMode::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(_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 0000000000..c4adb2f459 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AppView.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "AppController.hxx" + +#include + +#include + +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& 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 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(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(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 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 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(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(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 OAppDetailPageHelper::getEntry( const Point& _aPosPixel) const +{ + std::unique_ptr 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(m_aLists[E_TABLE]->getListBox()).UpdateTableList(_xConnection); + + std::unique_ptr 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."); + + OUString 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 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 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 OAppDetailPageHelper::createSimpleTree(const OUString& rHelpId, ElementType eType) +{ + const bool bSQLType = eType == E_TABLE || eType == E_QUERY; + std::unique_ptr 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(pTreeView->getListBox()).removedTable(rOldName); + static_cast(pTreeView->getListBox()).addedTable(rNewName); + break; + case E_QUERY: + { + std::unique_ptr 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 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 OAppDetailPageHelper::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject ) +{ + std::unique_ptr xRet; + DBTreeViewBase* pTreeView = _eType != E_NONE ? m_aLists[_eType].get() : nullptr; + if (!pTreeView) + return xRet; + weld::TreeView& rTreeView = pTreeView->GetWidget(); + rTreeView.make_unsorted(); + if (_eType == E_TABLE) + { + xRet = static_cast(pTreeView->getListBox()).addedTable( _rName ); + } + else + { + std::unique_ptr xEntry; + Reference xChild(_rObject,UNO_QUERY); + if ( xChild.is() && E_QUERY != _eType ) + { + Reference xContent(xChild->getParent(),UNO_QUERY); + if ( xContent.is() ) + { + OUString sName = xContent->getIdentifier()->getContentIdentifier(); + std::unique_ptr 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 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(pTreeView->getListBox()).removedTable(_rName); + break; + case E_QUERY: + { + std::unique_ptr 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 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 != PreviewMode::NONE; +} + +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(m_ePreviewMode)); + + OUString aCommand; + switch ( m_ePreviewMode ) + { + case PreviewMode::NONE: + aCommand = ".uno:DBDisablePreview"; + break; + case PreviewMode::Document: + aCommand = ".uno:DBShowDocPreview"; + break; + case PreviewMode::DocumentInfo: + if ( getBorderWin().getView()->getAppController().isCommandEnabled(SID_DB_APP_VIEW_DOCINFO_PREVIEW) ) + aCommand = ".uno:DBShowDocInfoPreview"; + else + { + m_ePreviewMode = PreviewMode::NONE; + 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 xContent(_xContent,UNO_QUERY); + if ( xContent.is() ) + { + css::ucb::Command aCommand; + if ( m_ePreviewMode == PreviewMode::Document ) + aCommand.Name = "preview"; + else + aCommand.Name = "getDocumentInfo"; + + Any aPreview = xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >()); + if ( m_ePreviewMode == PreviewMode::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 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 xSup(getBorderWin().getView()->getAppController().getXController()->getFrame(),UNO_QUERY); + if ( xSup.is() ) + { + Reference xFrames = xSup->getFrames(); + xFrames->append( Reference(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(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 + { + 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); + } + } + + 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 xContext(getBorderWin().getView()->getORB()); + css::uno::Reference xPopupMenuFactory(css::frame::thePopupMenuControllerFactory::get(xContext)); + if (!xPopupMenuFactory.is()) + return; + + auto xFrame = getBorderWin().getView()->getAppController().getFrame(); + + css::uno::Sequence 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 xPopupController + (xPopupMenuFactory->createInstanceWithArgumentsAndContext(".uno:DBPreview", aArgs, xContext), css::uno::UNO_QUERY); + + if (!xPopupController.is()) + return; + + css::uno::Reference xPopupMenu(css::awt::PopupMenu::create(xContext)); + xPopupController->setPopupMenu(xPopupMenu); + + css::util::URL aTargetURL; + Reference xDispatchProvider(xFrame, css::uno::UNO_QUERY); + + css::uno::Reference 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 xComponent(xPopupController, css::uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); +} + +IMPL_LINK(OAppDetailPageHelper, MenuSelectHdl, const OUString&, rIdent, void) +{ + if (rIdent.isEmpty()) + return; + + css::util::URL aURL; + aURL.Complete = rIdent; + + Reference xProvider(getBorderWin().getView()->getAppController().getFrame(), UNO_QUERY); + Reference xDisp = xProvider->queryDispatch(aURL, "_self", 0); + xDisp->dispatch(aURL, css::uno::Sequence()); + + 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(aNewSize.Width()) / aNewSize.Height(); + const double fWinWH = static_cast(aWinSize.Width()) / aWinSize.Height(); + + if ( fGrfWH < fWinWH ) + { + aNewSize.setWidth( static_cast( aWinSize.Height() * fGrfWH ) ); + aNewSize.setHeight( aWinSize.Height() ); + } + else + { + aNewSize.setWidth( aWinSize.Width() ); + aNewSize.setHeight( static_cast( 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 0000000000..fb47cb70c5 --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 + 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 m_aLists[size_t(E_ELEMENT_TYPE_COUNT)]; + OAppBorderWindow& m_rBorderWin; + std::unique_ptr m_xBox; + std::unique_ptr m_xFL; + std::unique_ptr m_xMBPreview; + + std::unique_ptr m_xPreview; + std::unique_ptr m_xPreviewWin; + + std::unique_ptr m_xDocumentInfo; + std::unique_ptr m_xDocumentInfoWin; + + std::unique_ptr 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 createSimpleTree(const OUString& 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 OUString&, 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(eType)].get() : nullptr; + } + + /// select all entries in the visible control + void selectAll(); + + /// returns 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 , 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 + if the entry is a leaf, otherwise + */ + static bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry); + + /** returns if one of the selected entries is a leaf + @return + if the entry is a leaf, otherwise + */ + bool isALeafSelected() const; + + std::unique_ptr getEntry(const Point& rPosPixel) const; + + /// clears the detail pages + void clearPages(); + + /// returns 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 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;} + + /// 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 + if it is a table, otherwise + @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 0000000000..63a9f7f39f --- /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 +#include +#include +#include "AppView.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "AppDetailPageHelper.hxx" +#include +#include +#include +#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(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(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(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(m_xTitleContainer->getChildContainer(), m_rBorderWin, ePreviewMode); + m_xTitleContainer->setChildWindow(m_xControlHelper); + + std::shared_ptr xTasks = std::make_shared(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 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 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(m_xControlHelper.get()); +} + +const OAppDetailPageHelper* OApplicationDetailView::GetControlHelper() const +{ + return static_cast(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 0000000000..f074df4401 --- /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 +#include +#include +#include +#include +#include +#include "AppTitleWindow.hxx" +#include + +#include + +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 m_xTreeView; + std::unique_ptr m_xDescription; + std::unique_ptr 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 m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr m_xHorzSplitter; + std::unique_ptr m_xTasksParent; + std::unique_ptr m_xContainerParent; + std::unique_ptr m_xTasks; + std::unique_ptr m_xTitleContainer; + OAppBorderWindow& m_rBorderWin; // my parent + std::shared_ptr 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 , 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 + if the entry is a leaf, otherwise + */ + static bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry); + + /** returns if one of the selected entries is a leaf + @return + if the entry is a leaf, otherwise + */ + bool isALeafSelected() const; + + /** select all entries in the detail page + */ + void selectAll(); + + /// returns 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 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 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 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; + + /// 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 + if it is a table, otherwise + @return void + */ + void showPreview( const OUString& _sDataSourceName, + const OUString& _sName, + bool _bTable); + + std::unique_ptr 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 0000000000..bd94d52c56 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 constexpr struct CategoryDescriptor + { + TranslateId pLabelResId; + ElementType eType; + OUString 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 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(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(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(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 0000000000..1146a77a1f --- /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 +#include +#include +#include + +class MnemonicGenerator; + +namespace dbaui +{ + class IControlActionListener; + class IconControl; + class OApplicationIconControlDropTarget; + + class OApplicationIconControl final : public ThumbnailView + { + std::unique_ptr 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 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 0000000000..ea2066c729 --- /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 +#include "AppView.hxx" +#include +#include +#include +#include +#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(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 0000000000..1ce972e3b0 --- /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 +#include "AppIconControl.hxx" +#include +#include + +struct ImplSVEvent; +class MnemonicGenerator; + +namespace dbaui +{ + class OAppBorderWindow; + class OApplicationSwapWindow : public OChildWindow + , public IClipboardTest + { + std::unique_ptr m_xIconControl; + std::unique_ptr 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 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 0000000000..d5e604394b --- /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 +#include +#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& 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 0000000000..d57f524165 --- /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 +#include + +namespace dbaui +{ + class OTitleWindow final + { + std::unique_ptr m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr m_xTitleFrame; + std::unique_ptr m_xTitle; + std::unique_ptr m_xChildContainer; + std::shared_ptr 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& 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 0000000000..e6536beecf --- /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 +#include +#include +#include +#include +#include +#include "AppDetailView.hxx" +#include "AppSwapWindow.hxx" +#include +#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 xSwap = std::make_shared(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(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::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 NotifyEventType::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& 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 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 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; + if ( _bTable ) + { + Reference xSup(_xConnection,UNO_QUERY); + if ( xSup.is() ) + xNameAccess = xSup->getTables(); + } + else + { + Reference 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 0000000000..59a6d477a3 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 m_xPanelParent; + std::unique_ptr m_xDetailViewParent; + std::unique_ptr m_xPanel; + std::unique_ptr m_xDetailView; + VclPtr 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 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 , 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 + if the entry is a leaf, otherwise + */ + bool isLeaf(const weld::TreeView& rTreeView, const weld::TreeIter& rEntry) const; + + /** returns if one of the selected entries is a leaf + @return + if the entry is a leaf, otherwise + */ + bool isALeafSelected() const; + + /** select all entries in the detail page + */ + void selectAll(); + + /// returns 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 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 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; + + /// 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 + if it is a table, otherwise + @return void + */ + void showPreview( const OUString& _sDataSourceName, + const css::uno::Reference< css::sdbc::XConnection>& _xConnection, + const OUString& _sName, + bool _bTable); + + std::unique_ptr 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 0000000000..2f27ccb30b --- /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 +#include + +namespace dbaui +{ +OChildWindow::OChildWindow(weld::Container* pParent, const OUString& rUIXMLDescription, + const OUString& 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 0000000000..cfa79be20c --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "DocumentInfoPreview.hxx" +#include +#include +#include +#include +#include +#include + +#include +#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 0000000000..0c9548d0a7 --- /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 + +#include + +#include + +namespace com :: sun :: star :: uno { template 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 0000000000..712996e093 --- /dev/null +++ b/dbaccess/source/ui/app/subcomponentmanager.cxx @@ -0,0 +1,552 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +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 + Reference< XFrame > xFrame; + /// the controller of the sub component. Must not be + Reference< XController > xController; + /// the model of the sub component. Might be + 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( ElementOpenMode::Normal ) + { + } + + SubComponentDescriptor( OUString i_sName, const sal_Int32 i_nComponentType, + const ElementOpenMode i_eOpenMode, const Reference< XComponent >& i_rComponent ) + :sName(std::move( i_sName )) + ,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( OUString i_sName, const sal_Int32 i_nComponentType, + const ElementOpenMode i_eOpenMode ) + :m_sName(std::move( i_sName )) + ,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, ::comphelper::SharedMutex _aMutex ) + :m_rController( _rController ) + ,m_aMutex(std::move( _aMutex )) + { + } + + 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 0000000000..402a3d593b --- /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 + +#include +#include + +#include +#include + +#include + +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 + 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 + 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 + 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 0000000000..224d8be0ae --- /dev/null +++ b/dbaccess/source/ui/app/templwin.cxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include "templwin.hxx" + +namespace SvtDocInfoTable_Impl +{ + OUString GetString(int nId) + { + auto const found = std::find_if(std::begin(STRARY_SVT_DOCINFO), std::end(STRARY_SVT_DOCINFO) + , [nId](auto const & docinfo){ return docinfo.second == nId; }); + return (found != std::end(STRARY_SVT_DOCINFO)) ? DBA_RES(found->first) : 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 0000000000..8978a6ea3e --- /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 + +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 0000000000..abb15f00b0 --- /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 0000000000..538ea702c4 --- /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 +#include + +// OAsynchronousLink +using namespace dbaui; +OAsynchronousLink::OAsynchronousLink(const Link& _rHandler) + : m_aHandler(_rHandler) + , m_nEventId(nullptr) +{ +} + +OAsynchronousLink::~OAsynchronousLink() +{ + { + std::unique_lock aEventGuard(m_aEventSafety); + if (m_nEventId) + Application::RemoveUserEvent(m_nEventId); + m_nEventId = nullptr; + } + + { + std::unique_lock 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) +{ + std::unique_lock aEventGuard(m_aEventSafety); + if (m_nEventId) + Application::RemoveUserEvent(m_nEventId); + m_nEventId = Application::PostUserEvent(LINK(this, OAsynchronousLink, OnAsyncCall), _pArgument); +} + +void OAsynchronousLink::CancelCall() +{ + std::unique_lock aEventGuard(m_aEventSafety); + if (m_nEventId) + Application::RemoveUserEvent(m_nEventId); + m_nEventId = nullptr; +} + +IMPL_LINK(OAsynchronousLink, OnAsyncCall, void*, _pArg, void) +{ + { + std::unique_lock aDestructionGuard(m_aDestructionSafety); + { + std::unique_lock 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 0000000000..ef78325898 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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(); +} + +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::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::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(_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 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::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(this)); + xFormSet->addPropertyChangeListener(PROPERTY_ISMODIFIED, static_cast(this)); + xFormSet->addPropertyChangeListener(PROPERTY_ROWCOUNT, static_cast(this)); + xFormSet->addPropertyChangeListener(PROPERTY_ACTIVECOMMAND, static_cast(this)); + xFormSet->addPropertyChangeListener(PROPERTY_ORDER, static_cast(this)); + xFormSet->addPropertyChangeListener(PROPERTY_FILTER, static_cast(this)); + xFormSet->addPropertyChangeListener(PROPERTY_HAVING_CLAUSE, static_cast(this)); + xFormSet->addPropertyChangeListener(PROPERTY_APPLYFILTER, static_cast(this)); + } + Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY); + if (xFormError.is()) + xFormError->addSQLErrorListener(static_cast(this)); + + if (m_xLoadable.is()) + m_xLoadable->addLoadListener(this); + + Reference< css::form::XDatabaseParameterBroadcaster > xFormParameter(getRowSet(), UNO_QUERY); + if (xFormParameter.is()) + xFormParameter->addParameterListener(static_cast(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(this)); + + Reference< css::form::XReset > xReset(_xGridControlModel, UNO_QUERY); + if (xReset.is()) + xReset->addResetListener(static_cast(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(this)); + + // introduce ourself as dispatch provider for the grid + Reference< XDispatchProviderInterception > xInterception(getBrowserView()->getGridControl(), UNO_QUERY); + if (xInterception.is()) + xInterception->registerDispatchProviderInterceptor(static_cast(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(this)); + + Reference< XDispatchProviderInterception > xInterception(_xGridControl, UNO_QUERY); + if (xInterception.is()) + xInterception->releaseDispatchProviderInterceptor(static_cast(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(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_ISMODIFIED, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_ROWCOUNT, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_ACTIVECOMMAND, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_ORDER, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_FILTER, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_HAVING_CLAUSE, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_APPLYFILTER, static_cast(this)); + } + + Reference< css::sdb::XSQLErrorBroadcaster > xFormError(Source.Source, UNO_QUERY); + if (xFormError.is()) + xFormError->removeSQLErrorListener(static_cast(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(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(static_cast(m_xFormControllerImpl.get()), UNO_QUERY) != Source.Source ) + { + Reference< XEventListener > xAggListener; + m_xFormControllerImpl->queryAggregation( cppu::UnoType::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(this)); + xFormSet->removePropertyChangeListener(PROPERTY_ISMODIFIED, static_cast(this)); + xFormSet->removePropertyChangeListener(PROPERTY_ROWCOUNT, static_cast(this)); + xFormSet->removePropertyChangeListener(PROPERTY_ACTIVECOMMAND, static_cast(this)); + xFormSet->removePropertyChangeListener(PROPERTY_ORDER, static_cast(this)); + xFormSet->removePropertyChangeListener(PROPERTY_FILTER, static_cast(this)); + xFormSet->removePropertyChangeListener(PROPERTY_HAVING_CLAUSE, static_cast(this)); + xFormSet->removePropertyChangeListener(PROPERTY_APPLYFILTER, static_cast(this)); + } + + Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY); + if (xFormError.is()) + xFormError->removeSQLErrorListener(static_cast(this)); + + if (m_xLoadable.is()) + m_xLoadable->removeLoadListener(this); + + Reference< css::form::XDatabaseParameterBroadcaster > xFormParameter(getRowSet(), UNO_QUERY); + if (xFormParameter.is()) + xFormParameter->removeParameterListener(static_cast(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 pParamValues = new OParameterContinuation; + rtl::Reference pAbort = new OInteractionAbort; + // the request + ParametersRequest aRequest; + aRequest.Parameters = xParameters; + aRequest.Connection = getConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY)); + rtl::Reference 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 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 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(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 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()); + + 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(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 xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/savemodifieddialog.ui")); + std::unique_ptr xQry(xBuilder->weld_message_dialog("SaveModifiedDialog")); + switch (xQry->run()) + { + case RET_NO: + Execute(ID_BROWSER_UNDORECORD,Sequence()); + 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; nViewPosgetCount(); ++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(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 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(this)); +} + +void SbaXDataBrowserController::AfterDrop() +{ + Reference< css::sdb::XSQLErrorBroadcaster > xFormError(getRowSet(), UNO_QUERY); + if (xFormError.is()) + xFormError->addSQLErrorListener(static_cast(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 0000000000..3bfb7eac9a --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(xGrid->getModel(),UNO_QUERY); + Reference 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 = dynamic_cast(xPeer.get()); + UnoDataBrowserView* pTHIS = const_cast(this); + if ( pPeer ) + { + m_pVclControl = static_cast(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() == NotifyEventType::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 0000000000..383a2c3f0a --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 NotifyEventType::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 NotifyEventType::KEYUP: + case NotifyEventType::MOUSEBUTTONDOWN: + case NotifyEventType::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 0000000000..dc6398f48a --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 void lcl_setListener(const Reference& _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; + 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& 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(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( 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 0000000000..0eeba92634 --- /dev/null +++ b/dbaccess/source/ui/browser/dbloader.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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 + { + OUString 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 ) ); + utl::ConnectModelController(xReportModel, 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 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 0000000000..88a9faeb0e --- /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 0000000000..53a34a8e42 --- /dev/null +++ b/dbaccess/source/ui/browser/dbtreemodel.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 +#include + +// 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 + +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 0000000000..b31261df1b --- /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 + +#include + +#include +#include +#include +#include +#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(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 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 0000000000..e84b391607 --- /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 +#include +#include "dbtreemodel.hxx" +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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 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(xConnection,UNO_QUERY); + Reference 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 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(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 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 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 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(rTreeView.get_id(rEntryLoop)); + if (pData) + { + rTreeView.set_id(rEntryLoop, OUString()); + Reference 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 0000000000..a34e67a241 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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(this), + static_cast(this)); + + return aRet; +} + +SbaExternalSourceBrowser::SbaExternalSourceBrowser(const Reference< css::uno::XComponentContext >& _rM) + :SbaXDataBrowserController(_rM) + ,m_aModifyListeners(getMutex()) + ,m_bInQueryDispatch( false ) +{ + +} + +SbaExternalSourceBrowser::~SbaExternalSourceBrowser() +{ +} + +css::uno::Sequence 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(rArgument.Value); + OSL_ENSURE(s, "invalid type for argument \"ColumnType\" !"); + if (s) + sControlType = *s; + } + else if ( rArgument.Name == "ColumnPosition" ) + { + auto n = o3tl::tryAccess(rArgument.Value); + OSL_ENSURE(n, "invalid type for argument \"ColumnPosition\" !"); + if (n) + nControlPos = *n; + } + else if ( rArgument.Name == "ColumnProperties" ) + { + auto s = o3tl::tryAccess>( + 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(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(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(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(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 0000000000..24791b44ff --- /dev/null +++ b/dbaccess/source/ui/browser/formadapter.cxx @@ -0,0 +1,1879 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(); +} + +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(static_cast(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{""}, &m_aPropertiesChangeListeners); + } + + // log off ourself + Reference< css::lang::XComponent > xComp(m_xMainForm, UNO_QUERY); + if (xComp.is()) + xComp->addEventListener(static_cast(static_cast(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 (); +} + +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_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(); +} + +// 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(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(); + m_xMainForm.clear(); + m_xParent.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 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*/, 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(this)); + + // we are now the parent of the new element + xElement->setParent(static_cast(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::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(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(this)); + xElementSet->addPropertyChangeListener(PROPERTY_NAME, static_cast(this)); + + // parent reset + xOld->setParent(Reference< XInterface > ()); + xElement->setParent(static_cast(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 0000000000..0d998d4ca1 --- /dev/null +++ b/dbaccess/source/ui/browser/genericcontroller.cxx @@ -0,0 +1,1176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +{ + +void OGenericUnoController::executeUserDefinedFeatures( const URL& _rFeatureURL, const Sequence< PropertyValue>& _rArgs ) +{ + try + { + Reference< XController > xController( getXController(), 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 +OGenericUnoController::OGenericUnoController(const Reference< XComponentContext >& _rM) + :OGenericUnoController_Base( getMutex() ) + ,m_aUserInputInterception(*this, 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) +{ + + 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 xParent = xFrame->getContainerWindow(); + VclPtr 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 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 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.has_value() ) + _out_rStates.push_back( Any( *_rFeatureState.bChecked ) ); + if ( _rFeatureState.bInvisible.has_value() ) + _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(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 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; + { + std::unique_lock 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 ); + } + + std::unique_lock 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; + { + std::unique_lock 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 ); + + { + std::unique_lock 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()) + { + std::erase_if(m_arrStatusListener, [&aListener](const DispatchTarget& rCurrent) { return rCurrent.xListener == aListener; }); + } + 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 + std::unique_lock aGuard( m_aFeatureMutex ); + std::erase_if( m_aFeaturesToInvalidate, FindFeatureListener(aListener)); +} + +void OGenericUnoController::releaseNumberForComponent() +{ + try + { + Reference< XUntitledNumbers > xUntitledProvider(getPrivateModel(), UNO_QUERY ); + if ( xUntitledProvider.is() ) + xUntitledProvider->releaseNumberForComponent(static_cast(this)); + } + catch( const Exception& ) + { + // NII + } +} + +void OGenericUnoController::disposing() +{ + { + EventObject aDisposeEvent; + aDisposeEvent.Source = static_cast(this); + Dispatch aStatusListener = m_arrStatusListener; + for (auto const& statusListener : aStatusListener) + { + statusListener.xListener->disposing(aDisposeEvent); + } + m_arrStatusListener.clear(); + } + + m_xDatabaseContext = nullptr; + { + std::unique_lock 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 + executeUserDefinedFeatures( 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(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(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 = aConnector.connect( _rDataSourceName, _pErrorInfo ); + startConnectionListening( xConnection ); + + return xConnection; +} + +void OGenericUnoController::setView( const VclPtr &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_aUserInputInterception.addKeyHandler( _rxHandler ); +} + +void SAL_CALL OGenericUnoController::removeKeyHandler( const Reference< XKeyHandler >& _rxHandler ) +{ + m_aUserInputInterception.removeKeyHandler( _rxHandler ); +} + +void SAL_CALL OGenericUnoController::addMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler ) +{ + if ( _rxHandler.is() ) + m_aUserInputInterception.addMouseClickHandler( _rxHandler ); +} + +void SAL_CALL OGenericUnoController::removeMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler ) +{ + 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_aUserInputInterception.handleNotifyEvent( _rEvent ); +} + +bool OGenericUnoController::isCommandChecked(sal_uInt16 _nCommandId) const +{ + FeatureState aState = GetState( _nCommandId ); + + return aState.bChecked.has_value() && *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(); + m_xUrlTransformer.clear(); + m_xSlaveDispatcher.clear(); + m_xMasterDispatcher.clear(); + m_xDatabaseContext.clear(); + m_xTitleHelper.clear(); +} + +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 0000000000..bec17b4095 --- /dev/null +++ b/dbaccess/source/ui/browser/sbagrid.cxx @@ -0,0 +1,1367 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 const& ) +{ + return cppu::acquire(new SbaXGridControl(context)); +} + +css::uno::Sequence 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 SbaXGridControl::imp_CreatePeer(vcl::Window* pParent) +{ + rtl::Reference 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::queryAggregation(const Type& _rType) +{ + Any aRet = FmXGridControl::queryAggregation(_rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface(_rType,static_cast(this)); +} + +Sequence< Type > SAL_CALL SbaXGridControl::getTypes( ) +{ + return comphelper::concatSequences( + FmXGridControl::getTypes(), + Sequence { cppu::UnoType::get() }); +} + +Sequence< sal_Int8 > SAL_CALL SbaXGridControl::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +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& 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& 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) +{ +} + +SbaXGridPeer::~SbaXGridPeer() +{ +} + +void SAL_CALL SbaXGridPeer::dispose() +{ + { + std::unique_lock g(m_aMutex); + EventObject aEvt(*this); + m_aStatusListeners.disposeAndClear(g, 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 + { + std::unique_lock g(m_aMutex); + ::comphelper::OInterfaceContainerHelper4 * pIter + = m_aStatusListeners.getContainer(g, _rUrl); + + if (pIter) + { + pIter->notifyEach( g, &XStatusListener::statusChanged, aEvt ); + } + } +} + +Any SAL_CALL SbaXGridPeer::queryInterface(const Type& _rType) +{ + Any aRet = ::cppu::queryInterface(_rType,static_cast(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(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) +{ + { + std::unique_lock g(m_aMutex); + ::comphelper::OInterfaceContainerHelper4< css::frame::XStatusListener >* pCont + = m_aStatusListeners.getContainer(g, aURL); + if (!pCont) + m_aStatusListeners.addInterface(g, aURL,xControl); + else + pCont->addInterface(g, xControl); + } + NotifyStatusChanged(aURL, xControl); +} + +void SAL_CALL SbaXGridPeer::removeStatusListener(const Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) +{ + std::unique_lock g(m_aMutex); + ::comphelper::OInterfaceContainerHelper4< css::frame::XStatusListener >* pCont = m_aStatusListeners.getContainer(g, aURL); + if ( pCont ) + pCont->removeInterface(g, xControl); +} + +Sequence< Type > SAL_CALL SbaXGridPeer::getTypes() +{ + return comphelper::concatSequences( + FmXGridPeer::getTypes(), + Sequence { cppu::UnoType::get() }); +} + +VclPtr SbaXGridPeer::imp_CreateControl(vcl::Window* pParent, WinBits nStyle) +{ + return VclPtr::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(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(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(GetParent())->GetModelColumnPos(nColId); + Reference< XPropertySet > xField = static_cast(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 OUString& rExecutionResult) +{ + if (rExecutionResult == "colwidth") + static_cast(GetParent())->SetColWidth(nColId); + else if (rExecutionResult == "colattrset") + static_cast(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 SbaGridControl::imp_CreateHeaderBar(BrowseBox* pParent) +{ + return VclPtr::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( 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 aArguments{ + Any(comphelper::makePropertyValue("IntrospectedObject", xGridModel)), + Any(comphelper::makePropertyValue("ParentWindow", VCLUnoHelper::GetInterface(this))) + }; + Reference 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 OUString& 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(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(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 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(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(nRowPos + 1)) }; + bSelectionBookmarks = false; + } + else if ( !IsAllSelected() && GetSelectRowCount() ) + { + aSelectedRows = getSelectionBookmarks(); + bSelectionBookmarks = true; + } + + try + { + rtl::Reference 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 aSupportingText = xFieldData->queryFieldDataType(cppu::UnoType::get()); + if (aSupportingText.getConstArray()[nColumnPos]) + { + Sequence< Any> aCellContents = xFieldData->queryFieldData(nRowPos, cppu::UnoType::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(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 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 0000000000..8bf7ed747c --- /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 +#include + +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* 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* pListeners = m_aListeners.getContainer(s); + if (!pListeners) + continue; + nLen += pListeners->getLength(); + } + return nLen; +} + +void SbaXPropertyChangeMultiplexer::Notify(::comphelper::OInterfaceContainerHelper3& 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* 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* pListeners = m_aListeners.getContainer(s); + if (!pListeners) + continue; + nLen += pListeners->getLength(); + } + return nLen; +} + +void SbaXVetoableChangeMultiplexer::Notify(::comphelper::OInterfaceContainerHelper3& 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 0000000000..7235ac3c69 --- /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 +#include +#include +#include +#include "dbtreemodel.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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 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::get() ) ) + { + OSL_PRECOND( m_aDocScriptSupport.has_value(), "SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" ); + if ( m_aDocScriptSupport.has_value() && *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.has_value(), "SbaTableQueryBrowser::getTypes: did not initialize this, yet!" ); + if ( !m_aDocScriptSupport.has_value() || !*m_aDocScriptSupport ) + { + auto [begin, end] = asNonConstRange(aTypes); + auto newEnd = std::remove_if( begin, end, + [](const Type& type) + { return type == cppu::UnoType::get(); } ); + aTypes.realloc( std::distance(begin, newEnd) ); + } + return aTypes; +} + +Sequence< sal_Int8 > SAL_CALL SbaTableQueryBrowser::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +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(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::Create(getBrowserView(),WB_HSCROLL); + m_pSplitter->SetPosSizePixel( ::Point(0,0), ::Size(nFrameWidth,0) ); + m_pSplitter->SetBackground( Wallpaper( Application::GetSettings().GetStyleSettings().GetDialogColor() ) ); + + m_pTreeView = VclPtr::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 WHERE . = ", it will return "". But + // there's no API at all to retrieve the information about "" - 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(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[] = + { + PROPERTY_APPLYFILTER, + PROPERTY_FILTER, + PROPERTY_HAVING_CLAUSE, + 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(6 + ( m_bPreview ? 5 : 0 )); + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pData = weld::fromId(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; + Reference xRowSetProps(getRowSet(),UNO_QUERY); + xRowSetProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection; + OSL_ENSURE(xConnection.is(),"A ActiveConnection should normally exists!"); + + Reference xChild(xConnection,UNO_QUERY); + Reference 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 xSupCols(getRowSet(),UNO_QUERY); + Reference xColumns = xSupCols->getColumns(); + + OUString sDefaultProperty; + Reference< XPropertySet > xColumn; + Reference< XPropertySetInfo > xColPSI; + const Sequence 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 getColumnHelper(const weld::TreeView& rTreeView, + const weld::TreeIter* pCurrentlyDisplayed, + const Reference& rxSource) +{ + Reference xRet; + if (pCurrentlyDisplayed) + { + DBTreeListUserData* pData = weld::fromId(rTreeView.get_id(*pCurrentlyDisplayed)); + Reference xColumnsSup(pData->xObjectProperties,UNO_QUERY); + Reference 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(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 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 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 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 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(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 xDataSourceEntry; + std::unique_ptr xContainerEntry; + std::unique_ptr xObjectEntry = getObjectEntry(m_aDocumentDataSource, &xDataSourceEntry, &xContainerEntry); + bool bKnownDocDataSource = static_cast(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( OUString _aId ) : sId(std::move( _aId )) { } + + virtual ~FilterByEntryDataId() {} + + virtual bool includeEntry(const void* pEntry) const override; + }; + + bool FilterByEntryDataId::includeEntry(const void* pUserData) const + { + const DBTreeListUserData* pData = static_cast(pUserData); + return ( !pData || ( pData->sAccessor == sId ) ); + } +} + +OUString SbaTableQueryBrowser::getDataSourceAccessor(const weld::TreeIter& rDataSourceEntry) const +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pData = weld::fromId(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 SbaTableQueryBrowser::getObjectEntry(const OUString& _rDataSource, const OUString& _rCommand, sal_Int32 nCommandType, + std::unique_ptr* ppDataSourceEntry, std::unique_ptr* ppContainerEntry, bool bExpandAncestors, + const SharedConnection& _rxConnection ) +{ + if (ppDataSourceEntry) + ppDataSourceEntry->reset(); + if (ppContainerEntry) + ppContainerEntry->reset(); + + std::unique_ptr 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 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 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(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 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 SbaTableQueryBrowser::getObjectEntry(const svx::ODataAccessDescriptor& rDescriptor, + std::unique_ptr* ppDataSourceEntry, std::unique_ptr* 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 < std::size( pURLs ); ++i ) + { + URL aURL; + aURL.Complete = OUString::createFromAscii( pURLs[i] ); + if ( m_xUrlTransformer.is() ) + m_xUrlTransformer->parseStrict( aURL ); + m_aExternalFeatures[ nIds[ i ] ] = ExternalFeature( std::move(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 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(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 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 xDSLoop(rTreeView.make_iterator()); + if (rTreeView.get_iter_first(*xDSLoop)) + { + do + { + DBTreeListUserData* pData = weld::fromId(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(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(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(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_FONT, static_cast(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast(this)); + xSourceSet->addPropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast(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(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_FONT, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_TEXTCOLOR, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_TEXTLINECOLOR, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_TEXTEMPHASIS, static_cast(this)); + xSourceSet->removePropertyChangeListener(PROPERTY_TEXTRELIEF, static_cast(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(this)); + SafeAddPropertyListener(xCol, PROPERTY_HIDDEN, static_cast(this)); + SafeAddPropertyListener(xCol, PROPERTY_ALIGN, static_cast(this)); + SafeAddPropertyListener(xCol, PROPERTY_FORMATKEY, static_cast(this)); +} + +void SbaTableQueryBrowser::RemoveColumnListener(const Reference< XPropertySet > & xCol) +{ + SbaXDataBrowserController::RemoveColumnListener(xCol); + SafeRemovePropertyListener(xCol, PROPERTY_WIDTH, static_cast(this)); + SafeRemovePropertyListener(xCol, PROPERTY_HIDDEN, static_cast(this)); + SafeRemovePropertyListener(xCol, PROPERTY_ALIGN, static_cast(this)); + SafeRemovePropertyListener(xCol, PROPERTY_FORMATKEY, static_cast(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 xCurrentEntry(rTreeView.make_iterator()); + if (!rTreeView.get_cursor(xCurrentEntry.get())) + return aReturn; + + EntryType eType = getEntryType(*xCurrentEntry); + if ( eType == etUnknown ) + return aReturn; + + std::unique_ptr xDataSourceEntry = m_pTreeView->GetRootLevelParent(xCurrentEntry.get()); + DBTreeListUserData* pDSData + = xDataSourceEntry + ? weld::fromId(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 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 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 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 xSelected = m_xCurrentlyDisplayed ? + rTreeView.make_iterator(m_xCurrentlyDisplayed.get()) : nullptr; + + // unload + unloadAndCleanup( false ); + + // reselect the entry + if ( xSelected ) + { + implSelect(xSelected.get()); + } + else + { + Reference 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(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(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 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 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 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 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 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 aDatasourceNames = m_xDatabaseContext->getElementNames(); + for (const OUString& rDatasource : aDatasourceNames) + implAddDatasource( rDatasource, aDBImage, sQueriesName, aQueriesImage, sTablesName, aTablesImage, SharedConnection() ); + } +} + +void SbaTableQueryBrowser::populateTree(const Reference& _xNameAccess, + const weld::TreeIter& rParent, + EntryType eEntryType) +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + rTreeView.make_unsorted(); + + DBTreeListUserData* pData = weld::fromId(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 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 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 SbaTableQueryBrowser::implAppendEntry(const weld::TreeIter* pParent, const OUString& rName, const DBTreeListUserData* pUserData) +{ + EntryType eEntryType = pUserData->eType; + + std::unique_ptr xImageProvider(getImageProviderFor(pParent)); + + OUString aImage = xImageProvider->getImageId(rName, getDatabaseObjectType(eEntryType)); + + OUString sId(weld::toId(pUserData)); + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr 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 xFirstParent = m_pTreeView->GetRootLevelParent(&rParent); + OSL_ENSURE(xFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!"); + + DBTreeListUserData* pData = weld::fromId(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 xViewSup(xConnection,UNO_QUERY); + if(xViewSup.is()) + populateTree( xViewSup->getViews(), rParent, etTableOrView ); + + Reference xTabSup(xConnection,UNO_QUERY); + if(xTabSup.is()) + { + populateTree( xTabSup->getTables(), rParent, etTableOrView ); + Reference 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(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(rTreeView.get_id(rEntry)); + OSL_ENSURE(pEntryData,"ensureEntryObject: user data should already be set!"); + + std::unique_ptr 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 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(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 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 xDataSource; + std::unique_ptr xCommandType; + std::unique_ptr 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 xSelection(rTreeView.make_iterator()); + if (!rTreeView.get_selected(xSelection.get())) + xSelection.reset(); + implSelect(xSelection.get()); +} + +std::unique_ptr SbaTableQueryBrowser::implGetConnectionEntry(const weld::TreeIter& rEntry) const +{ + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr xCurrentEntry(rTreeView.make_iterator(&rEntry)); + DBTreeListUserData* pEntryData = weld::fromId(rTreeView.get_id(*xCurrentEntry)); + while (pEntryData->eType != etDatasource) + { + rTreeView.iter_parent(*xCurrentEntry); + pEntryData = weld::fromId(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(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 xContainer = rTreeView.make_iterator(pEntry); + rTreeView.iter_parent(*xContainer); + DBTreeListUserData* pContainerData = weld::fromId(rTreeView.get_id(*xContainer)); + + // get the entry for the datasource + std::unique_ptr xConnection = implGetConnectionEntry(*xContainer); + DBTreeListUserData* pConData = weld::fromId(rTreeView.get_id(*xConnection)); + + // reinitialize the rowset + // but first check if it is necessary + // get all old properties + Reference xRowSetProps(getRowSet(),UNO_QUERY); + OUString aOldName; + xRowSetProps->getPropertyValue(PROPERTY_COMMAND) >>= aOldName; + sal_Int32 nOldType = 0; + xRowSetProps->getPropertyValue(PROPERTY_COMMAND_TYPE) >>= nOldType; + Reference 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 xTemp = rTreeView.make_iterator(xContainer.get()); + std::unique_ptr xNextTemp = rTreeView.make_iterator(xTemp.get()); + if (rTreeView.iter_parent(*xNextTemp)) + { + while (rTreeView.iter_compare(*xNextTemp, *xConnection) != 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; + switch(nCommandType) + { + case CommandType::TABLE: + { + // only for tables + if ( !pContainerData->xContainer.is() ) + { + Reference 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 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(getView()), sStatus); + + bool bEscapeProcessing = true; + if(xNameAccess.is() && xNameAccess->hasByName(sSimpleName)) + { + DBTreeListUserData* pData = weld::fromId(rTreeView.get_id(*pEntry)); + if ( !pData->xObjectProperties.is() ) + { + Reference 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 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 xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY); + if ( xAnalyzer.is() ) + { + xAnalyzer->setQuery(sSql); + Reference xParSup(xAnalyzer,UNO_QUERY); + if ( xParSup->getParameters()->getCount() > 0 ) + { + OUString sFilter = " WHERE " + xAnalyzer->getFilter(); + OUString sReplace = sSql.replaceFirst(sFilter, ""); + xAnalyzer->setQuery(sReplace); + Reference 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 SbaTableQueryBrowser::getEntryFromContainer(const Reference& rxNameAccess) +{ + std::unique_ptr xContainer; + + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + std::unique_ptr 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(rTreeView.get_id(*xContainer)); + if (pQueriesData && pQueriesData->xContainer == rxNameAccess) + break; + + if (rTreeView.iter_next_sibling(*xContainer)) + { + // 2nd child is tables + DBTreeListUserData* pTablesData = weld::fromId(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 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(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 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 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 xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get()); + + // unload + unloadAndCleanup( false ); // don't dispose the connection + + DBTreeListUserData* pData = weld::fromId(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 xChild(rTreeView.make_iterator(xContainer.get())); + if (rTreeView.get_iter_first(*xChild)) + { + do + { + if (rTreeView.get_text(*xChild) == aName) + { + DBTreeListUserData* pData = weld::fromId(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 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 xTemp = rTreeView.make_iterator(m_xCurrentlyDisplayed.get()); + unloadAndCleanup( false ); // don't dispose the connection + + DBTreeListUserData* pData = weld::fromId(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 xChild(rTreeView.make_iterator(xContainer.get())); + if (rTreeView.get_iter_first(*xChild)) + { + do + { + if (rTreeView.get_text(*xChild) == aName) + { + DBTreeListUserData* pData = weld::fromId(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(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 xRoot = m_pTreeView->GetRootLevelParent(m_xCurrentlyDisplayed.get()); + if (rTreeView.iter_compare(*xRoot, rDSEntry) == 0) + unloadAndCleanup(_bDisposeConnection); + } + + // collapse the query/table container + std::unique_ptr xContainers(rTreeView.make_iterator(&rDSEntry)); + if (rTreeView.iter_children(*xContainers)) + { + do + { + std::unique_ptr 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 xRemove(rTreeView.make_iterator(xElements.get())); + bElements = rTreeView.iter_next_sibling(*xElements); + DBTreeListUserData* pData = weld::fromId(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 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 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 xSup = xFrame->getCreator(); + Reference xCont = xSup.is() ? xSup->getController() : Reference(); + + 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 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 xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry); + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pDSData = + xDSEntry + ? weld::fromId(rTreeView.get_id(*xDSEntry)) + : nullptr; + + return ensureConnection(xDSEntry.get(), pDSData, rConnection); +} + +std::unique_ptr< ImageProvider > SbaTableQueryBrowser::getImageProviderFor(const weld::TreeIter* pAnyEntry) +{ + std::unique_ptr 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 xDSEntry = m_pTreeView->GetRootLevelParent(pAnyEntry); + weld::TreeView& rTreeView = m_pTreeView->GetWidget(); + DBTreeListUserData* pDSData = + xDSEntry + ? weld::fromId(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 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(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(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 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(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 xSelected(rTreeView.make_iterator()); + if (!rTreeView.get_selected(xSelected.get())) + return Any(); + + NamedDatabaseObject aSelectedObject; + DBTreeListUserData* pData = weld::fromId(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 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 xContainer = rTreeView.make_iterator(m_xCurrentlyDisplayed.get()); + if (!rTreeView.iter_parent(*xContainer)) + return OUString(); + // get the entry for the datasource + std::unique_ptr 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 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 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 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(rTreeView.get_id(*xChild)); + rTreeView.set_id(*xChild, OUString()); + delete pData; + } while (rTreeView.iter_next_sibling(*xChild)); + } + + // remove the entry + DBTreeListUserData* pData = weld::fromId(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 0000000000..f9f786f22e --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +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& _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& _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(); + 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 0000000000..3f3553d56e --- /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 +#include +#include + +namespace dbaui { + +OPropColumnEditCtrl::OPropColumnEditCtrl(std::unique_ptr 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 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 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 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 0000000000..f341482ea9 --- /dev/null +++ b/dbaccess/source/ui/control/FieldDescControl.cxx @@ -0,0 +1,1385 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& _pControl, std::unique_ptr& _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 + struct final + { + OWidgetBase * aggregate; + weld::Widget * text; + } const aggregates[] = { + {m_xRequired.get(), m_xRequiredText.get()} + , {m_xNumType.get(), m_xNumTypeText.get()} + , {m_xAutoIncrement.get(), m_xAutoIncrementText.get()} + , {m_xDefault.get(), m_xDefaultText.get()} + , {m_xTextLen.get(), m_xTextLenText.get()} + , {m_xLength.get(), m_xLengthText.get()} + , {m_xScale.get(), m_xScaleText.get()} + , {m_xColumnName.get(), m_xColumnNameText.get()} + , {m_xType.get(), m_xTypeText.get()} + , {m_xAutoIncrementValue.get(), m_xAutoIncrementValueText.get()}}; + + for (auto const & aggregate: aggregates) + { + if (aggregate.text) + aggregate.text->set_sensitive(!bReadOnly); + if (aggregate.aggregate) + aggregate.aggregate->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( 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 <> + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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 OUString& _sHelpId,bool _bAddChangeHandler) +{ + if ( _bAddChangeHandler ) + _pControl->GetComboBox().connect_changed(LINK(this,OFieldDescControl,ChangeHdl)); + + InitializeControl(_pControl->GetWidget(), _sHelpId); +} + +void OFieldDescControl::InitializeControl(weld::Widget* pControl,const OUString& _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(pControl)) + { + int nWidthRequest = Application::GetDefaultDevice()->LogicToPixel(Size(m_nEditWidth, 0), MapMode(MapUnit::MapAppFont)).Width(); + pControl->set_size_request(nWidthRequest, -1); + } +} + +std::unique_ptr OFieldDescControl::CreateNumericControl(const OUString& rId, TranslateId pHelpId, short _nProperty, const OUString& _sHelpId) +{ + auto xControl = std::make_unique( + 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(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(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(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 <> + OUString sValue; + pFieldDescr->GetControlDefault() >>= sValue; + OUString sDef = BoolStringUI(sValue); + + // Make sure that <> 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(m_xTextLen->get_value()) ); + else if (m_xLength) + pFieldDescr->SetPrecision( static_cast(m_xLength->get_value()) ); + if (m_xScale) + pFieldDescr->SetScale( static_cast(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(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos); + return bAllowed; +} + +bool OFieldDescControl::isCutAllowed() +{ + int nStartPos, nEndPos; + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() && + dynamic_cast(*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(*m_pActFocusWindow).cut_clipboard(); +} + +void OFieldDescControl::copy() +{ + if (isCopyAllowed()) // this only checks if the focus window is valid + dynamic_cast(*m_pActFocusWindow).copy_clipboard(); +} + +void OFieldDescControl::paste() +{ + if (m_pActFocusWindow) // this only checks if the focus window is valid + dynamic_cast(*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 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 0000000000..d6e3b3d87f --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +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& 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& 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::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() == NotifyEventType::LOSEFOCUS && !HasChildPathFocus() && !ControlHasFocus()) + PostUserEvent(LINK(this, ORelationControl, AsynchDeactivate), nullptr, true); + else if (rNEvt.GetType() == NotifyEventType::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 ) + { + + OUString 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 xSup(_xDest,UNO_QUERY); + Reference 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::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 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 0000000000..9ac58cfda8 --- /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 + +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(std::u16string_view _sToCheck, + OUString& _rsCorrected) + { + bool bCorrected = false; + if ( m_bCheck ) + { + sal_Int32 nMatch = 0; + for (size_t i = nMatch; i < _sToCheck.size(); ++i) + { + if ( !isCharOk( _sToCheck[i], i == 0, m_sAllowedChars ) ) + { + _rsCorrected += _sToCheck.substr(nMatch, i - nMatch); + bCorrected = true; + nMatch = i + 1; + } + } + _rsCorrected += _sToCheck.substr( 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 0000000000..607c019972 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 &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::Create( &GetDataWindow() ); + m_pCheckCell->EnableTriState(false); + + m_pEdit = VclPtr::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() == NotifyEventType::LOSEFOCUS) + if (!HasChildPathFocus()) + { + if (m_nDeactivateEvent) + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchDeactivate), nullptr, true); + } + if (rNEvt.GetType() == NotifyEventType::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 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 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 0000000000..f9866905c3 --- /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 + +#include +#include +#include + +namespace dbaui +{ + CharSetListBox::CharSetListBox(std::unique_ptr xControl) + : m_xControl(std::move(xControl)) + { + for (auto const& charset : m_aCharSets) + { + m_xControl->append_text(charset.getDisplayName()); + } + } + + void CharSetListBox::SelectEntryByIanaName( std::u16string_view _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, TypedWhichId _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 0000000000..9cccde370f --- /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 + +namespace dbaui +{ + +OConnectionURLEdit::OConnectionURLEdit(std::unique_ptr xEntry, std::unique_ptr 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 0000000000..be900d650f --- /dev/null +++ b/dbaccess/source/ui/control/dbtreelistbox.cxx @@ -0,0 +1,513 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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 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(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 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 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(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( Any _aSelection ) + :m_aSelection(std::move( _aSelection )) + { + } + + 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 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 xMenuController + (xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.framework.ResourceMenuController", aArgs, xContext), css::uno::UNO_QUERY); + + if (!xMenuController.is()) + return false; + + VclPtr 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 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 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 TreeListBox::GetRootLevelParent(const weld::TreeIter* pEntry) const +{ + if (!pEntry) + return nullptr; + std::unique_ptr 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 0000000000..2fb86bdca6 --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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 > xIconList( xImageManager->getImages( 0, aCommandList ) ); + if ( !xIconList.hasElements() ) + break; + + return xIconList[0]; + } + while ( false ); + } + catch ( Exception& ) {} + + return nullptr; + } + } + + // OpenButton + + OpenDocumentButton::OpenDocumentButton(std::unique_ptr 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 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 0000000000..5997e5b80e --- /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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + { + std::unique_lock 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 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); + { + std::unique_lock 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; + { + std::unique_lock 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 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 xBuilder(Application::CreateBuilder(pPopupParent, "vcl/ui/editmenu.ui")); + std::unique_ptr 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); + + OUString 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 0000000000..45050a1967 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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 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 xRootEntry(getAllObjectsEntry()); + std::unique_ptr xRet(m_xTreeView->make_iterator()); + for (auto const& folderName : aFolderNames) + { + std::unique_ptr 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 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 xChildEntry(m_xTreeView->make_iterator(&rEntry)); + std::unique_ptr 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 xChildEntry(m_xTreeView->make_iterator(&rSelected)); + std::unique_ptr 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 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 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 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 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 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 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 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 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 xSchema(m_xTreeView->make_iterator(&rEntry)); + bool bSchema = m_xTreeView->iter_parent(*xSchema); + if (bSchema) + { + std::unique_ptr 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 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 xParent(getAllObjectsEntry()); + std::unique_ptr xCat; + std::unique_ptr 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 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 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 0000000000..00a5fd4079 --- /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 +#include + +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 0000000000..9211e4e389 --- /dev/null +++ b/dbaccess/source/ui/dlg/CollectionView.cxx @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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, + css::uno::Reference< css::uno::XComponentContext > _xContext) + : GenericDialogController(pParent, "dbaccess/ui/collectionviewdialog.ui", "CollectionView") + , m_xContent(_xContent) + , m_xContext(std::move(_xContext)) + , 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 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(m_xContent,UNO_QUERY); + Reference 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 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 aValues(comphelper::InitAnyPropertySequence( + { + {"ResourceName", Any(sSubFolder)}, + {"ResourceType", Any(OUString("folder"))} + })); + InteractiveAugmentedIOException aException(OUString(),Reference(), + InteractionClassification_ERROR, + IOErrorCode_NOT_EXISTING_PATH,aValues); + + Reference xHandler( + InteractionHandler::createWithParent(m_xContext, m_xDialog->GetXWindow())); + rtl::Reference pRequest = new OInteractionRequest(Any(aException)); + + rtl::Reference pApprove = new OInteractionApprove; + pRequest->addContinuation(pApprove); + xHandler->handle(pRequest); + + return; + } + } + } + Reference xNameContainer(m_xContent,UNO_QUERY); + if ( xNameContainer.is() ) + { + if ( xNameContainer->hasByName(sName) ) + { + std::unique_ptr 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 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(m_xContent,UNO_QUERY); + if ( xChild.is() ) + { + Reference 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(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(m_xContent,UNO_QUERY); + bEnable = xChild.is() && Reference(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 aProps { "Title", "IsFolder" }; + auto xDynResultSet = aContent.createDynamicCursor(aProps, ucbhelper::INCLUDE_FOLDERS_ONLY); + if (!xDynResultSet.is()) + return; + + Reference xResultSet = xDynResultSet->getStaticResultSet(); + Reference 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 0000000000..81922a88be --- /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 +#include "dsnItem.hxx" +#include "ConnectionHelper.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dsselect.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "finteraction.hxx" +#include +#include + +#if defined _WIN32 +#include +#include +#include "adodatalinks.hxx" +#endif + +#include +#include +#include + +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 OUString& _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( _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(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 xSysDepWin(pDialog->GetXWindow(), css::uno::UNO_QUERY); + if (xSysDepWin.is()) + { + css::uno::Sequence aProcessIdent(16); + rtl_getGlobalProcessId(reinterpret_cast(aProcessIdent.getArray())); + css::uno::Any aAny = xSysDepWin->getWindowHandle(aProcessIdent, css::lang::SystemDependent::SYSTEM_WIN32); + sal_Int64 tmp(0); + aAny >>= tmp; + hWnd = reinterpret_cast(tmp); + } + + sNewDataSource = getAdoDatalink(reinterpret_cast(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 xContext = ::comphelper::getProcessComponentContext(); + Reference 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 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 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 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 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 >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFT_Connection.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xPB_Connection.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xPB_CreateDB.get())); + } + + void OConnectionHelper::fillControls(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back( new OSaveValueWidgetWrapper( 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 0000000000..bbcf247833 --- /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 +#include + +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 OUString& _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 m_xFT_Connection; + std::unique_ptr m_xPB_Connection; + std::unique_ptr m_xPB_CreateDB; + std::unique_ptr m_xConnectionURL; + + public: + + // OGenericAdministrationPage::fillControls + virtual void fillControls(std::vector< std::unique_ptr >& _rControlList) override; + // OGenericAdministrationPage::fillWindows + virtual void fillWindows(std::vector< std::unique_ptr >& _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 0000000000..bb56d81b2e --- /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 +#include "ConnectionPage.hxx" +#include +#include +#include +#include +#if HAVE_FEATURE_JAVA +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 OConnectionTabPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique(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 ? HID_DSADMIN_MYSQL_ODBC_DATASOURCE : 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(DSID_USER); + + const SfxStringItem* pJdbcDrvItem = _rSet.GetItem(DSID_JDBCDRIVERCLASS); + const SfxStringItem* pUrlItem = _rSet.GetItem(DSID_CONNECTURL); + const SfxBoolItem* pAllowEmptyPwd = _rSet.GetItem(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( !o3tl::trim(m_xJavaDriver->get_text()).empty() ); + 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 ( !o3tl::trim(m_xJavaDriver->get_text()).empty() ) + { + ::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 && (!o3tl::trim(m_xJavaDriver->get_text()).empty()); + m_xTestConnection->set_sensitive(bEnableTestConnection); + return true; + } + IMPL_LINK(OConnectionTabPage, OnEditModified, weld::Entry&, rEdit, void) + { + if (&rEdit == m_xJavaDriver.get()) + m_xTestJavaDriver->set_sensitive( !o3tl::trim(m_xJavaDriver->get_text()).empty() ); + + 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 0000000000..19e7694625 --- /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 m_xFL2; + std::unique_ptr m_xUserNameLabel; + std::unique_ptr m_xUserName; + std::unique_ptr m_xPasswordRequired; + + // jdbc driver + std::unique_ptr m_xFL3; + std::unique_ptr m_xJavaDriverLabel; + std::unique_ptr m_xJavaDriver; + std::unique_ptr m_xTestJavaDriver; + + // connection test + std::unique_ptr 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 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. +

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).

+ */ + 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 0000000000..33ea535a1d --- /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 +#include +#include +#include +#include +#include +#include + +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 OConnectionTabPageSetup::CreateDbaseTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_DBASE_HELPTEXT, STR_DBASE_HEADERTEXT, STR_DBASE_PATH_OR_FILE ); + } + + std::unique_ptr OConnectionTabPageSetup::CreateMSAccessTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_MSACCESS_HELPTEXT, STR_MSACCESS_HEADERTEXT, STR_MSACCESS_MDB_FILE ); + } + + std::unique_ptr OConnectionTabPageSetup::CreateADOTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_ADO_HELPTEXT, STR_ADO_HEADERTEXT, STR_COMMONURL ); + } + + std::unique_ptr OConnectionTabPageSetup::CreateODBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique( pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, STR_ODBC_HELPTEXT, STR_ODBC_HEADERTEXT, STR_NAME_OF_ODBC_DATASOURCE ); + } + + std::unique_ptr OConnectionTabPageSetup::CreateUserDefinedTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique(pPage, pController, "dbaccess/ui/dbwizconnectionpage.ui", "ConnectionPage", _rAttrSet, TranslateId(), TranslateId(), STR_COMMONURL); + } + + OConnectionTabPageSetup::OConnectionTabPageSetup(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OUString& _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 0000000000..27b8eab284 --- /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 + +namespace dbaui +{ + + // OConnectionTabPageSetup + + /** implements the connection page of the data source properties dialog. + */ + class OConnectionTabPageSetup : public OConnectionHelper + { + std::unique_ptr m_xHelpText; + std::unique_ptr 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 OUString& _rId, const SfxItemSet& _rCoreAttrs, TranslateId pHelpTextResId, TranslateId pHeaderResId, TranslateId pUrlResId); + virtual ~OConnectionTabPageSetup() override; + + static std::unique_ptr CreateDbaseTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + static std::unique_ptr CreateMSAccessTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + static std::unique_ptr CreateADOTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + static std::unique_ptr CreateODBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet); + static std::unique_ptr 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 0000000000..22cdefdd6c --- /dev/null +++ b/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx @@ -0,0 +1,912 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "DBSetupConnectionPages.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "dsnItem.hxx" + +#if HAVE_FEATURE_JAVA + #include +#endif + +#include +#include +#include "TextConnectionHelper.hxx" +#include + +#include +#include + +namespace dbaui +{ +using namespace ::com::sun::star; + + std::unique_ptr OTextConnectionPageSetup::CreateTextTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique(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 >& _rControlList) + { + OConnectionTabPageSetup::fillControls(_rControlList); + m_xTextConnectionHelper->fillControls(_rControlList); + } + + void OTextConnectionPageSetup::fillWindows(std::vector< std::unique_ptr >& _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 OLDAPConnectionPageSetup::CreateLDAPTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ) + { + return std::make_unique(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( _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( u"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 >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xETHostServer.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xETBaseDN.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xNFPortNumber.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xCBUseSSL.get())); + } + void OLDAPConnectionPageSetup::fillWindows(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTHelpText.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTHostServer.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTBaseDN.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTPortNumber.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(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(DSID_CONN_LDAP_BASEDN); + const SfxInt32Item* pPortNumber = _rSet.GetItem(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::CreateMySQLIntroTabPage(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& rAttrSet) + { + return std::make_unique(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( _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 >& /*_rControlList*/) + { + } + + void OMySQLIntroPageSetup::fillWindows(std::vector< std::unique_ptr >& /*_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 MySQLNativeSetupPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet) + { + return std::make_unique(pPage, pController, rAttrSet); + } + + void MySQLNativeSetupPage::fillControls( std::vector< std::unique_ptr >& _rControlList ) + { + m_xMySQLSettings->fillControls( _rControlList ); + } + + void MySQLNativeSetupPage::fillWindows(std::vector>& rControlList) + { + rControlList.emplace_back(new ODisableWidgetWrapper(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(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypesItem = _rCoreAttrs.GetItem(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 OGeneralSpecialJDBCConnectionPageSetup::CreateMySQLJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ) + { + return std::make_unique(pPage, pController, + _rAttrSet, + DSID_MYSQL_PORTNUMBER , + STR_MYSQL_DEFAULT, + STR_MYSQLJDBC_HELPTEXT, + STR_MYSQLJDBC_HEADERTEXT, + STR_MYSQL_DRIVERCLASSTEXT); + } + + std::unique_ptr OGeneralSpecialJDBCConnectionPageSetup::CreateOracleJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ) + { + return std::make_unique(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 >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xETDatabasename.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xETDriverClass.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xETHostname.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xNFPortNumber.get())); + } + + void OGeneralSpecialJDBCConnectionPageSetup::fillWindows(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTHelpText.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTDatabasename.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTHostname.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTPortNumber.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTDefaultPortNumber.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(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(DSID_DATABASENAME); + const SfxStringItem* pDrvItem = _rSet.GetItem(DSID_JDBCDRIVERCLASS); + const SfxStringItem* pHostName = _rSet.GetItem(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = _rSet.GetItem(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 ( o3tl::trim(m_xETDriverClass->get_text()).empty() ) + { + 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 ( !o3tl::trim(m_xETDriverClass->get_text()).empty() ) + { +// 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( !o3tl::trim(m_xETDriverClass->get_text()).empty() ); + bool bRoadmapState = ((!m_xETDatabasename->get_text().isEmpty() ) && ( !m_xETHostname->get_text().isEmpty() ) && (!m_xNFPortNumber->get_text().isEmpty() ) && ( !o3tl::trim(m_xETDriverClass->get_text()).empty() )); + SetRoadmapStateValue(bRoadmapState); + OGenericAdministrationPage::callModifiedHdl(); + } + + std::unique_ptr OJDBCConnectionPageSetup::CreateJDBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique(pPage, pController, _rAttrSet); + } + + // OPostgresConnectionPageSetup + OPostgresConnectionPageSetup::OPostgresConnectionPageSetup( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs , sal_uInt16 _nPortId ) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/postgrespage.ui", "SpecialPostgresPage", _rCoreAttrs) + , m_nPortId(_nPortId) + , m_xETDatabasename(m_xBuilder->weld_entry("dbNameEntry")) + , m_xETHostname(m_xBuilder->weld_entry("hostNameEntry")) + , m_xNFPortNumber(m_xBuilder->weld_spin_button("portNumEntry")) + , m_xConnectionURL(new OConnectionURLEdit(m_xBuilder->weld_entry("browseurl"), m_xBuilder->weld_label("browselabel"))) + { + 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)); + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast( _rCoreAttrs.GetItem(DSID_TYPECOLLECTION) ); + if (pCollectionItem) + m_pCollection = pCollectionItem->getCollection(); + OSL_ENSURE(m_pCollection, "OConnectionHelper::OConnectionHelper : really need a DSN type collection !"); + m_xConnectionURL->SetTypeCollection(m_pCollection); + + SetRoadmapStateValue(false); + } + + OPostgresConnectionPageSetup::~OPostgresConnectionPageSetup() + { + } + + std::unique_ptr OPostgresConnectionPageSetup::CreatePostgresTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ) + { + return std::make_unique(pPage, pController, + _rAttrSet, + DSID_POSTGRES_PORTNUMBER); + } + + void OPostgresConnectionPageSetup::fillControls(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xETDatabasename.get())); + _rControlList.emplace_back( new OSaveValueWidgetWrapper( m_xConnectionURL.get() ) ); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xETHostname.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xNFPortNumber.get())); + } + + bool OPostgresConnectionPageSetup::FillItemSet( SfxItemSet* _rSet ) + { + bool bChangedSomething = false; + fillString(*_rSet,m_xConnectionURL.get(), DSID_CONNECTURL, 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 OPostgresConnectionPageSetup::fillWindows(std::vector< std::unique_ptr >& /*_rControlList*/) + { + } + + void OPostgresConnectionPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + // check whether or not the selection is invalid or readonly (invalid implies readonly, but not vice versa) + SetRoadmapStateValue(true); + bool bValid, bReadonly; + getFlags(_rSet, bValid, bReadonly); + + m_xConnectionURL->show(); + m_xConnectionURL->ShowPrefix( false); + + const SfxStringItem* pDatabaseName = _rSet.GetItem(DSID_DATABASENAME); + const SfxStringItem* pUrlItem = _rSet.GetItem(DSID_CONNECTURL); + const SfxStringItem* pHostName = _rSet.GetItem(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = _rSet.GetItem(m_nPortId); + + if ( bValid ) + { + m_xETDatabasename->set_text(pDatabaseName->GetValue()); + m_xETDatabasename->save_value(); + + OUString sUrl = pUrlItem->GetValue(); + setURL( sUrl ); + m_xConnectionURL->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); + + callModifiedHdl(); + } + + bool OPostgresConnectionPageSetup::commitPage( ::vcl::WizardTypes::CommitPageReason /*_eReason*/ ) + { + return commitURL(); + } + + bool OPostgresConnectionPageSetup::commitURL() + { + OUString sURL = m_xConnectionURL->GetTextNoPrefix(); + setURLNoPrefix(sURL); + m_xConnectionURL->SaveValueNoPrefix(); + return true; + } + + void OPostgresConnectionPageSetup::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 ( _bPrefix ) + m_xConnectionURL->SetText( sURL ); + else + m_xConnectionURL->SetTextNoPrefix( sURL ); + } + + void OPostgresConnectionPageSetup::setURLNoPrefix( std::u16string_view _rURL ) + { + impl_setURL( _rURL,false); + } + + void OPostgresConnectionPageSetup::setURL( std::u16string_view _rURL ) + { + impl_setURL( _rURL, true); + } + + // 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 >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xETDriverClass.get())); + } + + void OJDBCConnectionPageSetup::fillWindows(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(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(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 OSpreadSheetConnectionPageSetup::CreateDocumentOrSpreadSheetTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique(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 >& /*_rControlList*/) + { + } + + void OSpreadSheetConnectionPageSetup::fillControls(std::vector< std::unique_ptr >& _rControlList) + { + OConnectionTabPageSetup::fillControls(_rControlList); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(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 OAuthentificationPageSetup::CreateAuthentificationTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique(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 >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTHelpText.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTUserName.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xPBTestConnection.get())); + } + + void OAuthentificationPageSetup::fillControls(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xETUserName.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(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(DSID_USER); + const SfxBoolItem* pAllowEmptyPwd = _rSet.GetItem(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 OFinalDBPageSetup::CreateFinalDBTabPageSetup(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique(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 >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTFinalHeader.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTFinalHelpText.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTAdditionalSettings.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTFinalText.get())); + } + + void OFinalDBPageSetup::fillControls(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xCBOpenAfterwards.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xCBStartTableWizard.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xRBRegisterDataSource.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(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 0000000000..909cfede58 --- /dev/null +++ b/dbaccess/source/ui/dlg/DBSetupConnectionPages.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 "ConnectionPageSetup.hxx" + +#include "adminpages.hxx" +#include "admincontrols.hxx" +#include "TextConnectionHelper.hxx" + +#include + +namespace dbaui +{ + class ODbTypeWizDialogSetup; + + // OSpreadSheetConnectionPageSetup + class OSpreadSheetConnectionPageSetup final : public OConnectionTabPageSetup + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr 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 m_xPasswordrequired; + + virtual void fillControls(std::vector< std::unique_ptr >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + }; + + // OTextConnectionPage + class OTextConnectionPageSetup : public OConnectionTabPageSetup + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + bool checkTestConnection() override; + private: + DECL_LINK(ImplGetExtensionHdl, OTextConnectionHelper*, void); + std::unique_ptr m_xSubContainer; + std::unique_ptr m_xTextConnectionHelper; + }; + + // OLDAPConnectionPageSetup + class OLDAPConnectionPageSetup : public OGenericAdministrationPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + + private: + std::unique_ptr m_xFTHelpText; + std::unique_ptr m_xFTHostServer; + std::unique_ptr m_xETHostServer; + std::unique_ptr m_xFTBaseDN; + std::unique_ptr m_xETBaseDN; + std::unique_ptr m_xFTPortNumber; + std::unique_ptr m_xNFPortNumber; + std::unique_ptr m_xFTDefaultPortNumber; + std::unique_ptr m_xCBUseSSL; + }; + + // MySQLNativeSetupPage + class MySQLNativeSetupPage : public OGenericAdministrationPage + { + private: + std::unique_ptr m_xHelpText; + std::unique_ptr m_xSettingsContainer; + std::unique_ptr m_xMySQLSettings; + + public: + MySQLNativeSetupPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs); + virtual ~MySQLNativeSetupPage() override; + + static std::unique_ptr Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rAttrSet); + + protected: + virtual void fillControls( std::vector< std::unique_ptr >& _rControlList ) override; + virtual void fillWindows( std::vector< std::unique_ptr >& _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 CreateMySQLJDBCTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ); + static std::unique_ptr 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + virtual void callModifiedHdl(weld::Widget* pControl = nullptr) override; + + DECL_LINK(OnTestJavaClickHdl, weld::Button&, void); + + OUString m_sDefaultJdbcDriverName; + TypedWhichId m_nPortId; + + std::unique_ptr m_xHeaderText; + std::unique_ptr m_xFTHelpText; + std::unique_ptr m_xFTDatabasename; + std::unique_ptr m_xETDatabasename; + std::unique_ptr m_xFTHostname; + std::unique_ptr m_xETHostname; + std::unique_ptr m_xFTPortNumber; + std::unique_ptr m_xFTDefaultPortNumber; + std::unique_ptr m_xNFPortNumber; + + std::unique_ptr m_xFTDriverClass; + std::unique_ptr m_xETDriverClass; + std::unique_ptr 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 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + + DECL_LINK(OnTestJavaClickHdl, weld::Button&, void); + DECL_LINK(OnEditModified, weld::Entry&, void); + std::unique_ptr m_xFTDriverClass; + std::unique_ptr m_xETDriverClass; + std::unique_ptr 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 CreateMySQLIntroTabPage(weld::Container* pPage, ODbTypeWizDialogSetup* pController, const SfxItemSet& rAttrSet); + ConnectionType getMySQLMode() const; + void SetClickHdl( const Link& 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + + private: + std::unique_ptr m_xODBCDatabase; + std::unique_ptr m_xJDBCDatabase; + std::unique_ptr m_xNATIVEDatabase; + Link maClickHdl; + + DECL_LINK(OnSetupModeSelected, weld::Toggleable&, void); + }; + + // OPostgresPageSetup + class OPostgresConnectionPageSetup final : public OGenericAdministrationPage + { + public: + OPostgresConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController + , const SfxItemSet& _rCoreAttrs + , sal_uInt16 _nPortId ); + virtual ~OPostgresConnectionPageSetup() override; + static std::unique_ptr CreatePostgresTabPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet ); + ::dbaccess::ODsnTypeCollection* m_pCollection; + + private: + virtual bool FillItemSet( SfxItemSet* _rCoreAttrs ) override; + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + TypedWhichId m_nPortId; + + std::unique_ptr m_xETDatabasename; + std::unique_ptr m_xETHostname; + std::unique_ptr m_xNFPortNumber; + std::unique_ptr m_xConnectionURL; + + /** used for the connection URL + @param _rURL + The URL to check. + */ + void impl_setURL( std::u16string_view _rURL, bool _bPrefix ); + void setURLNoPrefix( std::u16string_view _rURL ); + void setURL( std::u16string_view _rURL ); + bool commitURL(); + }; + + + // OAuthentificationPageSetup + class OAuthentificationPageSetup final : public OGenericAdministrationPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr 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 m_xFTHelpText; + std::unique_ptr m_xFTUserName; + std::unique_ptr m_xETUserName; + std::unique_ptr m_xCBPasswordRequired; + std::unique_ptr m_xPBTestConnection; + + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + virtual void fillControls(std::vector< std::unique_ptr >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + }; + + // OFinalDBPageSetup + class OFinalDBPageSetup : public OGenericAdministrationPage + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + private: + std::unique_ptr m_xFTFinalHeader; + std::unique_ptr m_xFTFinalHelpText; + std::unique_ptr m_xRBRegisterDataSource; + std::unique_ptr m_xRBDontregisterDataSource; + std::unique_ptr m_xFTAdditionalSettings; + std::unique_ptr m_xCBOpenAfterwards; + std::unique_ptr m_xCBStartTableWizard; + std::unique_ptr 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 0000000000..94cdee5a9f --- /dev/null +++ b/dbaccess/source/ui/dlg/DbAdminImpl.cxx @@ -0,0 +1,1110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dsnItem.hxx" +#include "optionalboolitem.hxx" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +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& 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(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(DSID_PASSWORD); + OUString sPassword = pPassword ? pPassword->GetValue() : OUString(); + const SfxBoolItem* pPasswordRequired = m_pItemSetHelper->getOutputSet()->GetItem(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(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 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(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,bool> ODbDataSourceAdministrationHelper::createConnection() +{ + std::pair< Reference,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 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(DSID_CONNECTURL); + OSL_ENSURE( pConnectURL , "ODbDataSourceAdministrationHelper::getDatasourceType: invalid items in the source set!" ); + const DbuTypeCollectionItem* pTypeCollection = _rSet.GetItem(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(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypeCollection = m_pItemSetHelper->getOutputSet()->GetItem(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(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem(DSID_MYSQL_PORTNUMBER); + const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem(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(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem(DSID_ORACLE_PORTNUMBER); + const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem(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(DSID_CONN_LDAP_PORTNUMBER); + sNewUrl = pCollection->cutPrefix(pUrlItem->GetValue()) + lcl_createHostWithPort(nullptr,pPortNumber); + } + break; + case ::dbaccess::DST_POSTGRES: + { + sNewUrl = pCollection->cutPrefix(pUrlItem->GetValue()); + OUString rURL(comphelper::string::stripEnd(pUrlItem->GetValue(), '*')); + const SfxStringItem* pHostName = m_pItemSetHelper->getOutputSet()->GetItem(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = m_pItemSetHelper->getOutputSet()->GetItem(DSID_POSTGRES_PORTNUMBER); + const SfxStringItem* pDatabaseName = m_pItemSetHelper->getOutputSet()->GetItem(DSID_DATABASENAME); + if (pHostName && pHostName->GetValue().getLength()) + { + OUString hostname( pHostName->GetValue() ); + hostname = hostname.replaceAll( "\\", "\\\\"); + hostname = hostname.replaceAll( "\'", "\\'"); + hostname = "'" + hostname + "'"; + rURL += " host=" + hostname; + } + // tdf#157260: if port is already in the URL, don't add another one + if (pPortNumber && pPortNumber->GetValue() && (rURL.indexOf("port=") == -1)) + { + OUString port = "'" + OUString::number(pPortNumber->GetValue()) + "'"; + rURL += " port=" + port; + } + if (pDatabaseName && pDatabaseName->GetValue().getLength()) + { + OUString dbname( pDatabaseName->GetValue() ); + dbname = dbname.replaceAll( "\\", "\\\\"); + dbname = dbname.replaceAll( "\'", "\\'"); + dbname = "'" + dbname + "'"; + rURL += " dbname=" + dbname; + } + sNewUrl = rURL; + return sNewUrl; + } + break; + case ::dbaccess::DST_JDBC: + // run through + default: + break; + } + if ( !sNewUrl.isEmpty() ) + sNewUrl = pCollection->getPrefix(eType) + sNewUrl; + else if (pUrlItem) + 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 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 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 constexpr OUStringLiteral sUrlProp(u"URL"); + // transfer the direct properties + for (auto const& elem : m_aDirectPropTranslator) + { + const SfxPoolItem* pCurrentItem = _rSource.GetItem(static_cast(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(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 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( _pItem ); + const SfxBoolItem* pBoolItem = dynamic_cast( _pItem ); + const OptionalBoolItem* pOptBoolItem = dynamic_cast( _pItem ); + const SfxInt32Item* pInt32Item = dynamic_cast< const SfxInt32Item* >( _pItem ); + const OStringListItem* pStringListItem = dynamic_cast( _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; + } + + return OUStringToOString( aString, RTL_TEXTENCODING_ASCII_US ); +} +template static bool checkItemType(const SfxPoolItem* pItem){ return dynamic_cast(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 ) ) + { + 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 ) ) + { + bool bVal = false; + _rValue >>= bVal; + _rSet.Put(SfxBoolItem(_nId, bVal)); + } + else if ( implCheckItemType( _rSet, _nId, checkItemType ) ) + { + 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 ) ) + { + sal_Int32 nValue = 0; + _rValue >>= nValue; + _rSet.Put( SfxInt32Item( TypedWhichId(_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 ) ) + { + // 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(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(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypeCollection = _rDest.GetItem(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!"); + + TypedWhichId 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; + case ::dbaccess::DST_POSTGRES: + nPortNumberId = DSID_POSTGRES_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 != TypedWhichId(0) ) + _rDest.Put(SfxInt32Item(nPortNumberId, nPortNumber)); + +} + +bool ODbDataSourceAdministrationHelper::saveChanges(const SfxItemSet& _rSource) +{ + // put the remembered settings into the property set + Reference 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( _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 0000000000..dd4adcdc52 --- /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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dbaui +{ + namespace DataSourceInfoConverter + { + void convert(const css::uno::Reference< css::uno::XComponentContext> & xContext, + const ::dbaccess::ODsnTypeCollection* _pCollection, + std::u16string_view _sOldURLPrefix, + std::u16string_view _sNewURLPrefix, + const css::uno::Reference< css::beans::XPropertySet >& _xDatasource); + }; + class IItemSetHelper; + // ODbDataSourceAdministrationHelper + class ODbDataSourceAdministrationHelper final + { + public: + typedef std::map 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

+ 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 uno + static css::uno::Any implTranslateProperty(const SfxPoolItem* _pItem); + + /// translate the given SfxPoolItem into an uno, 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

+ 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 0000000000..72ce3d459d --- /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 + +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 CreateDbase( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for ado + */ + static std::unique_ptr CreateAdo( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for ODBC + */ + static std::unique_ptr CreateODBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for user + */ + static std::unique_ptr CreateUser( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for MySQLODBC + */ + static std::unique_ptr CreateMySQLODBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for MySQLJDBC + */ + static std::unique_ptr CreateMySQLJDBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for MySQLNATIVE + */ + static std::unique_ptr CreateMySQLNATIVE( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for Oracle JDBC + */ + static std::unique_ptr CreateOracleJDBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /** Creates the detail page for LDAP + */ + static std::unique_ptr CreateLDAP( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /// Creates the detail page for Text + static std::unique_ptr CreateText( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /// creates the GeneratedValues page + static std::unique_ptr CreateGeneratedValuesPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ); + + /// creates the "Special Settings" page of the "Advanced Settings" dialog + static std::unique_ptr 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 0000000000..df0d38e4ba --- /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 +#include +#include + +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 0000000000..8abccb7785 --- /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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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(_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(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(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 0000000000..bcf039c5e1 --- /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 +#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(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 0000000000..3148aad279 --- /dev/null +++ b/dbaccess/source/ui/dlg/TextConnectionHelper.cxx @@ -0,0 +1,397 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "TextConnectionHelper.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + +OUString lcl_getListEntry(std::u16string_view rStr, sal_Int32& rIdx) +{ + const OUString sTkn {o3tl::getToken(rStr, 0, '\t', rIdx )}; + if (rIdx>=0) + { + size_t nFnd = rStr.find('\t', rIdx); + if (nFnd == std::u16string_view::npos) + rIdx = -1; + else + { + rIdx = nFnd + 1; + if (rIdx >= static_cast(rStr.size())) + 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; + } const aSections[] = { + { TC_EXTENSION, m_xExtensionHeader.get() }, + { TC_SEPARATORS, m_xFormatHeader.get() }, + { TC_HEADER, m_xRowHeader.get() }, + { TC_CHARSET, m_xCharSetHeader.get() } + }; + + for (auto const & section: aSections) + { + if ( ( m_nAvailableSections & section.nFlag ) != 0 ) + { + // the section is visible, no need to do anything here + continue; + } + + // hide all elements from this section + 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 >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xFieldSeparator.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xTextSeparator.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xDecimalSeparator.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xThousandsSeparator.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xRowHeader.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xCharSet->get_widget())); + } + + void OTextConnectionHelper::fillWindows(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFieldSeparatorLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xTextSeparatorLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xDecimalSeparatorLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xThousandsSeparatorLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xCharSetHeader.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xCharSetLabel.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xCharSet->get_widget())); + } + + void OTextConnectionHelper::implInitControls(const SfxItemSet& _rSet, bool _bValid) + { + if ( !_bValid ) + return; + + const SfxStringItem* pDelItem = _rSet.GetItem(DSID_FIELDDELIMITER); + const SfxStringItem* pStrItem = _rSet.GetItem(DSID_TEXTDELIMITER); + const SfxStringItem* pDecdelItem = _rSet.GetItem(DSID_DECIMALDELIMITER); + const SfxStringItem* pThodelItem = _rSet.GetItem(DSID_THOUSANDSDELIMITER); + const SfxStringItem* pExtensionItem = _rSet.GetItem(DSID_TEXTFILEEXTENSION); + const SfxStringItem* pCharsetItem = _rSet.GetItem(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(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 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(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 0000000000..6755a42237 --- /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 +#include + +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 m_aGetExtensionHandler; /// to be called if a new type is selected + + short m_nAvailableSections; + + std::unique_ptr m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr m_xExtensionHeader; + std::unique_ptr m_xAccessTextFiles; + std::unique_ptr m_xAccessCSVFiles; + std::unique_ptr m_xAccessOtherFiles; + std::unique_ptr m_xOwnExtension; + std::unique_ptr m_xExtensionExample; + std::unique_ptr m_xFormatHeader; + std::unique_ptr m_xFieldSeparatorLabel; + std::unique_ptr m_xFieldSeparator; + std::unique_ptr m_xTextSeparatorLabel; + std::unique_ptr m_xTextSeparator; + std::unique_ptr m_xDecimalSeparatorLabel; + std::unique_ptr m_xDecimalSeparator; + std::unique_ptr m_xThousandsSeparatorLabel; + std::unique_ptr m_xThousandsSeparator; + std::unique_ptr m_xRowHeader; + std::unique_ptr m_xCharSetHeader; + std::unique_ptr m_xCharSetLabel; + std::unique_ptr 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 >& _rControlList); + void fillWindows(std::vector< std::unique_ptr >& _rControlList); + void SetClickHandler(const Link& _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 0000000000..da6ec80c27 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 { + +#define MNI_ACTION_ADD_USER "add" +#define MNI_ACTION_DEL_USER "delete" +#define MNI_ACTION_CHANGE_PASSWORD "password" + +class OPasswordDialog : public weld::GenericDialogController +{ + std::unique_ptr m_xUser; + std::unique_ptr m_xEDOldPassword; + std::unique_ptr m_xEDPassword; + std::unique_ptr m_xEDPasswordRepeat; + std::unique_ptr 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 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) + , mxActionBar(m_xBuilder->weld_menu_button("action_menu")) + , m_xUSER(m_xBuilder->weld_combo_box("user")) + , m_xTable(m_xBuilder->weld_container("table")) + , m_xTableCtrlParent(m_xTable->CreateChildFrame()) + , m_xTableCtrl(VclPtr::Create(m_xTableCtrlParent)) +{ + mxActionBar->append_item(MNI_ACTION_ADD_USER, DBA_RES(STR_ADD_USER)); + mxActionBar->append_item(MNI_ACTION_DEL_USER, DBA_RES(STR_DELETE_USER)); + mxActionBar->append_item(MNI_ACTION_CHANGE_PASSWORD, DBA_RES(STR_CHANGE_PASSWORD)); + mxActionBar->connect_selected(LINK(this,OUserAdmin,MenuSelectHdl)); + + m_xTableCtrl->Show(); + + m_xUSER->connect_changed(LINK(this, OUserAdmin, ListDblClickHdl)); +} + +IMPL_LINK(OUserAdmin, MenuSelectHdl, const OUString&, rIdent, void) +{ + try + { + if (rIdent == MNI_ACTION_ADD_USER) { + SfxPasswordDialog aPwdDlg(GetFrameWeld()); + aPwdDlg.ShowExtras(SfxShowExtras::ALL); + if (aPwdDlg.run()) + { + Reference xUserFactory(m_xUsers,UNO_QUERY); + Reference xNewUser = xUserFactory->createDataDescriptor(); + if(xNewUser.is()) + { + xNewUser->setPropertyValue(PROPERTY_NAME,Any(aPwdDlg.GetUser())); + xNewUser->setPropertyValue(PROPERTY_PASSWORD,Any(aPwdDlg.GetPassword())); + Reference xAppend(m_xUsers,UNO_QUERY); + if(xAppend.is()) + xAppend->appendByDescriptor(xNewUser); + } + } + } + else if (rIdent == MNI_ACTION_DEL_USER) { + if (m_xUsers.is() && m_xUsers->hasByName(GetUser())) + { + Reference xDrop(m_xUsers,UNO_QUERY); + if(xDrop.is()) + { + std::unique_ptr xQry(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Question, VclButtonsType::YesNo, + DBA_RES(STR_QUERY_USERADMIN_DELETE_USER))); + if (xQry->run() == RET_YES) + xDrop->dropByName(GetUser()); + } + } + } + else if (rIdent == MNI_ACTION_CHANGE_PASSWORD) { + OUString sName = GetUser(); + if(m_xUsers->hasByName(sName)) + { + Reference 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); + } + } + } + } + FillUserNames(); + } + catch(const SQLException& e) + { + ::dbtools::showError(::dbtools::SQLExceptionInfo(e), GetDialogController()->getDialog()->GetXWindow(), m_xORB); + } + catch(Exception& ) + { + } +} + +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 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 xAuth; + m_xUsers->getByName(m_UserName) >>= xAuth; + m_xTableCtrl->setGrantUser(xAuth); + } + + m_xTableCtrl->setUserName(GetUser()); + m_xTableCtrl->Init(); + } + } + } + + Reference xAppend(m_xUsers,UNO_QUERY); + mxActionBar->set_item_sensitive(MNI_ACTION_ADD_USER, xAppend.is()); + Reference xDrop(m_xUsers,UNO_QUERY); + mxActionBar->set_item_sensitive(MNI_ACTION_DEL_USER, xDrop.is()); + mxActionBar->set_item_sensitive(MNI_ACTION_CHANGE_PASSWORD, m_xUsers.is()); + + m_xTableCtrl->Enable(m_xUsers.is()); +} + +std::unique_ptr OUserAdmin::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ) +{ + return std::make_unique( pPage, pController, *_rAttrSet ); +} + +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 >& /*_rControlList*/) +{ +} + +void OUserAdmin::fillWindows(std::vector< std::unique_ptr >& /*_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 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 0000000000..76460a8468 --- /dev/null +++ b/dbaccess/source/ui/dlg/UserAdmin.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 +#include "adminpages.hxx" + +namespace com::sun::star { + namespace sdbc { + class XConnection; + } +} + +namespace dbaui +{ + +class OUserAdmin final : public OGenericAdministrationPage +{ + std::unique_ptr mxActionBar; + std::unique_ptr m_xUSER; + std::unique_ptr m_xTable; + css::uno::Reference m_xTableCtrlParent; + VclPtr 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(MenuSelectHdl, const OUString&, void); + + void FillUserNames(); + +public: + OUserAdmin(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs); + static std::unique_ptr 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; + + // OGenericAdministrationPage::fillControls + virtual void fillControls(std::vector< std::unique_ptr >& _rControlList) override; + + // OGenericAdministrationPage::fillWindows + virtual void fillWindows(std::vector< std::unique_ptr >& _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 0000000000..b4cf62f3be --- /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 +#include "adminpages.hxx" +#include "DbAdminImpl.hxx" +#include +#include "UserAdmin.hxx" +#include + +#include + +#include +#include +#include +#include +#include +#include + +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 OUString& rId, SfxTabPage& _rPage) + { + // register ourself as modified listener + static_cast(_rPage).SetServiceFactory( m_pImpl->getORB() ); + static_cast(_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,bool> OUserAdminDlg::createConnection() + { + if ( !m_xConnection.is() ) + { + m_xConnection = m_pImpl->createConnection().first; + m_bOwnConnection = m_xConnection.is(); + } + return std::pair< Reference,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 0000000000..de515f9e37 --- /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 + +#include +#include +#include +#include + +namespace dbaui +{ + + // MySQLNativeSettings + MySQLNativeSettings::MySQLNativeSettings(weld::Widget* pParent, const Link& 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 >& _rControlList ) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xDatabaseName.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xHostName.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xPort.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xSocket.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xNamedPipe.get())); + } + + void MySQLNativeSettings::fillWindows( std::vector< std::unique_ptr >& _rControlList ) + { + _rControlList.emplace_back( new ODisableWidgetWrapper( m_xDatabaseNameLabel.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper( m_xHostNameLabel.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper( m_xPortLabel.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper( m_xDefaultPort.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper( m_xSocketRadio.get() ) ); + _rControlList.emplace_back( new ODisableWidgetWrapper( 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(DSID_INVALID_SELECTION); + bool bValid = !pInvalid || !pInvalid->GetValue(); + if ( !bValid ) + return; + + const SfxStringItem* pDatabaseName = _rSet.GetItem(DSID_DATABASENAME); + const SfxStringItem* pHostName = _rSet.GetItem(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = _rSet.GetItem(DSID_MYSQL_PORTNUMBER); + const SfxStringItem* pSocket = _rSet.GetItem(DSID_CONN_SOCKET); + const SfxStringItem* pNamedPipe = _rSet.GetItem(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 0000000000..7bd1e5edfc --- /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 + +namespace dbaui +{ + + // MySQLNativeSettings + class MySQLNativeSettings + { + private: + std::unique_ptr m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr m_xDatabaseNameLabel; + std::unique_ptr m_xDatabaseName; + std::unique_ptr m_xHostPortRadio; + std::unique_ptr m_xSocketRadio; + std::unique_ptr m_xNamedPipeRadio; + std::unique_ptr m_xHostNameLabel; + std::unique_ptr m_xHostName; + std::unique_ptr m_xPortLabel; + std::unique_ptr m_xPort; + std::unique_ptr m_xDefaultPort; + std::unique_ptr m_xSocket; + std::unique_ptr m_xNamedPipe; + Link 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& rControlModificationLink); + void fillControls( std::vector< std::unique_ptr >& _rControlList ); + void fillWindows( std::vector< std::unique_ptr >& _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 0000000000..ec837e8036 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include "dsselect.hxx" +#include "odbcconfig.hxx" +#include "optionalboolitem.hxx" +#include +#include +#include +#include +#include + +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 OUString& 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(DSID_INVALID_SELECTION); + _rValid = !pInvalid || !pInvalid->GetValue(); + const SfxBoolItem* pReadonly = _rSet.GetItem(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 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 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 > 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, TypedWhichId _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, TypedWhichId _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, TypedWhichId _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,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 0000000000..7d13a3886e --- /dev/null +++ b/dbaccess/source/ui/dlg/adminpages.hxx @@ -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 . + */ + +#pragma once + +#include +#include +#include + +class SfxInt32Item; +class SfxStringItem; + +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 : 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 : 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 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 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 OUString& rId, const SfxItemSet& rAttrSet); + /// set a handler which gets called every time something on the page has been modified + void SetModifiedHandler(const Link& _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 + contains the selected name. + @return + if an error occurred, otherwise + */ + 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 implInitControls 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 >& _rControlList) = 0; + + /** will be called inside implInitControls 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 >& _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 + if something changed otherwise + @param _bRevertValue + set to 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 + if something changed otherwise + */ + static void fillInt32(SfxItemSet& _rSet,const weld::SpinButton* pEdit,TypedWhichId _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 + if something changed otherwise + */ + static void fillString(SfxItemSet& _rSet,const weld::Entry* pEdit, TypedWhichId _nID, bool& _bChangedSomething); + static void fillString(SfxItemSet& _rSet,const dbaui::OConnectionURLEdit* pEdit, TypedWhichId _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 0000000000..82af63688c --- /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 + +#include +#include +#include +#include + +#include +#include +#include + +#include "adodatalinks.hxx" + +namespace { + +OUString PromptNew(sal_IntPtr hWnd) +{ + try + { + // Initialize COM + sal::systools::CoInitializeGuard aGuard(COINIT_APARTMENTTHREADED); + + // Instantiate DataLinks object. + sal::systools::COMReference 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 piDispatch; + sal::systools::ThrowIfFailed(dlPrompt->PromptNew(&piDispatch), "PromptNew failed"); + sal::systools::COMReference 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 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 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 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 0000000000..6b753f62e4 --- /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 +#include + +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 0000000000..2d98688f5b --- /dev/null +++ b/dbaccess/source/ui/dlg/adtabdlg.cxx @@ -0,0 +1,466 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 xEntry(rTableList.make_iterator()); + + if (!rTableList.get_selected(xEntry.get())) + return OUString(); + + OUString aCatalog, aSchema, aTableName; + std::unique_ptr xSchema(rTableList.make_iterator(xEntry.get())); + if (rTableList.iter_parent(*xSchema)) + { + auto xAll = m_rTableList.getAllObjectsEntry(); + if (!xAll || !xSchema->equal(*xAll)) + { + std::unique_ptr 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) + std::erase_if(aTables, + [&aEqualFunctor, pViewBegin](const OUString& lhs) + { return aEqualFunctor(lhs, *pViewBegin); } ); + sTables = Sequence< OUString>(aTables.data(), aTables.size()); + sViews = Sequence< OUString>(); + } + + m_rTableList.UpdateTableList( m_xConnection, sTables, sViews ); + + std::unique_ptr 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 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 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 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 0000000000..935a5370de --- /dev/null +++ b/dbaccess/source/ui/dlg/advancedsettings.cxx @@ -0,0 +1,470 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "advancedsettings.hxx" +#include +#include +#include "DbAdminImpl.hxx" +#include "DriverSettings.hxx" +#include "optionalboolitem.hxx" + +#include +#include +#include + +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& xControl; // the dialog's control which displays this setting + OUString 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(&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 >& _rControlList ) + { + if ( m_bHasBooleanComparisonMode ) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xBooleanComparisonModeLabel.get())); + } + if ( m_bHasMaxRowScan ) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xMaxRowScanLabel.get())); + } + } + + void SpecialSettingsPage::fillControls(std::vector< std::unique_ptr >& _rControlList) + { + for (auto const& booleanSetting : m_aBooleanSettings) + { + if (booleanSetting.xControl) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(booleanSetting.xControl.get())); + } + } + + if ( m_bHasBooleanComparisonMode ) + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xBooleanComparisonMode.get())); + if ( m_bHasMaxRowScan ) + _rControlList.emplace_back(new OSaveValueWidgetWrapper(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 aValue; + + const SfxPoolItem* pItem = _rSet.GetItem(booleanSetting.nItemId); + if (const SfxBoolItem *pBoolItem = dynamic_cast( pItem) ) + { + aValue = pBoolItem->GetValue(); + } + else if (const OptionalBoolItem *pOptionalItem = dynamic_cast( pItem) ) + { + aValue = pOptionalItem->GetFullValue(); + bTriState = true; + } + else + OSL_FAIL( "SpecialSettingsPage::implInitControls: unknown boolean item type!" ); + + if ( !aValue.has_value() ) + { + 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(DSID_BOOLEANCOMPARISON); + m_xBooleanComparisonMode->set_active(static_cast(pBooleanComparison->GetValue())); + } + + if ( m_bHasMaxRowScan ) + { + const SfxInt32Item* pMaxRowScan = _rSet.GetItem(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_xAutoIncrement(m_xBuilder->weld_entry("statement")) + , 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 >& _rControlList ) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xContainer.get())); + } + + void GeneratedValuesPage::fillControls( std::vector< std::unique_ptr >& _rControlList ) + { + _rControlList.emplace_back( new OSaveValueWidgetWrapper( m_xAutoRetrievingEnabled.get() ) ); + _rControlList.emplace_back( new OSaveValueWidgetWrapper( m_xAutoIncrement.get() ) ); + _rControlList.emplace_back( new OSaveValueWidgetWrapper( 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(DSID_AUTOINCREMENTVALUE); + const SfxStringItem* pAutoRetrieveValueItem = _rSet.GetItem(DSID_AUTORETRIEVEVALUE); + const SfxBoolItem* pAutoRetrieveEnabledItem = _rSet.GetItem(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 OUString& rId, SfxTabPage& _rPage) + { + // register ourself as modified listener + static_cast(_rPage).SetServiceFactory( getORB() ); + static_cast(_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 0000000000..9eaca4a41b --- /dev/null +++ b/dbaccess/source/ui/dlg/advancedsettings.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 "adminpages.hxx" +#include +#include + +namespace dbaui +{ + struct BooleanSettingDesc; + + // SpecialSettingsPage + // implements the "Special Settings" page of the advanced database settings + class SpecialSettingsPage final : public OGenericAdministrationPage + { + std::unique_ptr m_xIsSQL92Check; + std::unique_ptr m_xAppendTableAlias; + std::unique_ptr m_xAsBeforeCorrelationName; + std::unique_ptr m_xEnableOuterJoin; + std::unique_ptr m_xIgnoreDriverPrivileges; + std::unique_ptr m_xParameterSubstitution; + std::unique_ptr m_xSuppressVersionColumn; + std::unique_ptr m_xCatalog; + std::unique_ptr m_xSchema; + std::unique_ptr m_xIndexAppendix; + std::unique_ptr m_xDosLineEnds; + std::unique_ptr m_xCheckRequiredFields; + std::unique_ptr m_xIgnoreCurrency; + std::unique_ptr m_xEscapeDateTime; + std::unique_ptr m_xPrimaryKeySupport; + std::unique_ptr m_xRespectDriverResultSetType; + + std::unique_ptr m_xBooleanComparisonModeLabel; + std::unique_ptr m_xBooleanComparisonMode; + + std::unique_ptr m_xMaxRowScanLabel; + std::unique_ptr m_xMaxRowScan; + + std::map 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; + + // OGenericAdministrationPage::fillControls + virtual void fillControls(std::vector< std::unique_ptr >& _rControlList) override; + + // OGenericAdministrationPage::fillWindows + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + + DECL_LINK(BooleanComparisonSelectHdl, weld::ComboBox&, void); + }; + + // GeneratedValuesPage + class GeneratedValuesPage final : public OGenericAdministrationPage + { + std::unique_ptr m_xAutoRetrievingEnabled; + std::unique_ptr m_xGrid; + std::unique_ptr m_xAutoIncrement; + std::unique_ptr 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; + + // OGenericAdministrationPage::fillControls + virtual void fillControls(std::vector< std::unique_ptr >& _rControlList) override; + + // OGenericAdministrationPage::fillWindows + virtual void fillWindows(std::vector< std::unique_ptr >& _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 0000000000..372e72e258 --- /dev/null +++ b/dbaccess/source/ui/dlg/dbadmin.cxx @@ -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 . + */ + +#include "ConnectionPage.hxx" +#include "DbAdminImpl.hxx" +#include "DriverSettings.hxx" +#include "adminpages.hxx" +#include +#include +#include +#include +#include +#include +#include +#include "dsnItem.hxx" +#include "optionalboolitem.hxx" +#include + +#include + +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 OUString& rId, SfxTabPage& _rPage) +{ + // register ourself as modified listener + static_cast(_rPage).SetServiceFactory( getORB() ); + static_cast(_rPage).SetAdminDialog(this,this); + + SfxTabDialogController::PageCreated(rId, _rPage); +} + +void ODbAdminDialog::addDetailPage(const OUString& 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(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" + OUString::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(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(getOutputSet()->GetItem(DSID_TYPECOLLECTION)); + assert(pCollectionItem && "must exist"); + ::dbaccess::ODsnTypeCollection* pCollection = pCollectionItem->getCollection(); + if ( pCollection->determineType(getDatasourceType( *m_xExampleSet )) == ::dbaccess::DST_MYSQL_NATIVE ) + { + OUString 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,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& _rpSet, rtl::Reference& _rpPool, std::vector*& _rpDefaults, ::dbaccess::ODsnTypeCollection* _pTypeCollection) +{ + // just to be sure... + _rpSet = nullptr; + _rpPool = nullptr; + _rpDefaults = nullptr; + + static constexpr OUString sFilterAll( u"%"_ustr ); + // create and initialize the defaults + _rpDefaults = new std::vector(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}); + *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 ); + *pCounter++ = new SfxInt32Item(DSID_POSTGRES_PORTNUMBER, 5432); + + // create the pool + static SfxItemInfo const aItemInfos[DSID_LAST_ITEM_ID - DSID_FIRST_ITEM_ID + 1] = + { + // _nSID, _bNeedsPoolRegistration, _bShareable + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + {0,false,false}, + }; + + OSL_ENSURE(std::size(aItemInfos) == sal_uInt16(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& _rpSet, rtl::Reference& _rpPool, std::vector*& _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 0000000000..521a7934e0 --- /dev/null +++ b/dbaccess/source/ui/dlg/dbfindex.cxx @@ -0,0 +1,428 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dbaui +{ +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::svt; + +constexpr OString aGroupIdent("dBase III"_ostr); + + +ODbaseIndexDialog::ODbaseIndexDialog(weld::Window * pParent, OUString aDataSrcName) + : GenericDialogController(pParent, "dbaccess/ui/dbaseindexdialog.ui", "DBaseIndexDialog") + , m_aDSN(std::move(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(std::distance(_rList.begin(), aSearch)); + + aReturn = *aSearch; + + _rList.erase(aSearch); + _rDisplay.remove_text(_rName); + + // adjust selection if necessary + if (static_cast(nPos) == _rList.size()) + _rDisplay.select(static_cast(nPos)-1); + else + _rDisplay.select(static_cast(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 + + std::vector< OUString > aUsedIndexes; + + aURL.SetSmartProtocol(INetProtocol::File); + const Sequence 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 == "ndx") + { + m_aFreeIndexList.emplace_back(aURL.getName() ); + } + else if (aExt == "dbf") + { + 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(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(), 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 0000000000..938339314e --- /dev/null +++ b/dbaccess/source/ui/dlg/dbfindex.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 +#include +#include + +namespace dbaui +{ + +// OTableIndex +/// represents a single dbf index +class OTableIndex +{ +private: + OUString aIndexFileName; + +public: + OTableIndex() { } + explicit OTableIndex( OUString aFileName ) : aIndexFileName(std::move( aFileName )) { } + + 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( OUString aName ) : aTableName(std::move(aName)) { } + + void WriteInfFile( const OUString& rDSN ) const; +}; + +typedef std::deque< OTableInfo > TableInfoList; + +// IndexDialog +class ODbaseIndexDialog : public weld::GenericDialogController +{ + OUString m_aDSN; + TableInfoList m_aTableInfoList; + TableIndexList m_aFreeIndexList; + + std::unique_ptr m_xPB_OK; + std::unique_ptr m_xCB_Tables; + std::unique_ptr m_xIndexes; + std::unique_ptr m_xLB_TableIndexes; + std::unique_ptr m_xLB_FreeIndexes; + + std::unique_ptr m_xAdd; + std::unique_ptr m_xRemove; + std::unique_ptr m_xAddAll; + std::unique_ptr 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 ); + +protected: + 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, OUString aDataSrcName); + 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 0000000000..8d1f737c52 --- /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 +#include +#include +#include +#include +#include "dsnItem.hxx" +#include "adminpages.hxx" +#include "generalpage.hxx" +#include +#include "ConnectionPage.hxx" +#include "DriverSettings.hxx" +#include "DbAdminImpl.hxx" +#include + +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(_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,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 ODbTypeWizDialog::createPage(WizardState _nState) +{ + TranslateId pStringId = STR_PAGETITLE_ADVANCED; + std::unique_ptr xPage; + + OUString sIdent(OUString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch(_nState) + { + case START_PAGE: // start state + { + xPage = std::make_unique(pPageContainer, this, *m_pOutSet); + OGeneralPage* pGeneralPage = static_cast(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(xPage.get())->SetServiceFactory( m_pImpl->getORB() ); + static_cast(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(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(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(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 0000000000..720892e2a0 --- /dev/null +++ b/dbaccess/source/ui/dlg/dbwizsetup.cxx @@ -0,0 +1,1004 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include "DBSetupConnectionPages.hxx" +#include +#include +#include +#include "dsnItem.hxx" + +#include +#include +#include "adminpages.hxx" +#include +#include +#include "generalpage.hxx" +#include +#include "DbAdminImpl.hxx" +#include +#include "ConnectionPageSetup.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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_PostgresText( DBA_RES( STR_PAGETITLE_POSTGRES ) ) + , 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(_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(m_pCollection->size()+1), aPath); + + // Set general help ID for the roadmap + SetRoadmapHelpId(HID_DBWIZ_ROADMAP); + + 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); + m_xHelp->set_help_id(HID_DBWIZ_HELP); + 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_POSTGRES: + sRoadmapItem = m_sRM_PostgresText; + 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 & xContext, const ::dbaccess::ODsnTypeCollection* _pCollection, std::u16string_view _sOldURLPrefix, std::u16string_view _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(m_pCollection->getIndexOf(m_sURL) + 1), true); + updateTypeDependentStates(); + } + break; + case OGeneralPageWizard::eOpenExisting: + { + activatePath( static_cast(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(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,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 ODbTypeWizDialogSetup::createPage(WizardState _nState) +{ + std::unique_ptr xPage; + + OUString sIdent(OUString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch(_nState) + { + case PAGE_DBSETUPWIZARD_INTRO: + xPage = std::make_unique(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(u"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(u"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(u"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_POSTGRES: + xPage = OPostgresConnectionPageSetup::CreatePostgresTabPage(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(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(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(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 pRequest = new OInteractionRequest( _rRequest ); + rtl::Reference 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 ) ) + { + css::ucb::IOErrorCode code + = aError.isExtractableTo(::cppu::UnoType::get()) + ? IOErrorCode_CANT_WRITE // assume saving the document failed + : IOErrorCode_GENERAL; + InteractiveIOException aRequest(e.Message, e.Context, + InteractionClassification_ERROR, code); + 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 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(Concat2View(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( Concat2View(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(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 >& _xORB, OUString _aURL ); + + 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, OUString _aURL ) + :m_sURL(std::move( _aURL )) + ,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 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 0000000000..1e8f94a89b --- /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 +#include +#include "detailpages.hxx" +#include +#include +#include "advancedsettings.hxx" +#include "DbAdminImpl.hxx" +#include +#include "dbfindex.hxx" +#include "dsnItem.hxx" + +#include +#include + +#include +#include +#include +#include +#if HAVE_FEATURE_JAVA +#include +#endif +#include +#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 OUString& 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 >& _rControlList) + { + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xOptionsLabel.get())); + } + + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xCharsetLabel.get())); + } + } + + void OCommonBehaviourTabPage::fillControls(std::vector< std::unique_ptr >& _rControlList) + { + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions) + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xOptions.get())); + + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset) + _rControlList.emplace_back(new OSaveValueWidgetWrapper(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(DSID_ADDITIONALOPTIONS); + const SfxStringItem* pCharsetItem = _rSet.GetItem(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 ODriversSettings::CreateDbase(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique(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(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypesItem = _rSet.GetItem(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(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 ODriversSettings::CreateAdo(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) + { + return std::make_unique(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 ODriversSettings::CreateODBC(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique(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(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 ODriversSettings::CreateUser(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique(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 >& _rControlList) + { + OCommonBehaviourTabPage::fillControls(_rControlList); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xEDHostname.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xUseCatalog.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xNFPortNumber.get())); + } + void OUserDriverDetailsPage::fillWindows(std::vector< std::unique_ptr >& _rControlList) + { + OCommonBehaviourTabPage::fillWindows(_rControlList); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xFTHostname.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(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(DSID_USECATALOG); + const SfxStringItem* pHostName = _rSet.GetItem(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = _rSet.GetItem(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 ODriversSettings::CreateMySQLODBC(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique(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(DSID_CONNECTURL); + const DbuTypeCollectionItem* pTypesItem = rCoreAttrs.GetItem(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(DSID_JDBCDRIVERCLASS); + const SfxStringItem* pHostName = _rSet.GetItem(DSID_CONN_HOSTNAME); + const SfxInt32Item* pPortNumber = _rSet.GetItem(m_nPortId); + const SfxStringItem* pSocket = _rSet.GetItem(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 && o3tl::trim(m_xEDDriverClass->get_text()).empty() ) + { + 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 (!o3tl::trim(m_xEDDriverClass->get_text()).empty()) + { +// 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(!o3tl::trim(m_xEDDriverClass->get_text()).empty()); + + // 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 >& _rControlList) + { + OCommonBehaviourTabPage::fillControls( _rControlList ); + m_xMySQLSettings->fillControls( _rControlList ); + + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xUserName.get())); + _rControlList.emplace_back(new OSaveValueWidgetWrapper(m_xPasswordRequired.get())); + } + + void MySQLNativePage::fillWindows(std::vector< std::unique_ptr >& _rControlList) + { + OCommonBehaviourTabPage::fillWindows( _rControlList ); + m_xMySQLSettings->fillWindows( _rControlList); + + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xSeparator1.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xSeparator2.get())); + _rControlList.emplace_back(new ODisableWidgetWrapper(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(DSID_USER); + const SfxBoolItem* pAllowEmptyPwd = _rSet.GetItem(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 ODriversSettings::CreateMySQLJDBC( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ) + { + return std::make_unique(pPage, pController, *_rAttrSet,DSID_MYSQL_PORTNUMBER); + } + + std::unique_ptr ODriversSettings::CreateMySQLNATIVE(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique(pPage, pController, *pAttrSet); + } + + std::unique_ptr ODriversSettings::CreateOracleJDBC(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique(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 ODriversSettings::CreateLDAP(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique(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(DSID_CONN_LDAP_BASEDN); + const SfxBoolItem* pUseSSL = _rSet.GetItem(DSID_CONN_LDAP_USESSL); + const SfxInt32Item* pPortNumber = _rSet.GetItem(DSID_CONN_LDAP_PORTNUMBER); + const SfxInt32Item* pRowCount = _rSet.GetItem(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 ODriversSettings::CreateText(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pAttrSet) + { + return std::make_unique(pPage, pController, *pAttrSet); + } + + void OTextDetailsPage::fillControls(std::vector< std::unique_ptr >& _rControlList) + { + OCommonBehaviourTabPage::fillControls(_rControlList); + m_xTextConnectionHelper->fillControls(_rControlList); + + } + void OTextDetailsPage::fillWindows(std::vector< std::unique_ptr >& _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 ODriversSettings::CreateGeneratedValuesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + return std::make_unique(pPage, pController, *_rAttrSet); + } + + std::unique_ptr ODriversSettings::CreateSpecialSettingsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet) + { + OUString eType = ODbDataSourceAdministrationHelper::getDatasourceType( *_rAttrSet ); + DataSourceMetaData aMetaData( eType ); + return std::make_unique(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 0000000000..aa01c12f93 --- /dev/null +++ b/dbaccess/source/ui/dlg/detailpages.hxx @@ -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 . + */ + +#pragma once + +#include "adminpages.hxx" +#include +#include "TextConnectionHelper.hxx" +#include "admincontrols.hxx" + +#include + +enum class OCommonBehaviourTabPageFlags { + NONE = 0x0000, + UseCharset = 0x0002, + UseOptions = 0x0004, +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + +namespace dbaui +{ + /** eases the implementation of tab pages handling user/password and/or character + set and/or generic options input +
+ 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 m_xOptionsLabel; + std::unique_ptr m_xOptions; + + std::unique_ptr m_xDataConvertLabel; + std::unique_ptr m_xCharsetLabel; + std::unique_ptr m_xCharset; + + public: + virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override; + + OCommonBehaviourTabPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OUString& 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; + + // OGenericAdministrationPage::fillControls + virtual void fillControls(std::vector< std::unique_ptr >& _rControlList) override; + + // OGenericAdministrationPage::fillWindows + virtual void fillWindows(std::vector< std::unique_ptr >& _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 m_xShowDeleted; + std::unique_ptr m_xFT_Message; + std::unique_ptr 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 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + private: + std::unique_ptr m_xFTHostname; + std::unique_ptr m_xEDHostname; + std::unique_ptr m_xPortNumber; + std::unique_ptr m_xNFPortNumber; + std::unique_ptr 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; + TypedWhichId m_nPortId; + bool m_bUseClass; + + std::unique_ptr m_xEDHostname; + std::unique_ptr m_xNFPortNumber; + std::unique_ptr m_xFTSocket; + std::unique_ptr m_xEDSocket; + std::unique_ptr m_xFTDriverClass; + std::unique_ptr m_xEDDriverClass; + std::unique_ptr 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 m_xMySQLSettingsContainer; + std::unique_ptr m_xMySQLSettings; + std::unique_ptr m_xSeparator1; + std::unique_ptr m_xSeparator2; + std::unique_ptr m_xUserNameLabel; + std::unique_ptr m_xUserName; + std::unique_ptr 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _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 m_xETBaseDN; + std::unique_ptr m_xCBUseSSL; + std::unique_ptr m_xNFPortNumber; + std::unique_ptr 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + + private: + std::unique_ptr 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 0000000000..eab893e4e4 --- /dev/null +++ b/dbaccess/source/ui/dlg/directsql.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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(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 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( + Concat2View(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(Concat2View(OUString::number(resultCount) + " rows updated\n")); + } + else if (upperStatement.startsWith("INSERT")) + { + sal_Int32 resultCount = xStatement->executeUpdate(_rStatement); + addOutputText(Concat2View(OUString::number(resultCount) + " rows inserted\n")); + } + else if (upperStatement.startsWith("DELETE")) + { + sal_Int32 resultCount = xStatement->executeUpdate(_rStatement); + addOutputText(Concat2View(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(Concat2View(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) + { + + const Reference xResultSetMetaData = Reference(xRS,UNO_QUERY_THROW)->getMetaData(); + const sal_Int32 nColumnsCount = xResultSetMetaData->getColumnCount(); + + // 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 + { + for (sal_Int32 i = 1; i <= nColumnsCount; ++i) + { + switch (xResultSetMetaData->getColumnType(i)) + { + // tdf#153317, at least "Bit" type in Mysql/MariaDB gives: "\000" or "\001" + // so retrieve Sequence from getBytes, test if it has a length of 1 (so we avoid BLOB/CLOB or other complex types) + // and test if the value of first byte is one of those. + // In this case, there's a good chance it's a "Bit" field + case css::sdbc::DataType::BIT: + { + auto seq = xRow->getBytes(i); + if ((seq.getLength() == 1) && (seq[0] >= 0) && (seq[0] <= 1)) + { + out.append(OUString::number(static_cast(seq[0])) + ","); + } + else + { + out.append(xRow->getString(i) + ","); + } + break; + } + // for the rest, be dumb, treat everything as a string + default: + out.append(xRow->getString(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 0000000000..24a1c4e81c --- /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 + +#include + +#include + +#include +#include +#include + +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 OUString& 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 0000000000..23f6dbe373 --- /dev/null +++ b/dbaccess/source/ui/dlg/dlgsave.cxx @@ -0,0 +1,289 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +using namespace ::com::sun::star::lang; + + +IMPL_LINK(OSaveAsDlg, TextFilterHdl, OUString&, rTest, bool) +{ + OUString sCorrected; + if (m_aChecker.checkString(rTest, sCorrected)) + rTest = sCorrected; + return true; +} + +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_aName(rDefault) + , m_rObjectNameCheck( _rObjectNameCheck ) + , m_nType(_rType) + , m_nFlags(_nFlags) + , m_aChecker(OUString()) + , m_xDescription(m_xBuilder->weld_label("descriptionft")) + , m_xCatalogLbl(m_xBuilder->weld_label("catalogft")) + , m_xCatalog(m_xBuilder->weld_combo_box("catalog")) + , m_xSchemaLbl(m_xBuilder->weld_label("schemaft")) + , m_xSchema(m_xBuilder->weld_combo_box("schema")) + , m_xLabel(m_xBuilder->weld_label("titleft")) + , m_xTitle(m_xBuilder->weld_entry("title")) + , m_xPB_OK(m_xBuilder->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, OSaveAsDlg, TextFilterHdl)); + m_xSchema->connect_entry_insert_text(LINK(this, OSaveAsDlg, TextFilterHdl)); + m_xCatalog->connect_entry_insert_text(LINK(this, OSaveAsDlg, TextFilterHdl)); + + switch (_rType) { + case CommandType::QUERY: + implInitOnlyTitle(DBA_RES(STR_QRY_LABEL)); + break; + + case CommandType::TABLE: + OSL_ENSURE( m_xMetaData.is(), "OSaveAsDlg::OSaveAsDlg: no meta data for entering table names: this will crash!" ); + { + m_xLabel->set_label(DBA_RES(STR_TBL_LABEL)); + if(m_xMetaData.is() && !m_xMetaData->supportsCatalogsInTableDefinitions()) { + m_xCatalogLbl->hide(); + m_xCatalog->hide(); + } else { + // now fill the catalogs + lcl_fillComboList( *m_xCatalog, _xConnection, + &XDatabaseMetaData::getCatalogs, _xConnection->getCatalog() ); + } + + if ( !m_xMetaData->supportsSchemasInTableDefinitions()) { + m_xSchemaLbl->hide(); + m_xSchema->hide(); + } else { + lcl_fillComboList( *m_xSchema, _xConnection, + &XDatabaseMetaData::getSchemas, m_xMetaData->getUserName() ); + } + + OSL_ENSURE(m_xMetaData.is(),"The metadata can not be null!"); + if(m_aName.indexOf('.') != -1) { + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, + m_aName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + + int nPos = m_xCatalog->find_text(sCatalog); + if (nPos != -1) + m_xCatalog->set_active(nPos); + + if ( !sSchema.isEmpty() ) { + nPos = m_xSchema->find_text(sSchema); + if (nPos != -1) + m_xSchema->set_active(nPos); + } + m_xTitle->set_text(sTable); + } else + m_xTitle->set_text(m_aName); + m_xTitle->select_region(0, -1); + + sal_Int32 nLength = m_xMetaData.is() ? m_xMetaData->getMaxTableNameLength() : 0; + if (nLength) + { + m_xTitle->set_max_length(nLength); + m_xSchema->set_entry_max_length(nLength); + m_xCatalog->set_entry_max_length(nLength); + } + + bool bCheck = _xConnection.is() && isSQL92CheckEnabled(_xConnection); + 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_aName(rDefault) + , m_rObjectNameCheck( _rObjectNameCheck ) + , m_nType(CommandType::COMMAND) + , m_nFlags(_nFlags) + , m_aChecker(OUString()) + , m_xDescription(m_xBuilder->weld_label("descriptionft")) + , m_xCatalogLbl(m_xBuilder->weld_label("catalogft")) + , m_xCatalog(m_xBuilder->weld_combo_box("catalog")) + , m_xSchemaLbl(m_xBuilder->weld_label("schemaft")) + , m_xSchema(m_xBuilder->weld_combo_box("schema")) + , m_xLabel(m_xBuilder->weld_label("titleft")) + , m_xTitle(m_xBuilder->weld_entry("title")) + , m_xPB_OK(m_xBuilder->weld_button("ok")) +{ + m_xTitle->connect_insert_text(LINK(this, OSaveAsDlg, TextFilterHdl)); + m_xSchema->connect_entry_insert_text(LINK(this, OSaveAsDlg, TextFilterHdl)); + m_xCatalog->connect_entry_insert_text(LINK(this, OSaveAsDlg, TextFilterHdl)); + implInitOnlyTitle(_sLabel); + implInit(); +} + +OSaveAsDlg::~OSaveAsDlg() +{ +} + +IMPL_LINK_NOARG(OSaveAsDlg, ButtonClickHdl, weld::Button&, void) +{ + m_aName = m_xTitle->get_text(); + + OUString sNameToCheck( m_aName ); + + if ( m_nType == CommandType::TABLE ) { + sNameToCheck = ::dbtools::composeTableName( + m_xMetaData, + getCatalog(), + getSchema(), + sNameToCheck, + false, // no quoting + ::dbtools::EComposeRule::InDataManipulation + ); + } + + SQLExceptionInfo aNameError; + if ( m_rObjectNameCheck.isNameValid( sNameToCheck, aNameError ) ) + m_xDialog->response(RET_OK); + + showError(aNameError, m_xDialog->GetXWindow(), m_xContext); + m_xTitle->grab_focus(); +} + +IMPL_LINK_NOARG(OSaveAsDlg, EditModifyHdl, weld::Entry&, void) +{ + m_xPB_OK->set_sensitive(!m_xTitle->get_text().isEmpty()); +} + +void OSaveAsDlg::implInitOnlyTitle(const OUString& _rLabel) +{ + m_xLabel->set_label(_rLabel); + m_xCatalogLbl->hide(); + m_xCatalog->hide(); + m_xSchemaLbl->hide(); + m_xSchema->hide(); + + m_xTitle->set_text(m_aName); + m_aChecker.setCheck(false); // enable non valid sql chars as well +} + +void OSaveAsDlg::implInit() +{ + if ( !( m_nFlags & SADFlags::AdditionalDescription ) ) { + // hide the description window + m_xDescription->hide(); + } + + if ( SADFlags::TitlePasteAs == ( m_nFlags & SADFlags::TitlePasteAs ) ) + m_xDialog->set_title( DBA_RES( STR_TITLE_PASTE_AS ) ); + else if ( SADFlags::TitleRename == ( m_nFlags & SADFlags::TitleRename ) ) + m_xDialog->set_title( DBA_RES( STR_TITLE_RENAME ) ); + + m_xPB_OK->connect_clicked(LINK(this,OSaveAsDlg,ButtonClickHdl)); + m_xTitle->connect_changed(LINK(this,OSaveAsDlg,EditModifyHdl)); + m_xTitle->grab_focus(); +} + +const OUString& OSaveAsDlg::getName() const +{ + return m_aName; +} +OUString OSaveAsDlg::getCatalog() const +{ + return m_xCatalog->get_visible() ? m_xCatalog->get_active_text() : OUString(); +} +OUString OSaveAsDlg::getSchema() const +{ + return m_xSchema->get_visible() ? 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 0000000000..be9e96612a --- /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 + +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 ? OUString("RowHeightDialog") : OUString("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(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(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 0000000000..4ae414881e --- /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 + +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 0000000000..1eb158daa8 --- /dev/null +++ b/dbaccess/source/ui/dlg/dsselect.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 "dsselect.hxx" + +#include +#include + +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& _rDatasources) + : GenericDialogController(_pParent, "dbaccess/ui/choosedatasourcedialog.ui", "ChooseDataSourceDialog") + , m_xDatasource(m_xBuilder->weld_tree_view("treeview")) +{ + 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 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& _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 0000000000..bfd0688980 --- /dev/null +++ b/dbaccess/source/ui/dlg/dsselect.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 +#include + +#include +#include + +class SfxItemSet; +namespace dbaui +{ +// ODatasourceSelector +class ODatasourceSelectDialog final : public weld::GenericDialogController +{ + std::unique_ptr m_xDatasource; +#ifdef HAVE_ODBC_ADMINISTRATION + std::unique_ptr m_xODBCManagement; +#endif + +public: + ODatasourceSelectDialog(weld::Window* pParent, const std::set& 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& _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 0000000000..611119a0c5 --- /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 + +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 0000000000..a487392a59 --- /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 +#include + +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 0000000000..a2a48158c5 --- /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 +#include +#include "dsnItem.hxx" +#include "generalpage.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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( _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( OUString _eType, OUString _sDisplayName ) : eType(std::move( _eType )), sDisplayName(std::move( _sDisplayName )) { } + }; + 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(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 >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(m_xSpecialMessage.get())); + } + + void OGeneralPage::fillControls(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back(new OSaveValueWidgetWrapper(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_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 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 && !pFilter->GetWildcard().Matches(sPath)) + { + OUString sMessage(DBA_RES(STR_ERR_USE_CONNECT_TO)); + std::unique_ptr 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 0000000000..57ea5f5a49 --- /dev/null +++ b/dbaccess/source/ui/dlg/generalpage.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 "adminpages.hxx" +#include + +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 m_xSpecialMessage; + + enum SPECIAL_MESSAGE + { + smNone, + smUnsupportedType + }; + SPECIAL_MESSAGE m_eLastMessage; + + Link 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 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& _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 ); + + // OGenericAdministrationPage::fillControls + virtual void fillControls(std::vector< std::unique_ptr >& _rControlList) override; + // OGenericAdministrationPage::fillWindows + virtual void fillWindows(std::vector< std::unique_ptr >& _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 m_xRB_CreateDatabase; + std::unique_ptr m_xRB_OpenExistingDatabase; + std::unique_ptr m_xRB_ConnectDatabase; + + std::unique_ptr m_xFT_EmbeddedDBLabel; + std::unique_ptr m_xEmbeddedDBType; + + std::unique_ptr m_xFT_DocListLabel; + std::unique_ptr m_xLB_DocumentList; + std::unique_ptr m_xPB_OpenDatabase; + + std::unique_ptr m_xFT_NoEmbeddedDBLabel; + + // state + OUString m_aBrowsedDocumentURL; + CreationMode m_eOriginalCreationMode; + + Link m_aCreationModeHandler; /// to be called if a new type is selected + Link m_aDocumentSelectionHandler; /// to be called when a document in the RecentDoc list is selected + Link 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& _rHandler ) { m_aCreationModeHandler = _rHandler; } + CreationMode GetDatabaseCreationMode() const; + + void SetDocumentSelectionHandler( const Link& _rHandler) { m_aDocumentSelectionHandler = _rHandler; } + void SetChooseDocumentHandler( const Link& _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 0000000000..d12602ce2e --- /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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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::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 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 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 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 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 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 OUString&, 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 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 xBuilder(Application::CreateBuilder(m_xDialog.get(), "dbaccess/ui/saveindexdialog.ui")); + std::unique_ptr 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(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 xError(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + sError)); + xError->run(); + + updateToolbox(); + m_bEditAgain = true; + std::unique_ptr 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 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 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 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 0000000000..35b0e3f02a --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 m_aAdditionalModifyHdl; + + public: + explicit DbaMouseDownListBoxController(ListBoxControl* _pParent) + :ListBoxCellController(_pParent) + { + } + + void SetAdditionalModifyHdl(const Link& _rHdl); + + protected: + virtual void callModifyHdl() override; + }; + + void DbaMouseDownListBoxController::SetAdditionalModifyHdl(const Link& _rHdl) + { + m_aAdditionalModifyHdl = _rHdl; + } + + void DbaMouseDownListBoxController::callModifyHdl() + { + m_aAdditionalModifyHdl.Call(*this); + ListBoxCellController::callModifyHdl(); + } + + // IndexFieldsControl + IndexFieldsControl::IndexFieldsControl(const css::uno::Reference &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::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::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(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(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 0000000000..b2f3a45ff9 --- /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 +#include "odbcconfig.hxx" + +#include +#include +#include +#include +#include +#include + +#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 + +#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(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(m_pSetEnvAttr))(m_pImpl->hEnvironment, SQL_ATTR_ODBC_VERSION, reinterpret_cast(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(m_pFreeHandle))(SQL_HANDLE_ENV, m_pImpl->hEnvironment); + m_pImpl->hEnvironment = nullptr; +#endif +} + +void OOdbcEnumeration::getDatasourceNames(std::set& _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(m_pDataSources))(m_pImpl->hEnvironment, SQL_FETCH_FIRST, szDSN, + sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription); + ; + nResult = (*reinterpret_cast(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(szDSN),pcbDSN, nTextEncoding); + _rNames.insert(aCurrentDsn); + } + } +#else + (void) _rNames; +#endif +} + +#ifdef HAVE_ODBC_ADMINISTRATION + +// ProcessTerminationWait +class ProcessTerminationWait : public ::osl::Thread +{ + oslProcess m_hProcessHandle; + Link m_aFinishHdl; + ImplSVEvent* m_nEventId; + +public: + ProcessTerminationWait( oslProcess _hProcessHandle, const Link& _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(); + 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& 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 0000000000..16177ad8a8 --- /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 +#include +#include + +#include +#include + +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 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& _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 m_aAsyncFinishCallback; + +public: + explicit OOdbcManagement( const Link& _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 0000000000..30d176391b --- /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( _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 0000000000..1c1d039e26 --- /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 + +#include + +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.has_value(); } + 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 0000000000..b6c7a55a22 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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()); // 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 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(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 0000000000..dcfa811c28 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 xSelectColumns = Reference(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 > 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. .

becomes ""."
" + OUString aCatalog,aSchema,aTable; + ::dbtools::qualifiedNameComponents( m_xMetaData, sTableName, aCatalog, aSchema, aTable, ::dbtools::EComposeRule::InDataManipulation ); + sTableName = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation ); + } + } + xColumn->getPropertyValue(PROPERTY_REALNAME) >>= _rFilter.Name; + static constexpr OUString sAgg = u"AggregateFunction"_ustr; + if ( xInfo->hasPropertyByName(sAgg) ) + xColumn->getPropertyValue(sAgg) >>= bHaving; + static constexpr OUString sFunction = u"Function"_ustr; + 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 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(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 ; iget_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 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 > 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 >& _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 >& _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* pOrIter = _aValues.getConstArray(); + const Sequence* 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 0000000000..1bad7a802f --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 constexpr OUStringLiteral sNameProperty = u"Name"; + static constexpr 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 xMetaData = m_xConnection->getMetaData(); + OUString sQuote = xMetaData.is() ? xMetaData->getIdentifierQuoteString() : OUString(); + + OUStringBuffer sOrder; + for( sal_uInt16 i=0 ; iget_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 0000000000..e5cd612c28 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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(OUString defaultImageID) + : m_defaultImageID(std::move(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(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( 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 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 m_xExceptionList; + std::unique_ptr 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(aTmp); +} + +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, OUString sHelpURL) + : m_pImpl(new SQLMessageBox_Impl(rException)) + , m_sHelpURL(std::move(sHelpURL)) +{ + Construct(pParent, nStyle, AUTO); +} + +OSQLMessageBox::OSQLMessageBox(weld::Window* pParent, const OUString& rTitle, const OUString& rMessage, MessBoxStyle nStyle, MessageType eType, const ::dbtools::SQLExceptionInfo* pAdditionalErrorInfo ) +{ + css::uno::Any next; + if (pAdditionalErrorInfo) + next = pAdditionalErrorInfo->get(); + SQLContext aError(rTitle, {}, {}, 0, next, rMessage); + + 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 0000000000..aeba434ab8 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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 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 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(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 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 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(DSID_TABLEFILTER); + Sequence< OUString > aTableFilter; + if (pTableFilter) + aTableFilter = pTableFilter->getList(); + + implCompleteTablesCheck( aTableFilter ); + + // expand the first entry by default + std::unique_ptr xExpand = m_xTablesList->getAllObjectsEntry(); + while (xExpand) + { + m_xTablesList->GetWidget().expand_row(*xExpand); + if (!m_xTablesList->GetWidget().iter_children(*xExpand)) + break; + std::unique_ptr 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 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 OUString sWildcard = u"%"_ustr; + + std::unique_ptr xAllObjectsEntry(m_xTablesList->getAllObjectsEntry()); + if (!xAllObjectsEntry) + return aTableFilter; + std::unique_ptr 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 xSchema; + std::unique_ptr 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 OTableSubscriptionPage::implNextSibling(const weld::TreeIter* pEntry) const + { + std::unique_ptr xReturn; + if (pEntry) + { + xReturn = m_xTablesList->GetWidget().make_iterator(pEntry); + if (!m_xTablesList->GetWidget().iter_next_sibling(*xReturn)) + { + std::unique_ptr 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 >& /*_rControlList*/) + { + } + + void OTableSubscriptionPage::fillWindows(std::vector< std::unique_ptr >& _rControlList) + { + _rControlList.emplace_back(new ODisableWidgetWrapper(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 0000000000..483518b2ad --- /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 +#include + +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 m_xTables; + std::unique_ptr 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 >& _rControlList) override; + virtual void fillWindows(std::vector< std::unique_ptr >& _rControlList) override; + + DECL_LINK(OnTreeEntryChecked, const weld::TreeView::iter_col&, void); + + /** check the tables in m_aTablesList according to _rTables + */ + 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 implNextSibling(const weld::TreeIter* pEntry) const; + + /** return the current selection in m_aTablesList + */ + 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 0000000000..5076b3d328 --- /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 +#include "TextConnectionHelper.hxx" +#include +#include + +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( _rSet, DSID_TEXTFILEHEADER ); + _rValues[ PROPERTY_ID_FIELD_DELIMITER ] = std::make_shared( _rSet, DSID_FIELDDELIMITER ); + _rValues[ PROPERTY_ID_STRING_DELIMITER ] = std::make_shared( _rSet, DSID_TEXTDELIMITER ); + _rValues[ PROPERTY_ID_DECIMAL_DELIMITER ] = std::make_shared( _rSet, DSID_DECIMALDELIMITER ); + _rValues[ PROPERTY_ID_THOUSAND_DELIMITER ] = std::make_shared( _rSet, DSID_THOUSANDSDELIMITER ); + _rValues[ PROPERTY_ID_ENCODING ] = std::make_shared( _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 0000000000..b7265e5af6 --- /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 + +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 class PreviewMode + { + NONE = 0, + Document = 1, + DocumentInfo = 2 + }; + + enum class ElementOpenMode + { + Normal, + Design, + 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 0000000000..c2f68ac46f --- /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 + +namespace dbaui +{ +class OChildWindow +{ +protected: + OChildWindow(weld::Container* pParent, const OUString& rUIXMLDescription, const OUString& rID); + std::unique_ptr m_xBuilder; + std::unique_ptr 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 OUString& 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 0000000000..c49a5fd4fc --- /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 +#include +#include +#include + +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 m_xFTCurrentPath; + std::unique_ptr m_xNewFolder; + std::unique_ptr m_xUp; + std::unique_ptr m_xView; + std::unique_ptr m_xName; + std::unique_ptr 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, + css::uno::Reference< css::uno::XComponentContext > _xContext); + 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 0000000000..e68b99067e --- /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 +#include +#include + +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 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 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 0000000000..360395f94b --- /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 +#include "ConnectionLineData.hxx" +#include + +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 m_pTabConn; + OConnectionLineDataRef m_pData; + + Point m_aSourceConnPos, + m_aDestConnPos; + Point m_aSourceDescrLinePos, + m_aDestDescrLinePos; + public: + OConnectionLine( OTableConnection* pConn, OConnectionLineDataRef 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 0000000000..5e14186b07 --- /dev/null +++ b/dbaccess/source/ui/inc/ConnectionLineAccess.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 "TableConnection.hxx" +#include +#include +#include +#include + +namespace dbaui +{ + 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 cppu::ImplInheritanceHelper< + VCLXAccessibleComponent, + css::accessibility::XAccessibleRelationSet, + css::accessibility::XAccessible> + { + VclPtr 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); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int64 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 i ) override; + virtual sal_Int64 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 0000000000..2a41c93d9a --- /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 + +#include +#include +#include + +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( OUString sSourceFieldName, OUString sDestFieldName ); + 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 0000000000..a799996470 --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 TColumns; + typedef std::vector TColumnVector; + typedef std::vector< std::pair > TPositions; + + protected: + TPositions m_vColumnPositions; ///< columns to be used + std::vector m_vColumnTypes; ///< ColumnTypes for faster access + std::vector m_vColumnSize; + std::vector 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 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 > createPreparedStatement( 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 0000000000..7eb88ec4e0 --- /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 + +namespace dbaui +{ + + class OPropColumnEditCtrl : public OSQLNameEntry + { + short m_nPos; + OUString m_strHelpText; + public: + OPropColumnEditCtrl(std::unique_ptr 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 m_xEntry; + short m_nPos; + OUString m_strHelpText; + + public: + OPropEditCtrl(std::unique_ptr 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 m_xSpinButton; + short m_nPos; + OUString m_strHelpText; + + public: + OPropNumericEditCtrl(std::unique_ptr 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 m_xComboBox; + short m_nPos; + OUString m_strHelpText; + + public: + OPropListBoxCtrl(std::unique_ptr 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 0000000000..410e086116 --- /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 +#include "IClipBoardTest.hxx" +#include "QEnumTypes.hxx" +#include +#include +#include "TypeInfo.hxx" +#include + +// 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 m_xBuilder; + std::unique_ptr m_xContainer; + + OTableDesignHelpBar* m_pHelp; + weld::Widget* m_pLastFocusWindow; + weld::Widget* m_pActFocusWindow; + + std::unique_ptr m_xDefaultText; + std::unique_ptr m_xRequiredText; + std::unique_ptr m_xAutoIncrementText; + std::unique_ptr m_xTextLenText; + std::unique_ptr m_xNumTypeText; + std::unique_ptr m_xLengthText; + std::unique_ptr m_xScaleText; + std::unique_ptr m_xFormatText; + std::unique_ptr m_xBoolDefaultText; + std::unique_ptr m_xColumnNameText; + std::unique_ptr m_xTypeText; + std::unique_ptr m_xAutoIncrementValueText; + + std::unique_ptr m_xRequired; + std::unique_ptr m_xNumType; + std::unique_ptr m_xAutoIncrement; + std::unique_ptr m_xDefault; + std::unique_ptr m_xTextLen; + std::unique_ptr m_xLength; + std::unique_ptr m_xScale; + std::unique_ptr m_xFormatSample; + std::unique_ptr m_xBoolDefault; + std::unique_ptr m_xColumnName; + std::unique_ptr m_xType; + std::unique_ptr m_xAutoIncrementValue; + + std::unique_ptr m_xFormat; + + Link 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 CreateNumericControl(const OUString& rId, TranslateId pHelpId, short _nProperty, const OUString& _sHelpId); + void InitializeControl(weld::Widget* _pControl,const OUString& _sHelpId); + void InitializeControl(OPropListBoxCtrl* _pControl,const OUString& _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 OUString& 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& 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 0000000000..5eccd74309 --- /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 +#include "TypeInfo.hxx" +#include +#include + +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 0000000000..1bbb593e33 --- /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 +#include + +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 0000000000..5c4ddde13f --- /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 +#include +#include +#include + +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 0000000000..e3eb049627 --- /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 + +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 0000000000..cdc1026eaf --- /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 +#include +#include + +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 0000000000..e6ef24a967 --- /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 +#include +#include + +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 0000000000..6d0d52ec02 --- /dev/null +++ b/dbaccess/source/ui/inc/JAccess.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 "JoinTableView.hxx" +#include +#include +#include + +namespace dbaui +{ + class OJoinTableView; + /** the class OJoinDesignViewAccess represents the accessible object for join views + like the QueryDesign and the RelationDesign + */ + class OJoinDesignViewAccess : public cppu::ImplInheritanceHelper + { + VclPtr m_pTableView; // the window which I should give accessibility to + + public: + /** OJoinDesignViewAccess needs a valid view + */ + OJoinDesignViewAccess( OJoinTableView* _pTableView); + + virtual OUString SAL_CALL getImplementationName() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int64 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 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 0000000000..9410823222 --- /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 + +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 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 0000000000..f4871e9df5 --- /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 + +class Splitter; + +namespace dbaui +{ + class OJoinController; + class OScrollWindowHelper; + class OJoinTableView; + class OTableWindow; + + class OJoinDesignView : public ODataView + { + protected: + VclPtr m_pScrollWindow; // contains only the scrollbars + VclPtr 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 0000000000..7401ec886e --- /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 +#include +#include + +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 0000000000..9e2e2bf57e --- /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 +#include +#include +#include +#include +#include + +#include "callbacks.hxx" +#include "TableConnectionData.hxx" +#include "TableWindowData.hxx" + +#include +#include + +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 m_aHScrollBar; + VclPtr m_aVScrollBar; + VclPtr 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 + ScrollAdaptor& GetHScrollBar() { return *m_aHScrollBar; } + ScrollAdaptor& GetVScrollBar() { return *m_aVScrollBar; } + }; + + + class OJoinTableView : public vcl::Window, + public IDragTransferableListener, + public DropTargetHelper + { + friend class OJoinMoveTabWinUndoAct; + + public: + typedef std::map > OTableWindowMap; + + private: + OTableWindowMap m_aTableMap; + std::vector > 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 m_pDragWin; + VclPtr m_pSizingWin; + VclPtr m_pSelectedConn; + + + DECL_LINK(OnDragScrollTimer, Timer*, void); + + protected: + VclPtr m_pLastFocusTabWin; + VclPtr m_pView; + rtl::Reference 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 + ScrollAdaptor& GetHScrollBar() { return static_cast(GetParent())->GetHScrollBar(); } + ScrollAdaptor& GetVScrollBar() { return static_cast(GetParent())->GetVScrollBar(); } + DECL_LINK(VertScrollHdl, weld::Scrollbar&, void); + DECL_LINK(HorzScrollHdl, weld::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& 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_Int64 GetTabWinCount() const; + const Point& GetScrollOffset() const { return m_aScrollOffset; } + + OJoinDesignView* getDesignView() const { return m_pView; } + OTableWindow* GetTabWindow( const OUString& rName ); + + VclPtr& 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 >& 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 >::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& 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 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 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& 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 _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 0000000000..b889870c9b --- /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 0000000000..efef444e86 --- /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 +#include +#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 m_aSplitter; + + css::lang::Locale m_aLocale; + OUString m_sDecimalSep; + + VclPtr 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 , the instance pointed to by this parameter takes the error + which happened during the initialization. + If it is not , then any such error will be displayed, using the controller's + showError method. + + @return 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 0000000000..2d8bb80dcf --- /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 + +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 m_xRB_Distinct; + std::unique_ptr m_xRB_NonDistinct; + std::unique_ptr 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 0000000000..26133d2cca --- /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& rConnection) override; + + virtual VclPtr 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& 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 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 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 0000000000..33f66342b2 --- /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 +#include "querycontainerwindow.hxx" +#include "sqledit.hxx" + +namespace dbaui +{ + class OQueryTextView final : public InterimItemWindow + { + friend class OQueryViewSwitch; + + OQueryController& m_rController; + std::unique_ptr m_xSQL; + std::unique_ptr 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 0000000000..0f17d40bdc --- /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 +#include +#include + +namespace dbtools +{ + class SQLExceptionInfo; +} + +namespace dbaui +{ + class OQueryDesignView; + class OQueryTextView; + class OAddTableDlg; + class OQueryContainerWindow; + class OQueryController; + + class OQueryViewSwitch final + { + VclPtr m_pDesignView; + VclPtr 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 + if and only if the view could be successfully, switched, 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 0000000000..0dd40e2fab --- /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 +#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 NewInstance() const override { return std::make_shared(); } + + /** 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 0000000000..65ef79db0d --- /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 0000000000..5d4edee2aa --- /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 +#include "JoinTableView.hxx" + +namespace dbaui +{ + class OTableListBoxControl; + class IRelationControlInterface; + class ORelationControl; + + class OTableListBoxControl final + { + std::unique_ptr m_xLeftTable; + std::unique_ptr m_xRightTable; + std::unique_ptr m_xTable; + css::uno::Reference m_xTableCtrlParent; + VclPtr 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 0000000000..a457f38b80 --- /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 +#include + +#include "JoinController.hxx" + +namespace weld +{ + class WaitObject; +} + +namespace dbaui +{ + class ORelationController : public OJoinController + { + css::uno::Reference< css::container::XNameAccess > m_xTables; + std::unique_ptr 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 0000000000..2fba88be08 --- /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 0000000000..c4285f04aa --- /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 +#include +#include "JoinTableView.hxx" +#include "RelControliFace.hxx" +#include "RelationControl.hxx" + +namespace dbaui +{ + class OJoinTableView; + class ORelationDialog final : public weld::GenericDialogController + , public IRelationControlInterface + { + VclPtr m_pParent; + TTableConnectionData::value_type m_pConnData; + TTableConnectionData::value_type m_pOrigConnData; + bool m_bTriedOneUpdate; + + std::unique_ptr m_xRB_NoCascUpd; + std::unique_ptr m_xRB_CascUpd; + std::unique_ptr m_xRB_CascUpdNull; + std::unique_ptr m_xRB_CascUpdDefault; + std::unique_ptr m_xRB_NoCascDel; + std::unique_ptr m_xRB_CascDel; + std::unique_ptr m_xRB_CascDelNull; + std::unique_ptr m_xRB_CascDelDefault; + std::unique_ptr m_xPB_OK; + + std::unique_ptr 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 0000000000..6c178a3de9 --- /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 +#include +#include + +namespace dbaui +{ + class ORelationDesignView; + + class ORelationTableView : public ::cppu::BaseMutex, + public OJoinTableView, + public ::comphelper::OContainerListener + { + VclPtr 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& rConnection) override; + virtual void AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool bNewTable = false) override; + + virtual VclPtr 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& 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 0000000000..58f6aa26ba --- /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 +#include +#include "DExport.hxx" + +class SvStream; + +namespace dbaui +{ + class ORTFReader final : public SvRTFParser , public ODatabaseExport + { + std::vector 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 0000000000..14d845b4b1 --- /dev/null +++ b/dbaccess/source/ui/inc/SqlNameEdit.hxx @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + +namespace dbaui +{ + class OSQLNameChecker + { + OUString m_sAllowedChars; + bool m_bCheck; // true when we should check for invalid chars + public: + OSQLNameChecker(OUString _sAllowedChars) + :m_sAllowedChars(std::move(_sAllowedChars)) + ,m_bCheck(true) + { + } + + void setAllowedChars(const OUString& _rAllowedChars) + { + m_sAllowedChars = _rAllowedChars; + } + void setCheck(bool _bCheck) + { + m_bCheck = _bCheck; + } + bool checkString(std::u16string_view _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& rLink) override + { + m_ChainChangedHdl = rLink; + } + + private: + DECL_LINK(ModifyHdl, weld::Entry&, void); + + Link 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 m_xEntry; + + DECL_LINK(ModifyHdl, weld::Entry&, void); + + public: + OSQLNameEntry(std::unique_ptr 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 0000000000..a38aa1fe03 --- /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 +#include +#include +#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> m_vConnLine; + TTableConnectionData::value_type + m_pData; + VclPtr m_pParent; + + bool m_bSelected; + + void Init(); + /** loops through the vector and deletes all lines */ + void clearLineData(); + + public: + OTableConnection( OJoinTableView* pContainer, TTableConnectionData::value_type aTabConnData ); + 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>& 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 0000000000..096a6de70a --- /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 +#include + +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( TTableWindowData::value_type _aReferencingTable, + TTableWindowData::value_type _aReferencedTable ); + 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 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 > 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 0000000000..ce2017b586 --- /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 +#include "TypeInfo.hxx" +#include +#include +#include + +namespace dbaui +{ + class OTableRow; + typedef OSingleDocumentController OTableController_BASE; + class OTableController final : public OTableController_BASE + { + private: + std::vector< std::shared_ptr > m_vRowList; + OTypeInfoMap m_aTypeInfo; + std::vector 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 >& 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 0000000000..b543dade80 --- /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 +#include +#include +#include +#include +#include + +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 aHtmlRtfStorage; + ElementType nType; + std::unique_ptr 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 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 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 if the clipboard supports a table format, otherwise . + 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 0000000000..89debc9e11 --- /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 + +#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 0000000000..db4023d36c --- /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 +#include "IClipBoardTest.hxx" + +namespace dbaui +{ + class OTableDesignHelpBar final : public IClipboardTest + { + private: + std::unique_ptr m_xTextWin; + + public: + OTableDesignHelpBar(std::unique_ptr xTextWin); + + void SetHelpText( const OUString& rText ); + + bool HasFocus() const { return m_xTextWin->has_focus(); } + + void connect_focus_in(const Link& rLink) + { + m_xTextWin->connect_focus_in(rLink); + } + + void connect_focus_out(const Link& 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 0000000000..077eb211e3 --- /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 +#include +#include +#include +#include "IClipBoardTest.hxx" + +namespace dbaui +{ + class OTableController; + class OTableDesignView; + class OTableFieldDescWin; + class OTableEditorCtrl; + + class OTableBorderWindow final : public InterimItemWindow + { + std::unique_ptr m_xHorzSplitter; + std::unique_ptr m_xEditorParent; + css::uno::Reference m_xEditorParentWin; + VclPtr m_xEditorCtrl; + std::unique_ptr m_xFieldDescParent; + std::unique_ptr 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 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 0000000000..d21ad953ab --- /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 + +#include "QEnumTypes.hxx" +#include +#include +#include +#include +#include + +#include + +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 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 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 0000000000..74a9fd8b58 --- /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 + +#include + +#include +#include +#include +#include +#include + +class Edit; +namespace dbaui +{ + +class OTableGrantControl : public ::svt::EditBrowseBox +{ + typedef struct + { + sal_Int32 nRights; + sal_Int32 nWithGrant; + } TPrivileges; + + typedef std::map 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 &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 0000000000..4f34a94bf5 --- /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 +#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 then the row is readonly, otherwise not + */ + void SetReadOnly( bool _bRead=true ){ m_bReadOnly = _bRead; } + + /** returns if the row is readonly + @return + if readonly, otherwise + */ + 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 0000000000..36e2497951 --- /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 +#include + +namespace dbaui +{ + class OTableRow; + class OTableRowExchange : public TransferableHelper + { + std::vector< std::shared_ptr > m_vTableRow; + public: + OTableRowExchange(std::vector< std::shared_ptr >&& _rvTableRow); + protected: + virtual void AddSupportedFormats() override; + virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override; + virtual bool WriteObject( tools::SvRef& 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 0000000000..2ccf236d0c --- /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 +#include +#include "TableWindowTitle.hxx" +#include +#include "TableWindowData.hxx" +#include "TableWindowListBox.hxx" +#include +#include + +#include +#include +#include + +// 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 : is_typed_flags {}; +} + + +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 m_xTitle; + VclPtr 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 . _pUserData will be set to after call. + */ + virtual void deleteUserData(void*& _pUserData); + + /** creates user information that will be append at the ListBoxentry + @param _xColumn + The corresponding column, can be . + @param _bPrimaryKey + when the column belongs to the primary key + @return + the user data which will be append at the listbox entry, may be + */ + virtual void* createUserData(const css::uno::Reference< + css::beans::XPropertySet>& _xColumn, + bool _bPrimaryKey); + + /** updates image + */ + void impl_updateImage(); + + OTableWindow( vcl::Window* pParent, TTableWindowData::value_type aTabWinData ); + + 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& GetListBox() const { return m_xListBox; } + const TTableWindowData::value_type& GetData() const { return m_pData; } + const VclPtr& 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 0000000000..09aa268f1e --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindowAccess.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 "TableWindow.hxx" +#include +#include +#include +#include + +namespace dbaui +{ + 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 cppu::ImplInheritanceHelper< + VCLXAccessibleComponent, + css::accessibility::XAccessibleRelationSet, + css::accessibility::XAccessible> + { + VclPtr m_pTable; // the window which I should give accessibility to + + css::uno::Reference< css::accessibility::XAccessible > getParentChild(sal_Int64 _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); + + // 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_Int64 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 i ) override; + virtual sal_Int64 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 0000000000..0160ea7233 --- /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 +#include +#include +#include +#include +#include +#include +#include + +namespace dbaui +{ + class OTableWindowData : public ::utl::OEventListenerAdapter + { + mutable ::osl::Mutex m_aMutex; + + void listen(); + + // 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 + ,OUString _sComposedName + ,OUString strTableName + ,OUString sWinName ); + 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 > 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 0000000000..cdad4947ca --- /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 +#include +#include "callbacks.hxx" + +struct AcceptDropEvent; +struct ExecuteDropEvent; +namespace dbaui +{ + class OTableWindowListBox; + struct OJoinExchangeData + { + public: + VclPtr 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 m_xTreeView; + std::unique_ptr 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 m_xHelper; + + VclPtr 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& 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 0000000000..0a3779bd88 --- /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 + +namespace dbaui +{ + class OTableWindow; + class OTableWindowTitle final : public InterimItemWindow + { + VclPtr m_pTabWin; + std::unique_ptr m_xLabel; + std::unique_ptr 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 0000000000..c75fa1eb3d --- /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 +#include "IItemSetHelper.hxx" +#include + +#include + +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 m_pImpl; + bool m_bStopExecution; // set when the dialog should not be executed + + std::unique_ptr 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 0000000000..b82bd71a5f --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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( SharedConnection _xConnection, + 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 m_aColumnMapping; + std::vector 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 0000000000..e9958e8e8d --- /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 +#include +#include +#include +#include + +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 TOTypeInfoSP; + typedef std::multimap 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 0000000000..c622c73f65 --- /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 +#include +#include "TypeInfo.hxx" +#include +#include +#include +#include + +#include +#include + +#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& _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 SQLExceptions 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 InteractionHandler. + + @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 , 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& _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 + if so otherwise + */ + 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 + if so otherwise + */ + 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 + Set to sal_True when the property was set in the datasource. + @param _rsAutoIncrementValue + 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 + Set to sal_True when the property was set in the datasource. + @param _rsAutoIncrementValue + 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 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 , 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 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 + if a form should be inserted + @param _bCollection + A folder should be inserted + @param _xContent + The content which should be copied. + @param _bMove + if the name of the content must be inserted without any change, otherwise not. + @return + if the insert operation was successful, otherwise . + */ + 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 0000000000..95edbe5f55 --- /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 +#include "IItemSetHelper.hxx" +#include + +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 m_pImpl; + SfxItemSet* m_pItemSet; + css::uno::Reference< css::sdbc::XConnection> m_xConnection; + bool m_bOwnConnection; + protected: + virtual void PageCreated(const OUString& 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 0000000000..69dc96f144 --- /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 m_xEdTableName; + std::unique_ptr m_xRB_DefData; + std::unique_ptr m_xRB_Def; + std::unique_ptr m_xRB_View; + std::unique_ptr m_xRB_AppendData; + std::unique_ptr m_xCB_UseHeaderLine; + std::unique_ptr m_xCB_PrimaryColumn; + std::unique_ptr m_xFT_KeyName; + std::unique_ptr 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 0000000000..38b1317fd5 --- /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 + +namespace dbaui +{ + class OFieldDescription; + + // Wizard Page: OWizColumnSelect + + class OWizColumnSelect : public OWizardPage + { + std::unique_ptr m_xOrgColumnNames; // left side + std::unique_ptr m_xColumn_RH; + std::unique_ptr m_xColumns_RH; + std::unique_ptr m_xColumn_LH; + std::unique_ptr m_xColumns_LH; + std::unique_ptr 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 0000000000..d3c0672f8e --- /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 +#include +#include +#include +#include +#include +#include "TypeInfo.hxx" +#include +#include "DExport.hxx" +#include "WTabPage.hxx" +#include "FieldDescriptions.hxx" +#include +#include +#include +#include +#include + +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, + OUString _sTableName + ); + + // 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 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 m_aTypeInfoIndex; + OTypeInfoMap m_aDestTypeInfo; + std::vector m_aDestTypeInfoIndex; + TNameMapping m_mNameMapping; + + ODatabaseExport::TPositions m_vColumnPositions; + std::vector 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 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, + OUString _sDefaultName, + 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 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& 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 0000000000..7d75f2cc1a --- /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 Create(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rInput ) { return std::make_unique(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 Create(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream& rInput) { return std::make_unique(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 0000000000..d108c043c6 --- /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 m_xTABLE_LEFT; + std::unique_ptr m_xTABLE_RIGHT; + std::unique_ptr m_xCTRL_LEFT; // left side + std::unique_ptr m_xCTRL_RIGHT; // right side + std::unique_ptr m_xColumn_up; + std::unique_ptr m_xColumn_down; + std::unique_ptr m_xColumn_up_right; + std::unique_ptr m_xColumn_down_right; + std::unique_ptr m_xAll; + std::unique_ptr 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 0000000000..ef3d7f23b2 --- /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 + +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 OUString& 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 0000000000..56af0e355d --- /dev/null +++ b/dbaccess/source/ui/inc/WTypeSelect.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 "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 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 m_aChangeHdl; + + public: + OWizTypeSelectList(std::unique_ptr 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& 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 m_xColumnNames; + std::unique_ptr m_xControlContainer; + std::unique_ptr m_xTypeControl; + std::unique_ptr m_xAutoType; + std::unique_ptr m_xAutoFt; + std::unique_ptr m_xAutoEt; + std::unique_ptr 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 (*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 0000000000..5fe1d7c1da --- /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 +#include +#include +#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 m_xCaseTables; + std::unique_ptr m_xCaseQueries; + + std::unique_ptr m_xTableList; + std::unique_ptr m_xQueryList; + + std::unique_ptr m_xAddButton; + std::unique_ptr 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 0000000000..7c38562145 --- /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 +#include + +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 m_pImpl; + + protected: + virtual void PageCreated(const OUString& 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 0000000000..483dfb7c16 --- /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 + +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 + @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 0000000000..0c510497de --- /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 +#include + +#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 0000000000..e5e1db401a --- /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 +#include "brwview.hxx" +#include "sbagrid.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 + 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 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 0000000000..0933861b8c --- /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 + +#include +#include +#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 m_pTreeView; + VclPtr m_pSplitter; + mutable VclPtr 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 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 0000000000..e380b2671d --- /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 + +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 if the default quick help text should be used + */ + virtual bool requestQuickHelp(const void* pUserData, OUString& rText) const = 0; + + /** handler for StartDrag requests + @return 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//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 0000000000..a12b425cd9 --- /dev/null +++ b/dbaccess/source/ui/inc/charsetlistbox.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 +#include +#include "charsets.hxx" + +class SfxItemSet; +class SfxStringItem; + +namespace dbaui +{ + // CharSetListBox + class CharSetListBox + { + public: + CharSetListBox(std::unique_ptr xControl); + + void SelectEntryByIanaName( std::u16string_view _rIanaName ); + bool StoreSelectedCharSet( SfxItemSet& _rSet, TypedWhichId _nItemId ); + + weld::ComboBox* get_widget() { return m_xControl.get(); } + void connect_changed(const Link& rLink) { m_xControl->connect_changed(rLink); } + void show() { m_xControl->show(); } + + private: + OCharsetDisplay m_aCharSets; + std::unique_ptr 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 0000000000..49977bd562 --- /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 +#include + +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(std::u16string_view _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, OUString _sDisplayName); + }; + + //- 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, base_iterator _aPosition ); + }; + +} // 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 0000000000..50c5670104 --- /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 + +#include + +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 0000000000..6042f761ce --- /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 +#include + +namespace dbaui +{ + +class OConnectionURLEdit +{ + OUString m_sSavedValue; + + ::dbaccess::ODsnTypeCollection* m_pTypeCollection; + OUString m_sSaveValueNoPrefix; + bool m_bShowPrefix; // when the prefix will be visible, otherwise not + + std::unique_ptr m_xEntry; + std::unique_ptr m_xForcedPrefix; + +public: + OConnectionURLEdit(std::unique_ptr xEntry, std::unique_ptr xForcedPrefix); + ~OConnectionURLEdit(); + +public: + bool get_visible() const { return m_xEntry->get_visible(); } + void connect_changed(const Link& rLink) { m_xEntry->connect_changed(rLink); } + void set_help_id(const OUString& 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& rLink) + { + m_xEntry->connect_focus_in(rLink); + } + void connect_focus_out(const Link& 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 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 0000000000..46df991816 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 fillDispatchArgs, followed + by doDispatch. + + @param _rDataSource + the data source, as passed to the createNew or openExisting 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, + OUString _sComponentURL + ); + 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 , 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 0000000000..56f7bf2f06 --- /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 +#include +#include + +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, + OUString _sContextInformation + ); + + /// returns 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 0000000000..53222a6afc --- /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 +#include +#include "IItemSetHelper.hxx" +#include +#include + +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 m_pImpl; + + OUString m_sMainPageID; + +public: + /** ctor. The itemset given should have been created by createItemSet 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 ODatasourceMap. May be NULL, in this case + the pool will not contain a typecollection default. + */ + static void createItemSet(std::unique_ptr& _rpSet, rtl::Reference& _rpPool, std::vector*& _rpDefaults, ::dbaccess::ODsnTypeCollection* _pTypeCollection); + /** destroy and item set / item pool / pool defaults previously created by createItemSet + */ + static void destroyItemSet(std::unique_ptr& _rpSet, rtl::Reference& _rpPool, std::vector*& _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 OUString& rPageId, TranslateId pTextId, CreateTabPage pCreateFunc); + + virtual void PageCreated(const OUString& 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 _rxDatasource + 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 0000000000..7fb0c6ee0b --- /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 +#include +#include + +#include + +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& 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 0000000000..7682841a23 --- /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 +#include +#include +#include + +#include + +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 m_xTreeView; + TreeListBoxDropTarget m_aDropTargetHelper; + + std::unique_ptr 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 m_xHelper; + + Link m_aSelChangeHdl; // handler to be called (asynchronously) when the selection changes in any way + Link m_aCopyHandler; // called when someone press CTRL+C + Link m_aPasteHandler; // called when someone press CTRL+V + Link 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 xTreeView, bool bSQLType); + virtual ~TreeListBox(); + + std::unique_ptr GetEntryPosByName(std::u16string_view rName, + const weld::TreeIter* pStart = nullptr, + const IEntryFilter* pFilter = nullptr) const; + + std::unique_ptr 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& _rHdl ) { m_aSelChangeHdl = _rHdl; } + void setCopyHandler(const Link& _rHdl) { m_aCopyHandler = _rHdl; } + void setPasteHandler(const Link& _rHdl) { m_aPasteHandler = _rHdl; } + void setDeleteHandler(const Link& _rHdl) { m_aDeleteHandler = _rHdl; } + }; + + class InterimDBTreeListBox : public InterimItemWindow + , public TreeListBox + { + private: + std::unique_ptr 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 m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr 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 0000000000..ed97c4c937 --- /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 0000000000..744c308a68 --- /dev/null +++ b/dbaccess/source/ui/inc/dbwiz.hxx @@ -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 . + */ + +#pragma once + +#include +#include "IItemSetHelper.hxx" +#include +#include + +namespace com::sun::star { + namespace beans { + class XPropertySet; + } + namespace sdbc { + class XConnection; + } + namespace lang { + class XMultiServiceFactory; + } +} + +using vcl::WizardTypes::WizardState; + +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 m_pImpl; + std::unique_ptr m_pOutSet; + ::dbaccess::ODsnTypeCollection* + m_pCollection; /// the DSN type collection instance + OUString m_eType; + +public: + /** ctor. The itemset given should have been created by createItemSet 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 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 0000000000..50f463fac4 --- /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 +#include "IItemSetHelper.hxx" +#include +#include +#include + +namespace com::sun::star { + namespace beans { + class XPropertySet; + } + namespace sdbc { + class XConnection; + } + namespace lang { + class XMultiServiceFactory; + } +} + +using vcl::WizardTypes::WizardState; +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 m_pImpl; + std::unique_ptr 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_PostgresText; + 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 createItemSet 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 if the database should be opened, otherwise . + */ + bool IsDatabaseDocumentToBeOpened() const; + + /** returns if the table wizard should be opened, otherwise . + */ + 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 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 0000000000..c75528940e --- /dev/null +++ b/dbaccess/source/ui/inc/defaultobjectnamecheck.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 "objectnamecheck.hxx" + +#include +#include +#include + +#include + +namespace dbaui +{ + + // HierarchicalNameCheck + /** class implementing the IObjectNameCheck interface, and checking given object names + against a hierarchical name container + */ + class HierarchicalNameCheck :public IObjectNameCheck + { + private: + css::uno::Reference< css::container::XHierarchicalNameAccess > mxHierarchicalNames; + OUString msRelativeRoot; + + 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 + */ + 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 + /** 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: + sal_Int32 mnCommandType; + css::uno::Reference< css::sdb::tools::XObjectNames > mxObjectNames; + + 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 , 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 0000000000..bfe8195fc5 --- /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 + +#include +#include +#include + +#include +#include +#include + +#include "sqledit.hxx" + +struct ImplSVEvent; + +namespace dbaui +{ + // DirectSQLDialog + class DirectSQLDialog final + : public weld::GenericDialogController + , public ::utl::OEventListenerAdapter + { + ::osl::Mutex m_aMutex; + + std::unique_ptr m_xExecute; + std::unique_ptr m_xSQLHistory; + std::unique_ptr m_xStatus; + std::unique_ptr m_xDirectSQL; + std::unique_ptr m_xShowOutput; + std::unique_ptr m_xOutput; + std::unique_ptr m_xClose; + std::unique_ptr m_xSQL; + std::unique_ptr 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 0000000000..83fe0466e4 --- /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 + +class SvxNumberInfoItem; +class SfxItemSet; +class SvNumberFormatter; +namespace dbaui +{ + + class SbaSbAttrDlg : public SfxTabDialogController + { + std::unique_ptr pNumberInfoItem; + + public: + SbaSbAttrDlg(weld::Widget* pParent, const SfxItemSet*, SvNumberFormatter*, bool bHasFormat); + virtual ~SbaSbAttrDlg() override; + + virtual void PageCreated(const OUString& 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 0000000000..f3b33a2785 --- /dev/null +++ b/dbaccess/source/ui/inc/dlgsave.hxx @@ -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 . + */ + +#pragma once + +#include "SqlNameEdit.hxx" +#include +#include +#include +#include +#include + +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 : is_typed_flags {}; +} + +namespace dbaui +{ + class IObjectNameCheck; + class OSaveAsDlg : public weld::GenericDialogController + { + private: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + 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 m_xDescription; + std::unique_ptr m_xCatalogLbl; + std::unique_ptr m_xCatalog; + std::unique_ptr m_xSchemaLbl; + std::unique_ptr m_xSchema; + std::unique_ptr m_xLabel; + std::unique_ptr m_xTitle; + std::unique_ptr m_xPB_OK; + + DECL_LINK(TextFilterHdl, OUString&, bool); + + 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 0000000000..5a673d7122 --- /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 + +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 m_xMF_VALUE; + std::unique_ptr 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 0000000000..9d2d354432 --- /dev/null +++ b/dbaccess/source/ui/inc/dsitems.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 +#include + +class OptionalBoolItem; +class SfxBoolItem; +class SfxInt32Item; +class SfxStringItem; + +typedef sal_Int32 ItemID; + +// item ids for the data source administration dialog + +#define DSID_NAME TypedWhichId(1) // name of a data source, SfxStringItem +#define DSID_ORIGINALNAME TypedWhichId(2) // original name, internal, SfxStringItem +#define DSID_CONNECTURL TypedWhichId(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 TypedWhichId(6) // is the selection (thus the set data) invalid?, SfxBoolItem +#define DSID_READONLY TypedWhichId(7) // is the selection (thus the set data) readonly?, SfxBoolItem +#define DSID_USER TypedWhichId(8) // the user name used for logon, SfxStringItem +#define DSID_PASSWORD TypedWhichId(9) // the password used for logon, SfxStringItem +#define DSID_ADDITIONALOPTIONS TypedWhichId(10) // additional options used for connecting, SfxStringItem +#define DSID_CHARSET TypedWhichId(11) // character set to use, SfxStringItem by now +#define DSID_PASSWORDREQUIRED TypedWhichId(12) // is the password required to connect?, SfxBoolItem +#define DSID_SHOWDELETEDROWS TypedWhichId(13) // show deleted rows?, SfxBoolItem +#define DSID_ALLOWLONGTABLENAMES TypedWhichId(14) // allow tables names longer than 8.3?, SfxBoolItem +#define DSID_JDBCDRIVERCLASS TypedWhichId(15) // JDBC driver class, SfxStringItem +#define DSID_FIELDDELIMITER TypedWhichId(16) // field delimiter, SfxUInt16Item +#define DSID_TEXTDELIMITER TypedWhichId(17) // text delimiter, SfxUInt16Item +#define DSID_DECIMALDELIMITER TypedWhichId(18) // decimal delimiter, SfxUInt16Item +#define DSID_THOUSANDSDELIMITER TypedWhichId(19) // thousands delimiter, SfxUInt16Item +#define DSID_TEXTFILEEXTENSION TypedWhichId(20) // extension for text files, SfxStringItem +#define DSID_TEXTFILEHEADER TypedWhichId(21) // the text file contains a header?, SfxBoolItem +#define DSID_PARAMETERNAMESUBST TypedWhichId(22) +#define DSID_CONN_PORTNUMBER TypedWhichId(23) +#define DSID_SUPPRESSVERSIONCL TypedWhichId(24) // meta data: sal_True if the data source described by the set is to-be-deleted +#define DSID_CONN_SHUTSERVICE TypedWhichId(25) +#define DSID_CONN_DATAINC TypedWhichId(26) +#define DSID_CONN_CACHESIZE TypedWhichId(27) +#define DSID_CONN_CTRLUSER TypedWhichId(28) +#define DSID_CONN_CTRLPWD TypedWhichId(29) +#define DSID_USECATALOG TypedWhichId(30) // should the driver use the catalog name when the database is filebased +#define DSID_CONN_HOSTNAME TypedWhichId(31) +#define DSID_CONN_LDAP_BASEDN TypedWhichId(32) +#define DSID_CONN_LDAP_PORTNUMBER TypedWhichId(33) +#define DSID_CONN_LDAP_ROWCOUNT TypedWhichId(34) +#define DSID_SQL92CHECK TypedWhichId(35) +#define DSID_AUTOINCREMENTVALUE TypedWhichId(36) +#define DSID_AUTORETRIEVEVALUE TypedWhichId(37) +#define DSID_AUTORETRIEVEENABLED TypedWhichId(38) +#define DSID_APPEND_TABLE_ALIAS TypedWhichId(39) +#define DSID_MYSQL_PORTNUMBER TypedWhichId(40) +#define DSID_IGNOREDRIVER_PRIV TypedWhichId(41) +#define DSID_BOOLEANCOMPARISON TypedWhichId(42) +#define DSID_ORACLE_PORTNUMBER TypedWhichId(43) +#define DSID_ENABLEOUTERJOIN TypedWhichId(44) +#define DSID_CATALOG TypedWhichId(45) +#define DSID_SCHEMA TypedWhichId(46) +#define DSID_INDEXAPPENDIX TypedWhichId(47) +#define DSID_CONN_LDAP_USESSL TypedWhichId(48) +#define DSID_DOCUMENT_URL TypedWhichId(49) +#define DSID_DOSLINEENDS TypedWhichId(50) +#define DSID_DATABASENAME TypedWhichId(51) +#define DSID_AS_BEFORE_CORRNAME TypedWhichId(52) +#define DSID_CHECK_REQUIRED_FIELDS TypedWhichId(53) +#define DSID_IGNORECURRENCY TypedWhichId(54) +#define DSID_CONN_SOCKET TypedWhichId(55) +#define DSID_ESCAPE_DATETIME TypedWhichId(56) +#define DSID_NAMED_PIPE TypedWhichId(57) +#define DSID_PRIMARY_KEY_SUPPORT TypedWhichId(58) +#define DSID_MAX_ROW_SCAN TypedWhichId(59) +#define DSID_RESPECTRESULTSETTYPE TypedWhichId(60) +#define DSID_POSTGRES_PORTNUMBER TypedWhichId(61) + // 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_POSTGRES_PORTNUMBER + +/* 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 0000000000..0c8646a53c --- /dev/null +++ b/dbaccess/source/ui/inc/dsmeta.hxx @@ -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 . + */ + +#pragma once + +#include + +#include + +#include "dsitems.hxx" + +#include + +#include + +namespace dbaui +{ + + // AuthenticationMode + enum AuthenticationMode + { + AuthNone, + AuthUserPwd, + AuthPwd + }; + + // DataSourceMetaData + class FeatureSet; + /** 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: + OUString m_sURL; + }; + + // 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 0000000000..0ecda1ed64 --- /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 +#include + +// SbaExternalSourceBrowser + +namespace dbaui +{ + class SbaXFormAdapter; + class SbaExternalSourceBrowser final + :public SbaXDataBrowserController + ,public css::util::XModifyBroadcaster + { + ::comphelper::OInterfaceContainerHelper3 m_aModifyListeners; + // for multiplexing the modify events + rtl::Reference 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 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 0000000000..c6d5658962 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 m_aDisposeListeners; + ::comphelper::OInterfaceContainerHelper3 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 > 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_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 0000000000..28784e6dbf --- /dev/null +++ b/dbaccess/source/ui/inc/imageprovider.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 +#include + +namespace com::sun::star::sdb::application { class XTableUIProvider; } + +namespace dbaui +{ + /** 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 + { + 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 . + */ + 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 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(); + private: + /// the connection we work with + css::uno::Reference< css::sdbc::XConnection > mxConnection; + /// the views of the connection, if the DB supports views + css::uno::Reference< css::container::XNameAccess > mxViews; + /// interface for providing table's UI + css::uno::Reference< css::sdb::application::XTableUIProvider > mxTableUI; + }; + +} // 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 0000000000..3d227b0b38 --- /dev/null +++ b/dbaccess/source/ui/inc/indexcollection.hxx @@ -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 . + */ + +#pragma once + +#include +#include +#include "indexes.hxx" + +namespace dbaui +{ + + // OIndexCollection + class OIndexCollection + { + 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 0000000000..b3ba37936e --- /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 +#include +#include +#include +#include +#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 m_xIndexes; + std::unique_ptr m_xPreviousSelection; + bool m_bEditingActive; + bool m_bEditAgain; + bool m_bNoHandlerCall; + + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + + std::unique_ptr m_xActions; + std::unique_ptr m_xIndexList; + std::unique_ptr m_xIndexDetails; + std::unique_ptr m_xDescriptionLabel; + std::unique_ptr m_xDescription; + std::unique_ptr m_xUnique; + std::unique_ptr m_xFieldsLabel; + std::unique_ptr m_xClose; + std::unique_ptr m_xTable; + css::uno::Reference m_xTableCtrlParent; + VclPtr 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 IterString; + private: + void fillIndexList(); + void updateToolbox(); + void updateControls(const weld::TreeIter* pEntry); + + void IndexSelected(); + + DECL_LINK( OnIndexSelected, weld::TreeView&, void ); + DECL_LINK( OnIndexAction, const OUString&, 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 0000000000..75bd5b44ba --- /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 + +#include + +#include + +namespace dbaui +{ + // OIndexField + struct OIndexField + { + OUString sFieldName; + bool bSortAscending; + + OIndexField() : bSortAscending(true) { } + }; + + typedef std::vector 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 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 0000000000..90ae7172e3 --- /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 +#include +#include +#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 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 &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& _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(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 0000000000..c20f3a87ae --- /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 +#include +#include +#include +#include +#include + +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, + 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 0000000000..52f639e534 --- /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 + +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 + 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 0000000000..8448a047dc --- /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 +#include + +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 m_xControl; + public: + OpenDocumentButton(std::unique_ptr xControl, const char* _pAsciiModuleName); + + void set_sensitive(bool bSensitive) { m_xControl->set_sensitive(bSensitive); } + void connect_clicked(const Link& 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 m_aURLs; + + std::unique_ptr m_xControl; + + public: + OpenDocumentListBox(std::unique_ptr 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& 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 0000000000..489a621e60 --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace connectivity +{ + class OSQLParseNode; +} + +enum class VisitFlags { + NONE = 0x00, + Visited = 0x01, + Dirty = 0x02, +}; +namespace o3tl { + template<> struct typed_flags : is_typed_flags {}; +} + +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 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 m_xAllParams; + std::unique_ptr m_xParam; + std::unique_ptr m_xTravelNext; + std::unique_ptr m_xOKBtn; + std::unique_ptr 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 0000000000..35d9f24d6e --- /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 +#include +#include + +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 0000000000..12583ec0c0 --- /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 +#include +#include +#include +#include "QueryViewSwitch.hxx" +#include + +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 m_pBeamer; + VclPtr 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 0000000000..94bb5d8f4f --- /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 +#include "TableFieldDescription.hxx" + +#include +#include +#include + +#include +#include +#include +#include +#include + +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 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 0000000000..396778f229 --- /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 +#include + +#include +#include + +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 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 m_xLB_WHEREFIELD1; + std::unique_ptr m_xLB_WHERECOMP1; + std::unique_ptr m_xET_WHEREVALUE1; + + std::unique_ptr m_xLB_WHERECOND2; + std::unique_ptr m_xLB_WHEREFIELD2; + std::unique_ptr m_xLB_WHERECOMP2; + std::unique_ptr m_xET_WHEREVALUE2; + + std::unique_ptr m_xLB_WHERECOND3; + std::unique_ptr m_xLB_WHEREFIELD3; + std::unique_ptr m_xLB_WHERECOMP3; + std::unique_ptr 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 0000000000..523d84f31f --- /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 + +#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 m_xLB_ORDERFIELD1; + std::unique_ptr m_xLB_ORDERVALUE1; + std::unique_ptr m_xLB_ORDERFIELD2; + std::unique_ptr m_xLB_ORDERVALUE2; + std::unique_ptr m_xLB_ORDERFIELD3; + std::unique_ptr 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 0000000000..921faa6a9b --- /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 TypedWhichId(SBA_WHICHID_START+143) // RangeItem +#define SBA_DEF_FMTVALUE TypedWhichId(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 0000000000..ae96bb291b --- /dev/null +++ b/dbaccess/source/ui/inc/sbagrid.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 + +#include + +#include +#include +#include +#include +#include +#include "sbamultiplex.hxx" +#include +#include +#include +#include + +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, SbaURLCompare> StatusMultiplexerArray; + StatusMultiplexerArray m_aStatusMultiplexer; + + public: + SbaXGridControl(const css::uno::Reference< css::uno::XComponentContext >&); + virtual ~SbaXGridControl() override; + + // UNO + DECLARE_UNO3_AGG_DEFAULTS(SbaXGridControl, FmXGridControl) + virtual css::uno::Any SAL_CALL queryAggregation(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 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 imp_CreatePeer(vcl::Window* pParent) override; + }; + + // SbaXGridPeer + + class SbaXGridPeer final + :public FmXGridPeer + ,public css::frame::XDispatch + { + comphelper::OMultiTypeInterfaceContainerHelperVar4< css::util::URL, css::frame::XStatusListener, + 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; + + // 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 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 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 OUString& 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 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 OUString& 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 0000000000..47fd753d4a --- /dev/null +++ b/dbaccess/source/ui/inc/sbamultiplex.hxx @@ -0,0 +1,305 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + { + 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 + { + 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 + { + 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 + { + 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 + { + 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 + { + 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 + { + 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 + { + 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 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* getContainer(const OUString& rName) + { return m_aListeners.getContainer(rName); } + + private: + void Notify(::comphelper::OInterfaceContainerHelper3& rListeners, const css::beans::PropertyChangeEvent& e); + }; + + // css::beans::XVetoableChangeListener + class SbaXVetoableChangeMultiplexer final + :public OSbaWeakSubObject + ,public css::beans::XVetoableChangeListener + { + typedef ::comphelper::OMultiTypeInterfaceContainerHelperVar3 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; + + private: + void Notify(::comphelper::OInterfaceContainerHelper3& rListeners, const css::beans::PropertyChangeEvent& e); + }; + + // css::beans::XPropertiesChangeListener + class SbaXPropertiesChangeMultiplexer + :public OSbaWeakSubObject + ,public css::beans::XPropertiesChangeListener + ,public ::comphelper::OInterfaceContainerHelper3 + { + 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 0000000000..6b535882bc --- /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 +#include + +#include + +#include + +class SfxUndoAction; +class SfxUndoManager; + +namespace dbaui +{ +class UndoManager; + + 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 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: + // no Reference! see UndoManager::acquire + std::unique_ptr m_pUndoManager; + }; + +} // 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 0000000000..d0f8672cc6 --- /dev/null +++ b/dbaccess/source/ui/inc/sqledit.hxx @@ -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 . + */ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include + +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 m_xScrolledWindow; + Link m_aModifyLink; + const svtools::ColorConfig m_aColorConfig; + Timer m_aUpdateDataTimer; + const SyntaxHighlighter m_aHighlighter; + svtools::ColorConfig m_ColorConfig; + rtl::Reference m_pItemPool; + + rtl::Reference m_listener; + std::mutex m_mutex; + css::uno::Reference 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 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& 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 0000000000..481732985d --- /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 +#include +#include + +// 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 : is_typed_flags {}; +} + + +namespace dbaui +{ + +// OSQLMessageBox +struct SQLMessageBox_Impl; +class OSQLMessageBox : public weld::DialogController +{ + std::unique_ptr m_xDialog; + std::unique_ptr m_xMoreButton; + std::unique_ptr 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 SQLContext). + */ + OSQLMessageBox( + weld::Window* pParent, + const dbtools::SQLExceptionInfo& _rException, + MessBoxStyle _nStyle = MessBoxStyle::Ok | MessBoxStyle::DefaultOk, + OUString _sHelpURL = 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 OUString& rHelpId = {}) { 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 0000000000..3d16f6770c --- /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 + +#include +#include + +namespace dbaui +{ +// OStringListItem +/** SfxPoolItem which transports a sequence of OUString's +*/ +class OStringListItem : public SfxPoolItem +{ + css::uno::Sequence m_aList; + +public: + OStringListItem(sal_Int16 nWhich, const css::uno::Sequence& _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& 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 0000000000..ebfbf7d29c --- /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 +#include +#include +#include + +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 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 + SQLException 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 addedTable( const OUString& _rName ); + + /** to be used if a foreign instance removed a table + */ + void removedTable( const OUString& _rName ); + + std::unique_ptr getAllObjectsEntry() const; + + /** does a wildcard check of the given entry +

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.

+ */ + 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 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 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 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 0000000000..9d21c87956 --- /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 +#include + +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 m_xContainer; + std::unique_ptr m_xOK; + std::unique_ptr 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 0000000000..2b760bbada --- /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 + +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 0000000000..944dccf87a --- /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 +#include +#include + +class SfxItemSet; +class SfxItemPool; +class SfxPoolItem; + +namespace dbaui +{ + +// ODatabaseAdministrationDialog +typedef ::svt::OGenericUnoDialog ODatabaseAdministrationDialogBase; +class ODatabaseAdministrationDialog + :public ODatabaseAdministrationDialogBase +{ +protected: + std::unique_ptr m_pDatasourceItems; // item set for the dialog + rtl::Reference m_pItemPool; // item pool for the item set for the dialog + std::vector* + 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 0000000000..093cb8bb6a --- /dev/null +++ b/dbaccess/source/ui/inc/unodatbr.hxx @@ -0,0 +1,448 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include "brwctrlr.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.hxx" +#include +#include +#include +#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( css::util::URL _aURL ) : aURL(std::move( _aURL )), 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 m_pTreeView; // contains the datasources of the registry + VclPtr m_pSplitter; + std::unique_ptr 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 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 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 +

The slot is available if an external dispatcher is responsible for it, _and_ if this dispatcher + told us the slot is available.

+ */ + bool getExternalSlotState( sal_uInt16 _nId ) const; + + /** add an entry (including the subentries for queries/tables) to the list model + +

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.

+ */ + 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 + if the connection should be disposed + @param _bFlushData + 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 getEntryFromContainer(const css::uno::Reference& 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 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 implGetConnectionEntry(const weld::TreeIter& rEntry) const; + /// inserts an entry into the tree + std::unique_ptr 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 _rDescriptor + @param rDescriptor + the object descriptor + @param ppDataSourceEntry + If not , the data source tree entry will be returned here + @param ppContainerEntry + If not , the object container tree entry will be returned here + */ + std::unique_ptr getObjectEntry(const svx::ODataAccessDescriptor& rDescriptor, + std::unique_ptr* ppDataSourceEntry, std::unique_ptr* 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 , the data source tree entry will be returned here + @param ppContainerEntry + If not , the object container tree entry will be returned here + @param bExpandAncestors + If , all ancestor on the way to the entry will be expanded + */ + std::unique_ptr getObjectEntry( + const OUString& rDataSource, const OUString& rCommand, sal_Int32 nCommandType, + std::unique_ptr* ppDataSourceEntry, std::unique_ptr* 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 +

If the for is not based on a query or not even loaded, nothing happens and is returned.

+ */ + 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 + if it is the currently displayed otherwise + */ + 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 0000000000..c084ef240b --- /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 +#include + +namespace dbaui +{ + +typedef ::svt::OGenericUnoDialog OSQLMessageDialogBase; +class OSQLMessageDialog final + :public OSQLMessageDialogBase + ,public ::comphelper::OPropertyArrayUsageHelper< OSQLMessageDialog > +{ + // + css::uno::Any m_aException; + OUString m_sHelpURL; + // + +public: + OSQLMessageDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference 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 createDialog(const css::uno::Reference& 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 0000000000..a1e02b8745 --- /dev/null +++ b/dbaccess/source/ui/misc/DExport.cxx @@ -0,0 +1,839 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "UpdateHelperImpl.hxx" +#include + +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 & 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& _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 xTablesSup(m_xConnection,UNO_QUERY); + if(xTablesSup.is()) + m_xTables = xTablesSup->getTables(); + + Reference xMeta = m_xConnection->getMetaData(); + Reference xSet = xMeta.is() ? xMeta->getTypeInfo() : Reference(); + if(xSet.is()) + { + ::connectivity::ORowSetValue aValue; + std::vector aTypes; + std::vector aNullable; + Reference xResultSetMetaData = Reference(xSet,UNO_QUERY_THROW)->getMetaData(); + Reference 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(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(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(); + + m_pTypeInfo->aTypeName = sTypeName; + m_pTypeInfo->nType = nType; + + OSL_ENSURE((nPos) < static_cast(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(); +} + +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(m_vColumnPositions.size()),"m_vColumnPositions: Illegal index for vector"); + + if ( nNewPos < static_cast(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(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(nNumberFormat2); + } + else + { + Reference< XNumberFormatsSupplier > xSupplier = m_xFormatter->getNumberFormatsSupplier(); + Reference 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 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 xProp = xFormats->getByKey(nFormatKey); + xProp->getPropertyValue(PROPERTY_TYPE) >>= nNumberFormat; + } + else + { + Reference xNumType(xFormats,UNO_QUERY); + sal_Int32 nFormatKey = m_xFormatter->detectNumberFormat(xNumType->getStandardFormat(NumberFormat::ALL,m_aLocale),aCheckToken); + m_xFormatter->convertStringToNumber(nFormatKey,aCheckToken); + + Reference 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(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(aFind->second->nPrecision,nLength)); + elem->second->SetScale(std::min(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( 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( 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(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(createPreparedStatement(m_xConnection->getMetaData(),m_xTable,m_vColumnPositions)); +} + +bool ODatabaseExport::executeWizard(const OUString& _rTableName, const Any& _aTextColor, const FontDescriptor& _rFont) +{ + bool bHaveDefaultTable = !m_sDefaultTableName.isEmpty(); + const OUString& rTableName(bHaveDefaultTable ? m_sDefaultTableName : _rTableName); + OCopyTableWizard aWizard( + nullptr, + rTableName, + 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(m_vColumnPositions.size()),"Illegal index for vector"); + if ( nNewPos < static_cast(m_vColumnPositions.size()) ) + { + sal_Int32 nColPos = m_vColumnPositions[nNewPos].first; + if( nColPos != COLUMN_POSITION_NOT_FOUND) + { + --nColPos; + OSL_ENSURE((nColPos) < static_cast(m_vNumberFormat.size()),"m_vFormatKey: Illegal index for vector"); + OSL_ENSURE((nColPos) < static_cast(m_vColumnSize.size()),"m_vColumnSize: Illegal index for vector"); + m_vNumberFormat[nColPos] = CheckString(m_sTextToken,m_vNumberFormat[nColPos]); + m_vColumnSize[nColPos] = std::max(static_cast(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(xSupplier); + m_pFormatter = pSupplierImpl ? pSupplierImpl->GetNumberFormatter() : nullptr; + Reference xNumberFormatSettings = xSupplier->getNumberFormatSettings(); + xNumberFormatSettings->getPropertyValue("NullDate") >>= m_aNullDate; + } +} + +Reference< XPreparedStatement > ODatabaseExport::createPreparedStatement( const Reference& _xMetaData + ,const Reference& _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 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(j+1); }); + if ( _rvColumns.end() != aFind && aFind->second != COLUMN_POSITION_NOT_FOUND && aFind->first != COLUMN_POSITION_NOT_FOUND ) + { + OSL_ENSURE((aFind->first) < static_cast(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 + ","); + 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 0000000000..c2917a6300 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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((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(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 0000000000..065fee9ce9 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(m_xResultSet,UNO_QUERY); + OSL_ENSURE(xColumnLocate.is(),"The rowset normally should support this"); + + m_xTargetResultSetMetaData = Reference(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 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 0000000000..8895d494f8 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(nTokenValue)); break; + case RTF_BLUE: aColor.SetBlue(static_cast(nTokenValue)); break; + case RTF_GREEN: aColor.SetGreen(static_cast(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 0000000000..c69c046997 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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& 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& 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 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 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 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 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 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::TempFileNamed aTmp; + _rAsyncDrop.aUrl = aTmp.GetURL(); + ::tools::SvRef 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 0000000000..fd2f098db4 --- /dev/null +++ b/dbaccess/source/ui/misc/TokenWriter.cxx @@ -0,0 +1,967 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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( ::dbtools::SharedConnection _xConnection, + const Reference< XNumberFormatter >& _rxNumberF, const Reference< XComponentContext >& _rM ) + :m_bBookmarkSelection( false ) + ,m_pStream(nullptr) + ,m_xConnection(std::move(_xConnection)) + ,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(); + m_xRowSetColumns.clear(); +} + +void SAL_CALL ODatabaseImportExport::disposing( const EventObject& Source ) +{ + Reference 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 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(aInfo); + } + + Reference xNameAccess; + switch(m_nCommandType) + { + case CommandType::TABLE: + { + // only for tables + Reference xSup(m_xConnection,UNO_QUERY); + if(xSup.is()) + xNameAccess = xSup->getTables(); + } + break; + case CommandType::QUERY: + { + Reference 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(m_xRow,UNO_QUERY_THROW)->getMetaData(); + Reference 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( '{' ).WriteOString( OOO_STRING_SVTOOLS_RTF_RTF ); + m_pStream->WriteOString(OOO_STRING_SVTOOLS_RTF_ANSI); + if (sal_uInt32 nCpg = rtl_getWindowsCodePageFromTextEncoding(m_eDestEnc); nCpg && nCpg != 65001) + { + m_pStream->WriteOString(OOO_STRING_SVTOOLS_RTF_ANSICPG).WriteNumberAsString(nCpg); + } + m_pStream->WriteOString(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->WriteOString( "{\\fonttbl" ); + if (!aFonts.isEmpty()) + { + sal_Int32 nIdx{0}; + sal_Int32 nTok{-1}; // to compensate pre-increment + do { + m_pStream->WriteOString( "\\f" ); + m_pStream->WriteNumberAsString(++nTok); + m_pStream->WriteOString( "\\fcharset0\\fnil " ); + m_pStream->WriteOString( o3tl::getToken(aFonts, 0, ';', nIdx) ); + m_pStream->WriteChar( ';' ); + } while (nIdx>=0); + } + m_pStream->WriteChar( '}' ) ; + m_pStream->WriteOString( SAL_NEWLINE_STRING ); + // write the rtf color table + m_pStream->WriteChar( '{' ).WriteOString( OOO_STRING_SVTOOLS_RTF_COLORTBL ).WriteOString( OOO_STRING_SVTOOLS_RTF_RED ); + m_pStream->WriteNumberAsString(aColor.GetRed()); + m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_GREEN ); + m_pStream->WriteNumberAsString(aColor.GetGreen()); + m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_BLUE ); + m_pStream->WriteNumberAsString(aColor.GetBlue()); + + m_pStream->WriteOString( ";\\red255\\green255\\blue255;\\red192\\green192\\blue192;}" ) + .WriteOString( SAL_NEWLINE_STRING ); + + static char const aCell1[] = "\\clbrdrl\\brdrs\\brdrcf0\\clbrdrt\\brdrs\\brdrcf0\\clbrdrb\\brdrs\\brdrcf0\\clbrdrr\\brdrs\\brdrcf0\\clshdng10000\\clcfpat2\\cellx"; + + m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteOString( OOO_STRING_SVTOOLS_RTF_TRGAPH ); + m_pStream->WriteOString("40"); + m_pStream->WriteOString( SAL_NEWLINE_STRING ); + + if(m_xObject.is()) + { + Reference xColSup(m_xObject,UNO_QUERY); + Reference 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->WriteOString( aCell1 ); + m_pStream->WriteNumberAsString(i*CELL_X); + m_pStream->WriteOString( SAL_NEWLINE_STRING ); + } + + // column description + m_pStream->WriteChar( '{' ).WriteOString( SAL_NEWLINE_STRING ); + m_pStream->WriteOString( "\\trrh-270\\pard\\intbl" ); + + std::unique_ptr 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 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->WriteOString( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '{' ); + m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_QC ); // column header always centered + + if ( bBold ) m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_B ); + if ( bItalic ) m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_I ); + if ( bUnderline ) m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_UL ); + if ( bStrikeout ) m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_STRIKE ); + + m_pStream->WriteOString( "\\fs20\\f0\\cf0\\cb2" ); + m_pStream->WriteChar( ' ' ); + RTFOutFuncs::Out_String(*m_pStream, sColumnName, m_eDestEnc); + + m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_CELL ); + m_pStream->WriteChar( '}' ); + m_pStream->WriteOString( SAL_NEWLINE_STRING ); + m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_PARD ).WriteOString( OOO_STRING_SVTOOLS_RTF_INTBL ); + } + + m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_ROW ); + m_pStream->WriteOString( SAL_NEWLINE_STRING ).WriteChar( '}' ); + m_pStream->WriteOString( 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( '}' ).WriteOString( 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->WriteOString( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteOString( OOO_STRING_SVTOOLS_RTF_TRGAPH ); + m_pStream->WriteOString("40"); + m_pStream->WriteOString( 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->WriteOString( aCell2 ); + m_pStream->WriteNumberAsString(i*CELL_X); + m_pStream->WriteOString( 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->WriteOString( "\\trrh-270\\pard\\intbl" ); + for ( sal_Int32 i=1; i <= _nColumnCount; ++i ) + { + m_pStream->WriteOString( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '{' ); + m_pStream->WriteOString( pHorzChar[i-1] ); + + if ( bBold ) m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_B ); + if ( bItalic ) m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_I ); + if ( bUnderline ) m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_UL ); + if ( bStrikeout ) m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_STRIKE ); + + m_pStream->WriteOString( "\\fs20\\f1\\cf0\\cb1 " ); + + try + { + Reference 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->WriteOString( OOO_STRING_SVTOOLS_RTF_CELL ); + m_pStream->WriteChar( '}' ); + m_pStream->WriteOString( SAL_NEWLINE_STRING ); + m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_PARD ).WriteOString( OOO_STRING_SVTOOLS_RTF_INTBL ); + } + m_pStream->WriteOString( OOO_STRING_SVTOOLS_RTF_ROW ).WriteOString( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '}' ); + ++k; +} + +bool ORTFImportExport::Read() +{ + ODatabaseImportExport::Read(); + SvParserState eState = SvParserState::Error; + if ( m_pStream ) + { + tools::SvRef 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( '<' ).WriteOString( OOO_STRING_SVTOOLS_HTML_doctype ).WriteChar( ' ' ).WriteOString( OOO_STRING_SVTOOLS_HTML_doctype5 ).WriteChar( '>' ).WriteOString( SAL_NEWLINE_STRING ).WriteOString( SAL_NEWLINE_STRING ); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_html).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + WriteHeader(); + m_pStream->WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + WriteBody(); + m_pStream->WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_html, false).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + + return ((*m_pStream).GetError() == ERRCODE_NONE); + } + return false; +} + +bool OHTMLImportExport::Read() +{ + ODatabaseImportExport::Read(); + SvParserState eState = SvParserState::Error; + if ( m_pStream ) + { + tools::SvRef 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 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).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + + SfxFrameHTMLWriter::Out_DocInfo( (*m_pStream), OUString(), + xDocProps, sIndent ); + m_pStream->WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + IncIndent(-1); + m_pStream->WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_head, false).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); +} + +void OHTMLImportExport::WriteBody() +{ + IncIndent(1); + m_pStream->WriteOString( "<" ).WriteOString( OOO_STRING_SVTOOLS_HTML_style ).WriteOString( " " ).WriteOString( OOO_STRING_SVTOOLS_HTML_O_type ).WriteOString( "=\"text/css\">" ); + + m_pStream->WriteOString( "" ); + IncIndent(-1); + m_pStream->WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_style, false).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + m_pStream->WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + + // default Textcolour black + m_pStream->WriteChar( '<' ).WriteOString( OOO_STRING_SVTOOLS_HTML_body ).WriteChar( ' ' ).WriteOString( 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->WriteOString( " " OOO_STRING_SVTOOLS_HTML_O_bgcolor "=" ); + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + + m_pStream->WriteChar( '>' ); + m_pStream->WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + + WriteTables(); + + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_body, false).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); +} + +void OHTMLImportExport::WriteTables() +{ + OString aStrOut = OOO_STRING_SVTOOLS_HTML_table + " " + OOO_STRING_SVTOOLS_HTML_frame + "=" + OOO_STRING_SVTOOLS_HTML_TF_void ""_ostr; + + Sequence< OUString> aNames; + Reference xColumns; + bool bUseResultMetaData = false; + if(m_xObject.is()) + { + Reference 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); + + 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->WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + // + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + + if(m_xObject.is()) + { + std::unique_ptr pFormat(new sal_Int32[aNames.getLength()]); + + std::unique_ptr pHorJustify(new const char*[aNames.getLength()]); + std::unique_ptr 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 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).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead, false).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody).WriteOString(SAL_NEWLINE_STRING).WriteOString(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).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + + for(sal_Int32 i=1;i<=aNames.getLength();++i) + { + if(i == aNames.getLength()) + IncIndent(-1); + + OUString aValue; + try + { + Reference 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).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + } + } + else + { + IncIndent(-1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tablerow, false).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_thead, false).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + + IncIndent(1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + } + + IncIndent(-1); + m_pStream->WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_tbody, false).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); + IncIndent(-1); + HTMLOutFuncs::Out_AsciiTag(*m_pStream, OOO_STRING_SVTOOLS_HTML_table, false).WriteOString(SAL_NEWLINE_STRING).WriteOString(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
and 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(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); + + 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).WriteOString(SAL_NEWLINE_STRING).WriteOString(GetIndentStr()); +} + +void OHTMLImportExport::FontOn() +{ +#if OSL_DEBUG_LEVEL > 0 + m_bCheckFont = true; +#endif + + // + 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->WriteOString( ">" ); +} + +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 0000000000..483afced10 --- /dev/null +++ b/dbaccess/source/ui/misc/UITools.cxx @@ -0,0 +1,1371 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 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,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(); +} + +Reference< XInterface > getDataSourceOrModel(const Reference< XInterface >& _xObject) +{ + Reference< XInterface > xRet; + Reference xDocumentDataSource(_xObject,UNO_QUERY); + if ( xDocumentDataSource.is() ) + xRet = xDocumentDataSource->getDatabaseDocument(); + + if ( !xRet.is() ) + { + Reference 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 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& _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 = Reference(xRs,UNO_QUERY_THROW)->getMetaData(); + ::connectivity::ORowSetValue aValue; + std::vector aTypes; + std::vector aNullable; + // Loop on the result set until we reach end of file + while (xRs->next()) + { + TOTypeInfoSP pInfo = std::make_shared(); + 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& _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& _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 xRes = _xMetaData->getCatalogs(); + Reference 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& xAffectedCol, + const Reference& 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(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[] = + { + // _nSID, _bNeedsPoolRegistration, _bShareable + { 0, false, true }, // SBA_DEF_RANGEFORMAT + { SID_ATTR_NUMBERFORMAT_VALUE, false, true }, // SBA_DEF_FMTVALUE + { SID_ATTR_ALIGN_HOR_JUSTIFY, false, true }, // SBA_ATTR_ALIGN_HOR_JUSTIFY + { SID_ATTR_NUMBERFORMAT_INFO, false, true }, // SID_ATTR_NUMBERFORMAT_INFO + { SID_ATTR_NUMBERFORMAT_ONE_AREA, false, true } // SID_ATTR_NUMBERFORMAT_ONE_AREA + }; + 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 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 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 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(SBA_ATTR_ALIGN_HOR_JUSTIFY); + + _eJustify = pHorJustify->GetValue(); + + // format key + if (_bHasFormat) + { + const SfxUInt32Item* pFormat = pSet->GetItem(SBA_DEF_FMTVALUE); + _nFormatKey = static_cast(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(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 getStandardDatabaseFilter() +{ + std::shared_ptr pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)"); + OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!"); + return pFilter; +} + +bool appendToFilter(const Reference& _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& _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; + ::tools::Long 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) +{ + return ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_ENABLESQL92CHECK ); +} + +bool isAppendTableAliasEnabled(const Reference& _xConnection) +{ + return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_APPEND_TABLE_ALIAS ); +} + +bool generateAsBeforeTableAlias(const Reference& _xConnection) +{ + return ::dbtools::getBooleanDataSourceSetting( _xConnection, INFO_AS_BEFORE_CORRELATION_NAME ); +} + +void fillAutoIncrementValue(const Reference& _xDatasource, + bool& _rAutoIncrementValueEnabled, + OUString& _rsAutoIncrementValue) +{ + if ( !_xDatasource.is() ) + return; + + OSL_ENSURE(_xDatasource->getPropertySetInfo()->hasPropertyByName(PROPERTY_INFO),"NO datasource supplied!"); + Sequence 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, + 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& _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(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 xSup(_rxConnection,UNO_QUERY); + Reference< XNameAccess > xViews; + if(xSup.is()) + xViews = xSup->getViews(); + Reference xFact(xViews,UNO_QUERY); + OSL_ENSURE(xFact.is(),"No XDataDescriptorFactory available!"); + if(!xFact.is()) + return nullptr; + + Reference 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(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 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 createView( const OUString& _rName, const Reference< XConnection >& _rxConnection + ,const Reference& _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& _xNames, + const OUString& _sParentFolder, + bool _bForm, + bool _bCollection, + const Reference& _xContent, + bool _bMove) +{ + OSL_ENSURE( _xNames.is(), "insertHierarchyElement: illegal name container!" ); + if ( !_xNames.is() ) + return false; + + Reference xNameAccess( _xNames, UNO_QUERY ); + if ( _xNames->hasByHierarchicalName(_sParentFolder) ) + { + Reference 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 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 xORB( xNameAccess, UNO_QUERY_THROW ); + uno::Sequence aArguments(comphelper::InitAnyPropertySequence( + { + {"Name", uno::Any(sNewName)}, // set as folder + {"Parent", uno::Any(xNameAccess)}, + {PROPERTY_EMBEDDEDOBJECT, uno::Any(_xContent)}, + })); + OUString sServiceName(_bCollection ? (_bForm ? SERVICE_NAME_FORM_COLLECTION : SERVICE_NAME_REPORT_COLLECTION) : SERVICE_SDB_DOCUMENTDEFINITION); + + Reference 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 0000000000..9f8d0d3998 --- /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 +#include +#include + +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 0000000000..602edd2d6e --- /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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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 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(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 0000000000..3ad6d58a31 --- /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 +#include +#include +#include +#include +#include +#include + +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 OUString& 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(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(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(_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 0000000000..29be877474 --- /dev/null +++ b/dbaccess/source/ui/misc/WCopyTable.cxx @@ -0,0 +1,1553 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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[] = { + PROPERTY_FONT, PROPERTY_ROW_HEIGHT, PROPERTY_TEXTCOLOR,PROPERTY_TEXTLINECOLOR,PROPERTY_TEXTEMPHASIS,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 & 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 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( "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, OUString _sTableName ) + :m_xConnection( _rxConnection, UNO_SET_THROW ) + ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ) + ,m_sTableName(std::move( _sTableName )) +{ + ::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 xPage1(new OCopyTable(CreatePageContainer(), this)); + xPage1->disallowUseHeaderLine(); + if ( !bAllowViews ) + xPage1->disallowViews(); + xPage1->setCreateStyleAction(); + AddWizardPage(std::move(xPage1)); + + AddWizardPage( std::make_unique(CreatePageContainer(), this)); + AddWizardPage( std::make_unique(CreatePageContainer(), this)); + AddWizardPage( std::make_unique(CreatePageContainer(), this)); + ActivatePage(); + + m_xAssistant->set_current_page(0); +} + +weld::Container* OCopyTableWizard::CreatePageContainer() +{ + OUString sIdent(OUString::number(m_nPageCount)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + return pPageContainer; +} + +OCopyTableWizard::OCopyTableWizard( weld::Window* pParent, OUString _sDefaultName, 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(std::move(_sDefaultName)) + , 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 xPage1(new OCopyTable(CreatePageContainer(), this)); + xPage1->disallowViews(); + xPage1->setCreateStyleAction(); + AddWizardPage(std::move(xPage1)); + + AddWizardPage(std::make_unique(CreatePageContainer(), this)); + AddWizardPage(std::make_unique(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(); + 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(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(sMsg, {}, {}, 0, {}, {}); + ::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(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(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(GetPage(GetCurLevel())); + return pPage && pPage->LeavePage(); +} + +void OCopyTableWizard::AddWizardPage(std::unique_ptr 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; + static constexpr OUStringLiteral sCreateParam(u"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 const & _rxColSup, const ODatabaseExport::TColumnVector* _pVec, bool _bKeyColumns) +{ + // now append the columns + OSL_ENSURE(_rxColSup.is(),"No columns supplier"); + if(!_rxColSup.is()) + return; + Reference xColumns = _rxColSup->getColumns(); + OSL_ENSURE(xColumns.is(),"No columns"); + Reference xColumnFactory(xColumns,UNO_QUERY); + + Reference xAppend(xColumns,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + for (auto const& elem : *_pVec) + { + OFieldDescription* pField = elem->second; + if(!pField) + continue; + + Reference 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 const & _rxSup, const ODatabaseExport::TColumnVector* _pVec) +{ + if(!_rxSup.is()) + return; // the database doesn't support keys + OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!"); + Reference xKeyFactory(_rxSup->getKeys(),UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + if ( !xKeyFactory.is() ) + return; + Reference xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference xKey = xKeyFactory->createDataDescriptor(); + OSL_ENSURE(xKey.is(),"Key is null!"); + xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY)); + + Reference xColSup(xKey,UNO_QUERY); + if(xColSup.is()) + { + appendColumns(xColSup,_pVec,true); + Reference 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 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 xSup( m_xDestConnection, UNO_QUERY ); + Reference< XNameAccess > xTables; + if(xSup.is()) + xTables = xSup->getTables(); + Reference 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 xKeySup(xTable,UNO_QUERY); + appendKey(xKeySup, &rVec); + + Reference 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 = 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 0000000000..c7eac9181e --- /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 +#include +#include +#include + +using namespace com::sun::star; + +namespace dbaui +{ + +void OWizHTMLExtend::createReaderAndCallParser(sal_Int32 _nRows) +{ + tools::SvRef 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 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 0000000000..a6bb59da8e --- /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 +#include +#include +#include +#include +#include +#include +#include + +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 xLeftEntry = m_xCTRL_LEFT->make_iterator(); + std::unique_ptr 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(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(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(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(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 0000000000..f5b4ee4baa --- /dev/null +++ b/dbaccess/source/ui/misc/WTypeSelect.cxx @@ -0,0 +1,416 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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_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(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(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 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(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 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(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); + + OUString 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(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 0000000000..8323d47dba --- /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 + +#include + +#include +#include + +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 0000000000..5224e65d3c --- /dev/null +++ b/dbaccess/source/ui/misc/charsets.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 +#include +#include +#include +#include +#include +#include + +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(std::u16string_view _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, OUString _sDisplayName) + :CharsetDisplayDerefHelper_Base(_rBase) + ,m_sDisplayName(std::move(_sDisplayName)) + { + OSL_ENSURE( !m_sDisplayName.isEmpty(), "CharsetDisplayDerefHelper::CharsetDisplayDerefHelper: invalid display name!" ); + } + + // OCharsetDisplay::ExtendedCharsetIterator + OCharsetDisplay::ExtendedCharsetIterator::ExtendedCharsetIterator( const OCharsetDisplay* _pContainer, base_iterator _aPosition ) + :m_pContainer(_pContainer) + ,m_aPosition(std::move(_aPosition)) + { + 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 0000000000..365e144390 --- /dev/null +++ b/dbaccess/source/ui/misc/controllerframe.cxx @@ -0,0 +1,389 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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::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 0000000000..47c3932ca2 --- /dev/null +++ b/dbaccess/source/ui/misc/databaseobjectview.cxx @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +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, + OUString _sComponentURL ) + :m_xORB ( _rxORB ) + ,m_xParentFrame ( _rxParentFrame ) + ,m_xApplication ( _rxApplication ) + ,m_sComponentURL (std::move( _sComponentURL )) + { + 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 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; + 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 ? URL_COMPONENT_VIEWDESIGN : 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, 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, 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"); + i_rDispatchArgs.put( PROPERTY_COMMAND, _rQualifiedName ); + i_rDispatchArgs.put( PROPERTY_ENABLE_BROWSER, false ); + + if ( m_bTable ) + { + OUString sCatalog; + OUString sSchema; + OUString sTable; + ::dbtools::qualifiedNameComponents( getConnection()->getMetaData(), _rQualifiedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation ); + i_rDispatchArgs.put( PROPERTY_UPDATE_CATALOGNAME, sCatalog ); + i_rDispatchArgs.put( PROPERTY_UPDATE_SCHEMANAME, sSchema ); + i_rDispatchArgs.put( PROPERTY_UPDATE_TABLENAME, sTable ); + i_rDispatchArgs.put( PROPERTY_COMMAND_TYPE, CommandType::TABLE ); + } + else + i_rDispatchArgs.put( PROPERTY_COMMAND_TYPE, CommandType::QUERY ); + } + + // RelationDesigner + RelationDesigner::RelationDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, 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 0000000000..a170d02963 --- /dev/null +++ b/dbaccess/source/ui/misc/datasourceconnector.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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, + OUString _sContextInformation ) + :m_pErrorMessageParent(_pMessageParent) + ,m_xContext(_rxContext) + ,m_sContextInformation(std::move( _sContextInformation )) + { + } + + 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 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 = removeMnemonicFromString( sMessage ); + + SQLWarning aContext(sMessage, {}, {}, 0, aWarnings); + aInfo = aContext; + } + xConnectionWarnings->clearWarnings(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + else + { + if ( !m_sContextInformation.isEmpty() ) + { + SQLException aError(m_sContextInformation, {}, {}, 0, 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 0000000000..9ed72bbdf4 --- /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 + +#include +#include + +#include +#include +#include +#include + +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 0000000000..759f202c0d --- /dev/null +++ b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx @@ -0,0 +1,605 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + m_aModifyListeners; + + // + SharedConnection m_xConnection; + ::dbtools::DatabaseMetaData m_aSdbMetaData; + // + 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.has_value(), + "DBSubComponentController_Impl::documentHasScriptSupport: not completely initialized, yet - don't know!?" ); + return m_aDocScriptSupport.has_value() && *m_aDocScriptSupport; + } + + void setDocumentScriptSupport( const bool _bSupport ) + { + OSL_PRECOND( !m_aDocScriptSupport.has_value(), + "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::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::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 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 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( 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 0000000000..cc44de2bde --- /dev/null +++ b/dbaccess/source/ui/misc/defaultobjectnamecheck.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 +#include + +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include +#include + +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::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 ) + { + OUString sErrorMessage = DBA_RES(STR_NAMED_OBJECT_ALREADY_EXISTS); + SQLException aError(sErrorMessage.replaceAll("$#$", _rObjectName), {}, {}, 0, {}); + _out_rErrorToDisplay = aError; + } + + } + + // HierarchicalNameCheck + HierarchicalNameCheck::HierarchicalNameCheck( const Reference< XHierarchicalNameAccess >& _rxNames, const OUString& _rRelativeRoot ) + { + mxHierarchicalNames = _rxNames; + msRelativeRoot = _rRelativeRoot; + + if ( !mxHierarchicalNames.is() ) + throw IllegalArgumentException(); + } + + HierarchicalNameCheck::~HierarchicalNameCheck() + { + } + + bool HierarchicalNameCheck::isNameValid( const OUString& _rObjectName, SQLExceptionInfo& _out_rErrorToDisplay ) const + { + try + { + OUStringBuffer aCompleteName; + if ( !msRelativeRoot.isEmpty() ) + { + aCompleteName.append( msRelativeRoot + "/" ); + } + aCompleteName.append( _rObjectName ); + + OUString sCompleteName( aCompleteName.makeStringAndClear() ); + if ( !mxHierarchicalNames->hasByHierarchicalName( sCompleteName ) ) + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + lcl_fillNameExistsError( _rObjectName, _out_rErrorToDisplay ); + return false; + } + + // DynamicTableOrQueryNameCheck + DynamicTableOrQueryNameCheck::DynamicTableOrQueryNameCheck( const Reference< XConnection >& _rxSdbLevelConnection, sal_Int32 _nCommandType ) + { + Reference< XConnectionTools > xConnTools( _rxSdbLevelConnection, UNO_QUERY ); + if ( xConnTools.is() ) + mxObjectNames.set( xConnTools->getObjectNames() ); + if ( !mxObjectNames.is() ) + throw IllegalArgumentException(); + + if ( ( _nCommandType != CommandType::QUERY ) && ( _nCommandType != CommandType::TABLE ) ) + throw IllegalArgumentException(); + mnCommandType = _nCommandType; + } + + DynamicTableOrQueryNameCheck::~DynamicTableOrQueryNameCheck() + { + } + + bool DynamicTableOrQueryNameCheck::isNameValid( const OUString& _rObjectName, ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay ) const + { + try + { + mxObjectNames->checkNameForCreate( mnCommandType, _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 0000000000..526a39ecbc --- /dev/null +++ b/dbaccess/source/ui/misc/dsmeta.cxx @@ -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 . + */ + +#include +#include +#include +#include + +#include +#include + +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 + DataSourceMetaData::DataSourceMetaData( const OUString& _sURL ) + :m_sURL( _sURL ) + { + } + + DataSourceMetaData::~DataSourceMetaData() + { + } + + const FeatureSet& DataSourceMetaData::getFeatureSet() const + { + return lcl_getFeatureSet( m_sURL ); + } + + 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 0000000000..388df30e27 --- /dev/null +++ b/dbaccess/source/ui/misc/imageprovider.cxx @@ -0,0 +1,192 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +#include +#include +#include +#include + +#include + +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; + + namespace + { + void lcl_getConnectionProvidedTableIcon_nothrow( + const css::uno::Reference< css::sdb::application::XTableUIProvider >& _xTableUI, + const OUString& _rName, Reference< XGraphic >& _out_rxGraphic ) + { + try + { + if ( _xTableUI.is() ) + _out_rxGraphic = _xTableUI->getTableIcon( _rName, GraphicColorMode::NORMAL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void lcl_getTableImageResourceID_nothrow( + const css::uno::Reference< css::container::XNameAccess >& _xViews, + const OUString& _rName, + OUString& _out_rResourceID) + { + _out_rResourceID = OUString(); + try + { + bool bIsView = _xViews.is() && _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() + { + } + + ImageProvider::ImageProvider( const Reference< XConnection >& _rxConnection ) + : mxConnection(_rxConnection) + { + try + { + Reference< XViewsSupplier > xSuppViews( mxConnection, UNO_QUERY ); + if ( xSuppViews.is() ) + mxViews.set( xSuppViews->getViews(), UNO_SET_THROW ); + + mxTableUI.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( mxViews, _rName, sImageResourceID ); + return sImageResourceID; + } + } + + Reference ImageProvider::getXGraphic(const OUString& _rName, const sal_Int32 _nDatabaseObjectType) + { + Reference xGraphic; + if (_nDatabaseObjectType == DatabaseObject::TABLE) + { + // check whether the connection can give us an icon + lcl_getConnectionProvidedTableIcon_nothrow( mxTableUI, _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 0000000000..169512ce72 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +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 OUString s_sNamePropertyName = u"Name"_ustr; + // 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 0000000000..dff938e376 --- /dev/null +++ b/dbaccess/source/ui/misc/linkeddocuments.cxx @@ -0,0 +1,350 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +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(n1 >> 24), + /* [ 1] */ static_cast(( n1 << 8 ) >> 24), + /* [ 2] */ static_cast(( n1 << 16 ) >> 24), + /* [ 3] */ static_cast(( n1 << 24 ) >> 24), + /* [ 4] */ static_cast(n2 >> 8), + /* [ 5] */ static_cast(( n2 << 8 ) >> 8), + /* [ 6] */ static_cast(n3 >> 8), + /* [ 7] */ static_cast(( n3 << 8 ) >> 8), + /* [ 8] */ static_cast(b8), + /* [ 9] */ static_cast(b9), + /* [10] */ static_cast(b10), + /* [11] */ static_cast(b11), + /* [12] */ static_cast(b12), + /* [13] */ static_cast(b13), + /* [14] */ static_cast(b14), + /* [15] */ static_cast(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, OUString _sDataSourceName ) + :m_xContext(_rxContext) + ,m_xDocumentContainer(_rxContainer) + ,m_xConnection(_xConnection) + ,m_xDocumentUI( i_rDocumentUI ) + ,m_pDialogParent(pDialogParent) + ,m_sDataSourceName(std::move(_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 ElementOpenMode::Normal: + sOpenMode = "open"; + break; + + case ElementOpenMode::Mail: + aArguments.put( "Hidden", true ); + [[fallthrough]]; + + case ElementOpenMode::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 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 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 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(sMessage, {}, {}, 0, {}); + aInfo = dbtools::SQLExceptionInfo(aSQLException); + } + } + catch(const css::io::WrongFormatException &e) + { + css::sdbc::SQLException aSQLException(e.Message, e.Context, {}, 0, {}); + 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(e.Message, e.Context, {}, 0, {}); + 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 0000000000..c3c5049942 --- /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 + +#include +#include +#include + +#include + +#include +#include + +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 0000000000..6f58676629 --- /dev/null +++ b/dbaccess/source/ui/misc/singledoccontroller.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 +#include +#include +#include +#include +#include + +#include + +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 + OSingleDocumentController::OSingleDocumentController( const Reference< XComponentContext >& _rxORB ) + :OSingleDocumentController_Base( _rxORB ) + ,m_pUndoManager(new UndoManager(*this, getMutex())) + { + } + + OSingleDocumentController::~OSingleDocumentController() + { + } + + void SAL_CALL OSingleDocumentController::disposing() + { + OSingleDocumentController_Base::disposing(); + ClearUndoManager(); + m_pUndoManager->disposing(); + } + + void OSingleDocumentController::ClearUndoManager() + { + GetUndoManager().Clear(); + } + + SfxUndoManager& OSingleDocumentController::GetUndoManager() const + { + return m_pUndoManager->GetSfxUndoManager(); + } + + void OSingleDocumentController::addUndoActionAndInvalidate(std::unique_ptr _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_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 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 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 0000000000..97e75fe6d4 --- /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 + +namespace dbaui +{ +using namespace ::com::sun::star::uno; + +// OStringListItem +OStringListItem::OStringListItem(sal_Int16 _nWhich, const Sequence& _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(&_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 0000000000..b22a05424d --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLine.cxx @@ -0,0 +1,357 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 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( 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(pListBox->GetPosPixel().Y()*0.5) ); + + _rNewDescrPos.setY( _rNewConPos.Y() ); + } +} + +OConnectionLine::OConnectionLine( OTableConnection* _pConn, OConnectionLineDataRef _pLineData ) + : m_pTabConn( _pConn ) + , m_pData(std::move( _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( 0.5*pSourceWin->GetSizePixel().Width() ) ); + aDestCenter.setX( pDestWin->GetPosPixel().X() + static_cast( 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 0000000000..eac2bf1756 --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLineAccess.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 +#include +#include +#include +#include +#include +#include +#include + +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) + : ImplInheritanceHelper(_pLine->GetComponentInterface().is() ? _pLine->GetWindowPeer() : nullptr) + ,m_pLine(_pLine) + { + } + void SAL_CALL OConnectionLineAccess::disposing() + { + m_pLine = nullptr; + VCLXAccessibleComponent::disposing(); + } + OUString SAL_CALL OConnectionLineAccess::getImplementationName() + { + return "org.openoffice.comp.dbu.ConnectionLineAccessibility"; + } + // XAccessibleContext + sal_Int64 SAL_CALL OConnectionLineAccess::getAccessibleChildCount( ) + { + return 0; + } + Reference< XAccessible > SAL_CALL OConnectionLineAccess::getAccessibleChild( sal_Int64 /*i*/ ) + { + return Reference< XAccessible >(); + } + sal_Int64 SAL_CALL OConnectionLineAccess::getAccessibleIndexInParent( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int64 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.getOpenWidth(),aRect.getOpenHeight()); + } + 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 > 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 0000000000..8267cc3ed8 --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLineData.cxx @@ -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 . + */ + +#include +#include + +using namespace dbaui; +OConnectionLineData::OConnectionLineData() +{ +} + +OConnectionLineData::OConnectionLineData( OUString sSourceFieldName, OUString sDestFieldName ) + :m_aSourceFieldName(std::move( sSourceFieldName )) + ,m_aDestFieldName(std::move( sDestFieldName )) +{ +} + +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 0000000000..b67d31c309 --- /dev/null +++ b/dbaccess/source/ui/querydesign/JAccess.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 +#include +#include +#include +#include +#include +#include + +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) + :ImplInheritanceHelper(_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_Int64 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_Int64 nChildCount = 0; + if ( m_pTableView ) + nChildCount = m_pTableView->GetTabWinCount() + m_pTableView->getTableConnections().size(); + return nChildCount; + } + Reference< XAccessible > SAL_CALL OJoinDesignViewAccess::getAccessibleChild( sal_Int64 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_Int64 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; + } +} + +/* 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 0000000000..b96615c1d8 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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) +{ + std::erase(m_vTableConnectionData, _pData); +} + +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(elem->GetPosition().Y()) ); + aWindowData.put( "WindowLeft", static_cast(elem->GetPosition().X()) ); + aWindowData.put( "WindowWidth", static_cast(elem->GetSize().Width()) ); + aWindowData.put( "WindowHeight", static_cast(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 0000000000..c0d3ea81c7 --- /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 +#include +#include +#include +#include + +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::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 0000000000..0dc88e2cc7 --- /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 +#include +#include + +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(_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 0000000000..1be2fd39d9 --- /dev/null +++ b/dbaccess/source/ui/querydesign/JoinTableView.cxx @@ -0,0 +1,1567 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QueryMoveTabWinUndoAct.hxx" +#include "QuerySizeTabWinUndoAct.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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::Create(this, true) ) + ,m_aVScrollBar( VclPtr::Create(this, false) ) + ,m_pTableView(nullptr) +{ + StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings(); + SetBackground(aSystemStyle.GetFaceColor()); + + // ScrollBars + GetHScrollBar().SetRange( Range(0, 1000) ); + GetVScrollBar().SetRange( Range(0, 1000) ); + + GetHScrollBar().SetLineSize( LINE_SIZE ); + GetVScrollBar().SetLineSize( LINE_SIZE ); + + GetHScrollBar().Show(); + GetVScrollBar().Show(); + + // normally we should be SCROLL_PANE + SetAccessibleRole(AccessibleRole::SCROLL_PANE); +} + +OScrollWindowHelper::~OScrollWindowHelper() +{ + disposeOnce(); +} + +void OScrollWindowHelper::dispose() +{ + m_aHScrollBar.disposeAndClear(); + m_aVScrollBar.disposeAndClear(); + m_pTableView.clear(); + vcl::Window::dispose(); +} + +void OScrollWindowHelper::setTableView(OJoinTableView* _pTableView) +{ + m_pTableView = _pTableView; + // ScrollBars + GetHScrollBar().SetScrollHdl( LINK(m_pTableView, OJoinTableView, HorzScrollHdl) ); + GetVScrollBar().SetScrollHdl( LINK(m_pTableView, OJoinTableView, VertScrollHdl) ); +} + +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 ) + ); + + 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, HorzScrollHdl, weld::Scrollbar&, rScrollbar, void) +{ + // move all windows + ScrollPane(rScrollbar.adjustment_get_value() - m_aScrollOffset.X(), true, false); +} + +IMPL_LINK(OJoinTableView, VertScrollHdl, weld::Scrollbar&, rScrollbar, void) +{ + // move all windows + ScrollPane(rScrollbar.adjustment_get_value() - m_aScrollOffset.Y(), false, 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 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_Int64 OJoinTableView::GetTabWinCount() const +{ + return m_aTableMap.size(); +} + +bool OJoinTableView::RemoveConnection(VclPtr& rConn, bool _bDelete) +{ + VclPtr 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 OJoinTableView::CreateImpl(const OUString& _rComposedName + ,const OUString& _sTableName + ,const OUString& _rWinName) +{ + return std::make_shared( 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 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& 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(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 + ScrollAdaptor& 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.Top()) && (aOtherTabWinRect.Bottom()aNewPos.X() ) + aNewPos.setX( aOtherTabWinRect.Right() + TABWIN_SPACING_X ); + } + } + + // Is there space left in this line? + if( (aNewPos.X()+TABWIN_WIDTH_STD) 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& /*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>& 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 >::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 _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(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(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(m_aTableMap.size())) + return false; + } + catch(SQLException&) + { + return false; + } + + return true; +} + +void OJoinTableView::executePopup(const Point& rPos, VclPtr& rSelConnection) +{ + ::tools::Rectangle aRect(rPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/joinviewmenu.ui")); + std::unique_ptr xContextMenu(xBuilder->weld_menu("menu")); + OUString 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& rSelConnection = GetSelectedConn(); + // when it wasn't a mouse event use the selected connection + if (!rEvt.IsMouseEvent()) + { + if (rSelConnection) + { + const std::vector>& 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 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 NotifyEventType::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 NotifyEventType::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(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 NotifyEventType::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 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 0000000000..c5db155f22 --- /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 +#include + +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(GetData().get()); + OQueryTableConnectionData* pCompData = static_cast(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 0000000000..c6bd2e10d4 --- /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 +#include "QTableConnectionData.hxx" +#include + +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(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 0000000000..ce66828fac --- /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 + +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(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(rDragLeft->GetTabWindow()); + OQueryTableWindow* pDestWin = static_cast(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 OQueryTableConnectionData::NewInstance() const +{ + return std::make_shared(); +} + +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 0000000000..7ccbb03acd --- /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 +#include +#include + +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 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 0000000000..6b129c32d5 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TableFieldInfo.hxx" +#include +#include + +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(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(_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(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(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 xEntry(rTreeView.make_iterator()); + bool bEntry = rTreeView.get_iter_first(*xEntry); + try + { + Reference xMeta = xConnection->getMetaData(); + ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()); + + while (bEntry) + { + if (bCase(strFieldName, rTreeView.get_text(*xEntry))) + { + OTableFieldInfo* pInf = weld::fromId(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(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 0000000000..72c698c832 --- /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 +#include "QTableWindowData.hxx" +#include + +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(GetData().get())->GetAliasName(); + } + void SetAliasName(const OUString& strNewAlias) + { + static_cast(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 . + */ + virtual void deleteUserData(void*& _pUserData) override; + + /** creates user information that will be append at the ListBoxentry + @param _xColumn + The corresponding column, can be . + @param _bPrimaryKey + when the column belongs to the primary key + @return + the user data which will be append at the listbox entry, may be + */ + 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 0000000000..d8f2f2efd1 --- /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 0000000000..327dc27f1a --- /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 + + +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 0000000000..dd641be1da --- /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 0000000000..13262f5702 --- /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 +#include +#include "SelectionBrowseBox.hxx" +#include + +namespace dbaui +{ + // OQueryDesignFieldUndoAct - Basisclass for undo's in the fieldlist of a query design + + class OQueryDesignFieldUndoAct : public OCommentUndoAction + { + protected: + VclPtr 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 0000000000..8a87423930 --- /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 +#include +#include + +namespace dbaui +{ + // OQueryDesignUndoAction - undo base class for actions in graphical query design (without field list) + class OJoinTableView; + class OQueryDesignUndoAction : public OCommentUndoAction + { + protected: + VclPtr 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 0000000000..9d3adc7f8b --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryDesignView.cxx @@ -0,0 +1,3433 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include "QTableWindow.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "SelectionBrowseBox.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "QTableConnection.hxx" +#include +#include "QTableConnectionData.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +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, std::u16string_view _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(_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(_pView->getTableView()); + OQueryTableConnection* pConn = static_cast( pTableView->GetTabConn(static_cast(_aDragLeft->GetTabWindow()),static_cast(_aDragRight->GetTabWindow()),true)); + + if ( !pConn ) + { + auto xInfoData = std::make_shared(); + xInfoData->InitFromDrag(_aDragLeft, _aDragRight); + xInfoData->SetJoinType(_eJoinType); + + if ( _bNatural ) + { + xInfoData->ResetConnLines(); + xInfoData->setNatural(_bNatural); + try + { + Reference 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()) + std::swap(aSourceFieldName, aDestFieldName); + 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(_pView->getController()).getParseIterator(); + rParseIter.getColumnRange( pColumnRef, aColumnName, aTableRange ); + + if ( !aTableRange.isEmpty() ) + { + OQueryTableWindow* pSTW = static_cast(_pView->getTableView())->FindTable( aTableRange ); + bErg = (pSTW && pSTW->ExistsField( aColumnName, _rDragInfo ) ); + } + if ( !bErg ) + { + sal_uInt16 nCntAccount; + bErg = static_cast(_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 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) + + ::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_FROM) ) + + " = " + + quoteTableAlias(true,pData->GetAliasName(JTCS_TO),aQuote) + + ::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 &_rTableNames ) + { + // insert tables into table list to avoid double entries + const OQueryTableWindow* const pEntryTabFrom = static_cast(pEntryConn->GetSourceWin()); + const OQueryTableWindow* const pEntryTabTo = static_cast(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 &_rTableNames) + { + OQueryTableConnectionData* pEntryConnData = static_cast(pEntryConn->GetData().get()); + if ( pEntryConnData->GetJoinType() == INNER_JOIN && !pEntryConnData->isNatural() ) + return; + + if(aJoin.isEmpty()) + { + addConnectionTableNames(_xConnection, pEntryConn, _rTableNames); + OQueryTableWindow* pEntryTabFrom = static_cast(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(connection.get()); + if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabTo || pNext->GetDestWin() == pEntryTabTo)) + { + OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabTo ? static_cast(pNext->GetDestWin()) : static_cast(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(pEntryConn->GetSourceWin()); + for (auto const& connection : rConnections) + { + OQueryTableConnection* pNext = static_cast(connection.get()); + if(!pNext->IsVisited() && (pNext->GetSourceWin() == pEntryTabFrom || pNext->GetDestWin() == pEntryTabFrom)) + { + OQueryTableWindow* pEntryTab = pNext->GetSourceWin() == pEntryTabFrom ? static_cast(pNext->GetDestWin()) : static_cast(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(_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(_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(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 " + ::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(_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(nMaxCriteria,static_cast(field->GetCriteria().size())); + } + try + { + const Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + const OUString aQuote = xMetaData->getIdentifierQuoteString(); + const IParseContext& rContext = static_cast(_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 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 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 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(_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 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(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 >& _rConnList) + { + for (auto const& connection : _rConnList) + { + const OQueryTableConnection* pEntryConn = static_cast(connection.get()); + OQueryTableConnectionData* pEntryConnData = static_cast(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& _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 >& rConnList + ) + { + + OUString aTableListStr; + // used to avoid putting a table twice in FROM clause + std::set aTableNames; + + // generate outer join clause in from + if(!rConnList.empty()) + { + std::map aConnectionCount; + auto aEnd = rConnList.end(); + for (auto const& connection : rConnList) + { + static_cast(connection.get())->SetVisited(false); + ++aConnectionCount[connection->GetSourceWin()]; + ++aConnectionCount[connection->GetDestWin()]; + } + std::multimap aMulti; + for (auto const& elem : aConnectionCount) + { + aMulti.emplace(elem.second,elem.first); + } + + const bool bUseEscape = ::dbtools::getBooleanDataSourceSetting( _xConnection, PROPERTY_OUTERJOINESCAPE ); + std::multimap::const_reverse_iterator aRIter = aMulti.rbegin(); + std::multimap::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((*aConIter).get()); + if(!pEntryConn->IsVisited() && pEntryConn->GetSourceWin() == aRIter->second ) + { + OUString aJoin; + GetNextJoin(_xConnection, + pEntryConn, + static_cast(pEntryConn->GetDestWin()), + aJoin, + aTableNames); + + if(!aJoin.isEmpty()) + { + OUString aStr; + switch(static_cast(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(connection.get()); + if(!pEntryConn->IsVisited()) + { + searchAndAppendName(_xConnection, + static_cast(pEntryConn->GetSourceWin()), + aTableNames, + aTableListStr); + + searchAndAppendName(_xConnection, + static_cast(pEntryConn->GetDestWin()), + aTableNames, + aTableListStr); + } + } + } + // all tables that haven't a connection to anyone + for (auto const& table : *pTabList) + { + const OQueryTableWindow* pEntryTab = static_cast(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(_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 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(_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(_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(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(_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( + _pView->getTableView()->GetTabConn(static_cast(aDragLeft->GetTabWindow()), + static_cast(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(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(_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(_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(_pView->getTableView())->FindTable( getTableRange(_pView,pNode->getChild(0)) ); + OQueryTableWindow* pRightWindow = static_cast(_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(_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(_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(aMap.size()) ) + { + eErrorCode = eTooManyTables; + break; + } + + OUString sComposedName; + OUString sAlias; + + OQueryTableView* pTableView = static_cast(_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 + when columns could be inserted otherwise + */ + SqlParseError fillSelectSubList( OQueryDesignView* _pView, + OJoinTableView::OTableWindowMap* _pTabList) + { + SqlParseError eErrorCode = eOk; + bool bFirstField = true; + for (auto const& table : *_pTabList) + { + OQueryTableWindow* pTabWin = static_cast(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(_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(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(_pView->getController()); + EOrderDir eOrderDir; + for( size_t i=0 ; icount() ; 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(_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::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::Create(this); + + setNoneVisibleRow(static_cast(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(getController()).setSplitPos(m_aSplitter->GetSplitPosPixel()); + static_cast(getController()).setModified( true ); + Resize(); + m_bInSplitHandler = true; + } +} + +void OQueryDesignView::Construct() +{ + m_pTableView = VclPtr::Create(m_pScrollWindow,this); + ::dbaui::notifySystemWindow(this,m_pTableView,::comphelper::mem_fun(&TaskPaneList::AddWindow)); + OJoinDesignView::Construct(); +} + +void OQueryDesignView::initialize() +{ + if(static_cast(getController()).getSplitPos() != -1) + { + m_aSplitter->SetPosPixel( Point( m_aSplitter->GetPosPixel().X(),static_cast(getController()).getSplitPos() ) ); + m_aSplitter->SetSplitPosPixel(static_cast(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(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(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(getController()).setModified(true); + } +} + +void OQueryDesignView::paste() +{ + if( m_eChildFocus == SELECTION) + { + m_pSelectionBox->paste(); + static_cast(getController()).setModified(true); + } +} + +void OQueryDesignView::TableDeleted(const OUString& rAliasName) +{ + // message that the table was removed from the window + m_pSelectionBox->DeleteFields( rAliasName ); + static_cast(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(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(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() == NotifyEventType::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(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 + " FROM " + aTableListStr); + + if (!aCriteriaListStr.isEmpty()) + { + aSqlCmd.append(" WHERE " + aCriteriaListStr); + } + Reference 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 " + 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 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(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 OQueryDesignView::getPredicateTreeFromEntry(const OTableFieldDescRef& pEntry, + const OUString& _sCriteria, + OUString& _rsErrorMessage, + Reference& _rxColumn) const +{ + OSL_ENSURE(pEntry.is(),"Entry is null!"); + if(!pEntry.is()) + return nullptr; + Reference< XConnection> xConnection = static_cast(getController()).getConnection(); + if(!xConnection.is()) + return nullptr; + + ::connectivity::OSQLParser& rParser( static_cast(getController()).getParser() ); + OQueryTableWindow* pWin = static_cast(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 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 xMeta = xConnection->getMetaData(); + rtl::Reference 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 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 pParseNode = rParser.predicateTree( _rsErrorMessage, + _sCriteria, + static_cast(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(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 0000000000..3987328158 --- /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 + +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 0000000000..e6b58956ed --- /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 +#include +#include +#include + +namespace dbaui +{ + + // OQueryMoveTabWinUndoAct - Undo class for moving a TabWin + class OTableWindow; + class OJoinMoveTabWinUndoAct final : public OQueryDesignUndoAction + { + Point m_ptNextPosition; + VclPtr 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 0000000000..de244ccb53 --- /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 +#include + +namespace dbaui +{ + + // OQuerySizeTabWinUndoAct - undo class to change size of TabWins + class OTableWindow; + class OJoinSizeTabWinUndoAct final : public OQueryDesignUndoAction + { + Point m_ptNextPosition; + Size m_szNextSize; + VclPtr 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 0000000000..e3b6cd0e94 --- /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 +#include "QueryAddTabConnUndoAction.hxx" +#include "QueryTabWinShowUndoAct.hxx" +#include + +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(m_pOwner.get())->DropConnection(m_pConnection); + SetOwnership(true); +} + +void OQueryAddTabConnUndoAction::Redo() +{ + static_cast(m_pOwner.get())->GetConnection(m_pConnection); + SetOwnership(false); +} + +OQueryDelTabConnUndoAction::OQueryDelTabConnUndoAction(OQueryTableView* pOwner) + : OQueryTabConnUndoAction(pOwner, STR_QUERY_UNDO_REMOVECONNECTION) +{ +} + +void OQueryDelTabConnUndoAction::Undo() +{ + static_cast(m_pOwner.get())->GetConnection(m_pConnection); + SetOwnership(false); +} + +void OQueryDelTabConnUndoAction::Redo() +{ + static_cast(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(m_pOwner.get())->HideTabWin(m_pTabWin, this); + SetOwnership(true); +} + +void OQueryTabWinShowUndoAct::Redo() +{ + static_cast(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(m_pOwner.get())->ShowTabWin(m_pTabWin, this, true); + SetOwnership(false); +} + +void OQueryTabWinDelUndoAct::Redo() +{ + static_cast(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 0000000000..21077074ee --- /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 + +namespace dbaui +{ + class OQueryTableConnection; + class OQueryTableView; + class OQueryTabConnUndoAction : public OQueryDesignUndoAction + { + protected: + VclPtr 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 0000000000..95b740de98 --- /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 0000000000..2afe74db42 --- /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 +#include "QTableWindow.hxx" +#include "QueryDesignFieldUndoAct.hxx" +#include + +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 0000000000..9b43305428 --- /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 +#include + +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 > m_vTableConnection; + VclPtr 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 >& 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 0000000000..663d3a9e65 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTableView.cxx @@ -0,0 +1,885 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include "QTableWindow.hxx" +#include "QTableConnection.hxx" +#include "QTableConnectionData.hxx" +#include +#include "QueryAddTabConnUndoAction.hxx" +#include "QueryTabWinShowUndoAct.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "querydlg.hxx" +#include +#include +#include + +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 _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(_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& _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( _rSource.GetData(), _rDest.GetData() ); + + OUString sRelatedColumn; + + // iterate through all foreignkey columns to create the connections + const Sequence aKeyCols = _rxSourceForeignKeyColumns->getElementNames(); + for(const OUString& rElement : aKeyCols) + { + Reference 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 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 arrInvalidTables; + + TTableWindowData::const_reverse_iterator aIter = rTabWinDataList.rbegin(); + // Create the window and add it + + for(;aIter != rTabWinDataList.rend();++aIter) + { + OQueryTableWindowData* pData = static_cast(aIter->get()); + VclPtr 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()); + + std::erase(rTabWinDataList, *aIter); + 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(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 + std::erase(rTabConnDataList, *aConIter); + continue; + } + + // adds a new connection to join view and notifies our accessible and invalidates the controller + addConnection(VclPtr::Create(this, *aConIter)); + } +} + +void OQueryTableView::ClearAll() +{ + OJoinTableView::ClearAll(); + + SetUpdateMode(true); + m_pView->getController().setModified(true); +} + +VclPtr OQueryTableView::createWindow(const TTableWindowData::value_type& _pData) +{ + return VclPtr::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(const_cast(static_cast(&rNewConn))) + ); + if(aIter == aEnd) + { + for (auto const& connection : rConnections) + { + if(*static_cast(connection.get()) == rNewConn) + { + pTabConn = static_cast(connection.get()); + break; + } + } + } + else + pTabConn = static_cast((*aIter).get()); + + // no -> insert + if (pTabConn == nullptr) + { + // the new data ... + auto pNewData = std::static_pointer_cast(rNewConn.GetData()->NewInstance()); + pNewData->CopyFrom(*rNewConn.GetData()); + VclPtrInstance pNewConn(this, pNewData); + GetConnection(pNewConn); + + connectionModified(this,pNewConn,_bCreateUndoAction); + } +} + +std::shared_ptr OQueryTableView::CreateImpl(const OUString& _rComposedName + ,const OUString& _sTableName + ,const OUString& _rWinName) +{ + return std::make_shared( _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 getKeyReferencedTo(const Reference& _rxKeys,std::u16string_view _rReferencedTable) +{ + if(!_rxKeys.is()) + return Reference(); + + // search the one and only primary key + const sal_Int32 nCount = _rxKeys->getCount(); + for(sal_Int32 i=0;i 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(); +} + +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 pNewTabWin = static_cast(createWindow(pNewTabWinData).get()); + // No need to initialize, as that happens in ShowTabWin + + // New UndoAction + std::unique_ptr 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 xFKeyColumns; + OUString aReferencedTable; + Reference xColumnsSupplier; + + const sal_Int32 nKeyCount = xKeyIndex->getCount(); + for ( sal_Int32 i=0; i 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(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(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(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 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(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) + std::swap(aSourceFieldName, aDestFieldName); + + pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName ); + + connectionModified(this,pConn,false); + } +} + +void OQueryTableView::ConnDoubleClicked(VclPtr& rConnection) +{ + if (openJoinDialog(this, rConnection->GetData(), false)) + { + connectionModified(this, rConnection, false); + SelectConn(rConnection); + } +} + +void OQueryTableView::createNewConnection() +{ + TTableConnectionData::value_type pData = std::make_shared(); + 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 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& rConnection, bool /*_bDelete*/) +{ + VclPtr xConnection(static_cast(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(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(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(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(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 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 const & rConn) +{ + // Pay attention to the selection + // remove from me and the document + VclPtr 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(); + std::erase(rTabWinDataList, pTabWin->GetData()); + // 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 xTmpEntry = *aIter2; + OQueryTableConnection* pTmpEntry = static_cast(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(getDesignView())->InsertField(rInfo); +} + +bool OQueryTableView::ExistsAVisitedConn(const OQueryTableWindow* pFrom) const +{ + for(const auto& conn : getTableConnections()) + { + OQueryTableConnection* pTemp = static_cast(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(_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 0000000000..daeb6ee14f --- /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 +#include +#include +#include +#include +#include +#include + +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 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 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 0000000000..a51f2941ad --- /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 +#include +#include +#include +#include +#include + +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::Create(_pParent, _rController); + m_pDesignView = VclPtr::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(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(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 0000000000..eb6c666f53 --- /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 + +#include + +#include "SelectionBrowseBox.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TableFieldInfo.hxx" +#include +#include +#include +#include +#include "QTableWindow.hxx" +#include +#include +#include "QueryDesignFieldUndoAct.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(std::u16string_view _sFieldName ) + { + bool bAsterisk = _sFieldName.empty() || _sFieldName[0] == '*'; + 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::Create(&GetDataWindow()); + m_pVisibleCell = VclPtr::Create(&GetDataWindow()); + m_pTableCell = VclPtr::Create(&GetDataWindow()); + m_pFieldCell = VclPtr::Create(&GetDataWindow()); + m_pOrderCell = VclPtr::Create(&GetDataWindow()); + m_pFunctionCell = VclPtr::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(getDesignView()->getController()).getConnection(); + if(xConnection.is()) + { + const IParseContext& rContext = static_cast(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(GetParent()),"Parent isn't an OQueryDesignView!"); + return static_cast(GetParent()); +} + +OQueryDesignView* OSelectionBrowseBox::getDesignView() const +{ + OSL_ENSURE(static_cast(GetParent()),"Parent isn't an OQueryDesignView!"); + return static_cast(GetParent()); +} + +namespace +{ + class OSelectionBrwBoxHeader : public ::svt::EditBrowserHeader + { + VclPtr 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 OSelectionBrowseBox::imp_CreateHeaderBar(BrowseBox* /*pParent*/) +{ + return VclPtr::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 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 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 xConnection = static_cast(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(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(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 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(std::u16string_view _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& _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(_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(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(_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(getDesignView()->getController()); + + // first look if the name can be found in our tables + sal_uInt16 nTabCount = 0; + OUString sOldAlias = _pEntry->GetAlias(); + if ( static_cast(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( 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 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 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(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 = 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(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(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(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(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(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 xColumn; + std::unique_ptr pParseNode = getDesignView()->getPredicateTreeFromEntry(pEntry,aText,aErrorMsg,xColumn); + + if (pParseNode) + { + pParseNode->parseNodeToPredicateStr(aCrit, + xConnection, + static_cast(getDesignView()->getController()).getNumberFormatter(), + xColumn, + pEntry->GetAlias(), + getDesignView()->getLocale(), + getDesignView()->getDecimalSeparator(), + &(static_cast(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(getDesignView()->getController()).getParser(); + pParseNode = rParser.predicateTree(aErrorMsg, + aText, + static_cast(getDesignView()->getController()).getNumberFormatter(), + xColumn); + if (pParseNode) + { + pParseNode->parseNodeToPredicateStr(aCrit, + xConnection, + static_cast(getDesignView()->getController()).getNumberFormatter(), + xColumn, + pEntry->GetAlias(), + getDesignView()->getLocale(), + getDesignView()->getDecimalSeparator(), + &(static_cast(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(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(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(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(nPos - 1)) ; + pDesc->SetColWidth( static_cast(GetColumnWidth(nColumnId)) ); // was not stored this before + + // trigger UndoAction + if ( !m_bInUndoMode ) + { + std::unique_ptr 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(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(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(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(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(getDesignView()->getController()).setModified( true ); + + invalidateUndoRedo(); +} + +OTableFieldDescRef OSelectionBrowseBox::InsertField(const OJoinExchangeData& jxdSource) +{ + OQueryTableWindow* pSourceWin = static_cast(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(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 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(getDesignView()->getController()).getConnection(); + if(!xConnection.is()) + return; + OSL_ENSURE(!rInfo->IsEmpty(),"AddGroupBy:: OTableFieldDescRef should not be empty!"); + OTableFieldDescRef pEntry; + const Reference 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(getDesignView()->getController()).getConnection(); + if(!xConnection.is()) + return; + OSL_ENSURE(rInfo.is() && !rInfo->IsEmpty(),"AddCondition:: OTableFieldDescRef should not be Empty!"); + + OTableFieldDescRef pLastEntry; + Reference 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(getDesignView()->getController()).getConnection(); + if(!xConnection.is()) + return; + OSL_ENSURE(!rInfo->IsEmpty(),"AddOrder:: OTableFieldDescRef should not be Empty!"); + OTableFieldDescRef pEntry; + Reference 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(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(getDesignView()->getController()).isReadOnly()) + { + ::tools::Rectangle aRect(aMenuPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/querycolmenu.ui")); + std::unique_ptr xContextMenu(xBuilder->weld_menu("menu")); + OUString 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(getDesignView()->getController()).isReadOnly()) + { + ::tools::Rectangle aRect(aMenuPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + std::unique_ptr xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/queryfuncmenu.ui")); + std::unique_ptr 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(getDesignView()->getController()).isDistinct()); + + OUString sIdent = xContextMenu->popup_at_rect(pPopupParent, aRect); + if (sIdent == "functions") + { + SetRowVisible(BROW_FUNCTION_ROW, !IsRowVisible(BROW_FUNCTION_ROW)); + static_cast(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_FUNCTIONS ); + } + else if (sIdent == "tablename") + { + SetRowVisible(BROW_TABLE_ROW, !IsRowVisible(BROW_TABLE_ROW)); + static_cast(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_TABLES ); + } + else if (sIdent == "alias") + { + SetRowVisible(BROW_COLUMNALIAS_ROW, !IsRowVisible(BROW_COLUMNALIAS_ROW)); + static_cast(getDesignView()->getController()).InvalidateFeature( SID_QUERY_VIEW_ALIASES ); + } + else if (sIdent == "distinct") + { + static_cast(getDesignView()->getController()).setDistinct(!static_cast(getDesignView()->getController()).isDistinct()); + static_cast(getDesignView()->getController()).setModified( true ); + static_cast(getDesignView()->getController()).InvalidateFeature( SID_QUERY_DISTINCT_VALUES ); + } + + static_cast(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 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}; nIdxIsVisible() ? 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(nRow)) && (GetCurRow() == static_cast(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(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(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(getDesignView()->getController()).setModified( true ); +} + +void OSelectionBrowseBox::ColumnResized(sal_uInt16 nColId) +{ + if (static_cast(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(getDesignView()->getController()).setModified( true ); + EditBrowseBox::ColumnResized(nColId); + + if ( pEntry.is()) + { + if ( !m_bInUndoMode ) + { + // create the undo action + std::unique_ptr 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(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 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(getDesignView()->getController()).InvalidateFeature(SID_CUT); + static_cast(getDesignView()->getController()).InvalidateFeature(SID_COPY); + static_cast(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(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 OUString& _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(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(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(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 0000000000..d5e11c03e3 --- /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 + +#include + +#include +#include +#include +#include +#include + +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 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 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 OUString& _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 when we are in a list action otherwise + @return + if an error occurred otherwise + */ + 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 + if the table name was set otherwise + */ + 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 when we are in a list action otherwise + @return + if an error occurred otherwise + */ + 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 when we are in a list action otherwise + */ + 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 when we are in a list action otherwise + */ + 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 a list action will be created. + */ + void clearEntryFunctionField(std::u16string_view _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 0000000000..2bfceb1b6c --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableConnection.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 +#include +#include +#include +#include + +using namespace dbaui; +using namespace comphelper; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::accessibility; + +namespace dbaui +{ + OTableConnection::OTableConnection( OJoinTableView* _pContainer, TTableConnectionData::value_type _aTabConnData ) + :Window(_pContainer) + ,m_pData(std::move( _aTabConnData )) + ,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>& 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 & 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 0000000000..aa524a5ac7 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableConnectionData.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 +#include +#include + +using namespace dbaui; + +OTableConnectionData::OTableConnectionData() +{ + Init(); +} + +OTableConnectionData::OTableConnectionData(TTableWindowData::value_type _pReferencingTable + ,TTableWindowData::value_type _pReferencedTable ) + :m_pReferencingTable(std::move(_pReferencingTable)) + ,m_pReferencedTable(std::move(_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::NewInstance() const +{ + return std::make_shared(); +} + +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 0000000000..1e86041818 --- /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 + +#include +#include +#include + +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(m_eFieldType) ); + o_rSettings.put( "OrderDir", static_cast(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 0000000000..808862c11c --- /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 0000000000..e7d2c9b72d --- /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 +#include + +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 0000000000..fe5310ea65 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindow.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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, TTableWindowData::value_type pTabWinData ) + : ::comphelper::OContainerListener(m_aMutex) + , Window( pParent, WB_3DLOOK|WB_MOVEABLE ) + , m_xTitle( VclPtr::Create(this) ) + , m_pData(std::move( 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(GetParent()),"No OJoinTableView!"); + return static_cast(GetParent()); +} + +OJoinTableView* OTableWindow::getTableView() +{ + OSL_ENSURE(static_cast(GetParent()),"No OJoinTableView!"); + return static_cast(GetParent()); +} + +OJoinDesignView* OTableWindow::getDesignView() +{ + OSL_ENSURE(static_cast(GetParent()->GetParent()->GetParent()),"No OJoinDesignView!"); + return static_cast(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 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 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(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::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 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 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 xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/jointablemenu.ui")); + std::unique_ptr 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 NotifyEventType::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 NotifyEventType::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 0000000000..2af1168d58 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowAccess.cxx @@ -0,0 +1,240 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +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) + :ImplInheritanceHelper(_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 ); + } + 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_Int64 SAL_CALL OTableWindowAccess::getAccessibleChildCount( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int64 nCount = 0; + if(m_pTable) + { + ++nCount; + if(m_pTable->GetListBox()) + ++nCount; + } + return nCount; + } + Reference< XAccessible > SAL_CALL OTableWindowAccess::getAccessibleChild( sal_Int64 i ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XAccessible > aRet; + if (m_pTable && !m_pTable->isDisposed()) + { + switch(i) + { + case 0: + { + VclPtr xCtrl(m_pTable->GetTitleCtrl()); + if (xCtrl) + aRet = xCtrl->GetAccessible(); + break; + } + case 1: + { + VclPtr xCtrl(m_pTable->GetListBox()); + if (xCtrl) + aRet = xCtrl->GetAccessible(); + break; + } + default: + throw IndexOutOfBoundsException(); + } + } + return aRet; + } + sal_Int64 SAL_CALL OTableWindowAccess::getAccessibleIndexInParent( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int64 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()) + { + AbsoluteScreenPixelPoint aPoint(_aPoint.X,_aPoint.Y); + AbsoluteScreenPixelRectangle 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_Int64 _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 > 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 xInterface( + getParentChild(aIter - rConnectionList.begin())); + aRelations.push_back(xInterface); + } + + Sequence< Reference > 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 0000000000..3cbead6e40 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowData.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + ,OUString _sComposedName + ,OUString sTableName + ,OUString sWinName ) + :m_xTable(_xTable) + ,m_aTableName(std::move( sTableName )) + ,m_aWinName(std::move( sWinName )) + ,m_sComposedName(std::move(_sComposedName)) + ,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( 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( 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 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 0000000000..3066f8429f --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 = rController.getConnection(); + if (xConnection.is()) + { + Reference 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 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 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 xCurrent = m_xTreeView->make_iterator(); + if (!m_xTreeView->get_cursor(xCurrent.get())) + return false; + + static_cast(pParent)->OnEntryDoubleClicked(*xCurrent); + + return false; +} + +void OTableWindowListBox::Command(const CommandEvent& rEvt) +{ + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + static_cast(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 0000000000..50eb19c28b --- /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 +#include +#include +#include +#include +#include +#include + +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(GetParent()), aPos ); + } + } + else if (rEvt.IsRight()) + { + CommandEvent aCEvt(rEvt.GetPosPixel(), CommandEventId::ContextMenu, true); + // tdf#94709 - protect shutdown code-path. + VclPtr 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 0000000000..b1a3b6d272 Binary files /dev/null and b/dbaccess/source/ui/querydesign/class.jpg differ diff --git a/dbaccess/source/ui/querydesign/limitboxcontroller.cxx b/dbaccess/source/ui/querydesign/limitboxcontroller.cxx new file mode 100644 index 0000000000..37624aceb4 --- /dev/null +++ b/dbaccess/source/ui/querydesign/limitboxcontroller.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/. + */ + +#include "limitboxcontroller.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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 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 ) : + LimitBoxController_Base( rxContext, + uno::Reference< frame::XFrame >(), + ".uno:DBLimit" ), + m_xLimitBox( nullptr ) +{ +} + +LimitBoxController::~LimitBoxController() +{ +} + +/// 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 pParent = VCLUnoHelper::GetWindow( xParent ); + if ( pParent ) + { + SolarMutexGuard aSolarMutexGuard; + m_xLimitBox = VclPtr::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 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 0000000000..1422809372 --- /dev/null +++ b/dbaccess/source/ui/querydesign/limitboxcontroller.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 +#include +#include +#include + +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 + */ +typedef cppu::ImplInheritanceHelper< ::svt::ToolboxController, css::lang::XServiceInfo> LimitBoxController_Base; +class LimitBoxController: public LimitBoxController_Base +{ + public: + explicit LimitBoxController( + const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual ~LimitBoxController() 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 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 0000000000..7a14b7e3c4 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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::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() == NotifyEventType::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) + { + if(m_pBeamer) + return; + + m_pBeamer = VclPtr::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(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 0000000000..08a1ade4ce --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OQueryDesign_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence 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 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 OUString s_sDesignToolbar = u"private:resource/toolbar/designobjectbar"_ustr; + static constexpr OUString s_sSqlToolbar = u"private:resource/toolbar/sqlobjectbar"_ustr; + 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 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::get() ); + registerProperty( PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::READONLY | PropertyAttribute::BOUND, + &m_bEscapeProcessing, cppu::UnoType::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(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 ) + { + assert(m_pSqlIterator && "SqlIterator must exist"); + 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( + lcl_getObjectResourceString(STR_ERROR_PARSING_STATEMENT, m_nCommandType), *this, {}, 0, + _rErrorDetails, lcl_getObjectResourceString(STR_INFO_OPENING_IN_SQL_VIEW, m_nCommandType)); + 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 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::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 pField( new OTableFieldDesc()); + pField->Load( m_aFieldInformation[ _nColPos ], false ); + return pField->GetColWidth(); + } + return 0; +} + +Reference 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(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& _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 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( OUString sComment, bool bLastOnLine ) + : maComment(std::move( sComment)), 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 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() ); +} + +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 0000000000..a54b78e243 --- /dev/null +++ b/dbaccess/source/ui/querydesign/querydlg.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 "querydlg.hxx" +#include +#include +#include +#include +#include "QTableConnectionData.hxx" +#include +#include +#include +#include +#include + +#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(_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(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 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(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; + std::swap( sFirstWinName, sSecondWinName ); + 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(m_pConnData.get())->setNatural(bChecked); + m_xTableControl->enableRelation(!bChecked); + if ( !bChecked ) + return; + + m_pConnData->ResetConnLines(); + try + { + Reference 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(m_pConnData.get())->GetJoinType() ); + m_xCBNatural->set_active(static_cast(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 0000000000..3da416c6e9 --- /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 + +#include + +#include +#include + + +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 m_xML_HelpText; + std::unique_ptr m_xPB_OK; + std::unique_ptr m_xLB_JoinType; + std::unique_ptr m_xCBNatural; + std::unique_ptr 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 0000000000..ba60ae5466 --- /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 +#include +#include +#include +#include + +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>& 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 0000000000..0448d494f4 --- /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 + +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 0000000000..2fb7c0b821 --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RTableConnectionData.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 + std::swap( m_pReferencingTable, m_pReferencedTable ); +} + +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(&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 xTableProp(getReferencingTable()->getTable()); + Reference< XIndexAccess> xKeys ( getReferencingTable()->getKeys()); + + if ( !xKeys.is() ) + return false; + // create new relation + Reference xKeyFactory(xKeys,UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + Reference xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference 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 xColSup(xKey,UNO_QUERY); + if ( xColSup.is() ) + { + Reference xColumns = xColSup->getColumns(); + Reference xColumnFactory(xColumns,UNO_QUERY); + Reference xColumnAppend(xColumns,UNO_QUERY); + if ( xColumnFactory.is() ) + { + for (auto const& elem : m_vConnLineData) + { + if(!(elem->GetSourceFieldName().isEmpty() || elem->GetDestFieldName().isEmpty())) + { + Reference 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;igetCount();++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 xColumns = xColSup->getColumns(); + Sequence< OUString> aNames = xColumns->getElementNames(); + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + + Reference 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 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 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 0000000000..25b8d05a1b --- /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 + +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 0000000000..2c642cd765 --- /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 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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(static_cast( 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 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::Create( pParent, *this, getORB() ) ); + OJoinController::Construct(pParent); + return true; +} + +short ORelationController::saveModified() +{ + short nSaved = RET_YES; + if(haveDataSource() && isModified()) + { + std::unique_ptr xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/designsavemodifieddialog.ui")); + std::unique_ptr xQuery(xBuilder->weld_message_dialog("DesignSaveModifiedDialog")); + nSaved = xQuery->run(); + if(nSaved == RET_YES) + Execute(ID_BROWSER_SAVEDOC,Sequence()); + } + 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, ::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 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(xTableProp,sSourceName, sSourceName, OUString())).first; + aFind->second->ShowAll(false); + } + TTableWindowData::value_type pReferencingTable = aFind->second; + Reference xKeys = pReferencingTable->getKeys(); + const Reference xKeySup(xTableProp,UNO_QUERY); + + if ( !xKeys.is() && xKeySup.is() ) + { + xKeys = xKeySup->getKeys(); + } + + if ( !xKeys.is() ) + return; + + Reference 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 xReferencedTable(m_xTables->getByName(sReferencedTable),UNO_QUERY); + aRefFind = m_aTableData.emplace(sReferencedTable,std::make_shared(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( pReferencingTable, pReferencedTable, sKeyName ); + m_vTableConnectionData.push_back(xTabConnData); + // insert columns + const Reference xColsSup(xKey,UNO_QUERY); + OSL_ENSURE(xColsSup.is(),"Key is no XColumnsSupplier!"); + const Reference xColumns = xColsSup->getColumns(); + const Sequence< OUString> aNames = xColumns->getElementNames(); + OUString sColumnName,sRelatedName; + for(sal_Int32 j=0;j 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()); + } + 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 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 0000000000..cc333accde --- /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 +#include +#include +#include + +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::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() == NotifyEventType::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 0000000000..6c96d39520 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "RTableConnection.hxx" +#include +#include +#include +#include +#include +#include "RTableWindow.hxx" +#include +#include +#include + +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 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()); + + std::erase(rTabWinDataList, *aIter); + 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(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 + std::erase(rTabConnDataList, *aConIter); + continue; + } + } + + addConnection( VclPtr::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 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(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::Create( this, pTabConnData ) ); + } + } + catch(const SQLException&) + { + throw; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "dbaccess", "ORelationTableView::AddConnection"); + } + } +} + +void ORelationTableView::ConnDoubleClicked(VclPtr& 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(); + 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::Create(this, pNewConnData) ); + } +} + +bool ORelationTableView::RemoveConnection(VclPtr& rConn, bool /*_bDelete*/) +{ + ORelationTableConnectionData* pTabConnData = static_cast(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 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::Create( this, m_pCurrentlyTabConnData ) ); + } + m_pCurrentlyTabConnData.reset(); + } +} + +VclPtr ORelationTableView::createWindow(const TTableWindowData::value_type& _pData) +{ + return VclPtr::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 0000000000..4a4a499380 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx @@ -0,0 +1,642 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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(nPrec,_pType->nPrecision)); + } + break; + case DataType::TIME: + case DataType::TIME_WITH_TIMEZONE: + case DataType::TIMESTAMP: + case DataType::TIMESTAMP_WITH_TIMEZONE: + if ( bForce && _pType->nMaximumScale) + { + SetScale(std::min(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(nPrec ? nPrec : DEFAULT_NUMERIC_PRECISION,_pType->nPrecision)); + if ( _pType->nMaximumScale ) + SetScale(std::min(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(); + *pSpecialType = *m_pType; + pSpecialType->nPrecision = GetPrecision(); + pSpecialType->nMaximumScale = static_cast(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 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 0000000000..55696fe364 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TEditControl.cxx @@ -0,0 +1,1693 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TableUndo.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TableFieldControl.hxx" +#include +#include +#include + +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 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::Create(&GetDataWindow(), sExtraNameChars); + pNameCell->get_widget().set_max_length(nMaxTextLen); + pNameCell->setCheck( isSQL92CheckEnabled(xCon) ); + + // Cell type + pTypeCell = VclPtr::Create( &GetDataWindow() ); + + // Cell description + pDescrCell = VclPtr::Create(&GetDataWindow()); + pDescrCell->get_widget().set_max_length(MAX_DESCR_LEN); + + pHelpTextCell = VclPtr::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(m_pRowList->size()),"Row is greater than size!"); + if(nRow >= static_cast(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 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(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 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(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(this, nRow, nColId+1, TOTypeInfoSP()) ); + } + + if( nColId != FIELD_TYPE ) + GetUndoManager().AddUndoAction( std::make_unique(this, nRow, nColId) ); + else + { + GetUndoManager().AddUndoAction(std::make_unique(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 pClipboardRow; + std::shared_ptr pRow; + std::vector< std::shared_ptr > 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( *pRow ); + vClipboardList.push_back( pClipboardRow); + } + } + if(!vClipboardList.empty()) + { + rtl::Reference 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 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 > vInsertedUndoRedoRows; // need for undo/redo handling + // get rows from clipboard + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + if(aTransferData.HasFormat(SotClipboardFormatId::SBA_TABED)) + { + ::tools::SvRef 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 pRow; + sal_Int32 nSize = 0; + (*aStreamRef).ReadInt32( nSize ); + vInsertedUndoRedoRows.reserve(nSize); + for(sal_Int32 i=0;i < nSize;++i) + { + pRow = std::make_shared(); + 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(*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(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(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()); + 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(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()); + 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 >::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 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 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 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 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 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 xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/querycolmenu.ui")); + std::unique_ptr 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 xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/tabledesignrowmenu.ui")); + std::unique_ptr 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"); + // tdf#71224: WORKAROUND for the moment, we don't implement insert field at specific position + // It's not SQL standard and each database has made its choice (some use "BEFORE", other "FIRST" and "AFTER") + // and some, like Postgresql, don't allow this. + // So for the moment, test if the table already exists (and so it's an edition), in this case only + // we remove "Insert Fields" entry. Indeed, in case of new table, there's no pb. + // + // The real fix is to implement the insert for each database + error message for those which don't support this + //if (!IsInsertNewAllowed(nRow)) + if ( GetView()->getController().getTable().is() ) + xContextMenu->remove("insert"); + + if (IsPrimaryKeyAllowed()) + { + xContextMenu->set_active("primarykey", IsRowSelected(GetCurRow()) && IsPrimaryKey()); + } + else + { + xContextMenu->remove("primarykey"); + } + + 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(); + OUString 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& rxRow) { + return rxRow && rxRow->GetActFieldDescr() && !rxRow->GetActFieldDescr()->GetName().isEmpty(); }); + auto nFreeFromPos = static_cast(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 pRow = (*m_pRowList)[nIndex]; + OFieldDescription* pFieldDescr = pRow->GetActFieldDescr(); + if(pFieldDescr) + AdjustFieldDescription(pFieldDescr,aInsertedPrimKeys,nIndex,false,true); + + nIndex = NextSelectedRow(); + } + } + + GetUndoManager().AddUndoAction( std::make_unique(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 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() == NotifyEventType::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 0000000000..7b1d467815 --- /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 +#include +#include "TableFieldDescWin.hxx" +#include +#include + +class Edit; +class SfxUndoManager; +namespace dbaui +{ + class OSQLNameEditControl; + + class OTableEditorCtrl : public OTableRowView + { + enum ChildFocusState + { + HELPTEXT, + DESCRIPTION, + NAME, + ROW, + NONE + }; + + std::vector< std::shared_ptr >* m_pRowList; + + VclPtr m_pView; + VclPtr pNameCell; + VclPtr<::svt::ListBoxControl> pTypeCell; + VclPtr<::svt::EditControl> pHelpTextCell; + VclPtr<::svt::EditControl> pDescrCell; + OTableFieldDescWin* pDescrWin; // properties of one column + + std::shared_ptr 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 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 >* GetRowList(){ return m_pRowList; } + + const std::shared_ptr& 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 0000000000..7e13ba566b --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableController.cxx @@ -0,0 +1,1491 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "TEditControl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +org_openoffice_comp_dbu_OTableDesign_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence 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& _rxTable,const OUString& _sTableName) + { + if ( _rxTable->hasByName(_sTableName) ) + { + Reference 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(); + 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(this)); +} + +void OTableController::stopTableListening() +{ + Reference< XComponent > xComponent(m_xTable, UNO_QUERY); + if (xComponent.is()) + xComponent->removeEventListener(static_cast(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(getView())->isCutAllowed(); + break; + case ID_BROWSER_COPY: + aReturn.bEnabled = getView() && static_cast(getView())->isCopyAllowed(); + break; + case ID_BROWSER_PASTE: + aReturn.bEnabled = isEditable() && getView() && static_cast(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(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(getView())->GetEditorCtrl()->SaveCurRow(); + doSaveDoc(false); + break; + case ID_BROWSER_CUT: + static_cast(getView())->cut(); + break; + case ID_BROWSER_COPY: + static_cast(getView())->copy(); + break; + case ID_BROWSER_PASTE: + static_cast(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 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 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 xTable; + if(bNew || !xTables->hasByName(m_sName)) // just to make sure the table already exists + { + dropTable(xTables,m_sName); + + Reference 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 xColSup(xTable,UNO_QUERY); + appendColumns(xColSup,bNew); + // now append the primary key + Reference xKeySup(xTable,UNO_QUERY); + appendPrimaryKey(xKeySup,bNew); + } + // now set the properties + if(bNew) + { + Reference 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 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::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(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 xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/tabledesignsavemodifieddialog.ui")); + std::unique_ptr xQuery(xBuilder->weld_message_dialog("TableDesignSaveModifiedDialog")); + switch (xQuery->run()) + { + case RET_YES: + Execute(ID_BROWSER_SAVEDOC,Sequence()); + 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 xBuilder(Application::CreateBuilder(getFrameWeld(), "dbaccess/ui/deleteallrowsdialog.ui")); + std::unique_ptr xQuery(xBuilder->weld_message_dialog("DeleteAllRowsDialog")); + switch (xQuery->run()) + { + case RET_YES: + { + try + { + Reference xTablesSup(getConnection(),UNO_QUERY); + Reference 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 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 const & _rxColSup, bool _bNew, bool _bKeyColumns) +{ + try + { + // now append the columns + OSL_ENSURE(_rxColSup.is(),"No columns supplier"); + if(!_rxColSup.is()) + return; + Reference xColumns = _rxColSup->getColumns(); + OSL_ENSURE(xColumns.is(),"No columns"); + Reference xColumnFactory(xColumns,UNO_QUERY); + + Reference 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 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 const & _rxSup, bool _bNew) +{ + if(!_rxSup.is()) + return; // the database doesn't support keys + + OSL_ENSURE(_rxSup.is(),"No XKeysSupplier!"); + Reference xKeys = _rxSup->getKeys(); + Reference 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 xKeyFactory(xKeys,UNO_QUERY); + OSL_ENSURE(xKeyFactory.is(),"No XDataDescriptorFactory Interface!"); + if ( !xKeyFactory.is() ) + return; + Reference xAppend(xKeyFactory,UNO_QUERY); + OSL_ENSURE(xAppend.is(),"No XAppend Interface!"); + + Reference xKey = xKeyFactory->createDataDescriptor(); + OSL_ENSURE(xKey.is(),"Key is null!"); + xKey->setPropertyValue(PROPERTY_TYPE,Any(KeyType::PRIMARY)); + + Reference xColSup(xKey,UNO_QUERY); + if(xColSup.is()) + { + appendColumns(xColSup,_bNew,true); + Reference 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 pTabEdRow; + Reference< XDatabaseMetaData> xMetaData = getMetaData( ); + // fill data structure with data from DataDefinitionObject + if(m_xTable.is() && xMetaData.is()) + { + Reference xColSup(m_xTable,UNO_QUERY); + OSL_ENSURE(xColSup.is(),"No XColumnsSupplier!"); + Reference 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 aColNames = xColumns->getElementNames(); + for(const OUString& rColumn : aColNames) + { + Reference 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(); + 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 xKeyColumns = getKeyColumns(); + if(xKeyColumns.is()) + { + const Sequence aKeyColumnNames = xKeyColumns->getElementNames(); + for(const OUString& rKeyColumn : aKeyColumnNames) + { + for(std::shared_ptr 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(); + pTabEdRow->SetReadOnly(bReadRow); + m_vRowList.push_back( pTabEdRow); + } +} + +Reference 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 >::const_iterator aIter = m_vRowList.begin(); + std::vector< std::shared_ptr >::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& 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(); + 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(getView())->GetEditorCtrl()->Invalidate(); + static_cast(getView())->GetEditorCtrl()->RowInserted(0); + } + break; + case RET_CANCEL: + bOk = false; + break; + } + } + return bOk; +} + +void OTableController::alterColumns() +{ + Reference xColSup(m_xTable,UNO_QUERY_THROW); + + Reference xColumns = xColSup->getColumns(); + Reference xIdxColumns(xColumns,UNO_QUERY_THROW); + OSL_ENSURE(xColumns.is(),"No columns"); + if ( !xColumns.is() ) + return; + Reference xAlter(m_xTable,UNO_QUERY); // can be null + + sal_Int32 nColumnCount = xIdxColumns->getCount(); + Reference xDrop(xColumns,UNO_QUERY); // can be null + Reference xAppend(xColumns,UNO_QUERY); // can be null + Reference 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 aColumns( + comphelper::UStringMixLess( + !xMetaData.is() + || xMetaData->supportsMixedCaseQuotedIdentifiers())); + std::vector< std::shared_ptr >::const_iterator aIter = m_vRowList.begin(); + std::vector< std::shared_ptr >::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 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 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 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 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 xColumn; + if ( xColumns->hasByName(pField->GetName()) ) + { + xColumns->getByName(pField->GetName()) >>= xColumn; + Reference 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 xKeyColumns = getKeyColumns(); + // now we have to look for the columns who could be deleted + if ( xDrop.is() ) + { + const Sequence 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&) + { + const auto caughtException = ::cppu::getCaughtException(); + OUString sError( DBA_RES( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) ); + sError = sError.replaceFirst( "$column$", rColumnName ); + + throw SQLException(sError, {}, "S1000", 0, caughtException); + } + } + } + } + + // 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 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 xKeySup(m_xTable,UNO_QUERY); + Reference xKeys; + if(xKeySup.is()) + xKeys = xKeySup->getKeys(); + + if(xKeys.is()) + { + Reference 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(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; + Reference 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 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 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 xColsSup(m_xTable,UNO_QUERY); + bool bAddAllowed = !m_xTable.is(); + if(xColsSup.is()) + bAddAllowed = Reference(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 xColsSup(m_xTable,UNO_QUERY); + bool bDropAllowed = !m_xTable.is(); + if(xColsSup.is()) + { + Reference xNameAccess = xColsSup->getColumns(); + bDropAllowed = Reference(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(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(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& 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(getView())->reSync(); // show the windows and fill with our information + ClearUndoManager(); + setModified(false); // and we are not modified yet + static_cast(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(); + 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 0000000000..18e24c3d5e --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +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(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 xBuilder(Application::CreateBuilder(pPopupParent, "dbaccess/ui/tabledesignrowmenu.ui")); + std::unique_ptr xContextMenu(xBuilder->weld_menu("menu")); + sal_Int32 nSelectRowCount = GetSelectRowCount(); + xContextMenu->set_sensitive("cut", nSelectRowCount != 0); + xContextMenu->set_sensitive("copy", nSelectRowCount != 0); + OUString 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 0000000000..f81123e55d --- /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 +#include + +using namespace dbaui; + +#define DETAILS_MIN_HELP_WIDTH 200 + +OTableDesignHelpBar::OTableDesignHelpBar(std::unique_ptr 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 0000000000..627951fd2e --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignView.cxx @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include "TEditControl.hxx" +#include "TableFieldDescWin.hxx" +#include +#include +#include +#include +#include + +using namespace ::dbaui; +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::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::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() == NotifyEventType::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 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 0000000000..aa04b914aa --- /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 +#include +#include "TEditControl.hxx" +#include +#include +#include +#include + +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 xTable = GetCtrl()->GetView()->getController().getTable(); + if(xTable.is() && ::comphelper::getString(xTable->getPropertyValue(PROPERTY_TYPE)) == "VIEW") + bRead = true; + else + { + std::shared_ptr 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 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 0000000000..4a232f86c3 --- /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 + +namespace dbaui +{ + class OTableEditorCtrl; + class OTableDesignHelpBar; + class OTableDesignView; + + // OTableFieldControl + class OTableFieldControl : public OFieldDescControl + { + VclPtr 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 0000000000..9f110d4720 --- /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 +#include +#include +#include +#include + +using namespace dbaui; + +OTableFieldDescWin::OTableFieldDescWin(weld::Container* pParent, OTableDesignView* pView) + : OChildWindow(pParent, "dbaccess/ui/fielddescpanel.ui", "FieldDescPanel") + , m_aHelpBar(m_xBuilder->weld_text_view("textview")) + , m_xBox(m_xBuilder->weld_container("box")) + , m_xFieldControl(new OTableFieldControl(m_xBox.get(), &m_aHelpBar, 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_aHelpBar.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_aHelpBar.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 = const_cast(&m_aHelpBar); + 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 0000000000..f14e468c56 --- /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 +#include +#include "TableFieldControl.hxx" +#include + +namespace dbaui +{ + class OTableDesignView; + class OFieldDescription; + + class OTableFieldDescWin final : public OChildWindow + , public IClipboardTest + { + enum ChildFocusState + { + DESCRIPTION, + HELP, + NONE + }; + private: + OTableDesignHelpBar m_aHelpBar; + std::unique_ptr m_xBox; + std::unique_ptr m_xFieldControl; + std::unique_ptr m_xHeader; + Link 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& 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 0000000000..8f13193e1c --- /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 +#include +#include +#include + +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(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(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 0000000000..c56450ac1c --- /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 +#include +#include +#include + +namespace dbaui +{ + constexpr sal_uInt32 FORMAT_OBJECT_ID_SBA_TABED = 1; + + using namespace ::com::sun::star::uno; + OTableRowExchange::OTableRowExchange(std::vector< std::shared_ptr >&& _rvTableRow) + : m_vTableRow(std::move(_rvTableRow)) + { + } + bool OTableRowExchange::WriteObject( tools::SvRef& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId, const css::datatransfer::DataFlavor& /*rFlavor*/ ) + { + if(nUserObjectId == FORMAT_OBJECT_ID_SBA_TABED) + { + std::vector< std::shared_ptr >* pRows = static_cast< std::vector< std::shared_ptr >* >(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 0000000000..7829a09d69 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableUndo.cxx @@ -0,0 +1,353 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include "TEditControl.hxx" +#include +#include +#include +#include +#include +#include + +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, TOTypeInfoSP _pOldType ) + :OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_TYPE_CHANGED) + ,m_nCol( nColumn ) + ,m_nRow( nRowID ) + ,m_pOldType(std::move( _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 >* pOriginalRows = pOwner->GetRowList(); + sal_Int32 nIndex = pOwner->FirstSelectedRow(); + std::shared_ptr pOriginalRow; + std::shared_ptr pNewRow; + + while( nIndex != SFX_ENDOFSELECTION ) + { + pOriginalRow = (*pOriginalRows)[nIndex]; + pNewRow = std::make_shared( *pOriginalRow, nIndex ); + m_aDeletedRows.push_back( pNewRow); + + nIndex = pOwner->NextSelectedRow(); + } +} + +OTableEditorDelUndoAct::~OTableEditorDelUndoAct() +{ + m_aDeletedRows.clear(); +} + +void OTableEditorDelUndoAct::Undo() +{ + // Insert the deleted line + sal_Int32 nPos; + + std::shared_ptr pNewOrigRow; + std::vector< std::shared_ptr >* pOriginalRows = pTabEdCtrl->GetRowList(); + + for (auto const& deletedRow : m_aDeletedRows) + { + pNewOrigRow = std::make_shared( *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 >* 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 >&& _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 >* 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 pRow; + std::vector< std::shared_ptr >* pRowList = pTabEdCtrl->GetRowList(); + for (auto const& insertedRow : m_vInsertedRows) + { + pRow = std::make_shared( *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 >* 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 >* pRowList = pTabEdCtrl->GetRowList(); + + for( tools::Long i=m_nInsPos; i<(m_nInsPos+m_nInsRows); i++ ) + pRowList->insert( pRowList->begin()+i,std::make_shared() ); + + 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 >* pRowList = pTabEdCtrl->GetRowList(); + std::shared_ptr 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(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(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 >* 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 0000000000..1863555f75 --- /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 +#include + +#include + +#include +#include +#include + +namespace dbaui +{ + class OTableRowView; + class OTableRow; + class OTableDesignUndoAct : public OCommentUndoAction + { + protected: + VclPtr 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 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, TOTypeInfoSP _pOldType ); + virtual ~OTableEditorTypeSelUndoAct() override; + }; + + class OTableEditorDelUndoAct final : public OTableEditorUndoAct + { + std::vector< std::shared_ptr > 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 > 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 >&& _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 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 0000000000..3d24cfc242 --- /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 + +#include +#include +#include +#include + +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_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence 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 createDialog(const css::uno::Reference& rParent) override; + }; + + } + + OAdvancedSettingsDialog::OAdvancedSettingsDialog(const Reference< XComponentContext >& _rxORB) + :ODatabaseAdministrationDialog(_rxORB) + { + } + Sequence SAL_CALL OAdvancedSettingsDialog::getImplementationId( ) + { + return css::uno::Sequence(); + } + + OUString SAL_CALL OAdvancedSettingsDialog::getImplementationName() + { + return "org.openoffice.comp.dbu.OAdvancedSettingsDialog"; + } + + css::uno::Sequence SAL_CALL OAdvancedSettingsDialog::getSupportedServiceNames() + { + return { "com.sun.star.sdb.AdvancedDatabaseSettingsDialog" }; + } + + Reference SAL_CALL OAdvancedSettingsDialog::getPropertySetInfo() + { + Reference 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 OAdvancedSettingsDialog::createDialog(const css::uno::Reference& rParent) + { + return std::make_unique(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 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 0000000000..e7cde998d3 --- /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 +#include +#include + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dbu_OColumnControl_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence 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& 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 = dynamic_cast(rParentPeer.get()); + if (pParent) + pParentWin = pParent->GetWindow(); + } + + rtl::Reference 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 xProp(getModel(), UNO_QUERY); + if ( xProp.is() ) + { + Reference xCon(xProp->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY); + pPeer->setConnection(xCon); + Reference 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 0000000000..63f0665128 --- /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 +#include + +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 0000000000..de83b6176d --- /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 + +#include +#include + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dbu_OColumnControlModel_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence 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::get() ); + Any a; + a <<= m_xColumn; + registerProperty( PROPERTY_COLUMN, PROPERTY_ID_COLUMN, PropertyAttribute::TRANSIENT | PropertyAttribute::BOUND, + &m_xColumn, cppu::UnoType::get() ); + + registerMayBeVoidProperty( PROPERTY_TABSTOP, PROPERTY_ID_TABSTOP, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID, + &m_aTabStop, ::cppu::UnoType::get() ); + registerProperty( PROPERTY_DEFAULTCONTROL, PROPERTY_ID_DEFAULTCONTROL, PropertyAttribute::BOUND, + &m_sDefaultControl, cppu::UnoType::get() ); + registerProperty( PROPERTY_ENABLED, PROPERTY_ID_ENABLED, PropertyAttribute::BOUND, + &m_bEnable, cppu::UnoType::get() ); + registerProperty( PROPERTY_BORDER, PROPERTY_ID_BORDER, PropertyAttribute::BOUND, + &m_nBorder, cppu::UnoType::get() ); + registerProperty( PROPERTY_EDIT_WIDTH, PROPERTY_ID_EDIT_WIDTH, PropertyAttribute::BOUND, + &m_nWidth, cppu::UnoType::get() ); +} + +// XCloneable +Reference< XCloneable > SAL_CALL OColumnControlModel::createClone( ) +{ + return new OColumnControlModel( this ); +} + +css::uno::Sequence OColumnControlModel::getImplementationId() +{ + return css::uno::Sequence(); +} + +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& /*_rxOutStream*/) +{ + // TODO +} + +void OColumnControlModel::read(const Reference& /*_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 0000000000..400d03652d --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 SAL_CALL getTypes() override; + virtual css::uno::Sequence 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 0000000000..48f5fbce56 --- /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 +#include +#include +#include + +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& _rxContext) + :m_pActFieldDescr(nullptr) +{ + osl_atomic_increment( &m_refCount ); + { + VclPtrInstance pFieldControl(_pParent, _rxContext); + pFieldControl->SetComponentInterface(this); + pFieldControl->Show(); + } + osl_atomic_decrement( &m_refCount ); +} + +void OColumnPeer::setEditWidth(sal_Int32 _nWidth) +{ + SolarMutexGuard aGuard; + VclPtr pFieldControl = GetAs(); + if ( pFieldControl ) + pFieldControl->GetControl().setEditWidth(_nWidth); +} + +void OColumnPeer::setColumn(const Reference< XPropertySet>& _xColumn) +{ + SolarMutexGuard aGuard; + + VclPtr pFieldControl = GetAs(); + 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 pFieldControl = GetAs(); + if ( pFieldControl ) + pFieldControl->GetControl().setConnection(_xCon); +} + +void OColumnPeer::setProperty( const OUString& _rPropertyName, const Any& Value) +{ + SolarMutexGuard aGuard; + + if (_rPropertyName == PROPERTY_COLUMN) + { + Reference xProp(Value,UNO_QUERY); + setColumn(xProp); + } + else if (_rPropertyName == PROPERTY_ACTIVE_CONNECTION) + { + Reference xCon(Value,UNO_QUERY); + setConnection(xCon); + } + else + VCLXWindow::setProperty(_rPropertyName,Value); +} + +Any OColumnPeer::getProperty( const OUString& _rPropertyName ) +{ + Any aProp; + VclPtr pFieldControl = GetAs(); + 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 0000000000..8a92a40cdf --- /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 +#include +#include +#include + +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 0000000000..8c9d165963 --- /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 +#include + +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 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_CALL ODBTypeWizDialog::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +OUString SAL_CALL ODBTypeWizDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.ODBTypeWizDialog"; +} + +css::uno::Sequence SAL_CALL ODBTypeWizDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.DataSourceTypeChangeDialog" }; +} + +Reference SAL_CALL ODBTypeWizDialog::getPropertySetInfo() +{ + Reference 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 ODBTypeWizDialog::createDialog(const css::uno::Reference& rParent) +{ + return std::make_unique(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 0000000000..093981a0e5 --- /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 + +#include + +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_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence 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 createDialog(const css::uno::Reference& 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 0000000000..63c3d6304b --- /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 +#include +#include +#include + +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 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::get()); + + registerProperty("StartTableWizard", 4, PropertyAttribute::TRANSIENT, + &m_bStartTableWizard, cppu::UnoType::get()); +} + +Sequence SAL_CALL ODBTypeWizDialogSetup::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +OUString SAL_CALL ODBTypeWizDialogSetup::getImplementationName() +{ + return "org.openoffice.comp.dbu.ODBTypeWizDialogSetup"; +} + +css::uno::Sequence SAL_CALL ODBTypeWizDialogSetup::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.DatabaseWizardDialog" }; +} + +Reference 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 ODBTypeWizDialogSetup::createDialog(const css::uno::Reference& rParent) +{ + return std::make_unique(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(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 0000000000..56bd9a08ac --- /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 + +#include + +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_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence 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 createDialog(const css::uno::Reference& 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 0000000000..cd01f25873 --- /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 +#include + +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 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_CALL OTableFilterDialog::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +OUString SAL_CALL OTableFilterDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.OTableFilterDialog"; +} + +css::uno::Sequence SAL_CALL OTableFilterDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.TableFilterDialog" }; +} + +Reference SAL_CALL OTableFilterDialog::getPropertySetInfo() +{ + Reference 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 OTableFilterDialog::createDialog(const css::uno::Reference& rParent) +{ + return std::make_unique(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 0000000000..7c16a7f268 --- /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 + +#include + +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_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence 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 createDialog(const css::uno::Reference& 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 0000000000..7039c7396d --- /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 +#include + +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 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_CALL OUserSettingsDialog::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +OUString SAL_CALL OUserSettingsDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.OUserSettingsDialog"; +} + +css::uno::Sequence SAL_CALL OUserSettingsDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.UserAdministrationDialog" }; +} + +Reference SAL_CALL OUserSettingsDialog::getPropertySetInfo() +{ + Reference 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 OUserSettingsDialog::createDialog(const css::uno::Reference& rParent) +{ + return std::make_unique(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 0000000000..7e0780ea2b --- /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 + +#include + +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_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence 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 createDialog(const css::uno::Reference& 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 0000000000..3e524372ee --- /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 +#include + +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 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& _rxORB) + : ODatabaseAdministrationDialog(_rxORB) +{ +} + +Sequence SAL_CALL ODataSourcePropertyDialog::getImplementationId() +{ + return css::uno::Sequence(); +} + +OUString SAL_CALL ODataSourcePropertyDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.ODatasourceAdministrationDialog"; +} + +css::uno::Sequence SAL_CALL ODataSourcePropertyDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.DatasourceAdministrationDialog" }; +} + +Reference SAL_CALL ODataSourcePropertyDialog::getPropertySetInfo() +{ + Reference xInfo(createPropertySetInfo(getInfoHelper())); + return xInfo; +} + +::cppu::IPropertyArrayHelper& ODataSourcePropertyDialog::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* ODataSourcePropertyDialog::createArrayHelper() const +{ + Sequence aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +std::unique_ptr +ODataSourcePropertyDialog::createDialog(const css::uno::Reference& rParent) +{ + std::unique_ptr 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 0000000000..62faabf64f --- /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 + +#include + +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_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence 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 createDialog(const css::uno::Reference& 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 0000000000..3e9d51c096 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_uno_comp_sdb_RowsetOrderDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence 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 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::get() ); + registerProperty( PROPERTY_ROWSET, PROPERTY_ID_ROWSET, PropertyAttribute::TRANSIENT, + &m_xRowSet, cppu::UnoType::get() ); + } + + ComposerDialog::~ComposerDialog() + { + + } + + css::uno::Sequence ComposerDialog::getImplementationId() + { + return css::uno::Sequence(); + } + + 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 ComposerDialog::createDialog(const css::uno::Reference& 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 RowsetFilterDialog::createComposerDialog(weld::Window* _pParent, const Reference< XConnection >& _rxConnection, const Reference< XNameAccess >& _rxColumns ) + { + return std::make_unique(_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 xQueryComposer; + aArguments[0] >>= xQueryComposer; + Reference xRowSet; + aArguments[1] >>= xRowSet; + Reference 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(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 RowsetOrderDialog::createComposerDialog(weld::Window* pParent, const Reference< XConnection >& rxConnection, const Reference< XNameAccess >& rxColumns) + { + return std::make_unique(pParent, rxConnection, m_xComposer, rxColumns); + } + + void SAL_CALL RowsetOrderDialog::initialize( const Sequence< Any >& aArguments ) + { + if (aArguments.getLength() == 2 || aArguments.getLength() == 3) + { + Reference xQueryComposer; + aArguments[0] >>= xQueryComposer; + Reference xRowSet; + aArguments[1] >>= xRowSet; + setPropertyValue( "QueryComposer", Any( xQueryComposer ) ); + setPropertyValue( "RowSet", Any( xRowSet ) ); + if (aArguments.getLength() == 3) + { + Reference 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(m_xDialog.get())->BuildOrderPart(); + else if ( m_xComposer.is() ) + m_xComposer->setOrder(static_cast(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 0000000000..4e71b1c647 --- /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 +#include +#include +#include + +#include +#include +#include + +namespace dbaui +{ + + // ComposerDialog + class ComposerDialog; + typedef ::comphelper::OPropertyArrayUsageHelper< ComposerDialog > ComposerDialog_PBASE; + + class ComposerDialog + :public svt::OGenericUnoDialog + ,public ComposerDialog_PBASE + { + protected: + // + css::uno::Reference< css::sdb::XSingleSelectQueryComposer > + m_xComposer; + css::uno::Reference< css::sdbc::XRowSet > + m_xRowSet; + // + + protected: + explicit ComposerDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + virtual ~ComposerDialog() override; + + public: + virtual css::uno::Sequence 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 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 createDialog(const css::uno::Reference& 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 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 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 0000000000..880600342d --- /dev/null +++ b/dbaccess/source/ui/uno/copytablewizard.cxx @@ -0,0 +1,1576 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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 createDialog(const css::uno::Reference& 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 _out_rxDocInteractionHandler will be .) + @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 . + @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 + if and only if copying should be continued. + */ + bool impl_processCopyError_nothrow( + const CopyTableRowEvent& _rEvent ); + +private: + Reference 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 + 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 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(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, 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[] = { + PROPERTY_FILTER, PROPERTY_ORDER, PROPERTY_HAVING_CLAUSE, 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 + { + css::uno::Any next; + ::dbtools::SQLExceptionInfo aInfo( _rEvent.Error ); + if ( aInfo.isValid() ) + next = _rEvent.Error; + else + { + // a non-SQL exception happened + Exception aException; + OSL_VERIFY( _rEvent.Error >>= aException ); + SQLContext aContext(aException.Message, aException.Context, {}, 0, {}, + _rEvent.Error.getValueTypeName()); + next <<= aContext; + } + SQLContext aError(DBA_RES(STR_ERROR_OCCURRED_WHILE_COPYING), *this, {}, 0, next, {}); + + ::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::createPreparedStatement( 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("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(); + SAL_WARN("dbaccess", exceptionToString(aError)); + + // 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 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 CopyTableWizard::createDialog(const css::uno::Reference& rParent) +{ + OSL_PRECOND( isInitialized(), "CopyTableWizard::createDialog: not initialized!" ); + // this should have been prevented in ::execute already + + auto xWizard = std::make_unique( + 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 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 0000000000..3c0af86efd --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dbaccess_DatabaseInteractionHandler_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence 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 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& 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 0000000000..fdb0dbd2c9 --- /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 +#include + +#include +#include +#include +#include +#include +#include + +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 XInteractionHandler for + database related interaction requests. +

+ 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 + XInteractionRequest interface. +

    +
  • SQLException: requests to display a + standard error dialog for the (maybe chained) exception given
  • +
+ */ + 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

+ @return the index within _rContinuations 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 0000000000..5b1636f90b --- /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 +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +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& _rContext ); + + virtual css::uno::Sequence 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& p2) override + { ODatabaseAdministrationDialog::addPropertyChangeListener(p1, p2); } + virtual void SAL_CALL removePropertyChangeListener(const OUString& p1, const css::uno::Reference& p2) override + { ODatabaseAdministrationDialog::removePropertyChangeListener(p1, p2); } + virtual void SAL_CALL addVetoableChangeListener(const OUString& p1, const css::uno::Reference& p2) override + { ODatabaseAdministrationDialog::addVetoableChangeListener(p1, p2); } + virtual void SAL_CALL removeVetoableChangeListener(const OUString& p1, const css::uno::Reference& 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 createDialog(const css::uno::Reference& rParent) override; + using OTextConnectionSettingsDialog_BASE::getFastPropertyValue; + }; + + } + + // OTextConnectionSettingsDialog + OTextConnectionSettingsDialog::OTextConnectionSettingsDialog( const Reference& _rContext ) + :OTextConnectionSettingsDialog_BASE( _rContext ) + { + TextConnectionSettingsDialog::bindItemStorages( *m_pDatasourceItems, m_aPropertyValues ); + } + + css::uno::Sequence + OTextConnectionSettingsDialog::getImplementationId() + { + return css::uno::Sequence(); + } + + 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 OTextConnectionSettingsDialog::createDialog(const css::uno::Reference& rParent) + { + return std::make_unique(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 const& ) +{ + return cppu::acquire(static_cast(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 0000000000..4b1d61b55a --- /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 + +#include "unoDirectSql.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_sdb_DirectSQLDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence 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 ODirectSQLDialog::getImplementationId() + { + return css::uno::Sequence(); + } + + 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 ODirectSQLDialog::createDialog(const css::uno::Reference& 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(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 0000000000..c83f975d63 --- /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 +#include +#include +#include + +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_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 createDialog(const css::uno::Reference& 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 0000000000..3d863b92e8 --- /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 +#include + +#include + + +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 0000000000..39364ba254 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 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::get()); + registerProperty( PROPERTY_HELP_URL, PROPERTY_ID_HELP_URL, PropertyAttribute::TRANSIENT, + &m_sHelpURL, cppu::UnoType::get() ); +} + +Sequence SAL_CALL OSQLMessageDialog::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +OUString SAL_CALL OSQLMessageDialog::getImplementationName() +{ + return "org.openoffice.comp.dbu.OSQLMessageDialog"; +} + +css::uno::Sequence SAL_CALL OSQLMessageDialog::getSupportedServiceNames() +{ + return { "com.sun.star.sdb.ErrorMessageDialog" }; +} + +void OSQLMessageDialog::initialize(Sequence const & args) +{ + OUString title; + Reference< css::awt::XWindow > parentWindow; + + if ((args.getLength() == 3) && (args[0] >>= title) && (args[1] >>= parentWindow)) { + Sequence 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 SAL_CALL OSQLMessageDialog::getPropertySetInfo() +{ + Reference 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 OSQLMessageDialog::createDialog(const css::uno::Reference& rParent) +{ + weld::Window* pParent = Application::GetFrameWeld(rParent); + if ( m_aException.hasValue() ) + return std::make_unique(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(pParent, SQLException()); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3