From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- dbaccess/AllLangMoTarget_dba.mk | 13 + dbaccess/CppunitTest_dbaccess_RowSetClones.mk | 116 + dbaccess/CppunitTest_dbaccess_dialog_save.mk | 108 + dbaccess/CppunitTest_dbaccess_dialogs_test.mk | 69 + ...unitTest_dbaccess_embeddeddb_performancetest.mk | 73 + dbaccess/CppunitTest_dbaccess_empty_stdlib_save.mk | 108 + ...ppunitTest_dbaccess_firebird_regression_test.mk | 70 + dbaccess/CppunitTest_dbaccess_firebird_test.mk | 70 + dbaccess/CppunitTest_dbaccess_hsqlbinary_import.mk | 109 + dbaccess/CppunitTest_dbaccess_hsqldb_test.mk | 80 + dbaccess/CppunitTest_dbaccess_hsqlschema_import.mk | 101 + dbaccess/CppunitTest_dbaccess_macros_test.mk | 101 + dbaccess/CppunitTest_dbaccess_nolib_save.mk | 108 + dbaccess/CppunitTest_dbaccess_tdf119625.mk | 109 + dbaccess/CppunitTest_dbaccess_tdf126268.mk | 109 + dbaccess/Executable_odbcconfig.mk | 31 + dbaccess/IwyuFilter_dbaccess.yaml | 161 + dbaccess/JunitTest_dbaccess_complex.mk | 51 + dbaccess/JunitTest_dbaccess_unoapi.mk | 14 + dbaccess/Library_dba.mk | 135 + dbaccess/Library_dbahsql.mk | 51 + dbaccess/Library_dbaxml.mk | 74 + dbaccess/Library_dbu.mk | 257 ++ dbaccess/Library_sdbt.mk | 47 + dbaccess/Makefile | 14 + dbaccess/Module_dbaccess.mk | 103 + dbaccess/PythonTest_dbaccess_python.mk | 26 + dbaccess/README | 3 + dbaccess/UIConfig_dbaccess.mk | 83 + dbaccess/UIConfig_dbapp.mk | 34 + dbaccess/UIConfig_dbbrowser.mk | 25 + dbaccess/UIConfig_dbquery.mk | 22 + dbaccess/UIConfig_dbrelation.mk | 20 + dbaccess/UIConfig_dbtable.mk | 20 + dbaccess/UIConfig_dbtdata.mk | 24 + dbaccess/inc/bitmaps.hlst | 34 + dbaccess/inc/core_resource.hxx | 85 + dbaccess/inc/dbaccess_slotid.hrc | 108 + dbaccess/inc/dbadllapi.hxx | 35 + dbaccess/inc/helpids.h | 117 + dbaccess/inc/pch/precompiled_dba.cxx | 12 + dbaccess/inc/pch/precompiled_dba.hxx | 271 ++ dbaccess/inc/pch/precompiled_dbahsql.cxx | 12 + dbaccess/inc/pch/precompiled_dbahsql.hxx | 54 + dbaccess/inc/pch/precompiled_dbaxml.cxx | 12 + dbaccess/inc/pch/precompiled_dbaxml.hxx | 108 + dbaccess/inc/pch/precompiled_dbu.cxx | 12 + dbaccess/inc/pch/precompiled_dbu.hxx | 224 ++ dbaccess/inc/pch/precompiled_sdbt.cxx | 12 + dbaccess/inc/pch/precompiled_sdbt.hxx | 48 + dbaccess/inc/query.hrc | 33 + dbaccess/inc/strings.hrc | 454 +++ dbaccess/inc/strings.hxx | 284 ++ .../qa/complex/dbaccess/ApplicationController.java | 159 + dbaccess/qa/complex/dbaccess/Beamer.java | 127 + dbaccess/qa/complex/dbaccess/CRMBasedTestCase.java | 63 + .../dbaccess/CopyTableInterActionHandler.java | 37 + dbaccess/qa/complex/dbaccess/CopyTableWizard.java | 194 + dbaccess/qa/complex/dbaccess/DataSource.java | 68 + .../qa/complex/dbaccess/DatabaseApplication.java | 73 + dbaccess/qa/complex/dbaccess/DatabaseDocument.java | 995 ++++++ dbaccess/qa/complex/dbaccess/FileHelper.java | 35 + dbaccess/qa/complex/dbaccess/Parser.java | 183 + dbaccess/qa/complex/dbaccess/PropertyBag.java | 302 ++ dbaccess/qa/complex/dbaccess/Query.java | 107 + dbaccess/qa/complex/dbaccess/QueryInQuery.java | 177 + dbaccess/qa/complex/dbaccess/RowSet.java | 942 +++++ .../qa/complex/dbaccess/RowSetEventListener.java | 102 + .../dbaccess/SingleSelectQueryComposer.java | 351 ++ dbaccess/qa/complex/dbaccess/TestCase.java | 232 ++ dbaccess/qa/complex/dbaccess/UISettings.java | 132 + dbaccess/qa/complex/dbaccess/makefile.mk | 93 + dbaccess/qa/extras/dialog-save.cxx | 110 + dbaccess/qa/extras/empty-stdlib-save.cxx | 122 + dbaccess/qa/extras/hsql_schema_import.cxx | 232 ++ dbaccess/qa/extras/macros-test.cxx | 53 + dbaccess/qa/extras/nolib-save.cxx | 112 + dbaccess/qa/extras/rowsetclones.cxx | 136 + dbaccess/qa/extras/testdocuments/RowSetClones.odb | Bin 0 -> 33734 bytes dbaccess/qa/extras/testdocuments/fdo84315.odb | Bin 0 -> 3592 bytes .../qa/extras/testdocuments/testDialogSave.odb | Bin 0 -> 34059 bytes dbaccess/qa/extras/testdocuments/testdb.odb | Bin 0 -> 3700 bytes dbaccess/qa/python/fdo84315.py | 76 + dbaccess/qa/unit/data/dbaccess-dialogs-test.txt | 111 + dbaccess/qa/unit/data/firebird_empty.odb | Bin 0 -> 2148 bytes dbaccess/qa/unit/data/firebird_empty_le.odb | Bin 0 -> 1733 bytes dbaccess/qa/unit/data/firebird_integer_le.odb | Bin 0 -> 43990 bytes .../qa/unit/data/firebird_integer_le_ods12.odb | Bin 0 -> 75701 bytes dbaccess/qa/unit/data/firebird_integer_ods12.odb | Bin 0 -> 77617 bytes dbaccess/qa/unit/data/hsqldb_empty.odb | Bin 0 -> 2345 bytes dbaccess/qa/unit/data/hsqldb_migration_test.odb | Bin 0 -> 3949 bytes dbaccess/qa/unit/data/tdf119625.odb | Bin 0 -> 6350 bytes dbaccess/qa/unit/data/tdf126268.odb | Bin 0 -> 5015 bytes dbaccess/qa/unit/dbaccess-dialogs-test.cxx | 61 + dbaccess/qa/unit/dbtest_base.cxx | 86 + dbaccess/qa/unit/embeddeddb_performancetest.cxx | 359 ++ dbaccess/qa/unit/firebird-regression.cxx | 106 + dbaccess/qa/unit/firebird.cxx | 97 + dbaccess/qa/unit/hsql_binary_import.cxx | 92 + dbaccess/qa/unit/hsqldb.cxx | 49 + dbaccess/qa/unit/tdf119625.cxx | 115 + dbaccess/qa/unit/tdf126268.cxx | 89 + dbaccess/qa/unoapi/dbaccess.props | 24 + dbaccess/qa/unoapi/dbaccess.sce | 32 + dbaccess/qa/unoapi/knownissues.xcl | 80 + dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbf | Bin 0 -> 949 bytes dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbt | Bin 0 -> 512 bytes dbaccess/source/core/api/BookmarkSet.cxx | 204 ++ dbaccess/source/core/api/BookmarkSet.hxx | 59 + dbaccess/source/core/api/CIndexes.cxx | 87 + dbaccess/source/core/api/CIndexes.hxx | 50 + dbaccess/source/core/api/CRowSetColumn.cxx | 91 + dbaccess/source/core/api/CRowSetColumn.hxx | 52 + dbaccess/source/core/api/CRowSetDataColumn.cxx | 237 ++ dbaccess/source/core/api/CRowSetDataColumn.hxx | 102 + dbaccess/source/core/api/CacheSet.cxx | 579 +++ dbaccess/source/core/api/CacheSet.hxx | 174 + dbaccess/source/core/api/FilteredContainer.cxx | 467 +++ dbaccess/source/core/api/HelperCollections.cxx | 106 + dbaccess/source/core/api/HelperCollections.hxx | 108 + dbaccess/source/core/api/KeySet.cxx | 1463 ++++++++ dbaccess/source/core/api/KeySet.hxx | 218 ++ dbaccess/source/core/api/OptimisticSet.cxx | 586 +++ dbaccess/source/core/api/OptimisticSet.hxx | 78 + dbaccess/source/core/api/PrivateRow.cxx | 133 + dbaccess/source/core/api/PrivateRow.hxx | 60 + dbaccess/source/core/api/RowSet.cxx | 2966 ++++++++++++++++ dbaccess/source/core/api/RowSet.hxx | 527 +++ dbaccess/source/core/api/RowSetBase.cxx | 1437 ++++++++ dbaccess/source/core/api/RowSetBase.hxx | 405 +++ dbaccess/source/core/api/RowSetCache.cxx | 1714 +++++++++ dbaccess/source/core/api/RowSetCache.hxx | 192 + dbaccess/source/core/api/RowSetCacheIterator.cxx | 91 + dbaccess/source/core/api/RowSetCacheIterator.hxx | 74 + dbaccess/source/core/api/RowSetRow.hxx | 54 + .../source/core/api/SingleSelectQueryComposer.cxx | 1881 ++++++++++ dbaccess/source/core/api/StaticSet.cxx | 282 ++ dbaccess/source/core/api/StaticSet.hxx | 77 + dbaccess/source/core/api/TableDeco.cxx | 622 ++++ dbaccess/source/core/api/View.cxx | 120 + dbaccess/source/core/api/WrappedResultSet.cxx | 184 + dbaccess/source/core/api/WrappedResultSet.hxx | 62 + dbaccess/source/core/api/callablestatement.cxx | 250 ++ dbaccess/source/core/api/column.cxx | 411 +++ dbaccess/source/core/api/columnsettings.cxx | 150 + dbaccess/source/core/api/datacolumn.cxx | 396 +++ dbaccess/source/core/api/datacolumn.hxx | 110 + dbaccess/source/core/api/datasettings.cxx | 192 + dbaccess/source/core/api/definitioncolumn.cxx | 608 ++++ dbaccess/source/core/api/preparedstatement.cxx | 411 +++ dbaccess/source/core/api/query.cxx | 359 ++ dbaccess/source/core/api/query.hxx | 149 + dbaccess/source/core/api/querycomposer.cxx | 263 ++ dbaccess/source/core/api/querycontainer.cxx | 413 +++ dbaccess/source/core/api/querydescriptor.cxx | 266 ++ dbaccess/source/core/api/querydescriptor.hxx | 146 + dbaccess/source/core/api/resultcolumn.cxx | 292 ++ dbaccess/source/core/api/resultcolumn.hxx | 89 + dbaccess/source/core/api/resultset.cxx | 990 ++++++ dbaccess/source/core/api/resultset.hxx | 223 ++ dbaccess/source/core/api/statement.cxx | 586 +++ dbaccess/source/core/api/table.cxx | 347 ++ dbaccess/source/core/api/tablecontainer.cxx | 441 +++ dbaccess/source/core/api/viewcontainer.cxx | 236 ++ .../source/core/dataaccess/ComponentDefinition.cxx | 278 ++ .../source/core/dataaccess/ComponentDefinition.hxx | 161 + dbaccess/source/core/dataaccess/ContentHelper.cxx | 610 ++++ dbaccess/source/core/dataaccess/ModelImpl.cxx | 1440 ++++++++ .../source/core/dataaccess/SharedConnection.cxx | 157 + .../source/core/dataaccess/SharedConnection.hxx | 121 + .../source/core/dataaccess/bookmarkcontainer.cxx | 307 ++ .../source/core/dataaccess/commandcontainer.cxx | 94 + .../source/core/dataaccess/commandcontainer.hxx | 75 + .../source/core/dataaccess/commanddefinition.cxx | 132 + .../source/core/dataaccess/commanddefinition.hxx | 128 + dbaccess/source/core/dataaccess/connection.cxx | 808 +++++ dbaccess/source/core/dataaccess/connection.hxx | 232 ++ .../core/dataaccess/dataaccessdescriptor.cxx | 261 ++ .../source/core/dataaccess/databasecontext.cxx | 764 ++++ .../source/core/dataaccess/databasedocument.cxx | 2218 ++++++++++++ .../source/core/dataaccess/databasedocument.hxx | 751 ++++ .../core/dataaccess/databaseregistrations.cxx | 370 ++ .../core/dataaccess/databaseregistrations.hxx | 36 + dbaccess/source/core/dataaccess/datasource.cxx | 1430 ++++++++ dbaccess/source/core/dataaccess/datasource.hxx | 222 ++ .../source/core/dataaccess/definitioncontainer.cxx | 671 ++++ .../source/core/dataaccess/documentcontainer.cxx | 737 ++++ .../source/core/dataaccess/documentcontainer.hxx | 139 + .../source/core/dataaccess/documentdefinition.cxx | 2106 +++++++++++ .../source/core/dataaccess/documentdefinition.hxx | 359 ++ .../core/dataaccess/documenteventexecutor.cxx | 199 ++ .../core/dataaccess/documenteventexecutor.hxx | 62 + .../core/dataaccess/documenteventnotifier.cxx | 286 ++ .../core/dataaccess/documenteventnotifier.hxx | 131 + dbaccess/source/core/dataaccess/documentevents.cxx | 215 ++ dbaccess/source/core/dataaccess/intercept.cxx | 365 ++ dbaccess/source/core/dataaccess/intercept.hxx | 114 + .../source/core/dataaccess/myucp_datasupplier.cxx | 330 ++ .../source/core/dataaccess/myucp_datasupplier.hxx | 65 + .../source/core/dataaccess/myucp_resultset.cxx | 74 + .../source/core/dataaccess/myucp_resultset.hxx | 52 + dbaccess/source/core/inc/ContainerMediator.hxx | 82 + dbaccess/source/core/inc/ContentHelper.hxx | 185 + dbaccess/source/core/inc/DatabaseDataProvider.hxx | 273 ++ dbaccess/source/core/inc/FilteredContainer.hxx | 139 + dbaccess/source/core/inc/ModelImpl.hxx | 545 +++ dbaccess/source/core/inc/PropertyForward.hxx | 72 + dbaccess/source/core/inc/RefreshListener.hxx | 45 + .../source/core/inc/SingleSelectQueryComposer.hxx | 262 ++ dbaccess/source/core/inc/TableDeco.hxx | 166 + dbaccess/source/core/inc/View.hxx | 74 + dbaccess/source/core/inc/bookmarkcontainer.hxx | 151 + dbaccess/source/core/inc/callablestatement.hxx | 82 + dbaccess/source/core/inc/column.hxx | 219 ++ dbaccess/source/core/inc/columnsettings.hxx | 91 + dbaccess/source/core/inc/commandbase.hxx | 53 + dbaccess/source/core/inc/composertools.hxx | 124 + dbaccess/source/core/inc/containerapprove.hxx | 60 + dbaccess/source/core/inc/databasecontext.hxx | 191 + dbaccess/source/core/inc/datasettings.hxx | 80 + dbaccess/source/core/inc/definitioncolumn.hxx | 293 ++ dbaccess/source/core/inc/definitioncontainer.hxx | 325 ++ dbaccess/source/core/inc/documentevents.hxx | 78 + dbaccess/source/core/inc/migrwarndlg.hxx | 27 + dbaccess/source/core/inc/object.hxx | 33 + dbaccess/source/core/inc/objectnameapproval.hxx | 78 + dbaccess/source/core/inc/preparedstatement.hxx | 107 + dbaccess/source/core/inc/querycomposer.hxx | 93 + dbaccess/source/core/inc/querycontainer.hxx | 167 + .../source/core/inc/recovery/dbdocrecovery.hxx | 74 + dbaccess/source/core/inc/sdbcoretools.hxx | 58 + dbaccess/source/core/inc/statement.hxx | 182 + dbaccess/source/core/inc/table.hxx | 142 + dbaccess/source/core/inc/tablecontainer.hxx | 97 + dbaccess/source/core/inc/veto.hxx | 58 + dbaccess/source/core/inc/viewcontainer.hxx | 96 + dbaccess/source/core/misc/ContainerMediator.cxx | 231 ++ dbaccess/source/core/misc/DatabaseDataProvider.cxx | 1080 ++++++ dbaccess/source/core/misc/PropertyForward.cxx | 146 + dbaccess/source/core/misc/apitools.cxx | 114 + dbaccess/source/core/misc/dsntypes.cxx | 563 +++ dbaccess/source/core/misc/migrwarndlg.cxx | 22 + dbaccess/source/core/misc/objectnameapproval.cxx | 74 + dbaccess/source/core/misc/sdbcoretools.cxx | 146 + dbaccess/source/core/misc/services.cxx | 59 + dbaccess/source/core/misc/veto.cxx | 49 + dbaccess/source/core/recovery/dbdocrecovery.cxx | 347 ++ dbaccess/source/core/recovery/settingsimport.cxx | 216 ++ dbaccess/source/core/recovery/settingsimport.hxx | 166 + dbaccess/source/core/recovery/storagestream.cxx | 55 + dbaccess/source/core/recovery/storagestream.hxx | 54 + .../source/core/recovery/storagetextstream.cxx | 71 + .../source/core/recovery/storagetextstream.hxx | 55 + dbaccess/source/core/recovery/storagexmlstream.cxx | 151 + dbaccess/source/core/recovery/storagexmlstream.hxx | 91 + .../source/core/recovery/subcomponentloader.cxx | 124 + .../source/core/recovery/subcomponentloader.hxx | 74 + .../source/core/recovery/subcomponentrecovery.cxx | 628 ++++ .../source/core/recovery/subcomponentrecovery.hxx | 117 + dbaccess/source/core/recovery/subcomponents.hxx | 64 + dbaccess/source/core/resource/core_resource.cxx | 57 + dbaccess/source/filter/hsqldb/alterparser.cxx | 56 + dbaccess/source/filter/hsqldb/alterparser.hxx | 55 + dbaccess/source/filter/hsqldb/columndef.cxx | 44 + dbaccess/source/filter/hsqldb/columndef.hxx | 50 + dbaccess/source/filter/hsqldb/createparser.cxx | 284 ++ dbaccess/source/filter/hsqldb/createparser.hxx | 71 + dbaccess/source/filter/hsqldb/fbalterparser.cxx | 53 + dbaccess/source/filter/hsqldb/fbalterparser.hxx | 33 + dbaccess/source/filter/hsqldb/fbcreateparser.cxx | 218 ++ dbaccess/source/filter/hsqldb/fbcreateparser.hxx | 40 + dbaccess/source/filter/hsqldb/hsqlbinarynode.cxx | 60 + dbaccess/source/filter/hsqldb/hsqlbinarynode.hxx | 66 + dbaccess/source/filter/hsqldb/hsqlimport.cxx | 387 ++ dbaccess/source/filter/hsqldb/hsqlimport.hxx | 63 + dbaccess/source/filter/hsqldb/parseschema.cxx | 199 ++ dbaccess/source/filter/hsqldb/parseschema.hxx | 87 + dbaccess/source/filter/hsqldb/rowinputbinary.cxx | 402 +++ dbaccess/source/filter/hsqldb/rowinputbinary.hxx | 55 + dbaccess/source/filter/hsqldb/utils.cxx | 140 + dbaccess/source/filter/hsqldb/utils.hxx | 29 + dbaccess/source/filter/xml/dbaxml.component | 40 + dbaccess/source/filter/xml/dbloader2.cxx | 574 +++ dbaccess/source/filter/xml/xmlAutoStyle.cxx | 82 + dbaccess/source/filter/xml/xmlAutoStyle.hxx | 47 + dbaccess/source/filter/xml/xmlColumn.cxx | 165 + dbaccess/source/filter/xml/xmlColumn.hxx | 58 + dbaccess/source/filter/xml/xmlComponent.cxx | 101 + dbaccess/source/filter/xml/xmlComponent.hxx | 45 + dbaccess/source/filter/xml/xmlConnectionData.cxx | 93 + dbaccess/source/filter/xml/xmlConnectionData.hxx | 46 + .../source/filter/xml/xmlConnectionResource.cxx | 89 + .../source/filter/xml/xmlConnectionResource.hxx | 41 + dbaccess/source/filter/xml/xmlDataSource.cxx | 254 ++ dbaccess/source/filter/xml/xmlDataSource.hxx | 52 + dbaccess/source/filter/xml/xmlDataSourceInfo.cxx | 122 + dbaccess/source/filter/xml/xmlDataSourceInfo.hxx | 42 + .../source/filter/xml/xmlDataSourceSetting.cxx | 217 ++ .../source/filter/xml/xmlDataSourceSetting.hxx | 66 + .../source/filter/xml/xmlDataSourceSettings.cxx | 66 + .../source/filter/xml/xmlDataSourceSettings.hxx | 44 + dbaccess/source/filter/xml/xmlDatabase.cxx | 135 + dbaccess/source/filter/xml/xmlDatabase.hxx | 46 + .../source/filter/xml/xmlDatabaseDescription.cxx | 79 + .../source/filter/xml/xmlDatabaseDescription.hxx | 46 + dbaccess/source/filter/xml/xmlDocuments.cxx | 99 + dbaccess/source/filter/xml/xmlDocuments.hxx | 61 + dbaccess/source/filter/xml/xmlEnums.hxx | 26 + dbaccess/source/filter/xml/xmlExport.cxx | 1409 ++++++++ dbaccess/source/filter/xml/xmlExport.hxx | 189 + .../source/filter/xml/xmlFileBasedDatabase.cxx | 113 + .../source/filter/xml/xmlFileBasedDatabase.hxx | 41 + dbaccess/source/filter/xml/xmlHelper.cxx | 151 + dbaccess/source/filter/xml/xmlHelper.hxx | 59 + .../source/filter/xml/xmlHierarchyCollection.cxx | 133 + .../source/filter/xml/xmlHierarchyCollection.hxx | 60 + dbaccess/source/filter/xml/xmlLogin.cxx | 114 + dbaccess/source/filter/xml/xmlLogin.hxx | 42 + dbaccess/source/filter/xml/xmlQuery.cxx | 120 + dbaccess/source/filter/xml/xmlQuery.hxx | 51 + dbaccess/source/filter/xml/xmlServerDatabase.cxx | 136 + dbaccess/source/filter/xml/xmlServerDatabase.hxx | 41 + dbaccess/source/filter/xml/xmlStyleImport.cxx | 266 ++ dbaccess/source/filter/xml/xmlStyleImport.hxx | 103 + dbaccess/source/filter/xml/xmlTable.cxx | 227 ++ dbaccess/source/filter/xml/xmlTable.hxx | 72 + dbaccess/source/filter/xml/xmlTableFilterList.cxx | 95 + dbaccess/source/filter/xml/xmlTableFilterList.hxx | 70 + .../source/filter/xml/xmlTableFilterPattern.cxx | 59 + .../source/filter/xml/xmlTableFilterPattern.hxx | 49 + dbaccess/source/filter/xml/xmlfilter.cxx | 650 ++++ dbaccess/source/filter/xml/xmlfilter.hxx | 131 + dbaccess/source/filter/xml/xmlservices.cxx | 69 + dbaccess/source/filter/xml/xmlservices.hxx | 37 + .../source/inc/OAuthenticationContinuation.hxx | 70 + dbaccess/source/inc/apitools.hxx | 234 ++ dbaccess/source/inc/dbu_reghelper.hxx | 39 + dbaccess/source/inc/dsntypes.hxx | 220 ++ dbaccess/source/inc/flt_reghelper.hxx | 39 + dbaccess/source/inc/registrationhelper.hxx | 112 + dbaccess/source/inc/stringconstants.hxx | 174 + .../source/sdbtools/connection/connectiontools.cxx | 142 + .../sdbtools/connection/datasourcemetadata.cxx | 51 + .../sdbtools/connection/datasourcemetadata.hxx | 69 + .../source/sdbtools/connection/objectnames.cxx | 420 +++ .../source/sdbtools/connection/objectnames.hxx | 74 + dbaccess/source/sdbtools/connection/tablename.cxx | 232 ++ dbaccess/source/sdbtools/connection/tablename.hxx | 84 + .../source/sdbtools/inc/connectiondependent.hxx | 135 + dbaccess/source/sdbtools/inc/connectiontools.hxx | 83 + dbaccess/source/sdbtools/misc/sdbt_services.cxx | 46 + dbaccess/source/shared/dbu_reghelper.cxx | 34 + dbaccess/source/shared/flt_reghelper.cxx | 34 + dbaccess/source/shared/registrationhelper.cxx | 152 + dbaccess/source/ui/app/AppController.cxx | 2809 +++++++++++++++ dbaccess/source/ui/app/AppController.hxx | 526 +++ dbaccess/source/ui/app/AppControllerDnD.cxx | 808 +++++ dbaccess/source/ui/app/AppControllerGen.cxx | 741 ++++ dbaccess/source/ui/app/AppDetailPageHelper.cxx | 1305 +++++++ dbaccess/source/ui/app/AppDetailPageHelper.hxx | 350 ++ dbaccess/source/ui/app/AppDetailView.cxx | 877 +++++ dbaccess/source/ui/app/AppDetailView.hxx | 368 ++ dbaccess/source/ui/app/AppIconControl.cxx | 106 + dbaccess/source/ui/app/AppIconControl.hxx | 48 + dbaccess/source/ui/app/AppSwapWindow.cxx | 180 + dbaccess/source/ui/app/AppSwapWindow.hxx | 92 + dbaccess/source/ui/app/AppTitleWindow.cxx | 182 + dbaccess/source/ui/app/AppTitleWindow.hxx | 76 + dbaccess/source/ui/app/AppView.cxx | 524 +++ dbaccess/source/ui/app/AppView.hxx | 297 ++ dbaccess/source/ui/app/subcomponentmanager.cxx | 555 +++ dbaccess/source/ui/app/subcomponentmanager.hxx | 123 + dbaccess/source/ui/app/window_layout.txt | 49 + dbaccess/source/ui/browser/AsynchronousLink.cxx | 83 + dbaccess/source/ui/browser/brwctrlr.cxx | 2596 ++++++++++++++ dbaccess/source/ui/browser/brwview.cxx | 340 ++ dbaccess/source/ui/browser/dataview.cxx | 183 + dbaccess/source/ui/browser/dbexchange.cxx | 240 ++ dbaccess/source/ui/browser/dbloader.cxx | 298 ++ dbaccess/source/ui/browser/dbtreemodel.cxx | 33 + dbaccess/source/ui/browser/dbtreemodel.hxx | 60 + dbaccess/source/ui/browser/dbtreeview.cxx | 90 + dbaccess/source/ui/browser/dbtreeview.hxx | 66 + dbaccess/source/ui/browser/dsEntriesNoExp.cxx | 256 ++ dbaccess/source/ui/browser/dsbrowserDnD.cxx | 266 ++ dbaccess/source/ui/browser/exsrcbrw.cxx | 434 +++ dbaccess/source/ui/browser/formadapter.cxx | 1651 +++++++++ dbaccess/source/ui/browser/genericcontroller.cxx | 1235 +++++++ dbaccess/source/ui/browser/sbagrid.cxx | 1419 ++++++++ dbaccess/source/ui/browser/sbamultiplex.cxx | 96 + dbaccess/source/ui/browser/unodatbr.cxx | 3723 ++++++++++++++++++++ dbaccess/source/ui/control/ColumnControlWindow.cxx | 163 + dbaccess/source/ui/control/FieldControls.cxx | 60 + dbaccess/source/ui/control/FieldDescControl.cxx | 1391 ++++++++ dbaccess/source/ui/control/RelationControl.cxx | 695 ++++ dbaccess/source/ui/control/ScrollHelper.cxx | 52 + dbaccess/source/ui/control/SqlNameEdit.cxx | 84 + dbaccess/source/ui/control/TableGrantCtrl.cxx | 461 +++ dbaccess/source/ui/control/VertSplitView.cxx | 180 + dbaccess/source/ui/control/charsetlistbox.cxx | 69 + dbaccess/source/ui/control/curledit.cxx | 89 + dbaccess/source/ui/control/dbtreelistbox.cxx | 584 +++ dbaccess/source/ui/control/listviewitems.cxx | 68 + dbaccess/source/ui/control/marktree.cxx | 206 ++ dbaccess/source/ui/control/opendoccontrols.cxx | 196 ++ dbaccess/source/ui/control/sqledit.cxx | 248 ++ dbaccess/source/ui/control/tabletree.cxx | 1006 ++++++ dbaccess/source/ui/control/undosqledit.cxx | 34 + dbaccess/source/ui/dlg/CollectionView.cxx | 318 ++ dbaccess/source/ui/dlg/ConnectionHelper.cxx | 726 ++++ dbaccess/source/ui/dlg/ConnectionHelper.hxx | 106 + dbaccess/source/ui/dlg/ConnectionPage.cxx | 283 ++ dbaccess/source/ui/dlg/ConnectionPage.hxx | 75 + dbaccess/source/ui/dlg/ConnectionPageSetup.cxx | 153 + dbaccess/source/ui/dlg/ConnectionPageSetup.hxx | 65 + dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx | 786 +++++ dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx | 273 ++ dbaccess/source/ui/dlg/DbAdminImpl.cxx | 1076 ++++++ dbaccess/source/ui/dlg/DbAdminImpl.hxx | 170 + dbaccess/source/ui/dlg/DriverSettings.hxx | 82 + dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx | 63 + dbaccess/source/ui/dlg/RelationDlg.cxx | 215 ++ dbaccess/source/ui/dlg/TablesSingleDlg.cxx | 110 + dbaccess/source/ui/dlg/TextConnectionHelper.cxx | 391 ++ dbaccess/source/ui/dlg/TextConnectionHelper.hxx | 92 + dbaccess/source/ui/dlg/UserAdmin.cxx | 318 ++ dbaccess/source/ui/dlg/UserAdmin.hxx | 76 + dbaccess/source/ui/dlg/UserAdminDlg.cxx | 162 + dbaccess/source/ui/dlg/admincontrols.cxx | 201 ++ dbaccess/source/ui/dlg/admincontrols.hxx | 68 + dbaccess/source/ui/dlg/adminpages.cxx | 278 ++ dbaccess/source/ui/dlg/adminpages.hxx | 238 ++ dbaccess/source/ui/dlg/adodatalinks.cxx | 199 ++ dbaccess/source/ui/dlg/adodatalinks.hxx | 27 + dbaccess/source/ui/dlg/adtabdlg.cxx | 468 +++ dbaccess/source/ui/dlg/advancedsettings.cxx | 472 +++ dbaccess/source/ui/dlg/advancedsettings.hxx | 120 + dbaccess/source/ui/dlg/dbadmin.cxx | 432 +++ dbaccess/source/ui/dlg/dbfindex.cxx | 430 +++ dbaccess/source/ui/dlg/dbfindex.hxx | 113 + dbaccess/source/ui/dlg/dbwiz.cxx | 335 ++ dbaccess/source/ui/dlg/dbwizsetup.cxx | 999 ++++++ dbaccess/source/ui/dlg/detailpages.cxx | 718 ++++ dbaccess/source/ui/dlg/detailpages.hxx | 255 ++ dbaccess/source/ui/dlg/directsql.cxx | 504 +++ dbaccess/source/ui/dlg/dlgattr.cxx | 61 + dbaccess/source/ui/dlg/dlgsave.cxx | 351 ++ dbaccess/source/ui/dlg/dlgsize.cxx | 83 + dbaccess/source/ui/dlg/dsnItem.hxx | 51 + dbaccess/source/ui/dlg/dsselect.cxx | 133 + dbaccess/source/ui/dlg/dsselect.hxx | 69 + dbaccess/source/ui/dlg/finteraction.cxx | 59 + dbaccess/source/ui/dlg/finteraction.hxx | 57 + dbaccess/source/ui/dlg/generalpage.cxx | 683 ++++ 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 | 327 ++ dbaccess/source/ui/dlg/odbcconfig.hxx | 109 + dbaccess/source/ui/dlg/optionalboolitem.cxx | 45 + dbaccess/source/ui/dlg/optionalboolitem.hxx | 54 + dbaccess/source/ui/dlg/paramdialog.cxx | 339 ++ dbaccess/source/ui/dlg/queryfilter.cxx | 773 ++++ dbaccess/source/ui/dlg/queryorder.cxx | 218 ++ dbaccess/source/ui/dlg/sqlmessage.cxx | 607 ++++ dbaccess/source/ui/dlg/tablespage.cxx | 496 +++ dbaccess/source/ui/dlg/tablespage.hxx | 85 + dbaccess/source/ui/dlg/textconnectionsettings.cxx | 69 + dbaccess/source/ui/inc/AppElementType.hxx | 55 + dbaccess/source/ui/inc/CollectionView.hxx | 68 + dbaccess/source/ui/inc/ColumnControlWindow.hxx | 69 + dbaccess/source/ui/inc/ConnectionLine.hxx | 73 + dbaccess/source/ui/inc/ConnectionLineAccess.hxx | 93 + dbaccess/source/ui/inc/ConnectionLineData.hxx | 82 + dbaccess/source/ui/inc/DExport.hxx | 165 + dbaccess/source/ui/inc/FieldControls.hxx | 121 + dbaccess/source/ui/inc/FieldDescControl.hxx | 203 ++ dbaccess/source/ui/inc/FieldDescriptions.hxx | 113 + dbaccess/source/ui/inc/GeneralUndo.hxx | 42 + dbaccess/source/ui/inc/HtmlReader.hxx | 70 + dbaccess/source/ui/inc/IClipBoardTest.hxx | 42 + dbaccess/source/ui/inc/IItemSetHelper.hxx | 74 + dbaccess/source/ui/inc/IUpdateHelper.hxx | 47 + dbaccess/source/ui/inc/JAccess.hxx | 72 + dbaccess/source/ui/inc/JoinController.hxx | 156 + dbaccess/source/ui/inc/JoinDesignView.hxx | 70 + dbaccess/source/ui/inc/JoinExchange.hxx | 70 + dbaccess/source/ui/inc/JoinTableView.hxx | 327 ++ dbaccess/source/ui/inc/QEnumTypes.hxx | 81 + dbaccess/source/ui/inc/QueryDesignView.hxx | 156 + dbaccess/source/ui/inc/QueryPropertiesDialog.hxx | 48 + dbaccess/source/ui/inc/QueryTableView.hxx | 118 + dbaccess/source/ui/inc/QueryTextView.hxx | 58 + dbaccess/source/ui/inc/QueryViewSwitch.hxx | 96 + dbaccess/source/ui/inc/RTableConnectionData.hxx | 82 + dbaccess/source/ui/inc/RelControliFace.hxx | 42 + dbaccess/source/ui/inc/RelationControl.hxx | 93 + dbaccess/source/ui/inc/RelationController.hxx | 87 + dbaccess/source/ui/inc/RelationDesignView.hxx | 47 + dbaccess/source/ui/inc/RelationDlg.hxx | 76 + dbaccess/source/ui/inc/RelationTableView.hxx | 76 + dbaccess/source/ui/inc/RtfReader.hxx | 61 + dbaccess/source/ui/inc/ScrollHelper.hxx | 67 + dbaccess/source/ui/inc/SqlNameEdit.hxx | 116 + dbaccess/source/ui/inc/TableConnection.hxx | 100 + dbaccess/source/ui/inc/TableConnectionData.hxx | 103 + dbaccess/source/ui/inc/TableController.hxx | 139 + dbaccess/source/ui/inc/TableCopyHelper.hxx | 191 + dbaccess/source/ui/inc/TableDesignControl.hxx | 80 + dbaccess/source/ui/inc/TableDesignHelpBar.hxx | 60 + dbaccess/source/ui/inc/TableDesignView.hxx | 108 + dbaccess/source/ui/inc/TableFieldDescription.hxx | 152 + dbaccess/source/ui/inc/TableGrantCtrl.hxx | 107 + dbaccess/source/ui/inc/TableRow.hxx | 80 + dbaccess/source/ui/inc/TableRowExchange.hxx | 42 + dbaccess/source/ui/inc/TableWindow.hxx | 196 ++ dbaccess/source/ui/inc/TableWindowAccess.hxx | 96 + dbaccess/source/ui/inc/TableWindowData.hxx | 97 + dbaccess/source/ui/inc/TableWindowListBox.hxx | 100 + dbaccess/source/ui/inc/TableWindowTitle.hxx | 51 + dbaccess/source/ui/inc/TablesSingleDlg.hxx | 75 + dbaccess/source/ui/inc/TokenWriter.hxx | 212 ++ dbaccess/source/ui/inc/TypeInfo.hxx | 124 + dbaccess/source/ui/inc/UITools.hxx | 393 +++ dbaccess/source/ui/inc/UserAdminDlg.hxx | 79 + dbaccess/source/ui/inc/VertSplitView.hxx | 54 + dbaccess/source/ui/inc/WCPage.hxx | 81 + dbaccess/source/ui/inc/WColumnSelect.hxx | 84 + dbaccess/source/ui/inc/WCopyTable.hxx | 416 +++ dbaccess/source/ui/inc/WExtendPages.hxx | 71 + dbaccess/source/ui/inc/WNameMatch.hxx | 65 + dbaccess/source/ui/inc/WTabPage.hxx | 48 + dbaccess/source/ui/inc/WTypeSelect.hxx | 142 + dbaccess/source/ui/inc/adtabdlg.hxx | 100 + dbaccess/source/ui/inc/advancedsettingsdlg.hxx | 73 + dbaccess/source/ui/inc/asyncmodaldialog.hxx | 50 + dbaccess/source/ui/inc/browserids.hxx | 102 + dbaccess/source/ui/inc/brwctrlr.hxx | 336 ++ dbaccess/source/ui/inc/brwview.hxx | 99 + dbaccess/source/ui/inc/callbacks.hxx | 111 + dbaccess/source/ui/inc/charsetlistbox.hxx | 51 + dbaccess/source/ui/inc/charsets.hxx | 108 + dbaccess/source/ui/inc/commontypes.hxx | 42 + dbaccess/source/ui/inc/curledit.hxx | 105 + dbaccess/source/ui/inc/databaseobjectview.hxx | 233 ++ dbaccess/source/ui/inc/datasourceconnector.hxx | 79 + dbaccess/source/ui/inc/dbadmin.hxx | 116 + dbaccess/source/ui/inc/dbexchange.hxx | 84 + dbaccess/source/ui/inc/dbtreelistbox.hxx | 141 + dbaccess/source/ui/inc/dbu_dlg.hxx | 27 + dbaccess/source/ui/inc/dbwiz.hxx | 104 + dbaccess/source/ui/inc/dbwizsetup.hxx | 173 + dbaccess/source/ui/inc/defaultobjectnamecheck.hxx | 123 + dbaccess/source/ui/inc/directsql.hxx | 148 + dbaccess/source/ui/inc/dlgattr.hxx | 44 + dbaccess/source/ui/inc/dlgsave.hxx | 84 + dbaccess/source/ui/inc/dlgsize.hxx | 47 + dbaccess/source/ui/inc/dsitems.hxx | 98 + dbaccess/source/ui/inc/dsmeta.hxx | 128 + dbaccess/source/ui/inc/exsrcbrw.hxx | 105 + dbaccess/source/ui/inc/formadapter.hxx | 437 +++ dbaccess/source/ui/inc/imageprovider.hxx | 146 + dbaccess/source/ui/inc/indexcollection.hxx | 97 + dbaccess/source/ui/inc/indexdialog.hxx | 106 + dbaccess/source/ui/inc/indexes.hxx | 84 + dbaccess/source/ui/inc/indexfieldscontrol.hxx | 94 + dbaccess/source/ui/inc/linkeddocuments.hxx | 111 + dbaccess/source/ui/inc/listviewitems.hxx | 54 + dbaccess/source/ui/inc/marktree.hxx | 63 + dbaccess/source/ui/inc/objectnamecheck.hxx | 60 + dbaccess/source/ui/inc/opendoccontrols.hxx | 84 + dbaccess/source/ui/inc/paramdialog.hxx | 106 + dbaccess/source/ui/inc/propertystorage.hxx | 57 + dbaccess/source/ui/inc/querycontainerwindow.hxx | 107 + dbaccess/source/ui/inc/querycontroller.hxx | 227 ++ dbaccess/source/ui/inc/queryfilter.hxx | 118 + dbaccess/source/ui/inc/queryorder.hxx | 90 + dbaccess/source/ui/inc/sbagrid.hrc | 37 + dbaccess/source/ui/inc/sbagrid.hxx | 299 ++ dbaccess/source/ui/inc/sbamultiplex.hxx | 397 +++ dbaccess/source/ui/inc/singledoccontroller.hxx | 81 + dbaccess/source/ui/inc/sqledit.hxx | 86 + dbaccess/source/ui/inc/sqlmessage.hxx | 148 + dbaccess/source/ui/inc/stringlistitem.hxx | 52 + dbaccess/source/ui/inc/tabletree.hxx | 238 ++ dbaccess/source/ui/inc/textconnectionsettings.hxx | 62 + dbaccess/source/ui/inc/uiservices.hxx | 55 + dbaccess/source/ui/inc/undosqledit.hxx | 48 + dbaccess/source/ui/inc/unoadmin.hxx | 62 + dbaccess/source/ui/inc/unodatbr.hxx | 464 +++ dbaccess/source/ui/inc/unosqlmessage.hxx | 80 + dbaccess/source/ui/misc/DExport.cxx | 842 +++++ 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 | 309 ++ dbaccess/source/ui/misc/TokenWriter.cxx | 973 +++++ dbaccess/source/ui/misc/UITools.cxx | 1374 ++++++++ dbaccess/source/ui/misc/UpdateHelperImpl.hxx | 77 + dbaccess/source/ui/misc/WCPage.cxx | 324 ++ dbaccess/source/ui/misc/WColumnSelect.cxx | 403 +++ dbaccess/source/ui/misc/WCopyTable.cxx | 1558 ++++++++ dbaccess/source/ui/misc/WExtendPages.cxx | 62 + dbaccess/source/ui/misc/WNameMatch.cxx | 334 ++ dbaccess/source/ui/misc/WTypeSelect.cxx | 419 +++ dbaccess/source/ui/misc/asyncmodaldialog.cxx | 91 + dbaccess/source/ui/misc/charsets.cxx | 131 + dbaccess/source/ui/misc/controllerframe.cxx | 393 +++ dbaccess/source/ui/misc/databaseobjectview.cxx | 292 ++ dbaccess/source/ui/misc/datasourceconnector.cxx | 202 ++ dbaccess/source/ui/misc/dbaundomanager.cxx | 325 ++ .../source/ui/misc/dbsubcomponentcontroller.cxx | 606 ++++ dbaccess/source/ui/misc/defaultobjectnamecheck.cxx | 159 + dbaccess/source/ui/misc/dsmeta.cxx | 190 + dbaccess/source/ui/misc/imageprovider.cxx | 266 ++ dbaccess/source/ui/misc/indexcollection.cxx | 328 ++ dbaccess/source/ui/misc/linkeddocuments.cxx | 356 ++ dbaccess/source/ui/misc/propertystorage.cxx | 106 + dbaccess/source/ui/misc/singledoccontroller.cxx | 182 + dbaccess/source/ui/misc/stringlistitem.cxx | 63 + dbaccess/source/ui/misc/uiservices.cxx | 87 + dbaccess/source/ui/querydesign/ConnectionLine.cxx | 344 ++ .../source/ui/querydesign/ConnectionLineAccess.cxx | 187 + .../source/ui/querydesign/ConnectionLineData.cxx | 76 + dbaccess/source/ui/querydesign/JAccess.cxx | 91 + dbaccess/source/ui/querydesign/JoinController.cxx | 405 +++ dbaccess/source/ui/querydesign/JoinDesignView.cxx | 100 + dbaccess/source/ui/querydesign/JoinExchange.cxx | 129 + dbaccess/source/ui/querydesign/JoinTableView.cxx | 1566 ++++++++ .../source/ui/querydesign/QTableConnection.cxx | 73 + .../source/ui/querydesign/QTableConnection.hxx | 48 + .../source/ui/querydesign/QTableConnectionData.cxx | 113 + .../source/ui/querydesign/QTableConnectionData.hxx | 69 + dbaccess/source/ui/querydesign/QTableWindow.cxx | 176 + dbaccess/source/ui/querydesign/QTableWindow.hxx | 78 + .../source/ui/querydesign/QTableWindowData.cxx | 34 + .../source/ui/querydesign/QTableWindowData.hxx | 40 + .../ui/querydesign/QueryAddTabConnUndoAction.hxx | 51 + .../ui/querydesign/QueryDesignFieldUndoAct.hxx | 140 + .../ui/querydesign/QueryDesignUndoAction.hxx | 41 + dbaccess/source/ui/querydesign/QueryDesignView.cxx | 3442 ++++++++++++++++++ .../ui/querydesign/QueryMoveTabWinUndoAct.cxx | 39 + .../ui/querydesign/QueryMoveTabWinUndoAct.hxx | 56 + .../ui/querydesign/QuerySizeTabWinUndoAct.hxx | 73 + .../ui/querydesign/QueryTabConnUndoAction.cxx | 121 + .../ui/querydesign/QueryTabConnUndoAction.hxx | 52 + .../ui/querydesign/QueryTabWinShowUndoAct.hxx | 53 + .../source/ui/querydesign/QueryTabWinUndoAct.cxx | 113 + .../source/ui/querydesign/QueryTabWinUndoAct.hxx | 63 + dbaccess/source/ui/querydesign/QueryTableView.cxx | 887 +++++ dbaccess/source/ui/querydesign/QueryTextView.cxx | 110 + dbaccess/source/ui/querydesign/QueryViewSwitch.cxx | 293 ++ .../source/ui/querydesign/SelectionBrowseBox.cxx | 2695 ++++++++++++++ .../source/ui/querydesign/SelectionBrowseBox.hxx | 322 ++ dbaccess/source/ui/querydesign/TableConnection.cxx | 190 + .../source/ui/querydesign/TableConnectionData.cxx | 147 + .../ui/querydesign/TableFieldDescription.cxx | 196 ++ dbaccess/source/ui/querydesign/TableFieldInfo.cxx | 33 + dbaccess/source/ui/querydesign/TableFieldInfo.hxx | 46 + dbaccess/source/ui/querydesign/TableWindow.cxx | 744 ++++ .../source/ui/querydesign/TableWindowAccess.cxx | 250 ++ dbaccess/source/ui/querydesign/TableWindowData.cxx | 135 + .../source/ui/querydesign/TableWindowListBox.cxx | 370 ++ .../source/ui/querydesign/TableWindowTitle.cxx | 187 + dbaccess/source/ui/querydesign/class.jpg | Bin 0 -> 224242 bytes .../source/ui/querydesign/limitboxcontroller.cxx | 321 ++ .../source/ui/querydesign/limitboxcontroller.hxx | 76 + .../source/ui/querydesign/querycontainerwindow.cxx | 223 ++ dbaccess/source/ui/querydesign/querycontroller.cxx | 1819 ++++++++++ dbaccess/source/ui/querydesign/querydlg.cxx | 313 ++ dbaccess/source/ui/querydesign/querydlg.hxx | 79 + .../source/ui/relationdesign/RTableConnection.cxx | 117 + .../source/ui/relationdesign/RTableConnection.hxx | 42 + .../ui/relationdesign/RTableConnectionData.cxx | 399 +++ dbaccess/source/ui/relationdesign/RTableWindow.hxx | 42 + .../ui/relationdesign/RelationController.cxx | 566 +++ .../ui/relationdesign/RelationDesignView.cxx | 74 + .../source/ui/relationdesign/RelationTableView.cxx | 407 +++ dbaccess/source/ui/tabledesign/FieldDescGenWin.cxx | 149 + dbaccess/source/ui/tabledesign/FieldDescGenWin.hxx | 74 + .../source/ui/tabledesign/FieldDescriptions.cxx | 641 ++++ dbaccess/source/ui/tabledesign/TEditControl.cxx | 1633 +++++++++ dbaccess/source/ui/tabledesign/TEditControl.hxx | 205 ++ dbaccess/source/ui/tabledesign/TableController.cxx | 1511 ++++++++ .../source/ui/tabledesign/TableDesignControl.cxx | 181 + .../source/ui/tabledesign/TableDesignHelpBar.cxx | 105 + dbaccess/source/ui/tabledesign/TableDesignView.cxx | 302 ++ .../source/ui/tabledesign/TableFieldControl.cxx | 144 + .../source/ui/tabledesign/TableFieldControl.hxx | 60 + .../source/ui/tabledesign/TableFieldDescWin.cxx | 275 ++ .../source/ui/tabledesign/TableFieldDescWin.hxx | 95 + dbaccess/source/ui/tabledesign/TableRow.cxx | 193 + .../source/ui/tabledesign/TableRowExchange.cxx | 68 + dbaccess/source/ui/tabledesign/TableUndo.cxx | 352 ++ dbaccess/source/ui/tabledesign/TableUndo.hxx | 138 + dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx | 142 + dbaccess/source/ui/uno/ColumnControl.cxx | 137 + dbaccess/source/ui/uno/ColumnControl.hxx | 56 + dbaccess/source/ui/uno/ColumnModel.cxx | 149 + dbaccess/source/ui/uno/ColumnModel.hxx | 103 + dbaccess/source/ui/uno/ColumnPeer.cxx | 147 + dbaccess/source/ui/uno/ColumnPeer.hxx | 49 + dbaccess/source/ui/uno/DBTypeWizDlg.cxx | 101 + dbaccess/source/ui/uno/DBTypeWizDlg.hxx | 67 + dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx | 122 + dbaccess/source/ui/uno/DBTypeWizDlgSetup.hxx | 70 + dbaccess/source/ui/uno/TableFilterDlg.cxx | 101 + dbaccess/source/ui/uno/TableFilterDlg.hxx | 68 + dbaccess/source/ui/uno/UserSettingsDlg.cxx | 101 + dbaccess/source/ui/uno/UserSettingsDlg.hxx | 68 + dbaccess/source/ui/uno/admindlg.cxx | 107 + dbaccess/source/ui/uno/admindlg.hxx | 67 + dbaccess/source/ui/uno/composerdialogs.cxx | 235 ++ dbaccess/source/ui/uno/composerdialogs.hxx | 137 + dbaccess/source/ui/uno/copytablewizard.cxx | 1553 ++++++++ dbaccess/source/ui/uno/dbinteraction.cxx | 367 ++ dbaccess/source/ui/uno/dbinteraction.hxx | 184 + .../source/ui/uno/textconnectionsettings_uno.cxx | 271 ++ dbaccess/source/ui/uno/unoDirectSql.cxx | 126 + dbaccess/source/ui/uno/unoDirectSql.hxx | 70 + dbaccess/source/ui/uno/unoadmin.cxx | 77 + dbaccess/source/ui/uno/unosqlmessage.cxx | 160 + dbaccess/uiconfig/dbapp/menubar/menubar.xml | 164 + dbaccess/uiconfig/dbapp/popupmenu/edit.xml | 35 + dbaccess/uiconfig/dbapp/popupmenu/new.xml | 22 + dbaccess/uiconfig/dbapp/popupmenu/preview.xml | 14 + dbaccess/uiconfig/dbapp/statusbar/statusbar.xml | 25 + dbaccess/uiconfig/dbapp/toolbar/formobjectbar.xml | 31 + dbaccess/uiconfig/dbapp/toolbar/queryobjectbar.xml | 32 + .../uiconfig/dbapp/toolbar/reportobjectbar.xml | 32 + dbaccess/uiconfig/dbapp/toolbar/tableobjectbar.xml | 31 + dbaccess/uiconfig/dbapp/toolbar/toolbar.xml | 36 + dbaccess/uiconfig/dbbrowser/menubar/compat.xml | 1 + dbaccess/uiconfig/dbbrowser/menubar/preserve.txt | 1 + dbaccess/uiconfig/dbbrowser/popupmenu/explorer.xml | 17 + .../uiconfig/dbbrowser/popupmenu/refreshdata.xml | 13 + dbaccess/uiconfig/dbbrowser/toolbar/toolbar.xml | 50 + dbaccess/uiconfig/dbquery/menubar/menubar.xml | 119 + .../uiconfig/dbquery/toolbar/designobjectbar.xml | 29 + dbaccess/uiconfig/dbquery/toolbar/sqlobjectbar.xml | 22 + dbaccess/uiconfig/dbquery/toolbar/toolbar.xml | 38 + dbaccess/uiconfig/dbrelation/menubar/menubar.xml | 103 + dbaccess/uiconfig/dbrelation/toolbar/toolbar.xml | 31 + dbaccess/uiconfig/dbtable/menubar/menubar.xml | 103 + dbaccess/uiconfig/dbtable/toolbar/toolbar.xml | 35 + dbaccess/uiconfig/dbtdata/menubar/menubar.xml | 128 + .../uiconfig/dbtdata/popupmenu/refreshdata.xml | 13 + dbaccess/uiconfig/dbtdata/toolbar/toolbar.xml | 45 + dbaccess/uiconfig/ui/admindialog.ui | 161 + dbaccess/uiconfig/ui/advancedsettingsdialog.ui | 208 ++ dbaccess/uiconfig/ui/applycolpage.ui | 245 ++ dbaccess/uiconfig/ui/authentificationpage.ui | 122 + dbaccess/uiconfig/ui/autocharsetpage.ui | 81 + dbaccess/uiconfig/ui/choosedatasourcedialog.ui | 180 + dbaccess/uiconfig/ui/collectionviewdialog.ui | 269 ++ dbaccess/uiconfig/ui/colwidthdialog.ui | 156 + dbaccess/uiconfig/ui/connectionpage.ui | 316 ++ dbaccess/uiconfig/ui/copytablepage.ui | 246 ++ dbaccess/uiconfig/ui/dbaseindexdialog.ui | 391 ++ dbaccess/uiconfig/ui/dbasepage.ui | 172 + dbaccess/uiconfig/ui/dbwizconnectionpage.ui | 134 + dbaccess/uiconfig/ui/dbwizmysqlintropage.ui | 157 + dbaccess/uiconfig/ui/dbwizmysqlnativepage.ui | 90 + dbaccess/uiconfig/ui/dbwizspreadsheetpage.ui | 175 + dbaccess/uiconfig/ui/dbwiztextpage.ui | 176 + dbaccess/uiconfig/ui/deleteallrowsdialog.ui | 81 + dbaccess/uiconfig/ui/designsavemodifieddialog.ui | 82 + dbaccess/uiconfig/ui/directsqldialog.ui | 309 ++ dbaccess/uiconfig/ui/emptypage.ui | 17 + dbaccess/uiconfig/ui/fielddescpage.ui | 419 +++ dbaccess/uiconfig/ui/fielddialog.ui | 233 ++ dbaccess/uiconfig/ui/finalpagewizard.ui | 171 + dbaccess/uiconfig/ui/generalpagedialog.ui | 81 + dbaccess/uiconfig/ui/generalpagewizard.ui | 226 ++ .../uiconfig/ui/generalspecialjdbcdetailspage.ui | 250 ++ dbaccess/uiconfig/ui/generatedvaluespage.ui | 155 + dbaccess/uiconfig/ui/indexdesigndialog.ui | 351 ++ dbaccess/uiconfig/ui/jdbcconnectionpage.ui | 202 ++ dbaccess/uiconfig/ui/joindialog.ui | 329 ++ dbaccess/uiconfig/ui/jointablemenu.ui | 17 + dbaccess/uiconfig/ui/joinviewmenu.ui | 25 + dbaccess/uiconfig/ui/keymenu.ui | 17 + dbaccess/uiconfig/ui/ldapconnectionpage.ui | 186 + dbaccess/uiconfig/ui/ldappage.ui | 162 + dbaccess/uiconfig/ui/limitbox.ui | 30 + dbaccess/uiconfig/ui/migrwarndlg.ui | 81 + dbaccess/uiconfig/ui/mysqlnativepage.ui | 219 ++ dbaccess/uiconfig/ui/mysqlnativesettings.ui | 263 ++ dbaccess/uiconfig/ui/namematchingpage.ui | 305 ++ dbaccess/uiconfig/ui/odbcpage.ui | 179 + dbaccess/uiconfig/ui/parametersdialog.ui | 240 ++ dbaccess/uiconfig/ui/password.ui | 210 ++ dbaccess/uiconfig/ui/querycolmenu.ui | 31 + dbaccess/uiconfig/ui/queryfilterdialog.ui | 330 ++ dbaccess/uiconfig/ui/queryfuncmenu.ui | 53 + dbaccess/uiconfig/ui/querypropertiesdialog.ui | 187 + dbaccess/uiconfig/ui/relationdialog.ui | 460 +++ dbaccess/uiconfig/ui/rowheightdialog.ui | 156 + dbaccess/uiconfig/ui/savedialog.ui | 204 ++ dbaccess/uiconfig/ui/saveindexdialog.ui | 82 + dbaccess/uiconfig/ui/savemodifieddialog.ui | 82 + dbaccess/uiconfig/ui/sortdialog.ui | 270 ++ dbaccess/uiconfig/ui/specialjdbcconnectionpage.ui | 228 ++ dbaccess/uiconfig/ui/specialsettingspage.ui | 337 ++ dbaccess/uiconfig/ui/sqlexception.ui | 179 + dbaccess/uiconfig/ui/tabledesignrowmenu.ui | 59 + .../uiconfig/ui/tabledesignsavemodifieddialog.ui | 82 + dbaccess/uiconfig/ui/tablesfilterdialog.ui | 90 + dbaccess/uiconfig/ui/tablesfilterpage.ui | 137 + dbaccess/uiconfig/ui/tablesjoindialog.ui | 272 ++ dbaccess/uiconfig/ui/textconnectionsettings.ui | 105 + dbaccess/uiconfig/ui/textpage.ui | 404 +++ dbaccess/uiconfig/ui/typeselectpage.ui | 220 ++ dbaccess/uiconfig/ui/useradmindialog.ui | 160 + dbaccess/uiconfig/ui/useradminpage.ui | 198 ++ dbaccess/uiconfig/ui/userdetailspage.ui | 235 ++ dbaccess/util/dba.component | 59 + dbaccess/util/dbu.component | 104 + dbaccess/util/sdbt.component | 25 + dbaccess/win32/source/odbcconfig/odbcconfig.cxx | 111 + 820 files changed, 187410 insertions(+) create mode 100644 dbaccess/AllLangMoTarget_dba.mk create mode 100644 dbaccess/CppunitTest_dbaccess_RowSetClones.mk create mode 100644 dbaccess/CppunitTest_dbaccess_dialog_save.mk create mode 100644 dbaccess/CppunitTest_dbaccess_dialogs_test.mk create mode 100644 dbaccess/CppunitTest_dbaccess_embeddeddb_performancetest.mk create mode 100644 dbaccess/CppunitTest_dbaccess_empty_stdlib_save.mk create mode 100644 dbaccess/CppunitTest_dbaccess_firebird_regression_test.mk create mode 100644 dbaccess/CppunitTest_dbaccess_firebird_test.mk create mode 100644 dbaccess/CppunitTest_dbaccess_hsqlbinary_import.mk create mode 100644 dbaccess/CppunitTest_dbaccess_hsqldb_test.mk create mode 100644 dbaccess/CppunitTest_dbaccess_hsqlschema_import.mk create mode 100644 dbaccess/CppunitTest_dbaccess_macros_test.mk create mode 100644 dbaccess/CppunitTest_dbaccess_nolib_save.mk create mode 100644 dbaccess/CppunitTest_dbaccess_tdf119625.mk create mode 100644 dbaccess/CppunitTest_dbaccess_tdf126268.mk create mode 100644 dbaccess/Executable_odbcconfig.mk create mode 100644 dbaccess/IwyuFilter_dbaccess.yaml create mode 100644 dbaccess/JunitTest_dbaccess_complex.mk create mode 100644 dbaccess/JunitTest_dbaccess_unoapi.mk create mode 100644 dbaccess/Library_dba.mk create mode 100644 dbaccess/Library_dbahsql.mk create mode 100644 dbaccess/Library_dbaxml.mk create mode 100644 dbaccess/Library_dbu.mk create mode 100644 dbaccess/Library_sdbt.mk create mode 100644 dbaccess/Makefile create mode 100644 dbaccess/Module_dbaccess.mk create mode 100644 dbaccess/PythonTest_dbaccess_python.mk create mode 100644 dbaccess/README create mode 100644 dbaccess/UIConfig_dbaccess.mk create mode 100644 dbaccess/UIConfig_dbapp.mk create mode 100644 dbaccess/UIConfig_dbbrowser.mk create mode 100644 dbaccess/UIConfig_dbquery.mk create mode 100644 dbaccess/UIConfig_dbrelation.mk create mode 100644 dbaccess/UIConfig_dbtable.mk create mode 100644 dbaccess/UIConfig_dbtdata.mk create mode 100644 dbaccess/inc/bitmaps.hlst create mode 100644 dbaccess/inc/core_resource.hxx create mode 100644 dbaccess/inc/dbaccess_slotid.hrc create mode 100644 dbaccess/inc/dbadllapi.hxx create mode 100644 dbaccess/inc/helpids.h create mode 100644 dbaccess/inc/pch/precompiled_dba.cxx create mode 100644 dbaccess/inc/pch/precompiled_dba.hxx create mode 100644 dbaccess/inc/pch/precompiled_dbahsql.cxx create mode 100644 dbaccess/inc/pch/precompiled_dbahsql.hxx create mode 100644 dbaccess/inc/pch/precompiled_dbaxml.cxx create mode 100644 dbaccess/inc/pch/precompiled_dbaxml.hxx create mode 100644 dbaccess/inc/pch/precompiled_dbu.cxx create mode 100644 dbaccess/inc/pch/precompiled_dbu.hxx create mode 100644 dbaccess/inc/pch/precompiled_sdbt.cxx create mode 100644 dbaccess/inc/pch/precompiled_sdbt.hxx create mode 100644 dbaccess/inc/query.hrc create mode 100644 dbaccess/inc/strings.hrc create mode 100644 dbaccess/inc/strings.hxx create mode 100644 dbaccess/qa/complex/dbaccess/ApplicationController.java create mode 100644 dbaccess/qa/complex/dbaccess/Beamer.java create mode 100644 dbaccess/qa/complex/dbaccess/CRMBasedTestCase.java create mode 100644 dbaccess/qa/complex/dbaccess/CopyTableInterActionHandler.java create mode 100644 dbaccess/qa/complex/dbaccess/CopyTableWizard.java create mode 100644 dbaccess/qa/complex/dbaccess/DataSource.java create mode 100644 dbaccess/qa/complex/dbaccess/DatabaseApplication.java create mode 100644 dbaccess/qa/complex/dbaccess/DatabaseDocument.java create mode 100644 dbaccess/qa/complex/dbaccess/FileHelper.java create mode 100644 dbaccess/qa/complex/dbaccess/Parser.java create mode 100644 dbaccess/qa/complex/dbaccess/PropertyBag.java create mode 100644 dbaccess/qa/complex/dbaccess/Query.java create mode 100644 dbaccess/qa/complex/dbaccess/QueryInQuery.java create mode 100644 dbaccess/qa/complex/dbaccess/RowSet.java create mode 100644 dbaccess/qa/complex/dbaccess/RowSetEventListener.java create mode 100644 dbaccess/qa/complex/dbaccess/SingleSelectQueryComposer.java create mode 100644 dbaccess/qa/complex/dbaccess/TestCase.java create mode 100644 dbaccess/qa/complex/dbaccess/UISettings.java create mode 100644 dbaccess/qa/complex/dbaccess/makefile.mk create mode 100644 dbaccess/qa/extras/dialog-save.cxx create mode 100644 dbaccess/qa/extras/empty-stdlib-save.cxx create mode 100644 dbaccess/qa/extras/hsql_schema_import.cxx create mode 100644 dbaccess/qa/extras/macros-test.cxx create mode 100644 dbaccess/qa/extras/nolib-save.cxx create mode 100644 dbaccess/qa/extras/rowsetclones.cxx create mode 100644 dbaccess/qa/extras/testdocuments/RowSetClones.odb create mode 100644 dbaccess/qa/extras/testdocuments/fdo84315.odb create mode 100644 dbaccess/qa/extras/testdocuments/testDialogSave.odb create mode 100644 dbaccess/qa/extras/testdocuments/testdb.odb create mode 100644 dbaccess/qa/python/fdo84315.py create mode 100644 dbaccess/qa/unit/data/dbaccess-dialogs-test.txt create mode 100644 dbaccess/qa/unit/data/firebird_empty.odb create mode 100644 dbaccess/qa/unit/data/firebird_empty_le.odb create mode 100644 dbaccess/qa/unit/data/firebird_integer_le.odb create mode 100644 dbaccess/qa/unit/data/firebird_integer_le_ods12.odb create mode 100644 dbaccess/qa/unit/data/firebird_integer_ods12.odb create mode 100644 dbaccess/qa/unit/data/hsqldb_empty.odb create mode 100644 dbaccess/qa/unit/data/hsqldb_migration_test.odb create mode 100644 dbaccess/qa/unit/data/tdf119625.odb create mode 100644 dbaccess/qa/unit/data/tdf126268.odb create mode 100644 dbaccess/qa/unit/dbaccess-dialogs-test.cxx create mode 100644 dbaccess/qa/unit/dbtest_base.cxx create mode 100644 dbaccess/qa/unit/embeddeddb_performancetest.cxx create mode 100644 dbaccess/qa/unit/firebird-regression.cxx create mode 100644 dbaccess/qa/unit/firebird.cxx create mode 100644 dbaccess/qa/unit/hsql_binary_import.cxx create mode 100644 dbaccess/qa/unit/hsqldb.cxx create mode 100644 dbaccess/qa/unit/tdf119625.cxx create mode 100644 dbaccess/qa/unit/tdf126268.cxx create mode 100644 dbaccess/qa/unoapi/dbaccess.props create mode 100644 dbaccess/qa/unoapi/dbaccess.sce create mode 100644 dbaccess/qa/unoapi/knownissues.xcl create mode 100644 dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbf create mode 100644 dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbt 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/object.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/services.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/filter/xml/xmlservices.cxx create mode 100644 dbaccess/source/filter/xml/xmlservices.hxx create mode 100644 dbaccess/source/inc/OAuthenticationContinuation.hxx create mode 100644 dbaccess/source/inc/apitools.hxx create mode 100644 dbaccess/source/inc/dbu_reghelper.hxx create mode 100644 dbaccess/source/inc/dsntypes.hxx create mode 100644 dbaccess/source/inc/flt_reghelper.hxx create mode 100644 dbaccess/source/inc/registrationhelper.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/sdbtools/misc/sdbt_services.cxx create mode 100644 dbaccess/source/shared/dbu_reghelper.cxx create mode 100644 dbaccess/source/shared/flt_reghelper.cxx create mode 100644 dbaccess/source/shared/registrationhelper.cxx 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/subcomponentmanager.cxx create mode 100644 dbaccess/source/ui/app/subcomponentmanager.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/dbtreeview.cxx create mode 100644 dbaccess/source/ui/browser/dbtreeview.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/ScrollHelper.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/VertSplitView.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/listviewitems.cxx create mode 100644 dbaccess/source/ui/control/marktree.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/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/ScrollHelper.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/VertSplitView.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/listviewitems.hxx create mode 100644 dbaccess/source/ui/inc/marktree.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/uiservices.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/misc/uiservices.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/FieldDescGenWin.cxx create mode 100644 dbaccess/source/ui/tabledesign/FieldDescGenWin.hxx 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 create mode 100644 dbaccess/uiconfig/dbapp/menubar/menubar.xml create mode 100644 dbaccess/uiconfig/dbapp/popupmenu/edit.xml create mode 100644 dbaccess/uiconfig/dbapp/popupmenu/new.xml create mode 100644 dbaccess/uiconfig/dbapp/popupmenu/preview.xml create mode 100644 dbaccess/uiconfig/dbapp/statusbar/statusbar.xml create mode 100644 dbaccess/uiconfig/dbapp/toolbar/formobjectbar.xml create mode 100644 dbaccess/uiconfig/dbapp/toolbar/queryobjectbar.xml create mode 100644 dbaccess/uiconfig/dbapp/toolbar/reportobjectbar.xml create mode 100644 dbaccess/uiconfig/dbapp/toolbar/tableobjectbar.xml create mode 100644 dbaccess/uiconfig/dbapp/toolbar/toolbar.xml create mode 100644 dbaccess/uiconfig/dbbrowser/menubar/compat.xml create mode 100644 dbaccess/uiconfig/dbbrowser/menubar/preserve.txt create mode 100644 dbaccess/uiconfig/dbbrowser/popupmenu/explorer.xml create mode 100644 dbaccess/uiconfig/dbbrowser/popupmenu/refreshdata.xml create mode 100644 dbaccess/uiconfig/dbbrowser/toolbar/toolbar.xml create mode 100644 dbaccess/uiconfig/dbquery/menubar/menubar.xml create mode 100644 dbaccess/uiconfig/dbquery/toolbar/designobjectbar.xml create mode 100644 dbaccess/uiconfig/dbquery/toolbar/sqlobjectbar.xml create mode 100644 dbaccess/uiconfig/dbquery/toolbar/toolbar.xml create mode 100644 dbaccess/uiconfig/dbrelation/menubar/menubar.xml create mode 100644 dbaccess/uiconfig/dbrelation/toolbar/toolbar.xml create mode 100644 dbaccess/uiconfig/dbtable/menubar/menubar.xml create mode 100644 dbaccess/uiconfig/dbtable/toolbar/toolbar.xml create mode 100644 dbaccess/uiconfig/dbtdata/menubar/menubar.xml create mode 100644 dbaccess/uiconfig/dbtdata/popupmenu/refreshdata.xml create mode 100644 dbaccess/uiconfig/dbtdata/toolbar/toolbar.xml create mode 100644 dbaccess/uiconfig/ui/admindialog.ui create mode 100644 dbaccess/uiconfig/ui/advancedsettingsdialog.ui create mode 100644 dbaccess/uiconfig/ui/applycolpage.ui create mode 100644 dbaccess/uiconfig/ui/authentificationpage.ui create mode 100644 dbaccess/uiconfig/ui/autocharsetpage.ui create mode 100644 dbaccess/uiconfig/ui/choosedatasourcedialog.ui create mode 100644 dbaccess/uiconfig/ui/collectionviewdialog.ui create mode 100644 dbaccess/uiconfig/ui/colwidthdialog.ui create mode 100644 dbaccess/uiconfig/ui/connectionpage.ui create mode 100644 dbaccess/uiconfig/ui/copytablepage.ui create mode 100644 dbaccess/uiconfig/ui/dbaseindexdialog.ui create mode 100644 dbaccess/uiconfig/ui/dbasepage.ui create mode 100644 dbaccess/uiconfig/ui/dbwizconnectionpage.ui create mode 100644 dbaccess/uiconfig/ui/dbwizmysqlintropage.ui create mode 100644 dbaccess/uiconfig/ui/dbwizmysqlnativepage.ui create mode 100644 dbaccess/uiconfig/ui/dbwizspreadsheetpage.ui create mode 100644 dbaccess/uiconfig/ui/dbwiztextpage.ui create mode 100644 dbaccess/uiconfig/ui/deleteallrowsdialog.ui create mode 100644 dbaccess/uiconfig/ui/designsavemodifieddialog.ui create mode 100644 dbaccess/uiconfig/ui/directsqldialog.ui create mode 100644 dbaccess/uiconfig/ui/emptypage.ui create mode 100644 dbaccess/uiconfig/ui/fielddescpage.ui create mode 100644 dbaccess/uiconfig/ui/fielddialog.ui create mode 100644 dbaccess/uiconfig/ui/finalpagewizard.ui create mode 100644 dbaccess/uiconfig/ui/generalpagedialog.ui create mode 100644 dbaccess/uiconfig/ui/generalpagewizard.ui create mode 100644 dbaccess/uiconfig/ui/generalspecialjdbcdetailspage.ui create mode 100644 dbaccess/uiconfig/ui/generatedvaluespage.ui create mode 100644 dbaccess/uiconfig/ui/indexdesigndialog.ui create mode 100644 dbaccess/uiconfig/ui/jdbcconnectionpage.ui create mode 100644 dbaccess/uiconfig/ui/joindialog.ui create mode 100644 dbaccess/uiconfig/ui/jointablemenu.ui create mode 100644 dbaccess/uiconfig/ui/joinviewmenu.ui create mode 100644 dbaccess/uiconfig/ui/keymenu.ui create mode 100644 dbaccess/uiconfig/ui/ldapconnectionpage.ui create mode 100644 dbaccess/uiconfig/ui/ldappage.ui create mode 100644 dbaccess/uiconfig/ui/limitbox.ui create mode 100644 dbaccess/uiconfig/ui/migrwarndlg.ui create mode 100644 dbaccess/uiconfig/ui/mysqlnativepage.ui create mode 100644 dbaccess/uiconfig/ui/mysqlnativesettings.ui create mode 100644 dbaccess/uiconfig/ui/namematchingpage.ui create mode 100644 dbaccess/uiconfig/ui/odbcpage.ui create mode 100644 dbaccess/uiconfig/ui/parametersdialog.ui create mode 100644 dbaccess/uiconfig/ui/password.ui create mode 100644 dbaccess/uiconfig/ui/querycolmenu.ui create mode 100644 dbaccess/uiconfig/ui/queryfilterdialog.ui create mode 100644 dbaccess/uiconfig/ui/queryfuncmenu.ui create mode 100644 dbaccess/uiconfig/ui/querypropertiesdialog.ui create mode 100644 dbaccess/uiconfig/ui/relationdialog.ui create mode 100644 dbaccess/uiconfig/ui/rowheightdialog.ui create mode 100644 dbaccess/uiconfig/ui/savedialog.ui create mode 100644 dbaccess/uiconfig/ui/saveindexdialog.ui create mode 100644 dbaccess/uiconfig/ui/savemodifieddialog.ui create mode 100644 dbaccess/uiconfig/ui/sortdialog.ui create mode 100644 dbaccess/uiconfig/ui/specialjdbcconnectionpage.ui create mode 100644 dbaccess/uiconfig/ui/specialsettingspage.ui create mode 100644 dbaccess/uiconfig/ui/sqlexception.ui create mode 100644 dbaccess/uiconfig/ui/tabledesignrowmenu.ui create mode 100644 dbaccess/uiconfig/ui/tabledesignsavemodifieddialog.ui create mode 100644 dbaccess/uiconfig/ui/tablesfilterdialog.ui create mode 100644 dbaccess/uiconfig/ui/tablesfilterpage.ui create mode 100644 dbaccess/uiconfig/ui/tablesjoindialog.ui create mode 100644 dbaccess/uiconfig/ui/textconnectionsettings.ui create mode 100644 dbaccess/uiconfig/ui/textpage.ui create mode 100644 dbaccess/uiconfig/ui/typeselectpage.ui create mode 100644 dbaccess/uiconfig/ui/useradmindialog.ui create mode 100644 dbaccess/uiconfig/ui/useradminpage.ui create mode 100644 dbaccess/uiconfig/ui/userdetailspage.ui create mode 100644 dbaccess/util/dba.component create mode 100644 dbaccess/util/dbu.component create mode 100644 dbaccess/util/sdbt.component create mode 100644 dbaccess/win32/source/odbcconfig/odbcconfig.cxx (limited to 'dbaccess') diff --git a/dbaccess/AllLangMoTarget_dba.mk b/dbaccess/AllLangMoTarget_dba.mk new file mode 100644 index 000000000..5c57ae6a8 --- /dev/null +++ b/dbaccess/AllLangMoTarget_dba.mk @@ -0,0 +1,13 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +$(eval $(call gb_AllLangMoTarget_AllLangMoTarget,dba)) + +$(eval $(call gb_AllLangMoTarget_set_polocation,dba,dbaccess)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_RowSetClones.mk b/dbaccess/CppunitTest_dbaccess_RowSetClones.mk new file mode 100644 index 000000000..ac11256d6 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_RowSetClones.mk @@ -0,0 +1,116 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_RowSetClones)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_RowSetClones, \ + dbaccess/qa/extras/rowsetclones \ +)) + +$(eval $(call gb_CppunitTest_use_externals,dbaccess_RowSetClones,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_RowSetClones, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbu \ + sdbt \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + subsequenttest \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_jars,dbaccess_RowSetClones, \ + sdbc_hsqldb \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_RowSetClones,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_RowSetClones)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_RowSetClones)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_RowSetClones,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + connectivity/source/drivers/hsqldb/hsqldb \ + $(if $(ENABLE_FIREBIRD_SDBC),connectivity/source/drivers/firebird/firebird_sdbc) \ + connectivity/source/drivers/jdbc/jdbc \ + connectivity/source/manager/sdbc2 \ + dbaccess/util/dba \ + dbaccess/util/dbu \ + dbaccess/util/sdbt \ + dbaccess/source/filter/xml/dbaxml \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_RowSetClones)) + +$(call gb_CppunitTest_get_target,dbaccess_RowSetClones) : $(WORKDIR)/CppunitTest/RowSetClones.odb +$(WORKDIR)/CppunitTest/RowSetClones.odb : $(SRCDIR)/dbaccess/qa/extras/testdocuments/RowSetClones.odb + mkdir -p $(dir $@) + cp -P -f "$<" "$@" +.PHONY: $(WORKDIR)/CppunitTest/RowSetClones.odb + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_dialog_save.mk b/dbaccess/CppunitTest_dbaccess_dialog_save.mk new file mode 100644 index 000000000..408366ecb --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_dialog_save.mk @@ -0,0 +1,108 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_dialog_save)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_dialog_save, \ + dbaccess/qa/extras/dialog-save \ +)) + +$(eval $(call gb_CppunitTest_use_externals,dbaccess_dialog_save,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_dialog_save, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbu \ + sdbt \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + subsequenttest \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_dialog_save,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_dialog_save)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_dialog_save)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_dialog_save,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + dbaccess/util/dba \ + dbaccess/util/dbu \ + dbaccess/util/sdbt \ + dbaccess/source/filter/xml/dbaxml \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_dialog_save)) + +$(call gb_CppunitTest_get_target,dbaccess_dialog_save) : $(WORKDIR)/CppunitTest/testDialogSave.odb +$(WORKDIR)/CppunitTest/testDialogSave.odb : $(SRCDIR)/dbaccess/qa/extras/testdocuments/testDialogSave.odb + mkdir -p $(dir $@) + cp -P -f "$<" "$@" +.PHONY: $(WORKDIR)/CppunitTest/testDialogSave.odb + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_dialogs_test.mk b/dbaccess/CppunitTest_dbaccess_dialogs_test.mk new file mode 100644 index 000000000..3ed9a0649 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_dialogs_test.mk @@ -0,0 +1,69 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitScreenShot,dbaccess_dialogs_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_dialogs_test, \ + dbaccess/qa/unit/dbaccess-dialogs-test \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,dbaccess_dialogs_test)) + +$(eval $(call gb_CppunitTest_set_include,dbaccess_dialogs_test,\ + -I$(SRCDIR)/dbaccess/source/inc \ + -I$(SRCDIR)/dbaccess/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_dialogs_test, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + drawinglayer \ + editeng \ + i18nlangtag \ + i18nutil \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sfx \ + sot \ + svl \ + svt \ + test \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_external,dbaccess_dialogs_test,boost_headers)) + +$(eval $(call gb_CppunitTest_use_sdk_api,dbaccess_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_dialogs_test)) +$(eval $(call gb_CppunitTest_use_vcl_non_headless_with_windows,dbaccess_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_rdb,dbaccess_dialogs_test,services)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_uiconfigs,dbaccess_dialogs_test,\ + dbaccess \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_embeddeddb_performancetest.mk b/dbaccess/CppunitTest_dbaccess_embeddeddb_performancetest.mk new file mode 100644 index 000000000..6a9225693 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_embeddeddb_performancetest.mk @@ -0,0 +1,73 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_embeddeddb_performancetest)) + +$(eval $(call gb_CppunitTest_use_external,dbaccess_embeddeddb_performancetest,boost_headers)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_embeddeddb_performancetest, \ + dbaccess/qa/unit/embeddeddb_performancetest \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_embeddeddb_performancetest, \ + comphelper \ + cppu \ + cppuhelper \ + dbaxml \ + dbtools \ + firebird_sdbc \ + sal \ + subsequenttest \ + utl \ + test \ + tk \ + tl \ + unotest \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_embeddeddb_performancetest,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_embeddeddb_performancetest)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_embeddeddb_performancetest)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_embeddeddb_performancetest,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + connectivity/source/cpool/dbpool2 \ + connectivity/source/drivers/firebird/firebird_sdbc \ + connectivity/source/manager/sdbc2 \ + dbaccess/util/dba \ + dbaccess/source/filter/xml/dbaxml \ + dbaccess/util/dbu \ + filter/source/config/cache/filterconfig1 \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + sfx2/util/sfx \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + unotools/util/utl \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_embeddeddb_performancetest)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_empty_stdlib_save.mk b/dbaccess/CppunitTest_dbaccess_empty_stdlib_save.mk new file mode 100644 index 000000000..6d1e47df4 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_empty_stdlib_save.mk @@ -0,0 +1,108 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_empty_stdlib_save)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_empty_stdlib_save, \ + dbaccess/qa/extras/empty-stdlib-save \ +)) + +$(eval $(call gb_CppunitTest_use_externals,dbaccess_empty_stdlib_save,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_empty_stdlib_save, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbu \ + sdbt \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + subsequenttest \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_empty_stdlib_save,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_empty_stdlib_save)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_empty_stdlib_save)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_empty_stdlib_save,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + dbaccess/util/dba \ + dbaccess/util/dbu \ + dbaccess/util/sdbt \ + dbaccess/source/filter/xml/dbaxml \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_empty_stdlib_save)) + +$(call gb_CppunitTest_get_target,dbaccess_empty_stdlib_save) : $(WORKDIR)/CppunitTest/testEmptyStdlibSave.odb +$(WORKDIR)/CppunitTest/testEmptyStdlibSave.odb : $(SRCDIR)/dbaccess/qa/extras/testdocuments/testDialogSave.odb + mkdir -p $(dir $@) + cp -P -f "$<" "$@" +.PHONY: $(WORKDIR)/CppunitTest/testEmptyStdlibSave.odb + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_firebird_regression_test.mk b/dbaccess/CppunitTest_dbaccess_firebird_regression_test.mk new file mode 100644 index 000000000..654d2f616 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_firebird_regression_test.mk @@ -0,0 +1,70 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_firebird_regression)) + +$(eval $(call gb_CppunitTest_use_external,dbaccess_firebird_regression,boost_headers)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_firebird_regression, \ + dbaccess/qa/unit/firebird-regression \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_firebird_regression, \ + comphelper \ + cppu \ + dbaxml \ + firebird_sdbc \ + sal \ + subsequenttest \ + svt \ + test \ + unotest \ + utl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_firebird_regression,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_firebird_regression)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_firebird_regression)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_firebird_regression,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + connectivity/source/drivers/firebird/firebird_sdbc \ + connectivity/source/manager/sdbc2 \ + dbaccess/util/dba \ + dbaccess/source/filter/xml/dbaxml \ + dbaccess/util/dbu \ + filter/source/config/cache/filterconfig1 \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + sfx2/util/sfx \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + unotools/util/utl \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_firebird_regression)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_firebird_test.mk b/dbaccess/CppunitTest_dbaccess_firebird_test.mk new file mode 100644 index 000000000..88592d922 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_firebird_test.mk @@ -0,0 +1,70 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_firebird)) + +$(eval $(call gb_CppunitTest_use_external,dbaccess_firebird,boost_headers)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_firebird, \ + dbaccess/qa/unit/firebird \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_firebird, \ + comphelper \ + cppu \ + dbaxml \ + firebird_sdbc \ + sal \ + subsequenttest \ + svt \ + test \ + unotest \ + utl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_firebird,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_firebird)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_firebird)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_firebird,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + connectivity/source/drivers/firebird/firebird_sdbc \ + connectivity/source/manager/sdbc2 \ + dbaccess/util/dba \ + dbaccess/source/filter/xml/dbaxml \ + dbaccess/util/dbu \ + filter/source/config/cache/filterconfig1 \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + sfx2/util/sfx \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + unotools/util/utl \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_firebird)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_hsqlbinary_import.mk b/dbaccess/CppunitTest_dbaccess_hsqlbinary_import.mk new file mode 100644 index 000000000..6f682c040 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_hsqlbinary_import.mk @@ -0,0 +1,109 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_hsql_binary_import)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_hsql_binary_import, \ + dbaccess/qa/unit/hsql_binary_import \ +)) + +$(eval $(call gb_CppunitTest_use_external,dbaccess_hsql_binary_import,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_hsql_binary_import, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbahsql \ + dbu \ + sdbt \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + subsequenttest \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_hsql_binary_import)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_hsql_binary_import)) + +$(eval $(call gb_CppunitTest_set_include,dbaccess_hsql_binary_import,\ + -I$(SRCDIR)/dbaccess/source/filter/hsqldb \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_hsql_binary_import,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_hsql_binary_import,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + connectivity/source/drivers/hsqldb/hsqldb \ + $(if $(ENABLE_FIREBIRD_SDBC),connectivity/source/drivers/firebird/firebird_sdbc) \ + connectivity/source/manager/sdbc2 \ + dbaccess/util/dba \ + dbaccess/util/dbu \ + dbaccess/util/sdbt \ + dbaccess/source/filter/xml/dbaxml \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_hsql_binary_import)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_hsqldb_test.mk b/dbaccess/CppunitTest_dbaccess_hsqldb_test.mk new file mode 100644 index 000000000..500d8b376 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_hsqldb_test.mk @@ -0,0 +1,80 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_hsqldb_test)) + +$(eval $(call gb_CppunitTest_use_external,dbaccess_hsqldb_test,boost_headers)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_hsqldb_test, \ + dbaccess/qa/unit/hsqldb \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_hsqldb_test, \ + affine_uno_uno \ + comphelper \ + cppu \ + cppuhelper \ + dbaxml \ + dbtools \ + jvmfwk \ + sal \ + subsequenttest \ + utl \ + test \ + tk \ + unotest \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_jars,dbaccess_hsqldb_test, \ + sdbc_hsqldb \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_hsqldb_test,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_hsqldb_test)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_hsqldb_test)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_hsqldb_test,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + connectivity/source/cpool/dbpool2 \ + connectivity/source/drivers/hsqldb/hsqldb \ + $(if $(ENABLE_FIREBIRD_SDBC),connectivity/source/drivers/firebird/firebird_sdbc) \ + connectivity/source/drivers/jdbc/jdbc \ + connectivity/source/manager/sdbc2 \ + dbaccess/util/dba \ + dbaccess/source/filter/xml/dbaxml \ + dbaccess/util/dbu \ + filter/source/config/cache/filterconfig1 \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + sfx2/util/sfx \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + unotools/util/utl \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_hsqldb_test)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_hsqlschema_import.mk b/dbaccess/CppunitTest_dbaccess_hsqlschema_import.mk new file mode 100644 index 000000000..8c8d06698 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_hsqlschema_import.mk @@ -0,0 +1,101 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_hsql_schema_import)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_hsql_schema_import, \ + dbaccess/qa/extras/hsql_schema_import \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_hsql_schema_import, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbahsql \ + dbu \ + sdbt \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + subsequenttest \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_set_include,dbaccess_hsql_schema_import,\ + -I$(SRCDIR)/dbaccess/source/filter/hsqldb \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_hsql_schema_import,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_hsql_schema_import,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + dbaccess/util/dba \ + dbaccess/util/dbu \ + dbaccess/util/sdbt \ + dbaccess/source/filter/xml/dbaxml \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_hsql_schema_import)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_macros_test.mk b/dbaccess/CppunitTest_dbaccess_macros_test.mk new file mode 100644 index 000000000..8d8672e88 --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_macros_test.mk @@ -0,0 +1,101 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_macros_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_macros_test, \ + dbaccess/qa/extras/macros-test \ +)) + +$(eval $(call gb_CppunitTest_use_externals,dbaccess_macros_test,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_macros_test, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbu \ + sdbt \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + subsequenttest \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_macros_test,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_macros_test)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_macros_test)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_macros_test,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + dbaccess/util/dba \ + dbaccess/util/dbu \ + dbaccess/util/sdbt \ + dbaccess/source/filter/xml/dbaxml \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_macros_test)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_nolib_save.mk b/dbaccess/CppunitTest_dbaccess_nolib_save.mk new file mode 100644 index 000000000..1490c024a --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_nolib_save.mk @@ -0,0 +1,108 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_nolib_save)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_nolib_save, \ + dbaccess/qa/extras/nolib-save \ +)) + +$(eval $(call gb_CppunitTest_use_externals,dbaccess_nolib_save,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_nolib_save, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbu \ + sdbt \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + subsequenttest \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_nolib_save,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_nolib_save)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_nolib_save)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_nolib_save,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + dbaccess/util/dba \ + dbaccess/util/dbu \ + dbaccess/util/sdbt \ + dbaccess/source/filter/xml/dbaxml \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_nolib_save)) + +$(call gb_CppunitTest_get_target,dbaccess_nolib_save) : $(WORKDIR)/CppunitTest/testNolibSave.odb +$(WORKDIR)/CppunitTest/testNolibSave.odb : $(SRCDIR)/dbaccess/qa/extras/testdocuments/testDialogSave.odb + mkdir -p $(dir $@) + cp -P -f "$<" "$@" +.PHONY: $(WORKDIR)/CppunitTest/testNolibSave.odb + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_tdf119625.mk b/dbaccess/CppunitTest_dbaccess_tdf119625.mk new file mode 100644 index 000000000..3420f752d --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_tdf119625.mk @@ -0,0 +1,109 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_tdf119625)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_tdf119625, \ + dbaccess/qa/unit/tdf119625 \ +)) + +$(eval $(call gb_CppunitTest_use_external,dbaccess_tdf119625,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_tdf119625, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbahsql \ + dbu \ + sdbt \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + subsequenttest \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_tdf119625)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_tdf119625)) + +$(eval $(call gb_CppunitTest_set_include,dbaccess_tdf119625,\ + -I$(SRCDIR)/dbaccess/source/filter/hsqldb \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_tdf119625,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_tdf119625,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + connectivity/source/drivers/hsqldb/hsqldb \ + connectivity/source/drivers/firebird/firebird_sdbc \ + connectivity/source/manager/sdbc2 \ + dbaccess/util/dba \ + dbaccess/util/dbu \ + dbaccess/util/sdbt \ + dbaccess/source/filter/xml/dbaxml \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_tdf119625)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/CppunitTest_dbaccess_tdf126268.mk b/dbaccess/CppunitTest_dbaccess_tdf126268.mk new file mode 100644 index 000000000..5d2120ffd --- /dev/null +++ b/dbaccess/CppunitTest_dbaccess_tdf126268.mk @@ -0,0 +1,109 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_CppunitTest_CppunitTest,dbaccess_tdf126268)) + +$(eval $(call gb_CppunitTest_add_exception_objects,dbaccess_tdf126268, \ + dbaccess/qa/unit/tdf126268 \ +)) + +$(eval $(call gb_CppunitTest_use_external,dbaccess_tdf126268,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,dbaccess_tdf126268, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbahsql \ + dbu \ + sdbt \ + drawinglayer \ + editeng \ + for \ + forui \ + i18nlangtag \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + test \ + subsequenttest \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vbahelper \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_ure,dbaccess_tdf126268)) +$(eval $(call gb_CppunitTest_use_vcl,dbaccess_tdf126268)) + +$(eval $(call gb_CppunitTest_set_include,dbaccess_tdf126268,\ + -I$(SRCDIR)/dbaccess/source/filter/hsqldb \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_api,dbaccess_tdf126268,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_CppunitTest_use_components,dbaccess_tdf126268,\ + basic/util/sb \ + comphelper/util/comphelp \ + configmgr/source/configmgr \ + connectivity/source/drivers/hsqldb/hsqldb \ + connectivity/source/drivers/firebird/firebird_sdbc \ + connectivity/source/manager/sdbc2 \ + dbaccess/util/dba \ + dbaccess/util/dbu \ + dbaccess/util/sdbt \ + dbaccess/source/filter/xml/dbaxml \ + filter/source/config/cache/filterconfig1 \ + forms/util/frm \ + framework/util/fwk \ + i18npool/util/i18npool \ + linguistic/source/lng \ + oox/util/oox \ + package/source/xstor/xstor \ + package/util/package2 \ + sax/source/expatwrap/expwrap \ + scripting/source/basprov/basprov \ + scripting/util/scriptframe \ + sfx2/util/sfx \ + sot/util/sot \ + svl/source/fsstor/fsstorage \ + svl/util/svl \ + toolkit/util/tk \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + ucb/source/ucp/tdoc/ucptdoc1 \ + unotools/util/utl \ + unoxml/source/rdf/unordf \ + unoxml/source/service/unoxml \ + uui/util/uui \ + xmloff/util/xo \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,dbaccess_tdf126268)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/Executable_odbcconfig.mk b/dbaccess/Executable_odbcconfig.mk new file mode 100644 index 000000000..862c77b3b --- /dev/null +++ b/dbaccess/Executable_odbcconfig.mk @@ -0,0 +1,31 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,odbcconfig)) + +$(eval $(call gb_Executable_set_targettype_gui,odbcconfig,YES)) + +$(eval $(call gb_Executable_use_libraries,odbcconfig,\ + comphelper \ +)) + +$(eval $(call gb_Executable_use_system_win32_libs,odbcconfig,\ + legacy_stdio_definitions \ + odbccp32 \ +)) + +$(eval $(call gb_Library_use_sdk_api,odbcconfig)) + +$(eval $(call gb_Executable_add_exception_objects,odbcconfig,\ + dbaccess/win32/source/odbcconfig/odbcconfig \ +)) + +$(eval $(call gb_Executable_add_default_nativeres,odbcconfig)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/IwyuFilter_dbaccess.yaml b/dbaccess/IwyuFilter_dbaccess.yaml new file mode 100644 index 000000000..fe9bfae13 --- /dev/null +++ b/dbaccess/IwyuFilter_dbaccess.yaml @@ -0,0 +1,161 @@ +--- +assumeFilename: dbaccess/source/ui/querydesign/QueryDesignView.cxx +blacklist: + dbaccess/source/inc/dbu_reghelper.hxx: + # Needed for registrationhelper.hxx + - com/sun/star/lang/XSingleServiceFactory.hpp + - com/sun/star/lang/XMultiServiceFactory.hpp + - rtl/ustring.hxx + - cppuhelper/factory.hxx + dbaccess/source/inc/flt_reghelper.hxx: + # Needed for registrationhelper.hxx + - com/sun/star/lang/XSingleServiceFactory.hpp + - com/sun/star/lang/XMultiServiceFactory.hpp + - rtl/ustring.hxx + - cppuhelper/factory.hxx + dbaccess/source/inc/apitools.hxx: + # Needed for macros to work + - com/sun/star/beans/PropertyAttribute.hpp + - com/sun/star/lang/XMultiServiceFactory.hpp + - comphelper/sequence.hxx + - strings.hxx + dbaccess/source/filter/xml/xmlExport.hxx: + # Needed for implicit dtor + - xmloff/txtprmap.hxx + dbaccess/source/ui/inc/sbamultiplex.hxx: + # Needed for macros + - cppuhelper/queryinterface.hxx + dbaccess/source/ui/dlg/odbcconfig.hxx: + # Needed on WIN32 + - tools/link.hxx + dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx: + # Needed for direct member access + - JoinTableView.hxx + dbaccess/source/core/api/CacheSet.cxx: + # Actually used + - com/sun/star/io/XInputStream.hpp + dbaccess/source/core/api/KeySet.cxx: + # Actually used + - com/sun/star/sdbc/XDatabaseMetaData.hpp + - com/sun/star/sdbc/XPreparedStatement.hpp + - com/sun/star/io/XInputStream.hpp + dbaccess/source/core/api/TableDeco.cxx: + # Actually used + - com/sun/star/sdbc/XConnection.hpp + dbaccess/source/core/api/query.cxx: + # Actually used + - com/sun/star/sdbc/XConnection.hpp + # Needed for inline OMultiTypeInterfaceContainerHelperVar + - cppuhelper/interfacecontainer.hxx + dbaccess/source/core/api/querycontainer.cxx: + # Actually used + - com/sun/star/sdbc/XConnection.hpp + dbaccess/source/core/dataaccess/ComponentDefinition.cxx: + # Needed for inline OMultiTypeInterfaceContainerHelperVar + - cppuhelper/interfacecontainer.hxx + dbaccess/source/core/dataaccess/definitioncontainer.cxx: + # Needed for inline OMultiTypeInterfaceContainerHelperVar + - cppuhelper/interfacecontainer.hxx + dbaccess/source/core/dataaccess/databasedocument.cxx: + # Actually used + - com/sun/star/script/XStorageBasedLibraryContainer.hpp + - com/sun/star/io/XOutputStream.hpp + dbaccess/source/core/dataaccess/documentevents.cxx: + # Actually used + - com/sun/star/beans/PropertyValue.hpp + dbaccess/source/core/misc/DatabaseDataProvider.cxx: + # Needed for UnoType macro to work + - com/sun/star/task/XInteractionHandler.hpp + dbaccess/source/filter/hsqldb/parseschema.cxx: + # Actually used + - com/sun/star/embed/XStorage.hpp + dbaccess/source/filter/hsqldb/hsqlimport.cxx: + # Actually used + - com/sun/star/embed/XStorage.hpp + - com/sun/star/sdbc/XConnection.hpp + dbaccess/source/filter/hsqldb/rowinputbinary.cxx: + # Needed boost wrapper header + - boost/date_time/posix_time/posix_time.hpp + dbaccess/source/shared/flt_reghelper.cxx: + # Needed for weird included cxx file + - comphelper/sequence.hxx + dbaccess/source/shared/dbu_reghelper.cxx: + # Needed for weird included cxx file + - comphelper/sequence.hxx + dbaccess/source/ui/app/AppDetailPageHelper.cxx: + # Actually used + - com/sun/star/sdbc/XConnection.hpp + dbaccess/source/ui/browser/brwview.cxx: + # Needed for direct member access + - com/sun/star/awt/XControlContainer.hpp + dbaccess/source/ui/browser/genericcontroller.cxx: + # Actually used + - com/sun/star/sdbc/XDataSource.hpp + - com/sun/star/ui/XSidebarProvider.hpp + dbaccess/source/ui/browser/sbagrid.cxx: + # Actually used + - com/sun/star/form/XForm.hpp + dbaccess/source/ui/control/TableGrantCtrl.cxx: + # Actually used + - com/sun/star/sdbcx/XTablesSupplier.hpp + dbaccess/source/ui/control/RelationControl.cxx: + # Actually used + - com/sun/star/awt/XWindow.hpp + dbaccess/source/ui/dlg/ConnectionHelper.cxx: + # Actually used + - com/sun/star/awt/XSystemDependentWindowPeer.hpp + - com/sun/star/lang/SystemDependent.hpp + dbaccess/source/ui/dlg/DbAdminImpl.cxx: + # Actually used + - com/sun/star/sdbc/XDriver.hpp + dbaccess/source/ui/dlg/dbfindex.cxx: + # Keep for osl_getThreadTextEncoding + - osl/thread.hxx + dbaccess/source/ui/dlg/odbcconfig.cxx: + # Needed for HAVE_ODBC_ADMINISTRATION on WIN32 + - config_folders.h + - rtl/bootstrap.hxx + - osl/process.h + - osl/thread.hxx + - vcl/svapp.hxx + # Needed for platform-specific odbc headers + - connectivity/odbc.hxx + dbaccess/source/ui/dlg/queryfilter.cxx: + # Actually used + - com/sun/star/sdb/XSingleSelectQueryComposer.hpp + - com/sun/star/container/XNameAccess.hpp + - com/sun/star/sdbc/XConnection.hpp + dbaccess/source/ui/misc/DExport.cxx: + # Actually used + - com/sun/star/awt/FontDescriptor.hpp + - com/sun/star/uno/XComponentContext.hpp + dbaccess/source/ui/misc/UITools.cxx: + # Actually used + - com/sun/star/container/XHierarchicalNameContainer.hpp + dbaccess/source/ui/misc/indexcollection.cxx: + # Actually used + - com/sun/star/beans/XPropertySet.hpp + dbaccess/source/ui/querydesign/QTableWindow.cxx: + # Actually used + - com/sun/star/beans/XPropertySet.hpp + dbaccess/source/ui/querydesign/JoinTableView.cxx: + # Actually used + - com/sun/star/accessibility/XAccessible.hpp + dbaccess/source/ui/querydesign/TableWindow.cxx: + # Actually used + - com/sun/star/container/XNameAccess.hpp + dbaccess/source/ui/querydesign/limitboxcontroller.cxx: + # Actually used + - com/sun/star/beans/PropertyValue.hpp + dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx: + # Actually used + - com/sun/star/sdbc/XDatabaseMetaData.hpp + dbaccess/source/ui/tabledesign/TableFieldControl.cxx: + # Actually used + - com/sun/star/sdbc/XDatabaseMetaData.hpp + dbaccess/source/ui/uno/composerdialogs.cxx: + # Actually used + - com/sun/star/awt/XWindow.hpp + dbaccess/source/ui/uno/unoDirectSql.cxx: + # Actually used + - com/sun/star/connection/XConnection.hpp diff --git a/dbaccess/JunitTest_dbaccess_complex.mk b/dbaccess/JunitTest_dbaccess_complex.mk new file mode 100644 index 000000000..ba333cbf3 --- /dev/null +++ b/dbaccess/JunitTest_dbaccess_complex.mk @@ -0,0 +1,51 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_JunitTest_JunitTest,dbaccess_complex)) + +$(eval $(call gb_JunitTest_use_unoapi_jars,dbaccess_complex)) + +$(eval $(call gb_JunitTest_use_jars,dbaccess_complex,\ + ConnectivityTools \ + juh \ +)) + +$(eval $(call gb_JunitTest_set_defs,dbaccess_complex,\ + $$(DEFS) \ + -Dorg.openoffice.test.arg.tdoc=$(SRCDIR)/dbaccess/qa/dbaccess \ +)) + +$(eval $(call gb_JunitTest_add_classes,dbaccess_complex,\ + complex.dbaccess.Beamer \ + complex.dbaccess.PropertyBag \ + complex.dbaccess.RowSet \ +)) + +$(eval $(call gb_JunitTest_add_sourcefiles,dbaccess_complex,\ + dbaccess/qa/complex/dbaccess/ApplicationController \ + dbaccess/qa/complex/dbaccess/Beamer \ + dbaccess/qa/complex/dbaccess/CRMBasedTestCase \ + dbaccess/qa/complex/dbaccess/CopyTableInterActionHandler \ + dbaccess/qa/complex/dbaccess/CopyTableWizard \ + dbaccess/qa/complex/dbaccess/DataSource \ + dbaccess/qa/complex/dbaccess/DatabaseApplication \ + dbaccess/qa/complex/dbaccess/DatabaseDocument \ + dbaccess/qa/complex/dbaccess/FileHelper \ + dbaccess/qa/complex/dbaccess/Parser \ + dbaccess/qa/complex/dbaccess/PropertyBag \ + dbaccess/qa/complex/dbaccess/Query \ + dbaccess/qa/complex/dbaccess/QueryInQuery \ + dbaccess/qa/complex/dbaccess/RowSet \ + dbaccess/qa/complex/dbaccess/RowSetEventListener \ + dbaccess/qa/complex/dbaccess/SingleSelectQueryComposer \ + dbaccess/qa/complex/dbaccess/TestCase \ + dbaccess/qa/complex/dbaccess/UISettings \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/JunitTest_dbaccess_unoapi.mk b/dbaccess/JunitTest_dbaccess_unoapi.mk new file mode 100644 index 000000000..814cbbcdc --- /dev/null +++ b/dbaccess/JunitTest_dbaccess_unoapi.mk @@ -0,0 +1,14 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_JunitTest_JunitTest,dbaccess_unoapi)) + +$(eval $(call gb_JunitTest_set_unoapi_test_defaults,dbaccess_unoapi)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/Library_dba.mk b/dbaccess/Library_dba.mk new file mode 100644 index 000000000..0b3d18e37 --- /dev/null +++ b/dbaccess/Library_dba.mk @@ -0,0 +1,135 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Library_Library,dba)) + +$(eval $(call gb_Library_set_include,dba,\ + $$(INCLUDE) \ + -I$(SRCDIR)/dbaccess/inc \ + -I$(SRCDIR)/dbaccess/source/inc \ + -I$(SRCDIR)/dbaccess/source/core/inc \ + -I$(SRCDIR)/dbaccess/source/filter/hsqldb \ + -I$(WORKDIR)/YaccTarget/connectivity/source/parse \ +)) + +$(eval $(call gb_Library_set_precompiled_header,dba,dbaccess/inc/pch/precompiled_dba)) + +$(eval $(call gb_Library_add_defs,dba,\ + -DOOO_DLLIMPLEMENTATION_DBA \ +)) + +$(eval $(call gb_Library_use_external,dba,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,dba)) + +$(eval $(call gb_Library_use_libraries,dba,\ + comphelper \ + cppu \ + cppuhelper \ + dbahsql \ + dbtools \ + fwe \ + i18nlangtag \ + sal \ + salhelper \ + sax \ + sb \ + sfx \ + svl \ + svt \ + svxcore \ + tl \ + ucbhelper \ + utl \ + vcl \ + xo \ +)) + +$(eval $(call gb_Library_set_componentfile,dba,dbaccess/util/dba)) + +$(eval $(call gb_Library_add_exception_objects,dba,\ + dbaccess/source/core/api/BookmarkSet \ + dbaccess/source/core/api/CacheSet \ + dbaccess/source/core/api/callablestatement \ + dbaccess/source/core/api/CIndexes \ + dbaccess/source/core/api/column \ + dbaccess/source/core/api/columnsettings \ + dbaccess/source/core/api/CRowSetColumn \ + dbaccess/source/core/api/CRowSetDataColumn \ + dbaccess/source/core/api/datacolumn \ + dbaccess/source/core/api/datasettings \ + dbaccess/source/core/api/definitioncolumn \ + dbaccess/source/core/api/FilteredContainer \ + dbaccess/source/core/api/HelperCollections \ + dbaccess/source/core/api/KeySet \ + dbaccess/source/core/api/OptimisticSet \ + dbaccess/source/core/api/preparedstatement \ + dbaccess/source/core/api/PrivateRow \ + dbaccess/source/core/api/query \ + dbaccess/source/core/api/querycomposer \ + dbaccess/source/core/api/querycontainer \ + dbaccess/source/core/api/querydescriptor \ + dbaccess/source/core/api/resultcolumn \ + dbaccess/source/core/api/resultset \ + dbaccess/source/core/api/RowSet \ + dbaccess/source/core/api/RowSetBase \ + dbaccess/source/core/api/RowSetCache \ + dbaccess/source/core/api/RowSetCacheIterator \ + dbaccess/source/core/api/SingleSelectQueryComposer \ + dbaccess/source/core/api/statement \ + dbaccess/source/core/api/StaticSet \ + dbaccess/source/core/api/table \ + dbaccess/source/core/api/tablecontainer \ + dbaccess/source/core/api/TableDeco \ + dbaccess/source/core/api/View \ + dbaccess/source/core/api/viewcontainer \ + dbaccess/source/core/api/WrappedResultSet \ + dbaccess/source/core/dataaccess/bookmarkcontainer \ + dbaccess/source/core/dataaccess/commandcontainer \ + dbaccess/source/core/dataaccess/commanddefinition \ + dbaccess/source/core/dataaccess/ComponentDefinition \ + dbaccess/source/core/dataaccess/connection \ + dbaccess/source/core/dataaccess/ContentHelper \ + dbaccess/source/core/dataaccess/dataaccessdescriptor \ + dbaccess/source/core/dataaccess/databasecontext \ + dbaccess/source/core/dataaccess/databasedocument \ + dbaccess/source/core/dataaccess/databaseregistrations \ + dbaccess/source/core/dataaccess/datasource \ + dbaccess/source/core/dataaccess/definitioncontainer \ + dbaccess/source/core/dataaccess/documentcontainer \ + dbaccess/source/core/dataaccess/documentdefinition \ + dbaccess/source/core/dataaccess/documenteventexecutor \ + dbaccess/source/core/dataaccess/documenteventnotifier \ + dbaccess/source/core/dataaccess/documentevents \ + dbaccess/source/core/dataaccess/intercept \ + dbaccess/source/core/dataaccess/ModelImpl \ + dbaccess/source/core/dataaccess/myucp_datasupplier \ + dbaccess/source/core/dataaccess/myucp_resultset \ + dbaccess/source/core/dataaccess/SharedConnection \ + dbaccess/source/core/misc/apitools \ + dbaccess/source/core/misc/ContainerMediator \ + dbaccess/source/core/misc/DatabaseDataProvider \ + dbaccess/source/core/misc/dsntypes \ + dbaccess/source/core/misc/objectnameapproval \ + dbaccess/source/core/misc/migrwarndlg \ + dbaccess/source/core/misc/PropertyForward \ + dbaccess/source/core/misc/sdbcoretools \ + dbaccess/source/core/misc/services \ + dbaccess/source/core/misc/veto \ + dbaccess/source/core/recovery/dbdocrecovery \ + dbaccess/source/core/recovery/settingsimport \ + dbaccess/source/core/recovery/storagestream \ + dbaccess/source/core/recovery/storagetextstream \ + dbaccess/source/core/recovery/storagexmlstream \ + dbaccess/source/core/recovery/subcomponentloader \ + dbaccess/source/core/recovery/subcomponentrecovery \ + dbaccess/source/core/resource/core_resource \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/Library_dbahsql.mk b/dbaccess/Library_dbahsql.mk new file mode 100644 index 000000000..7929e9bd6 --- /dev/null +++ b/dbaccess/Library_dbahsql.mk @@ -0,0 +1,51 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Library_Library,dbahsql)) + +$(eval $(call gb_Library_set_include,dbahsql,\ + $$(INCLUDE) \ + -I$(WORKDIR)/YaccTarget/connectivity/source/parse \ +)) + +$(eval $(call gb_Library_use_externals,dbahsql,\ + boost_headers \ + boost_date_time \ +)) + +$(eval $(call gb_Library_set_precompiled_header,dbahsql,dbaccess/inc/pch/precompiled_dbahsql)) + +$(eval $(call gb_Library_use_sdk_api,dbahsql)) + +$(eval $(call gb_Library_use_libraries,dbahsql,\ + comphelper \ + cppu \ + cppuhelper \ + sal \ + salhelper \ + dbtools \ + ucbhelper \ + utl \ + tl \ +)) + +$(eval $(call gb_Library_add_exception_objects,dbahsql,\ + dbaccess/source/filter/hsqldb/hsqlimport \ + dbaccess/source/filter/hsqldb/parseschema \ + dbaccess/source/filter/hsqldb/alterparser \ + dbaccess/source/filter/hsqldb/createparser \ + dbaccess/source/filter/hsqldb/columndef \ + dbaccess/source/filter/hsqldb/fbalterparser \ + dbaccess/source/filter/hsqldb/fbcreateparser \ + dbaccess/source/filter/hsqldb/rowinputbinary \ + dbaccess/source/filter/hsqldb/hsqlbinarynode \ + dbaccess/source/filter/hsqldb/utils \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/Library_dbaxml.mk b/dbaccess/Library_dbaxml.mk new file mode 100644 index 000000000..0b9cb7666 --- /dev/null +++ b/dbaccess/Library_dbaxml.mk @@ -0,0 +1,74 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Library_Library,dbaxml)) + +$(eval $(call gb_Library_set_include,dbaxml,\ + $$(INCLUDE) \ + -I$(SRCDIR)/dbaccess/inc \ + -I$(SRCDIR)/dbaccess/source/inc \ +)) + +$(eval $(call gb_Library_use_external,dbaxml,boost_headers)) + +$(eval $(call gb_Library_set_precompiled_header,dbaxml,dbaccess/inc/pch/precompiled_dbaxml)) + +$(eval $(call gb_Library_use_sdk_api,dbaxml)) + +$(eval $(call gb_Library_use_libraries,dbaxml,\ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbtools \ + sal \ + salhelper \ + sax \ + sfx \ + svl \ + tk \ + tl \ + utl \ + vcl \ + xo \ +)) + +$(eval $(call gb_Library_set_componentfile,dbaxml,dbaccess/source/filter/xml/dbaxml)) + +$(eval $(call gb_Library_add_exception_objects,dbaxml,\ + dbaccess/source/filter/xml/dbloader2 \ + dbaccess/source/filter/xml/xmlAutoStyle \ + dbaccess/source/filter/xml/xmlColumn \ + dbaccess/source/filter/xml/xmlComponent \ + dbaccess/source/filter/xml/xmlConnectionData \ + dbaccess/source/filter/xml/xmlConnectionResource \ + dbaccess/source/filter/xml/xmlDatabase \ + dbaccess/source/filter/xml/xmlDatabaseDescription \ + dbaccess/source/filter/xml/xmlDataSource \ + dbaccess/source/filter/xml/xmlDataSourceInfo \ + dbaccess/source/filter/xml/xmlDataSourceSetting \ + dbaccess/source/filter/xml/xmlDataSourceSettings \ + dbaccess/source/filter/xml/xmlDocuments \ + dbaccess/source/filter/xml/xmlExport \ + dbaccess/source/filter/xml/xmlFileBasedDatabase \ + dbaccess/source/filter/xml/xmlfilter \ + dbaccess/source/filter/xml/xmlHelper \ + dbaccess/source/filter/xml/xmlHierarchyCollection \ + dbaccess/source/filter/xml/xmlLogin \ + dbaccess/source/filter/xml/xmlQuery \ + dbaccess/source/filter/xml/xmlServerDatabase \ + dbaccess/source/filter/xml/xmlservices \ + dbaccess/source/filter/xml/xmlStyleImport \ + dbaccess/source/filter/xml/xmlTable \ + dbaccess/source/filter/xml/xmlTableFilterList \ + dbaccess/source/filter/xml/xmlTableFilterPattern \ + dbaccess/source/shared/flt_reghelper \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/Library_dbu.mk b/dbaccess/Library_dbu.mk new file mode 100644 index 000000000..f56531b48 --- /dev/null +++ b/dbaccess/Library_dbu.mk @@ -0,0 +1,257 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Library_Library,dbu)) + +$(eval $(call gb_Library_set_include,dbu,\ + $$(INCLUDE) \ + -I$(SRCDIR)/dbaccess/inc \ + -I$(SRCDIR)/dbaccess/source/inc \ + -I$(SRCDIR)/dbaccess/source/ui/inc \ + -I$(WORKDIR)/YaccTarget/connectivity/source/parse \ +)) + +$(eval $(call gb_Library_set_precompiled_header,dbu,dbaccess/inc/pch/precompiled_dbu)) + +$(eval $(call gb_Library_use_custom_headers,dbu,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_use_sdk_api,dbu)) + +$(eval $(call gb_Library_add_defs,dbu,\ + -DDBACCESS_DLLIMPLEMENTATION \ +)) + +$(eval $(call gb_Library_use_externals,dbu,\ + boost_headers \ + odbc_headers \ +)) + +$(eval $(call gb_Library_use_libraries,dbu,\ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbtools \ + editeng \ + fwe \ + sal \ + salhelper \ + i18nlangtag \ + sfx \ + sot \ + svl \ + svt \ + svxcore \ + svx \ + tk \ + tl \ + ucbhelper \ + utl \ + vcl \ +)) + +ifeq ($(OS),WNT) +$(eval $(call gb_Library_use_system_win32_libs,dbu,\ + ole32 \ + oleaut32 \ + uuid \ +)) +endif + +$(eval $(call gb_Library_set_componentfile,dbu,dbaccess/util/dbu)) + +$(eval $(call gb_Library_add_exception_objects,dbu,\ + dbaccess/source/shared/dbu_reghelper \ + dbaccess/source/ui/app/AppController \ + dbaccess/source/ui/app/AppControllerDnD \ + dbaccess/source/ui/app/AppControllerGen \ + dbaccess/source/ui/app/AppDetailPageHelper \ + dbaccess/source/ui/app/AppDetailView \ + dbaccess/source/ui/app/AppIconControl \ + dbaccess/source/ui/app/AppSwapWindow \ + dbaccess/source/ui/app/AppTitleWindow \ + dbaccess/source/ui/app/AppView \ + dbaccess/source/ui/app/subcomponentmanager \ + dbaccess/source/ui/browser/AsynchronousLink \ + dbaccess/source/ui/browser/brwctrlr \ + dbaccess/source/ui/browser/brwview \ + dbaccess/source/ui/browser/dataview \ + dbaccess/source/ui/browser/dbexchange \ + dbaccess/source/ui/browser/dbloader \ + dbaccess/source/ui/browser/dbtreemodel \ + dbaccess/source/ui/browser/dbtreeview \ + dbaccess/source/ui/browser/dsbrowserDnD \ + dbaccess/source/ui/browser/dsEntriesNoExp \ + dbaccess/source/ui/browser/exsrcbrw \ + dbaccess/source/ui/browser/formadapter \ + dbaccess/source/ui/browser/genericcontroller \ + dbaccess/source/ui/browser/sbagrid \ + dbaccess/source/ui/browser/sbamultiplex \ + dbaccess/source/ui/browser/unodatbr \ + dbaccess/source/ui/control/charsetlistbox \ + dbaccess/source/ui/control/ColumnControlWindow \ + dbaccess/source/ui/control/curledit \ + dbaccess/source/ui/control/dbtreelistbox \ + dbaccess/source/ui/control/FieldControls \ + dbaccess/source/ui/control/FieldDescControl \ + dbaccess/source/ui/control/listviewitems \ + dbaccess/source/ui/control/marktree \ + dbaccess/source/ui/control/opendoccontrols \ + dbaccess/source/ui/control/RelationControl \ + dbaccess/source/ui/control/ScrollHelper \ + dbaccess/source/ui/control/sqledit \ + dbaccess/source/ui/control/SqlNameEdit \ + dbaccess/source/ui/control/TableGrantCtrl \ + dbaccess/source/ui/control/tabletree \ + dbaccess/source/ui/control/undosqledit \ + dbaccess/source/ui/control/VertSplitView \ + dbaccess/source/ui/dlg/admincontrols \ + dbaccess/source/ui/dlg/adminpages \ + dbaccess/source/ui/dlg/adtabdlg \ + dbaccess/source/ui/dlg/advancedsettings \ + dbaccess/source/ui/dlg/CollectionView \ + dbaccess/source/ui/dlg/ConnectionHelper \ + dbaccess/source/ui/dlg/ConnectionPage \ + dbaccess/source/ui/dlg/ConnectionPageSetup \ + dbaccess/source/ui/dlg/dbadmin \ + dbaccess/source/ui/dlg/DbAdminImpl \ + dbaccess/source/ui/dlg/dbfindex \ + dbaccess/source/ui/dlg/DBSetupConnectionPages \ + dbaccess/source/ui/dlg/dbwiz \ + dbaccess/source/ui/dlg/dbwizsetup \ + dbaccess/source/ui/dlg/detailpages \ + dbaccess/source/ui/dlg/directsql \ + dbaccess/source/ui/dlg/dlgattr \ + dbaccess/source/ui/dlg/dlgsave \ + dbaccess/source/ui/dlg/dlgsize \ + dbaccess/source/ui/dlg/dsselect \ + dbaccess/source/ui/dlg/finteraction \ + dbaccess/source/ui/dlg/generalpage \ + dbaccess/source/ui/dlg/indexdialog \ + dbaccess/source/ui/dlg/indexfieldscontrol \ + dbaccess/source/ui/dlg/odbcconfig \ + dbaccess/source/ui/dlg/optionalboolitem \ + dbaccess/source/ui/dlg/paramdialog \ + dbaccess/source/ui/dlg/queryfilter \ + dbaccess/source/ui/dlg/queryorder \ + dbaccess/source/ui/dlg/QueryPropertiesDialog \ + dbaccess/source/ui/dlg/RelationDlg \ + dbaccess/source/ui/dlg/sqlmessage \ + dbaccess/source/ui/dlg/tablespage \ + dbaccess/source/ui/dlg/TablesSingleDlg \ + dbaccess/source/ui/dlg/TextConnectionHelper \ + dbaccess/source/ui/dlg/textconnectionsettings \ + dbaccess/source/ui/dlg/UserAdmin \ + dbaccess/source/ui/dlg/UserAdminDlg \ + dbaccess/source/ui/misc/asyncmodaldialog \ + dbaccess/source/ui/misc/charsets \ + dbaccess/source/ui/misc/controllerframe \ + dbaccess/source/ui/misc/databaseobjectview \ + dbaccess/source/ui/misc/datasourceconnector \ + dbaccess/source/ui/misc/dbaundomanager \ + dbaccess/source/ui/misc/dbsubcomponentcontroller \ + dbaccess/source/ui/misc/defaultobjectnamecheck \ + dbaccess/source/ui/misc/DExport \ + dbaccess/source/ui/misc/dsmeta \ + dbaccess/source/ui/misc/HtmlReader \ + dbaccess/source/ui/misc/imageprovider \ + dbaccess/source/ui/misc/indexcollection \ + dbaccess/source/ui/misc/linkeddocuments \ + dbaccess/source/ui/misc/propertystorage \ + dbaccess/source/ui/misc/RowSetDrop \ + dbaccess/source/ui/misc/RtfReader \ + dbaccess/source/ui/misc/singledoccontroller \ + dbaccess/source/ui/misc/stringlistitem \ + dbaccess/source/ui/misc/TableCopyHelper \ + dbaccess/source/ui/misc/TokenWriter \ + dbaccess/source/ui/misc/uiservices \ + dbaccess/source/ui/misc/UITools \ + dbaccess/source/ui/misc/WColumnSelect \ + dbaccess/source/ui/misc/WCopyTable \ + dbaccess/source/ui/misc/WCPage \ + dbaccess/source/ui/misc/WExtendPages \ + dbaccess/source/ui/misc/WNameMatch \ + dbaccess/source/ui/misc/WTypeSelect \ + dbaccess/source/ui/querydesign/ConnectionLine \ + dbaccess/source/ui/querydesign/ConnectionLineAccess \ + dbaccess/source/ui/querydesign/ConnectionLineData \ + dbaccess/source/ui/querydesign/JAccess \ + dbaccess/source/ui/querydesign/JoinController \ + dbaccess/source/ui/querydesign/JoinDesignView \ + dbaccess/source/ui/querydesign/JoinExchange \ + dbaccess/source/ui/querydesign/JoinTableView \ + dbaccess/source/ui/querydesign/limitboxcontroller \ + dbaccess/source/ui/querydesign/QTableConnection \ + dbaccess/source/ui/querydesign/QTableConnectionData \ + dbaccess/source/ui/querydesign/QTableWindow \ + dbaccess/source/ui/querydesign/QTableWindowData \ + dbaccess/source/ui/querydesign/querycontainerwindow \ + dbaccess/source/ui/querydesign/querycontroller \ + dbaccess/source/ui/querydesign/QueryDesignView \ + dbaccess/source/ui/querydesign/querydlg \ + dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct \ + dbaccess/source/ui/querydesign/QueryTabConnUndoAction \ + dbaccess/source/ui/querydesign/QueryTableView \ + dbaccess/source/ui/querydesign/QueryTabWinUndoAct \ + dbaccess/source/ui/querydesign/QueryTextView \ + dbaccess/source/ui/querydesign/QueryViewSwitch \ + dbaccess/source/ui/querydesign/SelectionBrowseBox \ + dbaccess/source/ui/querydesign/TableConnection \ + dbaccess/source/ui/querydesign/TableConnectionData \ + dbaccess/source/ui/querydesign/TableFieldDescription \ + dbaccess/source/ui/querydesign/TableFieldInfo \ + dbaccess/source/ui/querydesign/TableWindow \ + dbaccess/source/ui/querydesign/TableWindowAccess \ + dbaccess/source/ui/querydesign/TableWindowData \ + dbaccess/source/ui/querydesign/TableWindowListBox \ + dbaccess/source/ui/querydesign/TableWindowTitle \ + dbaccess/source/ui/relationdesign/RelationController \ + dbaccess/source/ui/relationdesign/RelationDesignView \ + dbaccess/source/ui/relationdesign/RelationTableView \ + dbaccess/source/ui/relationdesign/RTableConnection \ + dbaccess/source/ui/relationdesign/RTableConnectionData \ + dbaccess/source/ui/tabledesign/FieldDescGenWin \ + dbaccess/source/ui/tabledesign/FieldDescriptions \ + dbaccess/source/ui/tabledesign/TableController \ + dbaccess/source/ui/tabledesign/TableDesignControl \ + dbaccess/source/ui/tabledesign/TableDesignHelpBar \ + dbaccess/source/ui/tabledesign/TableDesignView \ + dbaccess/source/ui/tabledesign/TableFieldControl \ + dbaccess/source/ui/tabledesign/TableFieldDescWin \ + dbaccess/source/ui/tabledesign/TableRow \ + dbaccess/source/ui/tabledesign/TableRowExchange \ + dbaccess/source/ui/tabledesign/TableUndo \ + dbaccess/source/ui/tabledesign/TEditControl \ + dbaccess/source/ui/uno/admindlg \ + dbaccess/source/ui/uno/AdvancedSettingsDlg \ + dbaccess/source/ui/uno/ColumnControl \ + dbaccess/source/ui/uno/ColumnModel \ + dbaccess/source/ui/uno/ColumnPeer \ + dbaccess/source/ui/uno/composerdialogs \ + dbaccess/source/ui/uno/copytablewizard \ + dbaccess/source/ui/uno/dbinteraction \ + dbaccess/source/ui/uno/DBTypeWizDlg \ + dbaccess/source/ui/uno/DBTypeWizDlgSetup \ + dbaccess/source/ui/uno/TableFilterDlg \ + dbaccess/source/ui/uno/textconnectionsettings_uno \ + dbaccess/source/ui/uno/unoadmin \ + dbaccess/source/ui/uno/unoDirectSql \ + dbaccess/source/ui/uno/unosqlmessage \ + dbaccess/source/ui/uno/UserSettingsDlg \ +)) + +ifeq ($(OS),WNT) +$(eval $(call gb_Library_add_exception_objects,dbu,\ + dbaccess/source/ui/dlg/adodatalinks \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/Library_sdbt.mk b/dbaccess/Library_sdbt.mk new file mode 100644 index 000000000..6021be9d9 --- /dev/null +++ b/dbaccess/Library_sdbt.mk @@ -0,0 +1,47 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Library_Library,sdbt)) + +$(eval $(call gb_Library_set_include,sdbt,\ + $$(INCLUDE) \ + -I$(SRCDIR)/dbaccess/inc/ \ + -I$(SRCDIR)/dbaccess/source/inc/ \ + -I$(SRCDIR)/dbaccess/source/sdbtools/inc \ +)) + +$(eval $(call gb_Library_use_external,sdbt,boost_headers)) + +$(eval $(call gb_Library_set_precompiled_header,sdbt,dbaccess/inc/pch/precompiled_sdbt)) + +$(eval $(call gb_Library_use_sdk_api,sdbt)) + +$(eval $(call gb_Library_use_libraries,sdbt,\ + comphelper \ + cppu \ + cppuhelper \ + dba \ + dbtools \ + sal \ + salhelper \ + tl \ + utl \ +)) + +$(eval $(call gb_Library_set_componentfile,sdbt,dbaccess/util/sdbt)) + +$(eval $(call gb_Library_add_exception_objects,sdbt,\ + dbaccess/source/sdbtools/connection/connectiontools \ + dbaccess/source/sdbtools/connection/datasourcemetadata \ + dbaccess/source/sdbtools/connection/objectnames \ + dbaccess/source/sdbtools/connection/tablename \ + dbaccess/source/sdbtools/misc/sdbt_services \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/Makefile b/dbaccess/Makefile new file mode 100644 index 000000000..0997e6284 --- /dev/null +++ b/dbaccess/Makefile @@ -0,0 +1,14 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +module_directory:=$(dir $(realpath $(firstword $(MAKEFILE_LIST)))) + +include $(module_directory)/../solenv/gbuild/partial_build.mk + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/Module_dbaccess.mk b/dbaccess/Module_dbaccess.mk new file mode 100644 index 000000000..49bd9d202 --- /dev/null +++ b/dbaccess/Module_dbaccess.mk @@ -0,0 +1,103 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Module_Module,dbaccess)) + +$(eval $(call gb_Module_add_targets,dbaccess,\ + Library_dba \ + Library_dbahsql \ +)) + +$(eval $(call gb_Module_add_l10n_targets,dbaccess,\ + AllLangMoTarget_dba \ +)) + +ifneq (,$(filter DBCONNECTIVITY,$(BUILD_TYPE))) + +$(eval $(call gb_Module_add_targets,dbaccess,\ + $(if $(filter WNT,$(OS)),Executable_odbcconfig) \ + Library_dbaxml \ + Library_dbu \ + Library_sdbt \ + UIConfig_dbaccess \ + UIConfig_dbapp \ + UIConfig_dbbrowser \ + UIConfig_dbquery \ + UIConfig_dbrelation \ + UIConfig_dbtable \ + UIConfig_dbtdata \ +)) + +ifneq ($(OS),iOS) +ifeq ($(ENABLE_FIREBIRD_SDBC),TRUE) +$(eval $(call gb_Module_add_check_targets,dbaccess,\ + $(if $(ENABLE_JAVA),CppunitTest_dbaccess_hsqlbinary_import) \ + $(if $(ENABLE_JAVA),CppunitTest_dbaccess_tdf119625) \ + $(if $(ENABLE_JAVA),CppunitTest_dbaccess_tdf126268) \ +)) + +# remove if we have a be file for this +ifeq ($(ENDIANNESS),little) +$(eval $(call gb_Module_add_check_targets,dbaccess,\ + CppunitTest_dbaccess_firebird_regression_test \ +)) +endif +$(eval $(call gb_Module_add_check_targets,dbaccess,\ + CppunitTest_dbaccess_firebird_test \ +)) +endif + +$(eval $(call gb_Module_add_check_targets,dbaccess,\ + CppunitTest_dbaccess_dialog_save \ + CppunitTest_dbaccess_empty_stdlib_save \ + CppunitTest_dbaccess_nolib_save \ + CppunitTest_dbaccess_macros_test \ + CppunitTest_dbaccess_hsqlschema_import \ +)) + +# this test fails 50% of the time on the mac jenkins buildbots +ifeq ($(ENABLE_JAVA),TRUE) +ifneq ($(OS),MACOSX) +$(eval $(call gb_Module_add_check_targets,dbaccess,\ + CppunitTest_dbaccess_hsqldb_test \ + CppunitTest_dbaccess_RowSetClones \ +)) +endif +endif + +# This runs a suite of performance tests on embedded firebird and HSQLDB. +# Instructions on running the test can be found in qa/unit/embeddedb_performancetest +ifeq ($(ENABLE_FIREBIRD_SDBC),TRUE) +ifeq ($(ENABLE_JAVA),TRUE) +$(eval $(call gb_Module_add_check_targets,dbaccess,\ + CppunitTest_dbaccess_embeddeddb_performancetest \ +)) +endif +endif + +$(eval $(call gb_Module_add_subsequentcheck_targets,dbaccess,\ + JunitTest_dbaccess_complex \ + JunitTest_dbaccess_unoapi \ +)) + +ifneq ($(ENABLE_JAVA),) +$(eval $(call gb_Module_add_subsequentcheck_targets,dbaccess,\ + PythonTest_dbaccess_python \ +)) +endif + +# screenshots +$(eval $(call gb_Module_add_screenshot_targets,dbaccess,\ + CppunitTest_dbaccess_dialogs_test \ +)) + +endif +endif + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/PythonTest_dbaccess_python.mk b/dbaccess/PythonTest_dbaccess_python.mk new file mode 100644 index 000000000..874dac927 --- /dev/null +++ b/dbaccess/PythonTest_dbaccess_python.mk @@ -0,0 +1,26 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_PythonTest_PythonTest,dbaccess_python)) + +$(eval $(call gb_PythonTest_set_defs,dbaccess_python,\ + TDOC="$(SRCDIR)/dbaccess/qa/extras/testdocuments" \ +)) + +$(eval $(call gb_PythonTest_add_modules,dbaccess_python,$(SRCDIR)/dbaccess/qa/python,\ + fdo84315 \ +)) + +$(call gb_PythonTest_get_target,dbaccess_python) : $(WORKDIR)/CppunitTest/fdo84315.odb +$(WORKDIR)/CppunitTest/fdo84315.odb : $(SRCDIR)/dbaccess/qa/extras/testdocuments/fdo84315.odb + mkdir -p $(dir $@) + cp -P -f "$<" "$@" +.PHONY: $(WORKDIR)/CppunitTest/fdo84315.odb + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/README b/dbaccess/README new file mode 100644 index 000000000..555835a00 --- /dev/null +++ b/dbaccess/README @@ -0,0 +1,3 @@ +Database access tools, for "base" database application + +Builds on top of drivers in [[connectivity]]. diff --git a/dbaccess/UIConfig_dbaccess.mk b/dbaccess/UIConfig_dbaccess.mk new file mode 100644 index 000000000..eed1ba41a --- /dev/null +++ b/dbaccess/UIConfig_dbaccess.mk @@ -0,0 +1,83 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_UIConfig_UIConfig,dbaccess)) + +$(eval $(call gb_UIConfig_add_uifiles,dbaccess, \ + dbaccess/uiconfig/ui/admindialog \ + dbaccess/uiconfig/ui/advancedsettingsdialog \ + dbaccess/uiconfig/ui/applycolpage \ + dbaccess/uiconfig/ui/authentificationpage \ + dbaccess/uiconfig/ui/autocharsetpage \ + dbaccess/uiconfig/ui/choosedatasourcedialog \ + dbaccess/uiconfig/ui/collectionviewdialog \ + dbaccess/uiconfig/ui/colwidthdialog \ + dbaccess/uiconfig/ui/connectionpage \ + dbaccess/uiconfig/ui/copytablepage \ + dbaccess/uiconfig/ui/dbaseindexdialog \ + dbaccess/uiconfig/ui/dbasepage \ + dbaccess/uiconfig/ui/dbwizconnectionpage \ + dbaccess/uiconfig/ui/dbwizmysqlintropage \ + dbaccess/uiconfig/ui/dbwizmysqlnativepage \ + dbaccess/uiconfig/ui/dbwizspreadsheetpage \ + dbaccess/uiconfig/ui/dbwiztextpage \ + dbaccess/uiconfig/ui/deleteallrowsdialog \ + dbaccess/uiconfig/ui/designsavemodifieddialog \ + dbaccess/uiconfig/ui/directsqldialog \ + dbaccess/uiconfig/ui/emptypage \ + dbaccess/uiconfig/ui/fielddialog \ + dbaccess/uiconfig/ui/fielddescpage \ + dbaccess/uiconfig/ui/finalpagewizard \ + dbaccess/uiconfig/ui/generalpagedialog \ + dbaccess/uiconfig/ui/generalpagewizard \ + dbaccess/uiconfig/ui/generalspecialjdbcdetailspage \ + dbaccess/uiconfig/ui/generatedvaluespage \ + dbaccess/uiconfig/ui/indexdesigndialog \ + dbaccess/uiconfig/ui/jdbcconnectionpage \ + dbaccess/uiconfig/ui/joindialog \ + dbaccess/uiconfig/ui/jointablemenu \ + dbaccess/uiconfig/ui/joinviewmenu \ + dbaccess/uiconfig/ui/keymenu \ + dbaccess/uiconfig/ui/ldapconnectionpage \ + dbaccess/uiconfig/ui/ldappage \ + dbaccess/uiconfig/ui/limitbox \ + dbaccess/uiconfig/ui/mysqlnativepage \ + dbaccess/uiconfig/ui/mysqlnativesettings \ + dbaccess/uiconfig/ui/namematchingpage \ + dbaccess/uiconfig/ui/odbcpage \ + dbaccess/uiconfig/ui/parametersdialog \ + dbaccess/uiconfig/ui/password \ + dbaccess/uiconfig/ui/querycolmenu \ + dbaccess/uiconfig/ui/queryfilterdialog \ + dbaccess/uiconfig/ui/queryfuncmenu \ + dbaccess/uiconfig/ui/querypropertiesdialog \ + dbaccess/uiconfig/ui/relationdialog \ + dbaccess/uiconfig/ui/rowheightdialog \ + dbaccess/uiconfig/ui/saveindexdialog \ + dbaccess/uiconfig/ui/savedialog \ + dbaccess/uiconfig/ui/savemodifieddialog \ + dbaccess/uiconfig/ui/specialjdbcconnectionpage \ + dbaccess/uiconfig/ui/specialsettingspage \ + dbaccess/uiconfig/ui/sortdialog \ + dbaccess/uiconfig/ui/sqlexception \ + dbaccess/uiconfig/ui/tabledesignrowmenu \ + dbaccess/uiconfig/ui/tabledesignsavemodifieddialog \ + dbaccess/uiconfig/ui/tablesfilterdialog \ + dbaccess/uiconfig/ui/tablesfilterpage \ + dbaccess/uiconfig/ui/tablesjoindialog \ + dbaccess/uiconfig/ui/textconnectionsettings \ + dbaccess/uiconfig/ui/textpage \ + dbaccess/uiconfig/ui/typeselectpage \ + dbaccess/uiconfig/ui/useradmindialog \ + dbaccess/uiconfig/ui/useradminpage \ + dbaccess/uiconfig/ui/userdetailspage \ + dbaccess/uiconfig/ui/migrwarndlg \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/UIConfig_dbapp.mk b/dbaccess/UIConfig_dbapp.mk new file mode 100644 index 000000000..d93641d35 --- /dev/null +++ b/dbaccess/UIConfig_dbapp.mk @@ -0,0 +1,34 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_UIConfig_UIConfig,modules/dbapp)) + +$(eval $(call gb_UIConfig_add_menubarfiles,modules/dbapp,\ + dbaccess/uiconfig/dbapp/menubar/menubar \ +)) + +$(eval $(call gb_UIConfig_add_popupmenufiles,modules/dbapp,\ + dbaccess/uiconfig/dbapp/popupmenu/edit \ + dbaccess/uiconfig/dbapp/popupmenu/new \ + dbaccess/uiconfig/dbapp/popupmenu/preview \ +)) + +$(eval $(call gb_UIConfig_add_statusbarfiles,modules/dbapp,\ + dbaccess/uiconfig/dbapp/statusbar/statusbar \ +)) + +$(eval $(call gb_UIConfig_add_toolbarfiles,modules/dbapp,\ + dbaccess/uiconfig/dbapp/toolbar/formobjectbar \ + dbaccess/uiconfig/dbapp/toolbar/queryobjectbar \ + dbaccess/uiconfig/dbapp/toolbar/reportobjectbar \ + dbaccess/uiconfig/dbapp/toolbar/tableobjectbar \ + dbaccess/uiconfig/dbapp/toolbar/toolbar \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/UIConfig_dbbrowser.mk b/dbaccess/UIConfig_dbbrowser.mk new file mode 100644 index 000000000..eaab6cc2b --- /dev/null +++ b/dbaccess/UIConfig_dbbrowser.mk @@ -0,0 +1,25 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_UIConfig_UIConfig,modules/dbbrowser)) + +$(eval $(call gb_UIConfig_add_menubarfiles,modules/dbbrowser,\ + dbaccess/uiconfig/dbbrowser/menubar/compat \ +)) + +$(eval $(call gb_UIConfig_add_popupmenufiles,modules/dbbrowser,\ + dbaccess/uiconfig/dbbrowser/popupmenu/explorer \ + dbaccess/uiconfig/dbbrowser/popupmenu/refreshdata \ +)) + +$(eval $(call gb_UIConfig_add_toolbarfiles,modules/dbbrowser,\ + dbaccess/uiconfig/dbbrowser/toolbar/toolbar \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/UIConfig_dbquery.mk b/dbaccess/UIConfig_dbquery.mk new file mode 100644 index 000000000..5af309335 --- /dev/null +++ b/dbaccess/UIConfig_dbquery.mk @@ -0,0 +1,22 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_UIConfig_UIConfig,modules/dbquery)) + +$(eval $(call gb_UIConfig_add_menubarfiles,modules/dbquery,\ + dbaccess/uiconfig/dbquery/menubar/menubar \ +)) + +$(eval $(call gb_UIConfig_add_toolbarfiles,modules/dbquery,\ + dbaccess/uiconfig/dbquery/toolbar/designobjectbar \ + dbaccess/uiconfig/dbquery/toolbar/sqlobjectbar \ + dbaccess/uiconfig/dbquery/toolbar/toolbar \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/UIConfig_dbrelation.mk b/dbaccess/UIConfig_dbrelation.mk new file mode 100644 index 000000000..51a3b215c --- /dev/null +++ b/dbaccess/UIConfig_dbrelation.mk @@ -0,0 +1,20 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_UIConfig_UIConfig,modules/dbrelation)) + +$(eval $(call gb_UIConfig_add_menubarfiles,modules/dbrelation,\ + dbaccess/uiconfig/dbrelation/menubar/menubar \ +)) + +$(eval $(call gb_UIConfig_add_toolbarfiles,modules/dbrelation,\ + dbaccess/uiconfig/dbrelation/toolbar/toolbar \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/UIConfig_dbtable.mk b/dbaccess/UIConfig_dbtable.mk new file mode 100644 index 000000000..9503cc22b --- /dev/null +++ b/dbaccess/UIConfig_dbtable.mk @@ -0,0 +1,20 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_UIConfig_UIConfig,modules/dbtable)) + +$(eval $(call gb_UIConfig_add_menubarfiles,modules/dbtable,\ + dbaccess/uiconfig/dbtable/menubar/menubar \ +)) + +$(eval $(call gb_UIConfig_add_toolbarfiles,modules/dbtable,\ + dbaccess/uiconfig/dbtable/toolbar/toolbar \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/UIConfig_dbtdata.mk b/dbaccess/UIConfig_dbtdata.mk new file mode 100644 index 000000000..2f8cb3f62 --- /dev/null +++ b/dbaccess/UIConfig_dbtdata.mk @@ -0,0 +1,24 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_UIConfig_UIConfig,modules/dbtdata)) + +$(eval $(call gb_UIConfig_add_menubarfiles,modules/dbtdata,\ + dbaccess/uiconfig/dbtdata/menubar/menubar \ +)) + +$(eval $(call gb_UIConfig_add_popupmenufiles,modules/dbtdata,\ + dbaccess/uiconfig/dbtdata/popupmenu/refreshdata \ +)) + +$(eval $(call gb_UIConfig_add_toolbarfiles,modules/dbtdata,\ + dbaccess/uiconfig/dbtdata/toolbar/toolbar \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/dbaccess/inc/bitmaps.hlst b/dbaccess/inc/bitmaps.hlst new file mode 100644 index 000000000..fb9c4567b --- /dev/null +++ b/dbaccess/inc/bitmaps.hlst @@ -0,0 +1,34 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_DBACCESS_INC_BITMAPS_HRC +#define INCLUDED_DBACCESS_INC_BITMAPS_HRC + +#define BMP_FORMFOLDER_TREE_L "dbaccess/res/forms_32.png" +#define BMP_REPORTFOLDER_TREE_L "dbaccess/res/reports_32.png" +#define BMP_QUERYFOLDER_TREE_L "dbaccess/res/queries_32.png" +#define BMP_TABLEFOLDER_TREE_L "dbaccess/res/tables_32.png" +#define DATABASE_TREE_ICON "dbaccess/res/db.png" +#define TABLE_TREE_ICON "res/sx03188.png" +#define TABLEFOLDER_TREE_ICON "res/sx03187.png" +#define VIEW_TREE_ICON "res/sx16670.png" +#define QUERY_TREE_ICON "res/sx03202.png" +#define QUERYFOLDER_TREE_ICON "res/sx03201.png" +#define FORM_TREE_ICON "dbaccess/res/form_16.png" +#define FORMFOLDER_TREE_ICON "dbaccess/res/forms_16.png" +#define REPORT_TREE_ICON "dbaccess/res/report_16.png" +#define REPORTFOLDER_TREE_ICON "dbaccess/res/reports_16.png" +#define BMP_PRIMARY_KEY "dbaccess/res/jo01.png" +#define BMP_PKEYICON "dbaccess/res/pkey.png" +#define BMP_UP "dbaccess/res/sortup.png" +#define BMP_DOWN "dbaccess/res/sortdown.png" + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/dbaccess/inc/core_resource.hxx b/dbaccess/inc/core_resource.hxx new file mode 100644 index 000000000..8cddf133f --- /dev/null +++ b/dbaccess/inc/core_resource.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_CORE_RESOURCE_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_CORE_RESOURCE_HXX + +#include +#include "dbadllapi.hxx" + +#define DBA_RES( id ) ::dbaccess::ResourceManager::loadString( id ) +#define DBA_RES_PARAM( id, ascii, replace ) ::dbaccess::ResourceManager::loadString( id, ascii, replace ) + +namespace dbaccess +{ + // ResourceManager + // handling resources within the DBA-Core library + class OOO_DLLPUBLIC_DBA ResourceManager + { + private: + // no instantiation allowed + ResourceManager() = delete; + ~ResourceManager() { } + + public: + /** loads the string with the specified resource id + */ + static OUString loadString(const char* pResId); + + /** loads a string from the resource file, substituting a placeholder with a given string + + @param pResId + the resource ID of the string to load + @param _pPlaceholderAscii + the ASCII representation of the placeholder string + @param _rReplace + the string which should substitute the placeholder + */ + static OUString loadString( + const char* pResId, + const char* _pPlaceholderAscii, + const OUString& _rReplace + ); + + /** loads a string from the resource file, substituting two placeholders with given strings + + @param pResId + the resource ID of the string to load + @param _pPlaceholderAscii1 + the ASCII representation of the first placeholder string + @param _rReplace1 + the string which should substitute the first placeholder + @param _pPlaceholderAscii2 + the ASCII representation of the second placeholder string + @param _rReplace2 + the string which should substitute the second placeholder + */ + static OUString loadString( + const char* pResId, + const char* _pPlaceholderAscii1, + const OUString& _rReplace1, + const char* _pPlaceholderAscii2, + const OUString& _rReplace2 + ); + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_CORE_RESOURCE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/dbaccess_slotid.hrc b/dbaccess/inc/dbaccess_slotid.hrc new file mode 100644 index 000000000..768887dc0 --- /dev/null +++ b/dbaccess/inc/dbaccess_slotid.hrc @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_INC_DBACCESS_SLOTID_HRC +#define INCLUDED_DBACCESS_INC_DBACCESS_SLOTID_HRC + +#include + +#define SID_INDEXDESIGN ( SID_DBACCESS_START + 0 ) +#define SID_DOCUMENT_DATA_SOURCE ( SID_DBACCESS_START + 1 ) +// free +#define SID_DB_APP_DISABLE_PREVIEW ( SID_DBACCESS_START + 3 ) +#define SID_DB_APP_DSCONNECTION_TYPE ( SID_DBACCESS_START + 4 ) +#define SID_DB_APP_DSADVANCED_SETTINGS ( SID_DBACCESS_START + 5 ) +// free +#define SID_DB_APP_VIEW_DOCINFO_PREVIEW ( SID_DBACCESS_START + 7 ) +#define SID_DB_APP_VIEW_DOC_PREVIEW ( SID_DBACCESS_START + 8 ) +#define SID_DB_APP_VIEW_TABLES ( SID_DBACCESS_START + 9 ) +#define SID_DB_APP_VIEW_QUERIES ( SID_DBACCESS_START + 10 ) +#define SID_DB_APP_DSIMPORT ( SID_DBACCESS_START + 11 ) +#define SID_DB_APP_VIEW_FORMS ( SID_DBACCESS_START + 12 ) +#define SID_DB_APP_DSRELDESIGN ( SID_DBACCESS_START + 13 ) +#define SID_DB_APP_DSUSERADMIN ( SID_DBACCESS_START + 14 ) +#define SID_DB_APP_TABLEFILTER ( SID_DBACCESS_START + 15 ) +// free +#define SID_DB_APP_DSPROPS ( SID_DBACCESS_START + 17 ) +#define SID_DB_APP_DBADMIN ( SID_DBACCESS_START + 18 ) +#define SID_APP_NEW_REPORT_PRE_SEL ( SID_DBACCESS_START + 19 ) +#define SID_DB_APP_CONVERTTOVIEW ( SID_DBACCESS_START + 20 ) +#define SID_DB_APP_REFRESH_TABLES ( SID_DBACCESS_START + 21 ) +#define SID_DB_APP_VIEW_REPORTS ( SID_DBACCESS_START + 22 ) +#define SID_DB_APP_DSEXPORT ( SID_DBACCESS_START + 23 ) + +#define SID_DB_APP_TABLE_DELETE ( SID_DBACCESS_START + 24 ) +#define SID_DB_APP_TABLE_RENAME ( SID_DBACCESS_START + 25 ) +#define SID_DB_APP_TABLE_EDIT ( SID_DBACCESS_START + 26 ) +#define SID_DB_APP_TABLE_OPEN ( SID_DBACCESS_START + 27 ) + +#define SID_DB_APP_QUERY_DELETE ( SID_DBACCESS_START + 28 ) +#define SID_DB_APP_QUERY_RENAME ( SID_DBACCESS_START + 29 ) +#define SID_DB_APP_QUERY_EDIT ( SID_DBACCESS_START + 30 ) +#define SID_DB_APP_QUERY_OPEN ( SID_DBACCESS_START + 31 ) + +#define SID_DB_APP_FORM_DELETE ( SID_DBACCESS_START + 32 ) +#define SID_DB_APP_FORM_RENAME ( SID_DBACCESS_START + 33 ) +#define SID_DB_APP_FORM_EDIT ( SID_DBACCESS_START + 34 ) +#define SID_DB_APP_FORM_OPEN ( SID_DBACCESS_START + 35 ) + +#define SID_DB_APP_REPORT_DELETE ( SID_DBACCESS_START + 36 ) +#define SID_DB_APP_REPORT_RENAME ( SID_DBACCESS_START + 37 ) +#define SID_DB_APP_REPORT_EDIT ( SID_DBACCESS_START + 38 ) +#define SID_DB_APP_REPORT_OPEN ( SID_DBACCESS_START + 39 ) + +#define SID_DB_APP_DELETE ( SID_DBACCESS_START + 40 ) +#define SID_DB_APP_RENAME ( SID_DBACCESS_START + 41 ) +#define SID_DB_APP_EDIT ( SID_DBACCESS_START + 42 ) +#define SID_DB_APP_OPEN ( SID_DBACCESS_START + 43 ) + +#define SID_BROWSER_CLEAR_QUERY ( SID_DBACCESS_START + 44 ) +#define SID_RELATION_ADD_RELATION ( SID_DBACCESS_START + 45 ) +#define SID_QUERY_VIEW_FUNCTIONS ( SID_DBACCESS_START + 46 ) +#define SID_QUERY_VIEW_TABLES ( SID_DBACCESS_START + 47 ) +#define SID_QUERY_VIEW_ALIASES ( SID_DBACCESS_START + 48 ) +#define SID_QUERY_DISTINCT_VALUES ( SID_DBACCESS_START + 49 ) +#define SID_FORM_CREATE_REPWIZ_PRE_SEL ( SID_DBACCESS_START + 50 ) +#define SID_REPORT_CREATE_REPWIZ_PRE_SEL ( SID_DBACCESS_START + 51 ) +#define SID_DB_QUERY_PREVIEW ( SID_DBACCESS_START + 52 ) +#define SID_APP_NEW_FOLDER ( SID_DBACCESS_START + 53 ) +#define SID_APP_NEW_FORM ( SID_DBACCESS_START + 54 ) +#define SID_DB_APP_PASTE_SPECIAL ( SID_DBACCESS_START + 55 ) +#define SID_QUERY_LIMIT ( SID_DBACCESS_START + 56 ) + +// status information +#define SID_DB_APP_STATUS_TYPE ( SID_DBACCESS_START + 57 ) +#define SID_DB_APP_STATUS_DBNAME ( SID_DBACCESS_START + 58 ) +#define SID_DB_APP_STATUS_USERNAME ( SID_DBACCESS_START + 59 ) +#define SID_DB_APP_STATUS_HOSTNAME ( SID_DBACCESS_START + 60 ) + +#define SID_DB_APP_SENDREPORTASMAIL ( SID_DBACCESS_START + 61 ) +#define SID_DB_APP_SENDREPORTTOWRITER ( SID_DBACCESS_START + 62 ) +#define SID_DB_FORM_NEW_PILOT ( SID_DBACCESS_START + 63 ) +#define SID_DB_NEW_VIEW_SQL ( SID_DBACCESS_START + 64 ) +#define SID_APP_NEW_REPORT ( SID_DBACCESS_START + 65 ) + +#define SID_DB_APP_EDIT_SQL_VIEW ( SID_DBACCESS_START + 66 ) +//FREE +//FREE +#define SID_QUERY_PROP_DLG ( SID_DBACCESS_START + 69 ) + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/dbadllapi.hxx b/dbaccess/inc/dbadllapi.hxx new file mode 100644 index 000000000..6388e579b --- /dev/null +++ b/dbaccess/inc/dbadllapi.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_INC_DBADLLAPI_HXX +#define INCLUDED_DBACCESS_SOURCE_INC_DBADLLAPI_HXX + +#include + +#include + +#if defined OOO_DLLIMPLEMENTATION_DBA +#define OOO_DLLPUBLIC_DBA SAL_DLLPUBLIC_EXPORT +#else +#define OOO_DLLPUBLIC_DBA SAL_DLLPUBLIC_IMPORT +#endif + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/helpids.h b/dbaccess/inc/helpids.h new file mode 100644 index 000000000..53032a3e6 --- /dev/null +++ b/dbaccess/inc/helpids.h @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_INC_HELPIDS_H +#define INCLUDED_DBACCESS_INC_HELPIDS_H + + +#define HID_DATABROWSE_HEADER "DBACCESS_HID_DATABROWSE_HEADER" +#define HID_CTL_TABBROWSER "DBACCESS_HID_CTL_TABBROWSER" +#define HID_CTL_TREEVIEW "DBACCESS_HID_CTL_TREEVIEW" +#define HID_TLB_TREELISTBOX "DBACCESS_HID_TLB_TREELISTBOX" + +#define HID_DSADMIN_BROWSECONN "DBACCESS_HID_DSADMIN_BROWSECONN" + +#define HID_BROWSER_COLUMNFORMAT "DBACCESS_HID_BROWSER_COLUMNFORMAT" +#define HID_BROWSER_COLUMNWIDTH "DBACCESS_HID_BROWSER_COLUMNWIDTH" +#define HID_BROWSER_TABLEFORMAT "DBACCESS_HID_BROWSER_TABLEFORMAT" +#define HID_BROWSER_ROWHEIGHT "DBACCESS_HID_BROWSER_ROWHEIGHT" + +#define HID_CTL_QRYSQLEDIT "DBACCESS_HID_CTL_QRYSQLEDIT" + +#define HID_CTL_QRYDGNTAB "DBACCESS_HID_CTL_QRYDGNTAB" +#define HID_CTL_QRYDGNCRIT "DBACCESS_HID_CTL_QRYDGNCRIT" +#define HID_QRYDGN_ROW_VISIBLE "DBACCESS_HID_QRYDGN_ROW_VISIBLE" +#define HID_QRYDGN_ROW_TABLE "DBACCESS_HID_QRYDGN_ROW_TABLE" +#define HID_QRYDGN_ROW_FIELD "DBACCESS_HID_QRYDGN_ROW_FIELD" +#define HID_QRYDGN_ROW_ORDER "DBACCESS_HID_QRYDGN_ROW_ORDER" +#define HID_QRYDGN_ROW_FUNCTION "DBACCESS_HID_QRYDGN_ROW_FUNCTION" +#define HID_QRYDGN_ROW_ALIAS "DBACCESS_HID_QRYDGN_ROW_ALIAS" +#define HID_QRYDGN_ROW_CRIT "DBACCESS_HID_QRYDGN_ROW_CRIT" + +#define HID_TAB_DESIGN_FIELDCONTROL "DBACCESS_HID_TAB_DESIGN_FIELDCONTROL" +#define HID_TABLE_DESIGN_HELP_WINDOW "DBACCESS_HID_TABLE_DESIGN_HELP_WINDOW" +#define HID_TAB_DESIGN_DESCWIN "DBACCESS_HID_TAB_DESIGN_DESCWIN" +#define HID_TABDESIGN_BACKGROUND "DBACCESS_HID_TABDESIGN_BACKGROUND" +#define HID_CTL_TABLEEDIT "DBACCESS_HID_CTL_TABLEEDIT" +#define HID_TABDESIGN_NAMECELL "DBACCESS_HID_TABDESIGN_NAMECELL" +#define HID_TABDESIGN_TYPECELL "DBACCESS_HID_TABDESIGN_TYPECELL" +#define HID_TABDESIGN_COMMENTCELL "DBACCESS_HID_TABDESIGN_COMMENTCELL" +#define HID_TAB_DESIGN_HELP_TEXT_FRAME "DBACCESS_HID_TAB_DESIGN_HELP_TEXT_FRAME" +#define HID_TABLE_DESIGN_TABPAGE_GENERAL "DBACCESS_HID_TABLE_DESIGN_TABPAGE_GENERAL" +#define HID_TAB_ENT_DEFAULT "DBACCESS_HID_TAB_ENT_DEFAULT" +#define HID_TAB_ENT_FORMAT_SAMPLE "DBACCESS_HID_TAB_ENT_FORMAT_SAMPLE" +#define HID_TAB_ENT_FORMAT "DBACCESS_HID_TAB_ENT_FORMAT" +#define HID_TAB_ENT_BOOL_DEFAULT "DBACCESS_HID_TAB_ENT_BOOL_DEFAULT" +#define HID_TAB_ENT_REQUIRED "DBACCESS_HID_TAB_ENT_REQUIRED" +#define HID_TAB_ENT_AUTOINCREMENT "DBACCESS_HID_TAB_ENT_AUTOINCREMENT" +#define HID_TAB_ENT_TEXT_LEN "DBACCESS_HID_TAB_ENT_TEXT_LEN" +#define HID_TAB_ENT_TYPE "DBACCESS_HID_TAB_ENT_TYPE" +#define HID_TAB_ENT_COLUMNNAME "DBACCESS_HID_TAB_ENT_COLUMNNAME" +#define HID_TAB_ENT_NUMTYP "DBACCESS_HID_TAB_ENT_NUMTYP" +#define HID_TAB_ENT_LEN "DBACCESS_HID_TAB_ENT_LEN" +#define HID_TAB_ENT_SCALE "DBACCESS_HID_TAB_ENT_SCALE" +#define HID_CTL_RELATIONTAB "DBACCESS_HID_CTL_RELATIONTAB" +#define HID_RELATIONDIALOG_LEFTFIELDCELL "DBACCESS_HID_RELATIONDIALOG_LEFTFIELDCELL" +#define HID_RELATIONDIALOG_RIGHTFIELDCELL "DBACCESS_HID_RELATIONDIALOG_RIGHTFIELDCELL" +#define HID_CONFIRM_DROP_BUTTON_ALL "DBACCESS_HID_CONFIRM_DROP_BUTTON_ALL" +#define HID_DSADMIN_LDAP_HOSTNAME "DBACCESS_HID_DSADMIN_LDAP_HOSTNAME" +#define HID_DSADMIN_MOZILLA_PROFILE_NAME "DBACCESS_HID_DSADMIN_MOZILLA_PROFILE_NAME" +#define HID_DSADMIN_THUNDERBIRD_PROFILE_NAME "DBACCESS_HID_DSADMIN_THUNDERBIRD_PROFILE_NAME" + +#define HID_DLGINDEX_INDEXDETAILS_FIELD "DBACCESS_HID_DLGINDEX_INDEXDETAILS_FIELD" +#define HID_DLGINDEX_INDEXDETAILS_SORTORDER "DBACCESS_HID_DLGINDEX_INDEXDETAILS_SORTORDER" + +#define HID_TAB_AUTOINCREMENTVALUE "DBACCESS_HID_TAB_AUTOINCREMENTVALUE" + +#define HID_DSADMIN_DBASE_PATH "DBACCESS_HID_DSADMIN_DBASE_PATH" +#define HID_DSADMIN_MYSQL_DATABASE "DBACCESS_HID_DSADMIN_MYSQL_DATABASE" +#define HID_DSADMIN_MYSQL_ODBC_DATASOURCE "DBACCESS_HID_DSADMIN_MYSQL_ODBC_DATASOURCE" +#define HID_DSADMIN_ODBC_DATASOURCE "DBACCESS_HID_DSADMIN_ODBC_DATASOURCE" +#define HID_DSADMIN_MSACCESS_MDB_FILE "DBACCESS_HID_DSADMIN_MSACCESS_MDB_FILE" +#define HID_DSADMIN_FLAT_PATH "DBACCESS_HID_DSADMIN_FLAT_PATH" +#define HID_DSADMIN_CALC_PATH "DBACCESS_HID_DSADMIN_CALC_PATH" +#define HID_DSADMIN_WRITER_PATH "DBACCESS_HID_DSADMIN_WRITER_PATH" +#define HID_DSADMIN_ORACLE_DATABASE "DBACCESS_HID_DSADMIN_ORACLE_DATABASE" + +#define HID_APP_TABLE_TREE "DBACCESS_HID_APP_TABLE_TREE" +#define HID_APP_FORM_TREE "DBACCESS_HID_APP_FORM_TREE" +#define HID_APP_QUERY_TREE "DBACCESS_HID_APP_QUERY_TREE" +#define HID_APP_REPORT_TREE "DBACCESS_HID_APP_REPORT_TREE" +#define HID_APP_CREATION_LIST "DBACCESS_HID_APP_CREATION_LIST" +#define HID_APP_SWAP_ICONCONTROL "DBACCESS_HID_APP_SWAP_ICONCONTROL" + + +#define HID_APP_HELP_TEXT "DBACCESS_HID_APP_HELP_TEXT" +#define HID_APP_DESCRIPTION_TEXT "DBACCESS_HID_APP_DESCRIPTION_TEXT" +#define HID_APP_VIEW_PREVIEW_CB "DBACCESS_HID_APP_VIEW_PREVIEW_CB" +#define HID_APP_VIEW_PREVIEW_1 "DBACCESS_HID_APP_VIEW_PREVIEW_1" +#define HID_APP_VIEW_PREVIEW_2 "DBACCESS_HID_APP_VIEW_PREVIEW_2" +#define HID_TABDESIGN_HELPTEXT "DBACCESS_HID_TABDESIGN_HELPTEXT" +#define HID_APP_VIEW_PREVIEW_3 "DBACCESS_HID_APP_VIEW_PREVIEW_3" + + +#define HID_DBWIZ_PREVIOUS "DBACCESS_HID_DBWIZ_PREVIOUS" +#define HID_DBWIZ_NEXT "DBACCESS_HID_DBWIZ_NEXT" +#define HID_DBWIZ_CANCEL "DBACCESS_HID_DBWIZ_CANCEL" +#define HID_DBWIZ_FINISH "DBACCESS_HID_DBWIZ_FINISH" + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_dba.cxx b/dbaccess/inc/pch/precompiled_dba.cxx new file mode 100644 index 000000000..17c8073e5 --- /dev/null +++ b/dbaccess/inc/pch/precompiled_dba.cxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 "precompiled_dba.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_dba.hxx b/dbaccess/inc/pch/precompiled_dba.hxx new file mode 100644 index 000000000..09dd21764 --- /dev/null +++ b/dbaccess/inc/pch/precompiled_dba.hxx @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + This file has been autogenerated by update_pch.sh. It is possible to edit it + manually (such as when an include file has been moved/renamed/removed). All such + manual changes will be rewritten by the next run of update_pch.sh (which presumably + also fixes all possible problems, so it's usually better to use it). + + Generated on 2020-04-25 20:54:56 using: + ./bin/update_pch dbaccess dba --cutoff=6 --exclude:system --include:module --include:local + + If after updating build fails, use the following command to locate conflicting headers: + ./bin/update_pch_bisect ./dbaccess/inc/pch/precompiled_dba.hxx "make dbaccess.build" --find-conflicts +*/ + +#if PCH_LEVEL >= 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 1 +#if PCH_LEVEL >= 2 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 2 +#if PCH_LEVEL >= 3 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 3 +#if PCH_LEVEL >= 4 +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 4 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_dbahsql.cxx b/dbaccess/inc/pch/precompiled_dbahsql.cxx new file mode 100644 index 000000000..b56d7b232 --- /dev/null +++ b/dbaccess/inc/pch/precompiled_dbahsql.cxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 "precompiled_dbahsql.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_dbahsql.hxx b/dbaccess/inc/pch/precompiled_dbahsql.hxx new file mode 100644 index 000000000..f5b60b095 --- /dev/null +++ b/dbaccess/inc/pch/precompiled_dbahsql.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 has been autogenerated by update_pch.sh. It is possible to edit it + manually (such as when an include file has been moved/renamed/removed). All such + manual changes will be rewritten by the next run of update_pch.sh (which presumably + also fixes all possible problems, so it's usually better to use it). + + Generated on 2020-04-21 11:14:14 using: + ./bin/update_pch dbaccess dbahsql --cutoff=1 --exclude:system --include:module --include:local + + If after updating build fails, use the following command to locate conflicting headers: + ./bin/update_pch_bisect ./dbaccess/inc/pch/precompiled_dbahsql.hxx "make dbaccess.build" --find-conflicts +*/ + +#if PCH_LEVEL >= 1 +#include +#endif // PCH_LEVEL >= 1 +#if PCH_LEVEL >= 2 +#include +#include +#include +#endif // PCH_LEVEL >= 2 +#if PCH_LEVEL >= 3 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 3 +#if PCH_LEVEL >= 4 +#endif // PCH_LEVEL >= 4 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_dbaxml.cxx b/dbaccess/inc/pch/precompiled_dbaxml.cxx new file mode 100644 index 000000000..3fd8cf9b6 --- /dev/null +++ b/dbaccess/inc/pch/precompiled_dbaxml.cxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 "precompiled_dbaxml.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_dbaxml.hxx b/dbaccess/inc/pch/precompiled_dbaxml.hxx new file mode 100644 index 000000000..3e41685ba --- /dev/null +++ b/dbaccess/inc/pch/precompiled_dbaxml.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 has been autogenerated by update_pch.sh. It is possible to edit it + manually (such as when an include file has been moved/renamed/removed). All such + manual changes will be rewritten by the next run of update_pch.sh (which presumably + also fixes all possible problems, so it's usually better to use it). + + Generated on 2020-04-25 20:54:57 using: + ./bin/update_pch dbaccess dbaxml --cutoff=2 --exclude:system --exclude:module --exclude:local + + If after updating build fails, use the following command to locate conflicting headers: + ./bin/update_pch_bisect ./dbaccess/inc/pch/precompiled_dbaxml.hxx "make dbaccess.build" --find-conflicts +*/ + +#if PCH_LEVEL >= 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 1 +#if PCH_LEVEL >= 2 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 2 +#if PCH_LEVEL >= 3 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 3 +#if PCH_LEVEL >= 4 +#include +#endif // PCH_LEVEL >= 4 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_dbu.cxx b/dbaccess/inc/pch/precompiled_dbu.cxx new file mode 100644 index 000000000..dbfa961a5 --- /dev/null +++ b/dbaccess/inc/pch/precompiled_dbu.cxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 "precompiled_dbu.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_dbu.hxx b/dbaccess/inc/pch/precompiled_dbu.hxx new file mode 100644 index 000000000..6a7aa8f60 --- /dev/null +++ b/dbaccess/inc/pch/precompiled_dbu.hxx @@ -0,0 +1,224 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + This file has been autogenerated by update_pch.sh. It is possible to edit it + manually (such as when an include file has been moved/renamed/removed). All such + manual changes will be rewritten by the next run of update_pch.sh (which presumably + also fixes all possible problems, so it's usually better to use it). + + Generated on 2020-04-25 20:54:58 using: + ./bin/update_pch dbaccess dbu --cutoff=12 --exclude:system --exclude:module --exclude:local + + If after updating build fails, use the following command to locate conflicting headers: + ./bin/update_pch_bisect ./dbaccess/inc/pch/precompiled_dbu.hxx "make dbaccess.build" --find-conflicts +*/ + +#if PCH_LEVEL >= 1 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 1 +#if PCH_LEVEL >= 2 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 2 +#if PCH_LEVEL >= 3 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 3 +#if PCH_LEVEL >= 4 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 4 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_sdbt.cxx b/dbaccess/inc/pch/precompiled_sdbt.cxx new file mode 100644 index 000000000..26650079d --- /dev/null +++ b/dbaccess/inc/pch/precompiled_sdbt.cxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 "precompiled_sdbt.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/pch/precompiled_sdbt.hxx b/dbaccess/inc/pch/precompiled_sdbt.hxx new file mode 100644 index 000000000..59acc51a9 --- /dev/null +++ b/dbaccess/inc/pch/precompiled_sdbt.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 has been autogenerated by update_pch.sh. It is possible to edit it + manually (such as when an include file has been moved/renamed/removed). All such + manual changes will be rewritten by the next run of update_pch.sh (which presumably + also fixes all possible problems, so it's usually better to use it). + + Generated on 2020-04-21 11:14:28 using: + ./bin/update_pch dbaccess sdbt --cutoff=1 --exclude:system --include:module --exclude:local + + If after updating build fails, use the following command to locate conflicting headers: + ./bin/update_pch_bisect ./dbaccess/inc/pch/precompiled_sdbt.hxx "make dbaccess.build" --find-conflicts +*/ + +#if PCH_LEVEL >= 1 +#include +#endif // PCH_LEVEL >= 1 +#if PCH_LEVEL >= 2 +#include +#endif // PCH_LEVEL >= 2 +#if PCH_LEVEL >= 3 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif // PCH_LEVEL >= 3 +#if PCH_LEVEL >= 4 +#include +#endif // PCH_LEVEL >= 4 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/query.hrc b/dbaccess/inc/query.hrc new file mode 100644 index 000000000..fe4042517 --- /dev/null +++ b/dbaccess/inc/query.hrc @@ -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 . + */ +#ifndef INCLUDED_VCL_INC_PRINTACCESSORYVIEW_HRC +#define INCLUDED_VCL_INC_PRINTACCESSORYVIEW_HRC + +#define NC_(Context, String) reinterpret_cast(Context "\004" u8##String) + +const char* RSC_QUERY_OBJECT_TYPE[] = +{ + NC_("RSC_QUERY_OBJECT_TYPE", "The table view"), + NC_("RSC_QUERY_OBJECT_TYPE", "The query"), + NC_("RSC_QUERY_OBJECT_TYPE", "The SQL statement") +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/strings.hrc b/dbaccess/inc/strings.hrc new file mode 100644 index 000000000..16b1ad7b3 --- /dev/null +++ b/dbaccess/inc/strings.hrc @@ -0,0 +1,454 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_INC_CORE_RESOURCE_HRC +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_CORE_RESOURCE_HRC + +#define NC_(Context, String) reinterpret_cast(Context "\004" u8##String) + +#define RID_STR_CONNECTION_INVALID NC_("RID_STR_CONNECTION_INVALID", "No connection could be established.") +#define RID_STR_TABLE_IS_FILTERED NC_("RID_STR_TABLE_IS_FILTERED", "The table $name$ already exists. It is not visible because it has been filtered out.") +#define RID_STR_COULDNOTCONNECT_UNSPECIFIED NC_("RID_STR_COULDNOTCONNECT_UNSPECIFIED", "The connection to the external data source could not be established. An unknown error occurred. The driver is probably defective.") +#define RID_STR_COULDNOTCONNECT_NODRIVER NC_("RID_STR_COULDNOTCONNECT_NODRIVER", "The connection to the external data source could not be established. No SDBC driver was found for the URL '$name$'.") +#define RID_STR_COULDNOTLOAD_MANAGER NC_("RID_STR_COULDNOTLOAD_MANAGER", "The connection to the external data source could not be established. The SDBC driver manager could not be loaded.") +#define RID_STR_FORM NC_("RID_STR_FORM", "Form") +#define RID_STR_REPORT NC_("RID_STR_REPORT", "Report") +#define RID_STR_DATASOURCE_NOT_STORED NC_("RID_STR_DATASOURCE_NOT_STORED", "The data source was not saved. Please use the interface XStorable to save the data source.") +#define RID_STR_ONLY_QUERY NC_("RID_STR_ONLY_QUERY", "The given command is not a SELECT statement.\nOnly queries are allowed.") +#define RID_STR_NO_VALUE_CHANGED NC_("RID_STR_NO_VALUE_CHANGED", "No values were modified.") +#define RID_STR_NO_XROWUPDATE NC_("RID_STR_NO_XROWUPDATE", "Values could not be inserted. The XRowUpdate interface is not supported by ResultSet.") +#define RID_STR_NO_XRESULTSETUPDATE NC_("RID_STR_NO_XRESULTSETUPDATE", "Values could not be inserted. The XResultSetUpdate interface is not supported by ResultSet.") +#define RID_STR_NO_UPDATE_MISSING_CONDITION NC_("RID_STR_NO_UPDATE_MISSING_CONDITION", "Values could not be modified, due to a missing condition statement.") +#define RID_STR_NO_COLUMN_ADD NC_("RID_STR_NO_COLUMN_ADD", "The adding of columns is not supported.") +#define RID_STR_NO_COLUMN_DROP NC_("RID_STR_NO_COLUMN_DROP", "The dropping of columns is not supported.") +#define RID_STR_NO_CONDITION_FOR_PK NC_("RID_STR_NO_CONDITION_FOR_PK", "The WHERE condition could not be created for the primary key.") +#define RID_STR_COLUMN_UNKNOWN_PROP NC_("RID_STR_COLUMN_UNKNOWN_PROP", "The column does not support the property '%value'.") +#define RID_STR_COLUMN_NOT_SEARCHABLE NC_("RID_STR_COLUMN_NOT_SEARCHABLE", "The column is not searchable!") +#define RID_STR_NOT_SEQUENCE_INT8 NC_("RID_STR_NOT_SEQUENCE_INT8", "The value of the columns is not of the type Sequence.") +#define RID_STR_COLUMN_NOT_VALID NC_("RID_STR_COLUMN_NOT_VALID", "The column is not valid.") +#define RID_STR_COLUMN_MUST_VISIBLE NC_("RID_STR_COLUMN_MUST_VISIBLE", "The column '%name' must be visible as a column.") +#define RID_STR_NO_XQUERIESSUPPLIER NC_("RID_STR_NO_XQUERIESSUPPLIER", "The interface XQueriesSupplier is not available.") +#define RID_STR_NO_ABS_ZERO NC_("RID_STR_NO_ABS_ZERO", "An 'absolute(0)' call is not allowed.") +#define RID_STR_NO_RELATIVE NC_("RID_STR_NO_RELATIVE", "Relative positioning is not allowed in this state.") +#define RID_STR_NO_REFRESH_AFTERLAST NC_("RID_STR_NO_REFRESH_AFTERLAST", "A row cannot be refreshed when the ResultSet is positioned after the last row.") +#define RID_STR_NO_MOVETOINSERTROW_CALLED NC_("RID_STR_NO_MOVETOINSERTROW_CALLED", "A new row cannot be inserted when the ResultSet is not first moved to the insert row.") +#define RID_STR_NO_UPDATEROW NC_("RID_STR_NO_UPDATEROW", "A row cannot be modified in this state") +#define RID_STR_NO_DELETEROW NC_("RID_STR_NO_DELETEROW", "A row cannot be deleted in this state.") +#define RID_STR_NO_TABLE_RENAME NC_("RID_STR_NO_TABLE_RENAME", "The driver does not support table renaming.") +#define RID_STR_COLUMN_ALTER_BY_NAME NC_("RID_STR_COLUMN_ALTER_BY_NAME", "The driver does not support the modification of column descriptions by changing the name.") +#define RID_STR_COLUMN_ALTER_BY_INDEX NC_("RID_STR_COLUMN_ALTER_BY_INDEX", "The driver does not support the modification of column descriptions by changing the index.") +#define RID_STR_FILE_DOES_NOT_EXIST NC_("RID_STR_FILE_DOES_NOT_EXIST", "The file \"$file$\" does not exist.") +#define RID_STR_TABLE_DOES_NOT_EXIST NC_("RID_STR_TABLE_DOES_NOT_EXIST", "There exists no table named \"$table$\".") +#define RID_STR_QUERY_DOES_NOT_EXIST NC_("RID_STR_QUERY_DOES_NOT_EXIST", "There exists no query named \"$table$\".") +#define RID_STR_CONFLICTING_NAMES NC_("RID_STR_CONFLICTING_NAMES", "There are tables in the database whose names conflict with the names of existing queries. To make full use of all queries and tables, make sure they have distinct names.") +#define RID_STR_COMMAND_LEADING_TO_ERROR NC_("RID_STR_COMMAND_LEADING_TO_ERROR", "The SQL command leading to this error is:\n\n$command$") +#define RID_STR_STATEMENT_WITHOUT_RESULT_SET NC_("RID_STR_STATEMENT_WITHOUT_RESULT_SET", "The SQL command does not describe a result set.") +#define RID_STR_NAME_MUST_NOT_BE_EMPTY NC_("RID_STR_NAME_MUST_NOT_BE_EMPTY", "The name must not be empty.") +#define RID_STR_NO_NULL_OBJECTS_IN_CONTAINER NC_("RID_STR_NO_NULL_OBJECTS_IN_CONTAINER", "The container cannot contain NULL objects.") +#define RID_STR_NAME_ALREADY_USED NC_("RID_STR_NAME_ALREADY_USED", "There already is an object with the given name.") +#define RID_STR_OBJECT_CONTAINER_MISMATCH NC_("RID_STR_OBJECT_CONTAINER_MISMATCH", "This object cannot be part of this container.") +#define RID_STR_OBJECT_ALREADY_CONTAINED NC_("RID_STR_OBJECT_ALREADY_CONTAINED", "The object already is, with a different name, part of the container.") +#define RID_STR_NAME_NOT_FOUND NC_("RID_STR_NAME_NOT_FOUND", "Unable to find the document '$name$'.") +#define RID_STR_ERROR_WHILE_SAVING NC_("RID_STR_ERROR_WHILE_SAVING", "Could not save the document to $location$:\n$message$") +#define RID_NO_SUCH_DATA_SOURCE NC_("RID_NO_SUCH_DATA_SOURCE", "Error accessing data source '$name$':\n$error$") +#define RID_STR_NO_SUB_FOLDER NC_("RID_STR_NO_SUB_FOLDER", "There exists no folder named \"$folder$\".") +#define RID_STR_NO_DELETE_BEFORE_AFTER NC_("RID_STR_NO_DELETE_BEFORE_AFTER", "Cannot delete the before-first or after-last row.") +#define RID_STR_NO_DELETE_INSERT_ROW NC_("RID_STR_NO_DELETE_INSERT_ROW", "Cannot delete the insert-row.") +#define RID_STR_RESULT_IS_READONLY NC_("RID_STR_RESULT_IS_READONLY", "Result set is read only.") +#define RID_STR_NO_DELETE_PRIVILEGE NC_("RID_STR_NO_DELETE_PRIVILEGE", "DELETE privilege not available.") +#define RID_STR_ROW_ALREADY_DELETED NC_("RID_STR_ROW_ALREADY_DELETED", "Current row is already deleted.") +#define RID_STR_UPDATE_FAILED NC_("RID_STR_UPDATE_FAILED", "Current row could not be updated.") +#define RID_STR_NO_INSERT_PRIVILEGE NC_("RID_STR_NO_INSERT_PRIVILEGE", "INSERT privilege not available.") +#define RID_STR_INTERNAL_ERROR NC_("RID_STR_INTERNAL_ERROR", "Internal error: no statement object provided by the database driver.") +#define RID_STR_EXPRESSION1 NC_("RID_STR_EXPRESSION1", "Expression1") +#define RID_STR_NO_SQL_COMMAND NC_("RID_STR_NO_SQL_COMMAND", "No SQL command was provided.") +#define RID_STR_INVALID_INDEX NC_("RID_STR_INVALID_INDEX", "Invalid column index.") +#define RID_STR_INVALID_CURSOR_STATE NC_("RID_STR_INVALID_CURSOR_STATE", "Invalid cursor state.") +#define RID_STR_CURSOR_BEFORE_OR_AFTER NC_("RID_STR_CURSOR_BEFORE_OR_AFTER", "The cursor points to before the first or after the last row.") +#define RID_STR_NO_BOOKMARK_BEFORE_OR_AFTER NC_("RID_STR_NO_BOOKMARK_BEFORE_OR_AFTER", "The rows before the first and after the last row don't have a bookmark.") +#define RID_STR_NO_BOOKMARK_DELETED NC_("RID_STR_NO_BOOKMARK_DELETED", "The current row is deleted, and thus doesn't have a bookmark.") +#define RID_STR_CONNECTION_REQUEST NC_("RID_STR_CONNECTION_REQUEST", "A connection for the following URL was requested \"$name$\".") +#define RID_STR_MISSING_EXTENSION NC_("RID_STR_MISSING_EXTENSION", "The extension is not installed.") + +#define STR_QUERY_AND_TABLE_DISTINCT_NAMES NC_("STR_QUERY_AND_TABLE_DISTINCT_NAMES", "You cannot give a table and a query the same name. Please use a name which is not yet used by a query or table.") +#define STR_BASENAME_TABLE NC_("STR_BASENAME_TABLE", "Table") +#define STR_BASENAME_QUERY NC_("STR_BASENAME_QUERY", "Query") +#define STR_CONN_WITHOUT_QUERIES_OR_TABLES NC_("STR_CONN_WITHOUT_QUERIES_OR_TABLES", "The given connection is no valid query and/or tables supplier.") +#define STR_NO_TABLE_OBJECT NC_("STR_NO_TABLE_OBJECT", "The given object is no table object.") +#define STR_INVALID_COMPOSITION_TYPE NC_("STR_INVALID_COMPOSITION_TYPE", "Invalid composition type - need a value from com.sun.star.sdb.tools.CompositionType.") +#define STR_INVALID_COMMAND_TYPE NC_("STR_INVALID_COMMAND_TYPE", "Invalid command type - only TABLE and QUERY from com.sun.star.sdb.CommandType are allowed.") + +#define STR_QUERY_UNDO_TABWINSHOW NC_("STR_QUERY_UNDO_TABWINSHOW", "Add Table Window" ) +#define STR_QUERY_UNDO_MOVETABWIN NC_("STR_QUERY_UNDO_MOVETABWIN", "Move table window" ) +#define STR_QUERY_UNDO_INSERTCONNECTION NC_("STR_QUERY_UNDO_INSERTCONNECTION", "Insert Join" ) +#define STR_QUERY_UNDO_REMOVECONNECTION NC_("STR_QUERY_UNDO_REMOVECONNECTION", "Delete Join" ) +#define STR_QUERY_UNDO_SIZETABWIN NC_("STR_QUERY_UNDO_SIZETABWIN", "Resize table window" ) +#define STR_QUERY_UNDO_TABFIELDDELETE NC_("STR_QUERY_UNDO_TABFIELDDELETE", "Delete Column" ) +#define STR_QUERY_UNDO_TABFIELDMOVED NC_("STR_QUERY_UNDO_TABFIELDMOVED", "Move column") +#define STR_QUERY_UNDO_TABFIELDCREATE NC_("STR_QUERY_UNDO_TABFIELDCREATE", "Add Column" ) +#define RID_STR_FIELD_DOESNT_EXIST NC_("RID_STR_FIELD_DOESNT_EXIST", "Invalid expression, field name '$name$' does not exist.") +#define STR_QUERY_UNDO_TABWINDELETE NC_("STR_QUERY_UNDO_TABWINDELETE", "Delete Table Window" ) +#define STR_QUERY_UNDO_MODIFY_CELL NC_("STR_QUERY_UNDO_MODIFY_CELL", "Edit Column Description") +#define STR_QUERY_UNDO_SIZE_COLUMN NC_("STR_QUERY_UNDO_SIZE_COLUMN", "Adjust column width") +#define STR_QUERY_SORTTEXT NC_("STR_QUERY_SORTTEXT", "(not sorted);ascending;descending" ) +#define STR_QUERY_FUNCTIONS NC_("STR_QUERY_FUNCTIONS", "(no function);Group") +#define STR_QUERY_NOTABLE NC_("STR_QUERY_NOTABLE", "(no table)") +#define STR_QRY_ORDERBY_UNRELATED NC_("STR_QRY_ORDERBY_UNRELATED", "The database only supports sorting for visible fields.") +#define STR_QUERY_HANDLETEXT NC_("STR_QUERY_HANDLETEXT", "Field;Alias;Table;Sort;Visible;Function;Criterion;Or;Or") +#define STR_QUERY_LIMIT_ALL NC_("STR_QUERY_LIMIT_ALL", "All") +#define STR_QRY_TOO_MANY_COLUMNS NC_("STR_QRY_TOO_MANY_COLUMNS", "There are too many columns.") +#define STR_QRY_CRITERIA_ON_ASTERISK NC_("STR_QRY_CRITERIA_ON_ASTERISK", "A condition cannot be applied to field [*]" ) +#define STR_QRY_TOO_LONG_STATEMENT NC_("STR_QRY_TOO_LONG_STATEMENT", "The SQL statement created is too long.") +#define STR_QRY_TOOCOMPLEX NC_("STR_QRY_TOOCOMPLEX", "Query is too complex" ) +#define STR_QRY_NOSELECT NC_("STR_QRY_NOSELECT", "Nothing has been selected." ) +#define STR_QRY_SYNTAX NC_("STR_QRY_SYNTAX", "SQL syntax error" ) +#define STR_QRY_ORDERBY_ON_ASTERISK NC_("STR_QRY_ORDERBY_ON_ASTERISK", "[*] cannot be used as a sort criterion.") +#define STR_QRY_TOO_MANY_TABLES NC_("STR_QRY_TOO_MANY_TABLES", "There are too many tables.") +#define STR_QRY_NATIVE NC_("STR_QRY_NATIVE", "The statement will not be applied when querying in the SQL dialect of the database." ) +#define STR_QRY_ILLEGAL_JOIN NC_("STR_QRY_ILLEGAL_JOIN", "Join could not be processed" ) +#define STR_SVT_SQL_SYNTAX_ERROR NC_("STR_SVT_SQL_SYNTAX_ERROR", "Syntax error in SQL statement" ) +#define STR_QUERYDESIGN_NO_VIEW_SUPPORT NC_("STR_QUERYDESIGN_NO_VIEW_SUPPORT", "This database does not support table views.") +#define STR_NO_ALTER_VIEW_SUPPORT NC_("STR_NO_ALTER_VIEW_SUPPORT", "This database does not support altering of existing table views.") +#define STR_QUERYDESIGN_NO_VIEW_ASK NC_("STR_QUERYDESIGN_NO_VIEW_ASK", "Do you want to create a query instead?") +#define STR_DATASOURCE_DELETED NC_("STR_DATASOURCE_DELETED", "The corresponding data source has been deleted. Therefore, data relevant to that data source cannot be saved.") +#define STR_QRY_COLUMN_NOT_FOUND NC_("STR_QRY_COLUMN_NOT_FOUND", "The column '$name$' is unknown.") +#define STR_QRY_JOIN_COLUMN_COMPARE NC_("STR_QRY_JOIN_COLUMN_COMPARE", "Columns can only be compared using '='.") +#define STR_QRY_LIKE_LEFT_NO_COLUMN NC_("STR_QRY_LIKE_LEFT_NO_COLUMN", "You must use a column name before 'LIKE'.") +#define STR_QRY_CHECK_CASESENSITIVE NC_("STR_QRY_CHECK_CASESENSITIVE", "The column could not be found. Please note that the database is case-sensitive.") +// To translators: for $object$, one of the values of the RSC_QUERY_OBJECT_TYPE resource will be inserted. +#define STR_QUERY_SAVEMODIFIED NC_("STR_QUERY_SAVEMODIFIED", "$object$ has been changed.\nDo you want to save the changes?" ) +// To translators: for $object$, one of the values of the RSC_QUERY_OBJECT_TYPE resource (except \"SQL command\", which doesn't make sense here) will be inserted. +#define STR_ERROR_PARSING_STATEMENT NC_("STR_ERROR_PARSING_STATEMENT", "$object$ is based on an SQL command which could not be parsed.") +// To translators: for $object$, one of the values of the RSC_QUERY_OBJECT_TYPE resource (except \"SQL command\", which doesn't make sense here) will be inserted. +#define STR_INFO_OPENING_IN_SQL_VIEW NC_("STR_INFO_OPENING_IN_SQL_VIEW", "$object$ will be opened in SQL view.") +#define STR_STATEMENT_WITHOUT_RESULT_SET NC_("STR_STATEMENT_WITHOUT_RESULT_SET", "The query does not create a result set, and thus cannot be part of another query.") + +#define RID_STR_COLUMN_FORMAT NC_("RID_STR_COLUMN_FORMAT", "Column ~Format...") +#define RID_STR_COLUMN_WIDTH NC_("RID_STR_COLUMN_WIDTH", "Column ~Width...") +#define RID_STR_TABLE_FORMAT NC_("RID_STR_TABLE_FORMAT", "Table Format...") +#define RID_STR_ROW_HEIGHT NC_("RID_STR_ROW_HEIGHT", "Row Height...") +#define RID_STR_COPY NC_("RID_STR_COPY", "~Copy") +#define RID_STR_UNDO_MODIFY_RECORD NC_("RID_STR_UNDO_MODIFY_RECORD", "Undo: Data Input") +#define RID_STR_SAVE_CURRENT_RECORD NC_("RID_STR_SAVE_CURRENT_RECORD", "Save current record") +#define STR_QRY_TITLE NC_("STR_QRY_TITLE", "Query #" ) +#define STR_TBL_TITLE NC_("STR_TBL_TITLE", "Table #" ) +#define STR_VIEW_TITLE NC_("STR_VIEW_TITLE", "View #" ) +#define STR_NAME_ALREADY_EXISTS NC_("STR_NAME_ALREADY_EXISTS", "The name \"#\" already exists.") +#define STR_NO_COLUMNNAME_MATCHING NC_("STR_NO_COLUMNNAME_MATCHING", "No matching column names were found.") +#define STR_ERROR_OCCURRED_WHILE_COPYING NC_("STR_ERROR_OCCURRED_WHILE_COPYING", "An error occurred. Do you want to continue copying?") +#define STR_DATASOURCE_GRIDCONTROL_NAME NC_("STR_DATASOURCE_GRIDCONTROL_NAME", "Data source table view") +#define STR_DATASOURCE_GRIDCONTROL_DESC NC_("STR_DATASOURCE_GRIDCONTROL_DESC", "Shows the selected table or query.") + +#define STR_QUERY_UNDO_MODIFYSQLEDIT NC_("STR_QUERY_UNDO_MODIFYSQLEDIT", "Modify SQL statement(s)" ) + +#define RID_STR_NEW_FORM NC_("RID_STR_NEW_FORM", "Create Form in Design View..." ) +#define RID_STR_NEW_FORM_AUTO NC_("RID_STR_NEW_FORM_AUTO", "Use Wizard to Create Form..." ) +#define RID_STR_NEW_REPORT_AUTO NC_("RID_STR_NEW_REPORT_AUTO", "Use Wizard to Create Report..." ) +#define RID_STR_NEW_REPORT NC_("RID_STR_NEW_REPORT", "Create Report in Design View..." ) +#define RID_STR_NEW_QUERY NC_("RID_STR_NEW_QUERY", "Create Query in Design View..." ) +#define RID_STR_NEW_QUERY_SQL NC_("RID_STR_NEW_QUERY_SQL", "Create Query in SQL View..." ) +#define RID_STR_NEW_QUERY_AUTO NC_("RID_STR_NEW_QUERY_AUTO", "Use Wizard to Create Query..." ) +#define RID_STR_NEW_TABLE NC_("RID_STR_NEW_TABLE", "Create Table in Design View..." ) +#define RID_STR_NEW_TABLE_AUTO NC_("RID_STR_NEW_TABLE_AUTO", "Use Wizard to Create Table..." ) +#define RID_STR_NEW_VIEW NC_("RID_STR_NEW_VIEW", "Create View..." ) +#define RID_STR_FORMS_CONTAINER NC_("RID_STR_FORMS_CONTAINER", "Forms" ) +#define RID_STR_REPORTS_CONTAINER NC_("RID_STR_REPORTS_CONTAINER", "Reports" ) +#define RID_STR_REPORTS_HELP_TEXT_WIZARD NC_("RID_STR_REPORTS_HELP_TEXT_WIZARD", "The wizard will guide you through the steps necessary to create a report." ) +#define RID_STR_FORMS_HELP_TEXT NC_("RID_STR_FORMS_HELP_TEXT", "Create a form by specifying the record source, controls, and control properties." ) +#define RID_STR_REPORT_HELP_TEXT NC_("RID_STR_REPORT_HELP_TEXT", "Create a report by specifying the record source, controls, and control properties." ) +#define RID_STR_FORMS_HELP_TEXT_WIZARD NC_("RID_STR_FORMS_HELP_TEXT_WIZARD", "The wizard will guide you through the steps necessary to create a form." ) +#define RID_STR_QUERIES_HELP_TEXT NC_("RID_STR_QUERIES_HELP_TEXT", "Create a query by specifying the filters, input tables, field names, and properties for sorting or grouping." ) +#define RID_STR_QUERIES_HELP_TEXT_SQL NC_("RID_STR_QUERIES_HELP_TEXT_SQL", "Create a query by entering an SQL statement directly." ) +#define RID_STR_QUERIES_HELP_TEXT_WIZARD NC_("RID_STR_QUERIES_HELP_TEXT_WIZARD", "The wizard will guide you through the steps necessary to create a query." ) +#define RID_STR_TABLES_HELP_TEXT_DESIGN NC_("RID_STR_TABLES_HELP_TEXT_DESIGN", "Create a table by specifying the field names and properties, as well as the data types." ) +#define RID_STR_TABLES_HELP_TEXT_WIZARD NC_("RID_STR_TABLES_HELP_TEXT_WIZARD", "Choose from a selection of business and personal table samples, which you customize to create a table." ) +#define RID_STR_VIEWS_HELP_TEXT_DESIGN NC_("RID_STR_VIEWS_HELP_TEXT_DESIGN", "Create a view by specifying the tables and field names you would like to have visible." ) +#define STR_DATABASE NC_("STR_DATABASE", "Database" ) +#define STR_TASKS NC_("STR_TASKS", "Tasks" ) +#define STR_DESCRIPTION NC_("STR_DESCRIPTION", "Description" ) +#define STR_PREVIEW NC_("STR_PREVIEW", "Preview" ) +#define STR_QUERY_CLOSEDOCUMENTS NC_("STR_QUERY_CLOSEDOCUMENTS", "The connection type has been altered.\n" \ + "For the changes to take effect, all forms, reports, queries and tables must be closed.\n\n" \ + "Do you want to close all documents now?") +#define STR_FRM_LABEL NC_("STR_FRM_LABEL", "F~orm name" ) +#define STR_RPT_LABEL NC_("STR_RPT_LABEL", "~Report name" ) +#define STR_FOLDER_LABEL NC_("STR_FOLDER_LABEL", "F~older name" ) +#define STR_SUB_DOCS_WITH_SCRIPTS NC_("STR_SUB_DOCS_WITH_SCRIPTS", "The document contains forms or reports with embedded macros.") +#define STR_SUB_DOCS_WITH_SCRIPTS_DETAIL NC_("STR_SUB_DOCS_WITH_SCRIPTS_DETAIL", "Macros should be embedded into the database document itself.\n\n" \ + "You can continue to use your document as before, however, you are encouraged to migrate " \ + "your macros. The menu item 'Tools / Migrate Macros ...' will assist you with this.\n\n" \ + "Note that you won't be able to embed macros into the database document itself until " \ + "this migration is done. ") +#define RID_STR_EMBEDDED_DATABASE NC_("RID_STR_EMBEDDED_DATABASE", "Embedded database") +#define RID_STR_NO_DIFF_CAT NC_("RID_STR_NO_DIFF_CAT", "You cannot select different categories.") +#define RID_STR_UNSUPPORTED_OBJECT_TYPE NC_("RID_STR_UNSUPPORTED_OBJECT_TYPE", "Unsupported object type found ($type$).") +#define STR_PAGETITLE_GENERAL NC_("STR_PAGETITLE_GENERAL", "Advanced Properties") +#define STR_PAGETITLE_ADVANCED NC_("STR_PAGETITLE_ADVANCED", "Additional Settings") +#define STR_PAGETITLE_CONNECTION NC_("STR_PAGETITLE_CONNECTION", "Connection settings") +#define STR_TBL_LABEL NC_("STR_TBL_LABEL", "~Table Name") +#define STR_QRY_LABEL NC_("STR_QRY_LABEL", "~Query name") +#define STR_TITLE_RENAME NC_("STR_TITLE_RENAME", "Rename to") +#define STR_TITLE_PASTE_AS NC_("STR_TITLE_PASTE_AS", "Insert as") + +#define STR_QUERY_BRW_DELETE_ROWS NC_("STR_QUERY_BRW_DELETE_ROWS", "Do you want to delete the selected data?" ) +#define SBA_BROWSER_SETTING_ORDER NC_("SBA_BROWSER_SETTING_ORDER", "Error setting the sort criteria") +#define SBA_BROWSER_SETTING_FILTER NC_("SBA_BROWSER_SETTING_FILTER", "Error setting the filter criteria") +#define RID_STR_CONNECTION_LOST NC_("RID_STR_CONNECTION_LOST", "Connection lost") +#define RID_STR_QUERIES_CONTAINER NC_("RID_STR_QUERIES_CONTAINER", "Queries") +#define RID_STR_TABLES_CONTAINER NC_("RID_STR_TABLES_CONTAINER", "Tables") +#define STR_TITLE_CONFIRM_DELETION NC_("STR_TITLE_CONFIRM_DELETION", "Confirm Deletion" ) +#define STR_QUERY_DELETE_TABLE NC_("STR_QUERY_DELETE_TABLE", "Do you want to delete the table '%1'?" ) +#define STR_QUERY_CONNECTION_LOST NC_("STR_QUERY_CONNECTION_LOST", "The connection to the database has been lost. Do you want to reconnect?" ) +#define STR_OPENTABLES_WARNINGS NC_("STR_OPENTABLES_WARNINGS", "Warnings encountered") +#define STR_OPENTABLES_WARNINGS_DETAILS NC_("STR_OPENTABLES_WARNINGS_DETAILS", "While retrieving the tables, warnings were reported by the database connection.") +#define STR_CONNECTING_DATASOURCE NC_("STR_CONNECTING_DATASOURCE", "Connecting to \"$name$\" ...") +#define STR_LOADING_QUERY NC_("STR_LOADING_QUERY", "Loading query $name$ ...") +#define STR_LOADING_TABLE NC_("STR_LOADING_TABLE", "Loading table $name$ ...") +#define STR_NO_TABLE_FORMAT_INSIDE NC_("STR_NO_TABLE_FORMAT_INSIDE", "No table format could be found." ) +#define STR_COULDNOTCONNECT_DATASOURCE NC_("STR_COULDNOTCONNECT_DATASOURCE", "The connection to the data source \"$name$\" could not be established.") + +#define STR_TABLEDESIGN_DBFIELDTYPES NC_("STR_TABLEDESIGN_DBFIELDTYPES", "Unknown;Text;Number;Date/Time;Date;Time;Yes/No;Currency;Memo;Counter;Image;Text (fix);Decimal;Binary (fix);Binary;BigInt;Double;Float;Real;Integer;Small Integer;Tiny Integer;SQL Null;Object;Distinct;Structure;Field;BLOB;CLOB;REF;OTHER;Bit (fix)") +#define STR_TABLEDESIGN_UNDO_PRIMKEY NC_("STR_TABLEDESIGN_UNDO_PRIMKEY", "Insert/remove primary key" ) +#define STR_VALUE_YES NC_("STR_VALUE_YES", "Yes" ) +#define STR_VALUE_NO NC_("STR_VALUE_NO", "No" ) +// Note: should somehow fit to the word "value" in other languages as well: value - none... +#define STR_VALUE_NONE NC_("STR_VALUE_NONE", "") +#define STR_TAB_FIELD_COLUMN_NAME NC_("STR_TAB_FIELD_COLUMN_NAME", "Field Name" ) +#define STR_TAB_FIELD_COLUMN_DATATYPE NC_("STR_TAB_FIELD_COLUMN_DATATYPE", "Field Type" ) +#define STR_TAB_HELP_TEXT NC_("STR_TAB_HELP_TEXT", "Description" ) +#define STR_COLUMN_DESCRIPTION NC_("STR_COLUMN_DESCRIPTION", "Column Description" ) +#define STR_TAB_PROPERTIES NC_("STR_TAB_PROPERTIES", "Field Properties" ) +#define STR_TABED_UNDO_CELLMODIFIED NC_("STR_TABED_UNDO_CELLMODIFIED", "Modify cell" ) +#define STR_TABED_UNDO_ROWDELETED NC_("STR_TABED_UNDO_ROWDELETED", "Delete row" ) +#define STR_TABED_UNDO_TYPE_CHANGED NC_("STR_TABED_UNDO_TYPE_CHANGED", "Modify field type") +#define STR_TABED_UNDO_ROWINSERTED NC_("STR_TABED_UNDO_ROWINSERTED", "Insert row" ) +#define STR_TABED_UNDO_NEWROWINSERTED NC_("STR_TABED_UNDO_NEWROWINSERTED", "Insert new row" ) +#define STR_DEFAULT_VALUE NC_("STR_DEFAULT_VALUE", "~Default value" ) +#define STR_HELP_BOOL_DEFAULT NC_("STR_HELP_BOOL_DEFAULT", "Select a value that is to appear in all new records as default.\nIf the field is not to have a default value, select the empty string.") +#define STR_HELP_DEFAULT_VALUE NC_("STR_HELP_DEFAULT_VALUE", "Enter a default value for this field.\n\nWhen you later enter data in the table, this string will be used in each new record for the field selected. It should, therefore, correspond to the cell format that needs to be entered below." ) +#define STR_HELP_TEXT_LENGTH NC_("STR_HELP_TEXT_LENGTH", "Enter the maximum text length permitted." ) +#define STR_HELP_NUMERIC_TYPE NC_("STR_HELP_NUMERIC_TYPE", "Enter the number format." ) +#define STR_HELP_LENGTH NC_("STR_HELP_LENGTH", "Determine the length data can have in this field.\n\nIf decimal fields, then the maximum length of the number to be entered, if binary fields, then the length of the data block.\nThe value will be corrected accordingly when it exceeds the maximum for this database." ) +#define STR_HELP_SCALE NC_("STR_HELP_SCALE", "Specify the number of decimal places permitted in this field." ) +#define STR_HELP_FORMAT_CODE NC_("STR_HELP_FORMAT_CODE", "This is where you see how the data would be displayed in the current format (use the button on the right to modify the format).") +#define STR_HELP_FORMAT_BUTTON NC_("STR_HELP_FORMAT_BUTTON", "This is where you determine the output format of the data.") +#define STR_HELP_AUTOINCREMENT NC_("STR_HELP_AUTOINCREMENT", "Choose if this field should contain AutoIncrement values.\n\nYou can not enter data in fields of this type. An intrinsic value will be assigned to each new record automatically (resulting from the increment of the previous record)." ) +#define STR_TABLEDESIGN_DUPLICATE_NAME NC_("STR_TABLEDESIGN_DUPLICATE_NAME", "The table cannot be saved because column name \"$column$\" was assigned twice.") +#define STR_TBL_COLUMN_IS_KEYCOLUMN NC_("STR_TBL_COLUMN_IS_KEYCOLUMN", "The column \"$column$\" belongs to the primary key. If the column is deleted, the primary key will also be deleted. Do you really want to continue?") +#define STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE NC_("STR_TBL_COLUMN_IS_KEYCOLUMN_TITLE", "Primary Key Affected") +#define STR_COLUMN_NAME NC_("STR_COLUMN_NAME", "Column") +#define STR_QRY_CONTINUE NC_("STR_QRY_CONTINUE", "Continue anyway?" ) +#define STR_TABLEDESIGN_CONNECTION_MISSING NC_("STR_TABLEDESIGN_CONNECTION_MISSING", "The table could not be saved due to problems connecting to the database.") +#define STR_TABLEDESIGN_DATASOURCE_DELETED NC_("STR_TABLEDESIGN_DATASOURCE_DELETED", "The table filter could not be adjusted because the data source has been deleted.") +#define STR_QUERY_SAVE_TABLE_EDIT_INDEXES NC_("STR_QUERY_SAVE_TABLE_EDIT_INDEXES", "Before you can edit the indexes of a table, you have to save it.\nDo you want to save the changes now?") +#define STR_TABLEDESIGN_NO_PRIM_KEY_HEAD NC_("STR_TABLEDESIGN_NO_PRIM_KEY_HEAD", "No primary key" ) +#define STR_TABLEDESIGN_NO_PRIM_KEY NC_("STR_TABLEDESIGN_NO_PRIM_KEY", "A unique index or primary key is required for data record identification in this database.\nYou can only enter data into this table when one of these two structural conditions has been met.\n\nShould a primary key be created now?" ) +#define STR_TABLEDESIGN_ALTER_ERROR NC_("STR_TABLEDESIGN_ALTER_ERROR", "The column \"$column$\" could not be changed. Should the column instead be deleted and the new format appended?" ) +#define STR_TABLEDESIGN_SAVE_ERROR NC_("STR_TABLEDESIGN_SAVE_ERROR", "Error while saving the table design") +#define STR_TABLEDESIGN_COULD_NOT_DROP_COL NC_("STR_TABLEDESIGN_COULD_NOT_DROP_COL", "The column $column$ could not be deleted.") +#define STR_HELP_AUTOINCREMENT_VALUE NC_("STR_HELP_AUTOINCREMENT_VALUE", "Enter an SQL statement for the auto-increment field.\n\nThis statement will be directly transferred to the database when the table is created.") +#define STR_NO_TYPE_INFO_AVAILABLE NC_("STR_NO_TYPE_INFO_AVAILABLE", "No type information could be retrieved from the database.\nThe table design mode is not available for this data source.") +#define STR_CHANGE_COLUMN_NAME NC_("STR_CHANGE_COLUMN_NAME", "change field name") +#define STR_CHANGE_COLUMN_TYPE NC_("STR_CHANGE_COLUMN_TYPE", "change field type") +#define STR_CHANGE_COLUMN_DESCRIPTION NC_("STR_CHANGE_COLUMN_DESCRIPTION", "change field description") +#define STR_CHANGE_COLUMN_ATTRIBUTE NC_("STR_CHANGE_COLUMN_ATTRIBUTE", "change field attribute") + +#define STR_ENTER_CONNECTION_PASSWORD NC_("STR_ENTER_CONNECTION_PASSWORD", "A password is needed to connect to the data source \"$name$\".") +#define STR_ASK_FOR_DIRECTORY_CREATION NC_("STR_ASK_FOR_DIRECTORY_CREATION", "The directory\n\n$path$\n\ndoes not exist. Should it be created?") +#define STR_COULD_NOT_CREATE_DIRECTORY NC_("STR_COULD_NOT_CREATE_DIRECTORY", "The directory $name$ could not be created.") +#define STR_ALREADYEXISTOVERWRITE NC_("STR_ALREADYEXISTOVERWRITE", "The file already exists. Overwrite?" ) +#define STR_NEW_FOLDER NC_("STR_NEW_FOLDER", "Folder" ) + +#define STR_DATABASE_TYPE_CHANGE NC_("STR_DATABASE_TYPE_CHANGE", "Database properties" ) +#define STR_PARENTTITLE_GENERAL NC_("STR_PARENTTITLE_GENERAL", "Data Source Properties: #" ) +#define STR_ERR_USE_CONNECT_TO NC_("STR_ERR_USE_CONNECT_TO", "Please choose 'Connect to an existing database' to connect to an existing database instead.") +#define STR_COULD_NOT_LOAD_ODBC_LIB NC_("STR_COULD_NOT_LOAD_ODBC_LIB", "Could not load the program library #lib# or it is corrupted. The ODBC data source selection is not available.") +#define STR_UNSUPPORTED_DATASOURCE_TYPE NC_("STR_UNSUPPORTED_DATASOURCE_TYPE", "This kind of data source is not supported on this platform.\nYou are allowed to change the settings, but you probably will not be able to connect to the database.") +#define STR_AUTOTEXT_FIELD_SEP_NONE NC_("STR_AUTOTEXT_FIELD_SEP_NONE", "{None}") +// To translators: EM Dec 2002: 'Space' refers t o what you get when you hit the space bar on your keyboard. +#define STR_AUTOFIELDSEPARATORLIST NC_("STR_AUTOFIELDSEPARATORLIST", ";\t59\t,\t44\t:\t58\t{Tab}\t9\t{Space}\t32" ) +#define STR_AUTODELIMITER_MISSING NC_("STR_AUTODELIMITER_MISSING", "#1 must be set." ) +#define STR_AUTODELIMITER_MUST_DIFFER NC_("STR_AUTODELIMITER_MUST_DIFFER", "#1 and #2 must be different." ) +#define STR_AUTONO_WILDCARDS NC_("STR_AUTONO_WILDCARDS", "Wildcards such as ?,* are not allowed in #1." ) + +#define STR_CONNECTION_TEST NC_("STR_CONNECTION_TEST", "Connection Test") +#define STR_CONNECTION_SUCCESS NC_("STR_CONNECTION_SUCCESS", "The connection was established successfully.") +#define STR_CONNECTION_NO_SUCCESS NC_("STR_CONNECTION_NO_SUCCESS", "The connection could not be established.") +#define STR_JDBCDRIVER_SUCCESS NC_("STR_JDBCDRIVER_SUCCESS", "The JDBC driver was loaded successfully.") +#define STR_JDBCDRIVER_NO_SUCCESS NC_("STR_JDBCDRIVER_NO_SUCCESS", "The JDBC driver could not be loaded.") +#define STR_MSACCESS_FILTERNAME NC_("STR_MSACCESS_FILTERNAME", "MS Access file") +#define STR_MSACCESS_2007_FILTERNAME NC_("STR_MSACCESS_2007_FILTERNAME", "MS Access 2007 file") +#define STR_FIREBIRD_FILTERNAME NC_("STR_FIREBIRD_FILTERNAME", "Firebird Database") + +#define STR_RSC_CHARSETS NC_("STR_RSC_CHARSETS", "System") +#define STR_ERROR_DURING_CREATION NC_("STR_ERROR_DURING_CREATION", "Error during creation") +#define STR_UNEXPECTED_ERROR NC_("STR_UNEXPECTED_ERROR", "An error occurred. The operation could not be performed.") +#define STR_COULDNOTOPEN_LINKEDDOC NC_("STR_COULDNOTOPEN_LINKEDDOC", "The document \"$file$\" could not be opened.") +#define STR_MISSING_TABLES_XDROP NC_("STR_MISSING_TABLES_XDROP", "The table cannot be deleted because the database connection does not support this.") +#define STR_BUTTON_TEXT_ALL NC_("STR_BUTTON_TEXT_ALL", "~All") +#define STR_UNDO_COLON NC_("STR_UNDO_COLON", "Undo:") +#define STR_REDO_COLON NC_("STR_REDO_COLON", "Redo:") +#define STR_UNKNOWN_TYPE_FOUND NC_("STR_UNKNOWN_TYPE_FOUND", "No corresponding column type could be found for column '#1'." ) +#define STR_FILE_DOES_NOT_EXIST NC_("STR_FILE_DOES_NOT_EXIST", "The file \"$file$\" does not exist.") +#define STR_WARNINGS_DURING_CONNECT NC_("STR_WARNINGS_DURING_CONNECT", "Warnings were encountered while connecting to the data source. Press \"$buttontext$\" to view them.") +#define STR_NAMED_OBJECT_ALREADY_EXISTS NC_("STR_NAMED_OBJECT_ALREADY_EXISTS", "The name '$#$' already exists.\nPlease enter another name." ) +// #i96130# use hard coded name +#define RID_STR_EXTENSION_NOT_PRESENT NC_("RID_STR_EXTENSION_NOT_PRESENT", "The report, \"$file$\", requires the Report Builder feature.") + +#define STR_COULDNOTCREATE_DRIVERMANAGER NC_("STR_COULDNOTCREATE_DRIVERMANAGER", "Cannot connect to the SDBC driver manager (#servicename#).") +#define STR_NOREGISTEREDDRIVER NC_("STR_NOREGISTEREDDRIVER", "A driver is not registered for the URL #connurl#.") +#define STR_NOTABLEINFO NC_("STR_NOTABLEINFO", "Successfully connected, but information about database tables is not available.") +#define STR_ALL_TABLES NC_("STR_ALL_TABLES", "All tables") +#define STR_ALL_VIEWS NC_("STR_ALL_VIEWS", "All views") +#define STR_ALL_TABLES_AND_VIEWS NC_("STR_ALL_TABLES_AND_VIEWS", "All tables and views") + +#define STR_TABLE_PRIV_NAME NC_("STR_TABLE_PRIV_NAME", "Table name") +#define STR_TABLE_PRIV_INSERT NC_("STR_TABLE_PRIV_INSERT", "Insert data") +#define STR_TABLE_PRIV_DELETE NC_("STR_TABLE_PRIV_DELETE", "Delete data") +#define STR_TABLE_PRIV_UPDATE NC_("STR_TABLE_PRIV_UPDATE", "Modify data") +#define STR_TABLE_PRIV_ALTER NC_("STR_TABLE_PRIV_ALTER", "Alter structure") +#define STR_TABLE_PRIV_SELECT NC_("STR_TABLE_PRIV_SELECT", "Read data") +#define STR_TABLE_PRIV_REFERENCE NC_("STR_TABLE_PRIV_REFERENCE", "Modify references") +#define STR_TABLE_PRIV_DROP NC_("STR_TABLE_PRIV_DROP", "Drop structure") + +#define STR_DBASE_PATH_OR_FILE NC_("STR_DBASE_PATH_OR_FILE", "Path to the dBASE files") +#define STR_FLAT_PATH_OR_FILE NC_("STR_FLAT_PATH_OR_FILE", "Path to the text files") +#define STR_CALC_PATH_OR_FILE NC_("STR_CALC_PATH_OR_FILE", "Path to the spreadsheet document") +#define STR_NAME_OF_ODBC_DATASOURCE NC_("STR_NAME_OF_ODBC_DATASOURCE", "Name of the ODBC data source on your system") +#define STR_WRITER_PATH_OR_FILE NC_("STR_WRITER_PATH_OR_FILE", "Path to the Writer document") +#define STR_MYSQL_DATABASE_NAME NC_("STR_MYSQL_DATABASE_NAME", "Name of the MySQL database") +#define STR_ORACLE_DATABASE_NAME NC_("STR_ORACLE_DATABASE_NAME", "Name of the Oracle database") +#define STR_MSACCESS_MDB_FILE NC_("STR_MSACCESS_MDB_FILE", "Microsoft Access database file") +#define STR_NO_ADDITIONAL_SETTINGS NC_("STR_NO_ADDITIONAL_SETTINGS", "No more settings are necessary. To verify that the connection is working, click the '%test' button.") +#define STR_COMMONURL NC_("STR_COMMONURL", "Datasource URL (e.g. host=$host:$port dbname=$database)" ) +#define STR_HOSTNAME NC_("STR_HOSTNAME", "~Host name") +#define STR_MOZILLA_PROFILE_NAME NC_("STR_MOZILLA_PROFILE_NAME", "~Mozilla profile name") +#define STR_THUNDERBIRD_PROFILE_NAME NC_("STR_THUNDERBIRD_PROFILE_NAME", "~Thunderbird profile name") +#define STR_ADD_TABLES NC_("STR_ADD_TABLES", "Add Tables") +#define STR_ADD_TABLE_OR_QUERY NC_("STR_ADD_TABLE_OR_QUERY", "Add Table or Query" ) + +#define STR_WIZ_COLUMN_SELECT_TITLE NC_("STR_WIZ_COLUMN_SELECT_TITEL", "Apply columns") +#define STR_WIZ_TYPE_SELECT_TITLE NC_("STR_WIZ_TYPE_SELECT_TITEL", "Type formatting") +#define STR_WIZ_NAME_ALREADY_DEFINED NC_("STR_WIZ_NAME_ALREADY_DEFINED", "Enter a unique name for the new primary key data field.\nThe following name is already in use:") +#define STR_WIZ_NAME_MATCHING_TITLE NC_("STR_WIZ_NAME_MATCHING_TITEL", "Assign columns" ) +#define STR_WIZ_PB_PREV NC_("STR_WIZ_PB_PREV", "< ~Back") +#define STR_WIZ_PB_NEXT NC_("STR_WIZ_PB_NEXT", "~Next>") +#define STR_WIZ_PB_OK NC_("STR_WIZ_PB_OK", "C~reate") +#define STR_WIZ_TABLE_COPY NC_("STR_WIZ_TABLE_COPY", "Copy table" ) +#define STR_COPYTABLE_TITLE_COPY NC_("STR_COPYTABLE_TITLE_COPY", "Copy table" ) +#define STR_INVALID_TABLE_NAME NC_("STR_INVALID_TABLE_NAME", "This table name is not valid in the current database.") +#define STR_SUGGEST_APPEND_TABLE_DATA NC_("STR_SUGGEST_APPEND_TABLE_DATA", "Choose the option 'Append data' on the first page to append data to an existing table.") +#define STR_INVALID_TABLE_NAME_LENGTH NC_("STR_INVALID_TABLE_NAME_LENGTH", "Please change the table name. It is too long.") + +#define STR_DBWIZARDTITLE NC_("STR_DBWIZARDTITLE", "Database Wizard" ) +#define STR_PAGETITLE_INTROPAGE NC_("STR_PAGETITLE_INTROPAGE", "Select database" ) +#define STR_PAGETITLE_DBASE NC_("STR_PAGETITLE_DBASE", "Set up dBASE connection" ) +#define STR_PAGETITLE_TEXT NC_("STR_PAGETITLE_TEXT", "Set up a connection to text files" ) +#define STR_PAGETITLE_MSACCESS NC_("STR_PAGETITLE_MSACCESS", "Set up Microsoft Access connection" ) +#define STR_PAGETITLE_LDAP NC_("STR_PAGETITLE_LDAP", "Set up LDAP connection" ) +#define STR_PAGETITLE_ADO NC_("STR_PAGETITLE_ADO", "Set up ADO connection" ) +#define STR_PAGETITLE_JDBC NC_("STR_PAGETITLE_JDBC", "Set up JDBC connection" ) +#define STR_PAGETITLE_ORACLE NC_("STR_PAGETITLE_ORACLE", "Set up Oracle database connection" ) +#define STR_PAGETITLE_MYSQL NC_("STR_PAGETITLE_MYSQL", "Set up MySQL connection" ) +#define STR_PAGETITLE_ODBC NC_("STR_PAGETITLE_ODBC", "Set up ODBC connection" ) +#define STR_PAGETITLE_DOCUMENT_OR_SPREADSHEET NC_("STR_PAGETITLE_DOCUMENT_OR_SPREADSHEET", "Set up Writer Document or Spreadsheet connection" ) +#define STR_PAGETITLE_AUTHENTIFICATION NC_("STR_PAGETITLE_AUTHENTIFICATION", "Set up user authentication" ) +#define STR_PAGETITLE_MYSQL_NATIVE NC_("STR_PAGETITLE_MYSQL_NATIVE", "Set up MySQL server data") +#define STR_PAGETITLE_FINAL NC_("STR_PAGETITLE_FINAL", "Save and proceed" ) +#define STR_DATABASEDEFAULTNAME NC_("STR_DATABASEDEFAULTNAME", "New Database" ) +#define STR_MYSQLJDBC_HEADERTEXT NC_("STR_MYSQLJDBC_HEADERTEXT", "Set up connection to a MySQL database using JDBC" ) +#define STR_MYSQLJDBC_HELPTEXT NC_("STR_MYSQLJDBC_HELPTEXT", "Please enter the required information to connect to a MySQL database using JDBC. Note that a JDBC driver class must be installed on your system and registered with %PRODUCTNAME.\nPlease contact your system administrator if you are unsure about the following settings.") +#define STR_MYSQL_DRIVERCLASSTEXT NC_("STR_MYSQL_DRIVERCLASSTEXT", "MySQL JDBC d~river class:") +#define STR_MYSQL_DEFAULT NC_("STR_MYSQL_DEFAULT", "Default: 3306") +#define STR_DBASE_HEADERTEXT NC_("STR_DBASE_HEADERTEXT", "Set up a connection to dBASE files" ) +#define STR_DBASE_HELPTEXT NC_("STR_DBASE_HELPTEXT", "Select the folder where the dBASE files are stored." ) +#define STR_TEXT_HEADERTEXT NC_("STR_TEXT_HEADERTEXT", "Set up a connection to text files" ) +#define STR_TEXT_HELPTEXT NC_("STR_TEXT_HELPTEXT", "Select the folder where the CSV (Comma Separated Values) text files are stored. %PRODUCTNAME Base will open these files in read-only mode." ) +#define STR_TEXT_PATH_OR_FILE NC_("STR_TEXT_PATH_OR_FILE", "Path to text files") +#define STR_MSACCESS_HEADERTEXT NC_("STR_MSACCESS_HEADERTEXT", "Set up a connection to a Microsoft Access database" ) +#define STR_MSACCESS_HELPTEXT NC_("STR_MSACCESS_HELPTEXT", "Please select the Microsoft Access file you want to access.") +#define STR_ADO_HEADERTEXT NC_("STR_ADO_HEADERTEXT", "Set up a connection to an ADO database" ) +#define STR_ADO_HELPTEXT NC_("STR_ADO_HELPTEXT", "Please enter the URL of the ADO data source you want to connect to.\nClick 'Browse' to configure provider-specific settings.\nPlease contact your system administrator if you are unsure about the following settings." ) +#define STR_ODBC_HEADERTEXT NC_("STR_ODBC_HEADERTEXT", "Set up a connection to an ODBC database" ) +#define STR_ODBC_HELPTEXT NC_("STR_ODBC_HELPTEXT", "Enter the name of the ODBC database you want to connect to.\nClick 'Browse...' to select an ODBC database that is already registered in %PRODUCTNAME.\nPlease contact your system administrator if you are unsure about the following settings." ) +#define STR_JDBC_HEADERTEXT NC_("STR_JDBC_HEADERTEXT", "Set up a connection to a JDBC database" ) +#define STR_JDBC_HELPTEXT NC_("STR_JDBC_HELPTEXT", "Please enter the required information to connect to a JDBC database.\nPlease contact your system administrator if you are unsure about the following settings." ) +#define STR_ORACLE_HEADERTEXT NC_("STR_ORACLE_HEADERTEXT", "Set up a connection to an Oracle database") +#define STR_ORACLE_DEFAULT NC_("STR_ORACLE_DEFAULT", "Default: 1521" ) +#define STR_ORACLE_DRIVERCLASSTEXT NC_("STR_ORACLE_DRIVERCLASSTEXT", "Oracle JDBC ~driver class") +#define STR_ORACLE_HELPTEXT NC_("STR_ORACLE_HELPTEXT", "Please enter the required information to connect to an Oracle database. Note that a JDBC Driver Class must be installed on your system and registered with %PRODUCTNAME.\nPlease contact your system administrator if you are unsure about the following settings." ) +#define STR_SPREADSHEET_HEADERTEXT NC_("STR_SPREADSHEET_HEADERTEXT", "Set up a connection to spreadsheets") +#define STR_SPREADSHEET_HELPTEXT NC_("STR_SPREADSHEET_HELPTEXT", "Click 'Browse...' to select a %PRODUCTNAME spreadsheet or Microsoft Excel workbook.\n%PRODUCTNAME will open this file in read-only mode." ) +#define STR_SPREADSHEETPATH NC_("STR_SPREADSHEETPATH", "~Location and file name" ) + +#define STR_COMMAND_EXECUTED_SUCCESSFULLY NC_("STR_COMMAND_EXECUTED_SUCCESSFULLY", "Command successfully executed." ) +#define STR_DIRECTSQL_CONNECTIONLOST NC_("STR_DIRECTSQL_CONNECTIONLOST", "The connection to the database has been lost. This dialog will be closed.") + +#define STR_TAB_INDEX_SORTORDER NC_("STR_TAB_INDEX_SORTORDER", "Sort order" ) +#define STR_TAB_INDEX_FIELD NC_("STR_TAB_INDEX_FIELD", "Index field" ) +#define STR_ORDER_ASCENDING NC_("STR_ORDER_ASCENDING", "Ascending" ) +#define STR_ORDER_DESCENDING NC_("STR_ORDER_DESCENDING", "Descending" ) +#define STR_CONFIRM_DROP_INDEX NC_("STR_CONFIRM_DROP_INDEX", "Do you really want to delete the index '$name$'?") +#define STR_LOGICAL_INDEX_NAME NC_("STR_LOGICAL_INDEX_NAME", "index") +#define STR_NEED_INDEX_FIELDS NC_("STR_NEED_INDEX_FIELDS", "The index must contain at least one field.") +#define STR_INDEX_NAME_ALREADY_USED NC_("STR_INDEX_NAME_ALREADY_USED", "There is already another index named \"$name$\".") +#define STR_INDEXDESIGN_DOUBLE_COLUMN_NAME NC_("STR_INDEXDESIGN_DOUBLE_COLUMN_NAME", "In an index definition, no table column may occur more than once. However, you have entered column \"$name$\" twice.") + +#define STR_COULD_NOT_CONVERT_PARAM NC_("STR_COULD_NOT_CONVERT_PARAM", "The entry could not be converted to a valid value for the \"$name$\" parameter") + +#define STR_EXCEPTION_STATUS NC_("STR_EXCEPTION_STATUS", "SQL Status") +#define STR_EXCEPTION_ERRORCODE NC_("STR_EXCEPTION_ERRORCODE", "Error code") +#define STR_EXPLAN_STRINGCONVERSION_ERROR NC_("STR_EXPLAN_STRINGCONVERSION_ERROR", "A frequent reason for this error is an inappropriate character set setting for the language of your database. Check the setting by choosing Edit - Database - Properties.") +#define STR_EXCEPTION_ERROR NC_("STR_EXCEPTION_ERROR", "Error") +#define STR_EXCEPTION_WARNING NC_("STR_EXCEPTION_WARNING", "Warning") +#define STR_EXCEPTION_INFO NC_("STR_EXCEPTION_INFO", "Information") +#define STR_EXCEPTION_DETAILS NC_("STR_EXCEPTION_DETAILS", "Details") + +#define STR_QUERY_USERADMIN_DELETE_USER NC_("STR_QUERY_USERADMIN_DELETE_USER", "Do you really want to delete the user?") +#define STR_USERADMIN_NOT_AVAILABLE NC_("STR_USERADMIN_NOT_AVAILABLE", "The database does not support user administration." ) +#define STR_ERROR_PASSWORDS_NOT_IDENTICAL NC_("STR_ERROR_PASSWORDS_NOT_IDENTICAL", "The passwords do not match. Please enter the password again.") + +#define STR_JOIN_TYPE_HINT NC_("STR_JOIN_TYPE_HINT", "Please note that some databases may not support this join type.") +#define STR_QUERY_INNER_JOIN NC_("STR_QUERY_INNER_JOIN", "Includes only records for which the contents of the related fields of both tables are identical.") +#define STR_QUERY_LEFTRIGHT_JOIN NC_("STR_QUERY_LEFTRIGHT_JOIN", "Contains ALL records from table '%1' but only records from table '%2' where the values in the related fields are matching.") +#define STR_QUERY_FULL_JOIN NC_("STR_QUERY_FULL_JOIN", "Contains ALL records from '%1' and from '%2'.") +#define STR_QUERY_CROSS_JOIN NC_("STR_QUERY_CROSS_JOIN", "Contains the Cartesian product of ALL records from '%1' and from '%2'.") + +#define STR_CTW_NO_VIEWS_SUPPORT NC_("STR_CTW_NO_VIEWS_SUPPORT", "The destination database does not support views.") +#define STR_CTW_NO_PRIMARY_KEY_SUPPORT NC_("STR_CTW_NO_PRIMARY_KEY_SUPPORT", "The destination database does not support primary keys.") +#define STR_CTW_INVALID_DATA_ACCESS_DESCRIPTOR NC_("STR_CTW_INVALID_DATA_ACCESS_DESCRIPTOR", "no data access descriptor found, or no data access descriptor able to provide all necessary information") +#define STR_CTW_ONLY_TABLES_AND_QUERIES_SUPPORT NC_("STR_CTW_ONLY_TABLES_AND_QUERIES_SUPPORT", "Only tables and queries are supported at the moment.") +#define STR_CTW_COPY_SOURCE_NEEDS_BOOKMARKS NC_("STR_CTW_COPY_SOURCE_NEEDS_BOOKMARKS", "The copy source's result set must support bookmarks.") +#define STR_CTW_UNSUPPORTED_COLUMN_TYPE NC_("STR_CTW_UNSUPPORTED_COLUMN_TYPE", "Unsupported source column type ($type$) at column position $pos$.") +#define STR_CTW_ILLEGAL_PARAMETER_COUNT NC_("STR_CTW_ILLEGAL_PARAMETER_COUNT", "Illegal number of initialization parameters.") +#define STR_CTW_ERROR_DURING_INITIALIZATION NC_("STR_CTW_ERROR_DURING_INITIALIZATION", "An error occurred during initialization.") +#define STR_CTW_ERROR_UNSUPPORTED_SETTING NC_("STR_CTW_ERROR_UNSUPPORTED_SETTING", "Unsupported setting in the copy source descriptor: $name$.") +#define STR_CTW_ERROR_NO_QUERY NC_("STR_CTW_ERROR_NO_QUERY", "To copy a query, your connection must be able to provide queries.") +#define STR_CTW_ERROR_INVALID_INTERACTIONHANDLER NC_("STR_CTW_ERROR_INVALID_INTERACTIONHANDLER", "The given interaction handler is invalid.") + +#define STR_QUERY_REL_EDIT_RELATION NC_("STR_QUERY_REL_EDIT_RELATION", "This relation already exists. Do you want to edit it or create a new one?" ) +#define STR_QUERY_REL_EDIT NC_("STR_QUERY_REL_EDIT", "Edit..." ) +#define STR_QUERY_REL_CREATE NC_("STR_QUERY_REL_CREATE", "Create..." ) +#define STR_RELATIONDESIGN NC_("STR_RELATIONDESIGN", " - %PRODUCTNAME Base: Relation design" ) +#define STR_RELATIONDESIGN_NOT_AVAILABLE NC_("STR_RELATIONDESIGN_NOT_AVAILABLE", "The database does not support relations." ) +#define STR_QUERY_REL_DELETE_WINDOW NC_("STR_QUERY_REL_DELETE_WINDOW", "When you delete this table all corresponding relations will be deleted as well. Continue?") +#define STR_QUERY_REL_COULD_NOT_CREATE NC_("STR_QUERY_REL_COULD_NOT_CREATE", "The database could not create the relation. Maybe foreign keys for this kind of table aren't supported.\nPlease check your documentation of the database.") + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/inc/strings.hxx b/dbaccess/inc/strings.hxx new file mode 100644 index 000000000..793807f0c --- /dev/null +++ b/dbaccess/inc/strings.hxx @@ -0,0 +1,284 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_DBACCESS_INC_STRINGS_HXX +#define INCLUDED_DBACCESS_INC_STRINGS_HXX + +// property names + +#define PROPERTY_URL "URL" +#define PROPERTY_INFO "Info" +#define PROPERTY_SETTINGS "Settings" +#define PROPERTY_ISPASSWORDREQUIRED "IsPasswordRequired" +#define PROPERTY_TABLEFILTER "TableFilter" +#define PROPERTY_TABLETYPEFILTER "TableTypeFilter" +#define PROPERTY_NAME "Name" +#define PROPERTY_SCHEMANAME "SchemaName" +#define PROPERTY_CATALOGNAME "CatalogName" +#define PROPERTY_PRIVILEGES "Privileges" +#define PROPERTY_ESCAPE_PROCESSING "EscapeProcessing" +#define PROPERTY_COMMAND "Command" +#define PROPERTY_TYPE "Type" +#define PROPERTY_TYPENAME "TypeName" +#define PROPERTY_PRECISION "Precision" +#define PROPERTY_SCALE "Scale" +#define PROPERTY_ISNULLABLE "IsNullable" +#define PROPERTY_ISAUTOINCREMENT "IsAutoIncrement" +#define PROPERTY_ISROWVERSION "IsRowVersion" +#define PROPERTY_DESCRIPTION "Description" +#define PROPERTY_DEFAULTVALUE "DefaultValue" +#define PROPERTY_NUMBERFORMAT "FormatKey" +#define PROPERTY_QUERYTIMEOUT "QueryTimeOut" +#define PROPERTY_MAXFIELDSIZE "MaxFieldSize" +#define PROPERTY_MAXROWS "MaxRows" +#define PROPERTY_CURSORNAME "CursorName" +#define PROPERTY_RESULTSETCONCURRENCY "ResultSetConcurrency" +#define PROPERTY_RESULTSETTYPE "ResultSetType" +#define PROPERTY_FETCHDIRECTION "FetchDirection" +#define PROPERTY_FETCHSIZE "FetchSize" +#define PROPERTY_USEBOOKMARKS "UseBookmarks" +#define PROPERTY_ISSEARCHABLE "IsSearchable" +#define PROPERTY_ISCURRENCY "IsCurrency" +#define PROPERTY_ISSIGNED "IsSigned" +#define PROPERTY_DISPLAYSIZE "DisplaySize" +#define PROPERTY_LABEL "Label" +#define PROPERTY_ISREADONLY "IsReadOnly" +#define PROPERTY_ISWRITABLE "IsWritable" +#define PROPERTY_ISDEFINITELYWRITABLE "IsDefinitelyWritable" +#define PROPERTY_VALUE "Value" +#define PROPERTY_TABLENAME "TableName" +#define PROPERTY_ISCASESENSITIVE "IsCaseSensitive" +#define PROPERTY_SERVICENAME "ServiceName" +#define PROPERTY_ISBOOKMARKABLE "IsBookmarkable" +#define PROPERTY_CANUPDATEINSERTEDROWS "CanUpdateInsertedRows" +#define PROPERTY_ISSET "IsSet" +#define PROPERTY_ISOUTPARAMETER "IsOutParameter" +#define PROPERTY_NUMBERFORMATSSUPPLIER "NumberFormatsSupplier" +#define PROPERTY_ISCALCULATED "IsCalculated" +#define PROPERTY_DATASOURCENAME "DataSourceName" +#define PROPERTY_DATABASE_LOCATION "DatabaseLocation" +#define PROPERTY_CONNECTION_RESOURCE "ConnectionResource" +#define PROPERTY_CONNECTION_INFO "ConnectionInfo" +#define PROPERTY_RESULT_SET "ResultSet" +#define PROPERTY_SELECTION "Selection" +#define PROPERTY_BOOKMARK_SELECTION "BookmarkSelection" +#define PROPERTY_COLUMN_NAME "ColumnName" +#define PROPERTY_COLUMN "Column" +#define PROPERTY_DATASOURCE "DataSource" +#define PROPERTY_TRANSACTIONISOLATION "TransactionIsolation" +#define PROPERTY_TYPEMAP "TypeMap" +#define PROPERTY_USER "User" +#define PROPERTY_PASSWORD "Password" +#define PROPERTY_COMMAND_TYPE "CommandType" +#define PROPERTY_ACTIVECOMMAND "ActiveCommand" +#define PROPERTY_ACTIVE_CONNECTION "ActiveConnection" +#define PROPERTY_FILTER "Filter" +#define PROPERTY_APPLYFILTER "ApplyFilter" +#define PROPERTY_ORDER "Order" +#define PROPERTY_APPLYORDER "ApplyOrder" +#define PROPERTY_ISMODIFIED "IsModified" +#define PROPERTY_ISNEW "IsNew" +#define PROPERTY_ROWCOUNT "RowCount" +#define PROPERTY_ISROWCOUNTFINAL "IsRowCountFinal" +#define PROPERTY_HELPFILENAME "HelpFileName" +#define PROPERTY_WIDTH "Width" +#define PROPERTY_ROW_HEIGHT "RowHeight" +#define PROPERTY_AUTOGROW "AutoGrow" +#define PROPERTY_FORMATKEY "FormatKey" +#define PROPERTY_ALIGN "Align" +#define PROPERTY_FONT "FontDescriptor" +#define PROPERTY_TEXTCOLOR "TextColor" +#define PROPERTY_BOUNDFIELD "BoundField" +#define PROPERTY_CONTROLSOURCE "DataField" +#define PROPERTY_REALNAME "RealName" +#define PROPERTY_ISHIDDEN "IsHidden" +#define PROPERTY_UPDATE_TABLENAME "UpdateTableName" +#define PROPERTY_UPDATE_SCHEMANAME "UpdateSchemaName" +#define PROPERTY_UPDATE_CATALOGNAME "UpdateCatalogName" +#define PROPERTY_RELATIVEPOSITION "RelativePosition" +#define PROPERTY_CONTROLMODEL "ControlModel" +#define PROPERTY_ISASCENDING "IsAscending" +#define PROPERTY_RELATEDCOLUMN "RelatedColumn" +#define PROPERTY_ISUNIQUE "IsUnique" +#define PROPERTY_ISPRIMARYKEYINDEX "IsPrimaryKeyIndex" +#define PROPERTY_IGNORERESULT "IgnoreResult" +#define PROPERTY_UPDATERULE "UpdateRule" +#define PROPERTY_DELETERULE "DeleteRule" +#define PROPERTY_REFERENCEDTABLE "ReferencedTable" +#define PROPERTY_REFERENCEDCOLUMN "ReferencedColumn" +#define PROPERTY_PARENTWINDOW "ParentWindow" +#define PROPERTY_SQLEXCEPTION "SQLException" +#define PROPERTY_BORDER "Border" +#define PROPERTY_THREADSAFE "ThreadSafe" +#define PROPERTY_HELPTEXT "HelpText" +#define PROPERTY_CONTROLDEFAULT "ControlDefault" +#define PROPERTY_HIDDEN "Hidden" +#define PROPERTY_DEFAULTSTATE "DefaultState" +#define PROPERTY_SUPPRESSVERSIONCL "SuppressVersionColumns" +#define PROPERTY_SHOW_BROWSER "ShowBrowser" +#define PROPERTY_ENABLE_BROWSER "EnableBrowser" +#define PROPERTY_SHOWMENU "ShowMenu" +#define PROPERTY_LAYOUTINFORMATION "LayoutInformation" +#define PROPERTY_CURRENTTABLE "CurrentTable" +#define PROPERTY_DATABASENAME "DatabaseName" +#define PROPERTY_CONTROLUSER "ControlUser" +#define PROPERTY_CONTROLPASSWORD "ControlPassword" +#define PROPERTY_CACHESIZE "CacheSize" +#define PROPERTY_TEXTLINECOLOR "TextLineColor" +#define PROPERTY_TEXTEMPHASIS "FontEmphasisMark" +#define PROPERTY_TEXTRELIEF "FontRelief" +#define PROPERTY_DEFAULTTEXT "DefaultText" +#define PROPERTY_EFFECTIVEDEFAULT "EffectiveDefault" +#define PROPERTY_AUTOINCREMENTCREATION "AutoIncrementCreation" +#define PROPERTY_BOOLEANCOMPARISONMODE "BooleanComparisonMode" +#define PROPERTY_ENABLESQL92CHECK "EnableSQL92Check" +#define PROPERTY_FONTCHARWIDTH "FontCharWidth" +#define PROPERTY_FONTCHARSET "FontCharset" +#define PROPERTY_FONTFAMILY "FontFamily" +#define PROPERTY_FONTHEIGHT "FontHeight" +#define PROPERTY_FONTKERNING "FontKerning" +#define PROPERTY_FONTNAME "FontName" +#define PROPERTY_FONTORIENTATION "FontOrientation" +#define PROPERTY_FONTPITCH "FontPitch" +#define PROPERTY_FONTSLANT "FontSlant" +#define PROPERTY_FONTSTRIKEOUT "FontStrikeout" +#define PROPERTY_FONTSTYLENAME "FontStyleName" +#define PROPERTY_FONTUNDERLINE "FontUnderline" +#define PROPERTY_FONTWEIGHT "FontWeight" +#define PROPERTY_FONTWIDTH "FontWidth" +#define PROPERTY_FONTWORDLINEMODE "FontWordLineMode" +#define PROPERTY_FONTTYPE "FontType" +#define PROPERTY_PERSISTENT_NAME "PersistentName" +#define PROPERTY_EMBEDDEDOBJECT "EmbeddedObject" +#define PROPERTY_ORIGINAL "Original" +#define PROPERTY_USECATALOGINSELECT "UseCatalogInSelect" +#define PROPERTY_USESCHEMAINSELECT "UseSchemaInSelect" +#define PROPERTY_OUTERJOINESCAPE "EnableOuterJoinEscape" +#define PROPERTY_AS_TEMPLATE "AsTemplate" +#define PROPERTY_HAVING_CLAUSE "HavingClause" +#define PROPERTY_GROUP_BY "GroupBy" +#define PROPERTY_EDIT_WIDTH "EditWidth" +#define PROPERTY_SINGLESELECTQUERYCOMPOSER "SingleSelectQueryComposer" +#define PROPERTY_CHANGE_NOTIFICATION_ENABLED "PropertyChangeNotificationEnabled" + + +// service names + +#define SERVICE_SDBC_RESULTSET "com.sun.star.sdbc.ResultSet" +#define SERVICE_SDBC_ROWSET "com.sun.star.sdbc.RowSet" +#define SERVICE_SDBC_STATEMENT "com.sun.star.sdbc.Statement" +#define SERVICE_SDBC_PREPAREDSTATEMENT "com.sun.star.sdbc.PreparedStatement" +#define SERVICE_SDBC_CALLABLESTATEMENT "com.sun.star.sdbc.CallableStatement" +#define SERVICE_SDBC_CONNECTION "com.sun.star.sdbc.Connection" +#define SERVICE_SDBCX_CONTAINER "com.sun.star.sdbcx.Container" +#define SERVICE_SDBCX_TABLE "com.sun.star.sdbcx.Table" +#define SERVICE_SDBCX_RESULTSET "com.sun.star.sdbcx.ResultSet" +#define SERVICE_SDB_CONNECTION "com.sun.star.sdb.Connection" +#define SERVICE_SDBCX_COLUMN "com.sun.star.sdbcx.Column" +#define SERVICE_SDBCX_COLUMNDESCRIPTOR "com.sun.star.sdbcx.ColumnDescriptor" +#define SERVICE_SDB_COLUMNSETTINGS "com.sun.star.sdb.ColumnSettings" +#define SERVICE_SDB_RESULTCOLUMN "com.sun.star.sdb.ResultColumn" +#define SERVICE_SDB_DATACOLUMN "com.sun.star.sdb.DataColumn" +#define SERVICE_SDB_DATASOURCE "com.sun.star.sdb.DataSource" +#define SERVICE_SDB_RESULTSET "com.sun.star.sdb.ResultSet" +#define SERVICE_SDB_ROWSET "com.sun.star.sdb.RowSet" +#define SERVICE_SDB_PREPAREDSTATMENT "com.sun.star.sdb.PreparedStatement" +#define SERVICE_SDB_CALLABLESTATEMENT "com.sun.star.sdb.CallableStatement" +#define SERVICE_SDB_SQLQUERYCOMPOSER "com.sun.star.sdb.SQLQueryComposer" +#define SERVICE_SDB_DATASETTINGS "com.sun.star.sdb.DefinitionSettings" +#define SERVICE_SDB_QUERYDESCRIPTOR "com.sun.star.sdb.QueryDescriptor" +#define SERVICE_SDB_QUERY "com.sun.star.sdb.Query" +#define SERVICE_SDBCX_COLUMNS "com.sun.star.sdbcx.Columns" +#define SERVICE_SDBCX_TABLES "com.sun.star.sdbcx.Tables" +#define SERVICE_SDB_QUERIES "com.sun.star.sdb.Queries" +#define SERVICE_SDBCX_INDEXCOLUMN "com.sun.star.sdbcx.IndexColumn" +#define SERVICE_SDBCX_KEYCOLUMN "com.sun.star.sdbcx.KeyColumn" +#define SERVICE_SDB_DOCUMENTDEFINITION "com.sun.star.sdb.DocumentDefinition" +#define SERVICE_NAME_FORM "com.sun.star.sdb.Form" +#define SERVICE_NAME_FORM_COLLECTION "com.sun.star.sdb.Forms" +#define SERVICE_NAME_REPORT "com.sun.star.sdb.Report" +#define SERVICE_NAME_REPORT_COLLECTION "com.sun.star.sdb.Reports" +#define SERVICE_NAME_QUERY_COLLECTION "com.sun.star.sdb.Queries" +#define SERVICE_NAME_TABLE_COLLECTION "com.sun.star.sdb.Tables" +#define SERVICE_NAME_SINGLESELECTQUERYCOMPOSER "com.sun.star.sdb.SingleSelectQueryComposer" +#define SERVICE_SDB_APPLICATIONCONTROLLER "org.openoffice.comp.dbu.OApplicationController" + +// info properties +#define INFO_JDBCDRIVERCLASS "JavaDriverClass" +#define INFO_TEXTFILEEXTENSION "Extension" +#define INFO_CHARSET "CharSet" +#define INFO_TEXTFILEHEADER "HeaderLine" +#define INFO_FIELDDELIMITER "FieldDelimiter" +#define INFO_TEXTDELIMITER "StringDelimiter" +#define INFO_DECIMALDELIMITER "DecimalDelimiter" +#define INFO_THOUSANDSDELIMITER "ThousandDelimiter" +#define INFO_SHOWDELETEDROWS "ShowDeleted" +#define INFO_ALLOWLONGTABLENAMES "NoNameLengthLimit" +#define INFO_ADDITIONALOPTIONS "SystemDriverSettings" +#define INFO_AUTORETRIEVEVALUE "AutoRetrievingStatement" +#define INFO_AUTORETRIEVEENABLED "IsAutoRetrievingEnabled" +#define INFO_APPEND_TABLE_ALIAS "AppendTableAliasName" +#define INFO_AS_BEFORE_CORRELATION_NAME "GenerateASBeforeCorrelationName" +#define INFO_FORMS_CHECK_REQUIRED_FIELDS "FormsCheckRequiredFields" +#define INFO_PARAMETERNAMESUBST "ParameterNameSubstitution" +#define INFO_IGNOREDRIVER_PRIV "IgnoreDriverPrivileges" +#define INFO_USECATALOG "UseCatalog" +#define INFO_CONN_LDAP_BASEDN "BaseDN" +#define INFO_CONN_LDAP_ROWCOUNT "MaxRowCount" +#define INFO_PREVIEW "Preview" +#define INFO_MEDIATYPE "MediaType" +#define INFO_ESCAPE_DATETIME "EscapeDateTime" + +// other +#define INFO_POOLURL "PoolURL" +#define URL_INTERACTIVE "Interactive" + +// URLs + +#define URL_COMPONENT_QUERYDESIGN ".component:DB/QueryDesign" +#define URL_COMPONENT_VIEWDESIGN ".component:DB/ViewDesign" +#define URL_COMPONENT_TABLEDESIGN ".component:DB/TableDesign" +#define URL_COMPONENT_FORMGRIDVIEW ".component:DB/FormGridView" +#define URL_COMPONENT_DATASOURCEBROWSER ".component:DB/DataSourceBrowser" +#define URL_COMPONENT_RELATIONDESIGN ".component:DB/RelationDesign" +#define URL_COMPONENT_APPLICATION ".component:DB/Application" +#define URL_COMPONENT_REPORTDESIGN ".component:DB/ReportDesign" + +// service names + +#define SERVICE_SDB_DIRECTSQLDIALOG "org.openoffice.comp.dbu.DirectSqlDialog" + +// other DBU relevant strings + +#define FRAME_NAME_QUERY_PREVIEW "QueryPreview" +#define SERVICE_CONTROLDEFAULT "com.sun.star.comp.dbu.OColumnControl" +#define PROPERTY_QUERYDESIGNVIEW "QueryDesignView" +#define PROPERTY_GRAPHICAL_DESIGN "GraphicalDesign" +#define PROPERTY_HELP_URL "HelpURL" + +// other DBU properties + +#define PROPERTY_TRISTATE "TriState" +#define PROPERTY_ENABLEOUTERJOIN "EnableOuterJoinEscape" +#define PROPERTY_TABSTOP "TabStop" +#define PROPERTY_DEFAULTCONTROL "DefaultControl" +#define PROPERTY_ENABLED "Enabled" +#define PROPERTY_MOUSE_WHEEL_BEHAVIOR "MouseWheelBehavior" + +#define SQLSTATE_GENERAL "01000" + +#define PROPERTY_APPLYFORMDESIGNMODE "ApplyFormDesignMode" +#define PROPERTY_IS_FORM "IsForm" +#define PROPERTY_PERSISTENT_PATH "PersistentPath" + +#define STR_AUTOTEXTSEPARATORLIST "\"\t34\t'\t39" + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/dbaccess/qa/complex/dbaccess/ApplicationController.java b/dbaccess/qa/complex/dbaccess/ApplicationController.java new file mode 100644 index 000000000..eafc32dba --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/ApplicationController.java @@ -0,0 +1,159 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.beans.PropertyValue; +import com.sun.star.container.XNameAccess; +import com.sun.star.frame.FrameSearchFlag; +import com.sun.star.frame.XComponentLoader; +import com.sun.star.frame.XModel; +import com.sun.star.frame.XStorable; +import com.sun.star.lang.XComponent; +import com.sun.star.sdb.XOfficeDatabaseDocument; +import com.sun.star.sdb.application.XDatabaseDocumentUI; +import com.sun.star.sdbcx.XTablesSupplier; +import com.sun.star.uno.Exception; +import com.sun.star.uno.UnoRuntime; +import connectivity.tools.HsqlColumnDescriptor; +import connectivity.tools.HsqlDatabase; +import connectivity.tools.HsqlTableDescriptor; +import java.io.IOException; + + +// ---------- junit imports ----------------- +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + + +/** complex test case for Base's application UI + */ +public class ApplicationController extends TestCase +{ + + private HsqlDatabase m_database; + private XOfficeDatabaseDocument m_databaseDocument; + private XDatabaseDocumentUI m_documentUI; + + public String getTestObjectName() + { + return getClass().getName(); + } + + + private void impl_closeDocument() + { + if (m_database != null) + { + m_database.close(); + m_database = null; + m_databaseDocument = null; + m_documentUI = null; + } + } + + + private void impl_switchToDocument(String _documentURL) throws java.lang.Exception + { + // close previous database document + impl_closeDocument(); + + // create/load the new database document + m_database = (_documentURL == null) + ? new HsqlDatabase(getMSF()) + : new HsqlDatabase(getMSF(), _documentURL); + m_databaseDocument = m_database.getDatabaseDocument(); + + // load it into a frame + final Object object = getMSF().createInstance("com.sun.star.frame.Desktop"); + final XComponentLoader xComponentLoader = UnoRuntime.queryInterface(XComponentLoader.class, object); + final XComponent loadedComponent = xComponentLoader.loadComponentFromURL(m_database.getDocumentURL(), "_blank", FrameSearchFlag.ALL, new PropertyValue[0]); + + assertTrue("too many document instances!", + UnoRuntime.areSame(loadedComponent, m_databaseDocument)); + + // get the controller, which provides access to various UI operations + final XModel docModel = UnoRuntime.queryInterface(XModel.class, + loadedComponent); + m_documentUI = UnoRuntime.queryInterface(XDatabaseDocumentUI.class, + docModel.getCurrentController()); + } + + + @Before + @Override + public void before() throws java.lang.Exception + { + super.before(); + impl_switchToDocument(null); + } + + + @After + @Override + public void after() throws java.lang.Exception + { + impl_closeDocument(); + super.after(); + } + + + @Test + public void checkSaveAs() throws Exception, IOException, java.lang.Exception + { + // issue 93737 describes the problem that when you save-as a database document, and do changes to it, + // then those changes are saved in the old document, actually + final String oldDocumentURL = m_database.getDocumentURL(); + + final String newDocumentURL = createTempFileURL(); + + // store the doc in a new location + final XStorable storeDoc = UnoRuntime.queryInterface( XStorable.class, m_databaseDocument ); + storeDoc.storeAsURL( newDocumentURL, new PropertyValue[] { } ); + + // connect + m_documentUI.connect(); + assertTrue("could not connect to " + m_database.getDocumentURL(), m_documentUI.isConnected()); + + // create a table in the database + m_database.createTable(new HsqlTableDescriptor("abc", new HsqlColumnDescriptor[] + { + new HsqlColumnDescriptor("a", "VARCHAR(50)"), + new HsqlColumnDescriptor("b", "VARCHAR(50)"), + new HsqlColumnDescriptor("c", "VARCHAR(50)") + })); + + // load the old document, and verify there is *no* table therein + impl_switchToDocument(oldDocumentURL); + m_documentUI.connect(); + assertTrue("could not connect to " + m_database.getDocumentURL(), m_documentUI.isConnected()); + XTablesSupplier suppTables = UnoRuntime.queryInterface( XTablesSupplier.class, m_documentUI.getActiveConnection() ); + XNameAccess tables = suppTables.getTables(); + assertTrue("the table was created in the wrong database", !tables.hasByName("abc")); + + // load the new document, and verify there *is* a table therein + impl_switchToDocument(newDocumentURL); + m_documentUI.connect(); + assertTrue("could not connect to " + m_database.getDocumentURL(), m_documentUI.isConnected()); + + suppTables = UnoRuntime.queryInterface( XTablesSupplier.class, m_documentUI.getActiveConnection() ); + tables = suppTables.getTables(); + assertTrue("the newly created table has not been written", tables.hasByName("abc")); + } +} diff --git a/dbaccess/qa/complex/dbaccess/Beamer.java b/dbaccess/qa/complex/dbaccess/Beamer.java new file mode 100644 index 000000000..3342c70df --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/Beamer.java @@ -0,0 +1,127 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.beans.PropertyState; +import com.sun.star.beans.PropertyValue; +import com.sun.star.container.XEnumeration; +import com.sun.star.frame.FrameSearchFlag; +import com.sun.star.frame.XComponentLoader; +import com.sun.star.frame.XController; +import com.sun.star.frame.XDispatch; +import com.sun.star.frame.XDispatchProvider; +import com.sun.star.frame.XFrame; +import com.sun.star.frame.XGlobalEventBroadcaster; +import com.sun.star.frame.XModel; +import com.sun.star.frame.theGlobalEventBroadcaster; +import com.sun.star.lang.XComponent; +import com.sun.star.sdb.CommandType; +import com.sun.star.uno.Exception; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.URL; +import com.sun.star.util.XURLTransformer; +import com.sun.star.view.XSelectionSupplier; +// ---------- junit imports ----------------- +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + + + +/** complex test case for Base's application UI + */ +public class Beamer extends TestCase +{ + + private XModel docModel; + + @Before + @Override + public void before() throws Exception, java.lang.Exception + { + // load it into a frame + final Object object = getMSF().createInstance("com.sun.star.frame.Desktop"); + final XComponentLoader xComponentLoader = UnoRuntime.queryInterface(XComponentLoader.class, object); + final XComponent loadedComponent = xComponentLoader.loadComponentFromURL("private:factory/swriter", "_blank", 0, new PropertyValue[0]); + // get the controller, which provides access to various UI operations + docModel = UnoRuntime.queryInterface(XModel.class, loadedComponent); + } + + + @After + @Override + public void after() + { + } + + + @Test + public void testBeamer() throws Exception, java.lang.Exception + { + final XController controller = docModel.getCurrentController(); + final XFrame frame = controller.getFrame(); + final XDispatchProvider dispatchP = UnoRuntime.queryInterface(XDispatchProvider.class, frame); + URL command = new URL(); + command.Complete = ".uno:ViewDataSourceBrowser"; + + Object instance = getMSF().createInstance("com.sun.star.util.URLTransformer"); + XURLTransformer atrans = UnoRuntime.queryInterface(XURLTransformer.class, instance); + com.sun.star.util.URL[] aURLA = new com.sun.star.util.URL[1]; + aURLA[0] = command; + atrans.parseStrict(aURLA); + command = aURLA[0]; + + final XDispatch dispatch = dispatchP.queryDispatch(command, "_self", FrameSearchFlag.AUTO); + assertNotNull(dispatch); + dispatch.dispatch(command, new PropertyValue[0]); + + final PropertyValue[] props = new PropertyValue[] + { + new PropertyValue("DataSourceName", 0, "Bibliography", PropertyState.DIRECT_VALUE), + new PropertyValue("CommandType", 0, Integer.valueOf(CommandType.TABLE), PropertyState.DIRECT_VALUE), + new PropertyValue("Command", 0, "biblio", PropertyState.DIRECT_VALUE) + }; + + final XFrame beamer = frame.findFrame("_beamer", 0); + assertNotNull(beamer); + final XGlobalEventBroadcaster evtBc = theGlobalEventBroadcaster.get( + getComponentContext()); + XEnumeration enumeration = evtBc.createEnumeration(); + int count = -1; + while (enumeration.hasMoreElements()) + { + enumeration.nextElement(); + ++count; + } + final XSelectionSupplier selSup = UnoRuntime.queryInterface(XSelectionSupplier.class, beamer.getController()); + selSup.select(props); + final com.sun.star.util.XCloseable close = UnoRuntime.queryInterface(com.sun.star.util.XCloseable.class, frame); + close.close(false); + + enumeration = evtBc.createEnumeration(); + int count2 = 0; + while (enumeration.hasMoreElements()) + { + enumeration.nextElement(); + ++count2; + } + + assertTrue("count1 = " + count + " count2 = " + count2, count == count2); + } +} diff --git a/dbaccess/qa/complex/dbaccess/CRMBasedTestCase.java b/dbaccess/qa/complex/dbaccess/CRMBasedTestCase.java new file mode 100644 index 000000000..a61ffdfa7 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/CRMBasedTestCase.java @@ -0,0 +1,63 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.sdb.XSingleSelectQueryComposer; +import connectivity.tools.CRMDatabase; + +// ---------- junit imports ----------------- +import org.junit.After; +import org.junit.Before; + + +public abstract class CRMBasedTestCase extends TestCase +{ + protected CRMDatabase m_database; + + protected void createTestCase() throws Exception + { + m_database = new CRMDatabase( getMSF(), false ); + } + + + @Before + @Override + public void before() throws Exception + { + createTestCase(); + } + + + @After + @Override + public void after() throws Exception + { + if ( m_database != null ) + { + m_database.saveAndClose(); + } + } + + + /** creates a SingleSelectQueryComposer for our connection + */ + protected final XSingleSelectQueryComposer createQueryComposer() throws com.sun.star.uno.Exception + { + return m_database.getConnection().createSingleSelectQueryComposer(); + } +} diff --git a/dbaccess/qa/complex/dbaccess/CopyTableInterActionHandler.java b/dbaccess/qa/complex/dbaccess/CopyTableInterActionHandler.java new file mode 100644 index 000000000..57f4172e3 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/CopyTableInterActionHandler.java @@ -0,0 +1,37 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.lib.uno.helper.WeakBase; +import com.sun.star.task.XInteractionHandler; +import com.sun.star.task.XInteractionRequest; + +import static org.junit.Assert.*; + +class CopyTableInterActionHandler extends WeakBase + implements XInteractionHandler +{ + CopyTableInterActionHandler() + { + } + + public void handle(XInteractionRequest xRequest) + { + fail( "interaction handler is not expected to be called" ); + } +} diff --git a/dbaccess/qa/complex/dbaccess/CopyTableWizard.java b/dbaccess/qa/complex/dbaccess/CopyTableWizard.java new file mode 100644 index 000000000..a9254fac3 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/CopyTableWizard.java @@ -0,0 +1,194 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.accessibility.XAccessible; +import com.sun.star.accessibility.XAccessibleContext; +import com.sun.star.awt.XExtendedToolkit; +import com.sun.star.awt.XWindow; +import com.sun.star.beans.Optional; +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.XNameAccess; +import com.sun.star.sdb.CommandType; +import com.sun.star.sdb.application.XCopyTableWizard; +import com.sun.star.sdb.DataAccessDescriptorFactory; +import com.sun.star.sdbc.XConnection; +import com.sun.star.sdbcx.XTablesSupplier; +import com.sun.star.task.XInteractionHandler; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import connectivity.tools.DbaseDatabase; +import java.io.IOException; +import util.UITools; + +// ---------- junit imports ----------------- +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + + +/** complex test case for Base's application UI + */ +public class CopyTableWizard extends CRMBasedTestCase +{ + + private DatabaseApplication source; + private DbaseDatabase destinationDB = null; + private DatabaseApplication dest; + + @After + @Override + public void after() throws Exception + { + dest.store(); + if ( destinationDB != null ) + destinationDB.close(); + destinationDB = null; + super.after(); + } + + @Before + @Override + public void before() throws Exception + { + createTestCase(); + source = new DatabaseApplication(m_database.getDatabase()); + destinationDB = new DbaseDatabase( getMSF() ); + dest = new DatabaseApplication( destinationDB ); + } + + + private static class CopyThread implements Runnable + { + + private final XCopyTableWizard copyWizard; + + private CopyThread(final XCopyTableWizard copyWizard) + { + this.copyWizard = copyWizard; + } + + public void run() + { + copyWizard.execute(); + } + } + + private XWindow getActiveWindow() + { + Object toolKit = null; + try + { + toolKit = getMSF().createInstance("com.sun.star.awt.Toolkit"); + } + catch (com.sun.star.uno.Exception e) + { + return null; + } + + XExtendedToolkit tk = UnoRuntime.queryInterface( XExtendedToolkit.class, toolKit ); + Object atw = tk.getActiveTopWindow(); + return UnoRuntime.queryInterface( XWindow.class, atw ); + } + + @Test + public void copyTable() throws Exception, IOException, java.lang.Exception + { + copyTable(source,source); + } + + @Test + public void copyTableDbase() throws Exception, IOException, java.lang.Exception + { + copyTable(source,dest); + } + private void copyTable(final DatabaseApplication sourceDb,final DatabaseApplication destDb) throws Exception, IOException, java.lang.Exception + { + final XConnection destConnection = destDb.getDocumentUI().getActiveConnection(); + + final XConnection sourceConnection = sourceDb.getDocumentUI().getActiveConnection(); + final XTablesSupplier suppTables = UnoRuntime.queryInterface(XTablesSupplier.class, sourceConnection); + final XNameAccess tables = suppTables.getTables(); + + final String[] names = tables.getElementNames(); + for (int i = 0; i < names.length; i++) + { + copyTable(names[i], sourceConnection, destConnection); + } + } + + private void copyTable(final String tableName, final XConnection sourceConnection, final XConnection destConnection) throws Exception, java.lang.Exception + { + + final XInteractionHandler interAction = new CopyTableInterActionHandler(); + final XComponentContext context = getComponentContext(); + final XPropertySet sourceDescriptor = DataAccessDescriptorFactory.get(context).createDataAccessDescriptor(); + sourceDescriptor.setPropertyValue("CommandType", CommandType.TABLE); + sourceDescriptor.setPropertyValue("Command", tableName); + sourceDescriptor.setPropertyValue("ActiveConnection", sourceConnection); + + final XPropertySet destDescriptor = DataAccessDescriptorFactory.get(context).createDataAccessDescriptor(); + destDescriptor.setPropertyValue("ActiveConnection", destConnection); + + final XCopyTableWizard copyWizard = com.sun.star.sdb.application.CopyTableWizard.createWithInteractionHandler( + context, sourceDescriptor, destDescriptor, interAction); + copyWizard.setOperation((short) 0); // com.sun.star.sdb.application.CopyDefinitionAndData + Optional auto = new Optional(); + + auto.IsPresent = destConnection.getMetaData().supportsCoreSQLGrammar(); + if (auto.IsPresent) + { + auto.Value = "ID_test"; + } + copyWizard.setCreatePrimaryKey(auto); + Thread thread = new Thread(new CopyThread(copyWizard)); + thread.start(); + util.utils.shortWait(); + + try + { + final XWindow dialog = getActiveWindow(); + final UITools uiTools = new UITools(dialog); + final XAccessible root = uiTools.getRoot(); + final XAccessibleContext accContext = root.getAccessibleContext(); + final int count = accContext.getAccessibleChildCount(); + String buttonName = "Create"; + final XAccessibleContext childContext = accContext.getAccessibleChild(count - 3).getAccessibleContext(); + final String name = childContext.getAccessibleName(); + if (name != null && !"".equals(name)) + { + buttonName = name; + } + try + { + uiTools.clickButton(buttonName); + } + catch (java.lang.Exception exception) + { + exception.printStackTrace( System.err ); + } + } + catch (com.sun.star.lang.IndexOutOfBoundsException indexOutOfBoundsException) + { + } + util.utils.shortWait(); + + thread.join(); + } + +} diff --git a/dbaccess/qa/complex/dbaccess/DataSource.java b/dbaccess/qa/complex/dbaccess/DataSource.java new file mode 100644 index 000000000..0413a6e07 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/DataSource.java @@ -0,0 +1,68 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.container.XNameAccess; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XNamingService; +import connectivity.tools.CRMDatabase; +import connectivity.tools.HsqlDatabase; + +// ---------- junit imports ----------------- +import org.junit.Test; +import static org.junit.Assert.*; + + + +public class DataSource extends TestCase +{ + + HsqlDatabase m_database; + connectivity.tools.DataSource m_dataSource; + + + private void createTestCase() throws Exception + { + if (m_database == null) + { + final CRMDatabase database = new CRMDatabase( getMSF(), false ); + m_database = database.getDatabase(); + m_dataSource = m_database.getDataSource(); + } + } + + + @Test + public void testRegistrationName() throws Exception + { + createTestCase(); + // 1. check the existing "Bibliography" data source whether it has the proper name + String dataSourceName = "Bibliography"; + final connectivity.tools.DataSource bibliography = new connectivity.tools.DataSource(getMSF(), dataSourceName); + assertEquals("pre-registered database has a wrong name!", dataSourceName, bibliography.getName()); + // 2. register a newly created data source, and verify it has the proper name + dataSourceName = "someDataSource"; + final XNamingService dataSourceRegistrations = UnoRuntime.queryInterface( + XNamingService.class, getMSF().createInstance( "com.sun.star.sdb.DatabaseContext" ) ); + final XNameAccess existenceCheck = UnoRuntime.queryInterface( XNameAccess.class, dataSourceRegistrations ); + if ( existenceCheck.hasByName( "someDataSource" ) ) + dataSourceRegistrations.revokeObject( "someDataSource" ); + dataSourceRegistrations.registerObject("someDataSource", m_dataSource.getXDataSource()); + assertEquals("registration name of a newly registered data source is wrong", dataSourceName, m_dataSource.getName()); + } +} diff --git a/dbaccess/qa/complex/dbaccess/DatabaseApplication.java b/dbaccess/qa/complex/dbaccess/DatabaseApplication.java new file mode 100644 index 000000000..dad7644f8 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/DatabaseApplication.java @@ -0,0 +1,73 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.beans.PropertyValue; +import com.sun.star.frame.FrameSearchFlag; +import com.sun.star.frame.XComponentLoader; +import com.sun.star.frame.XModel; +import com.sun.star.frame.XStorable; +import com.sun.star.lang.XComponent; +import com.sun.star.sdb.XOfficeDatabaseDocument; +import com.sun.star.sdb.application.XDatabaseDocumentUI; +import com.sun.star.uno.Exception; +import com.sun.star.uno.UnoRuntime; +import connectivity.tools.DatabaseAccess; + +public class DatabaseApplication +{ + + private final XOfficeDatabaseDocument databaseDocument; + private final XDatabaseDocumentUI documentUI; + + public DatabaseApplication(final DatabaseAccess _db) throws Exception + { + databaseDocument = _db.getDatabaseDocument(); + + // load it into a frame + final Object object = _db.getORB().createInstance("com.sun.star.frame.Desktop"); + final XComponentLoader xComponentLoader = UnoRuntime.queryInterface(XComponentLoader.class, object); + final XComponent loadedComponent = xComponentLoader.loadComponentFromURL(_db.getDocumentURL(), "_blank", FrameSearchFlag.ALL, new PropertyValue[0]); + + // get the controller, which provides access to various UI operations + final XModel docModel = UnoRuntime.queryInterface(XModel.class, loadedComponent); + documentUI = UnoRuntime.queryInterface(XDatabaseDocumentUI.class, docModel.getCurrentController()); + documentUI.connect(); + } + + public XDatabaseDocumentUI getDocumentUI() + { + return documentUI; + } + + public void store() + { + // store the doc in a new location + try + { + final XStorable storeDoc = UnoRuntime.queryInterface(XStorable.class, databaseDocument); + if (storeDoc != null) + { + storeDoc.store(); + } + } + catch (com.sun.star.io.IOException iOException) + { + } + } +} diff --git a/dbaccess/qa/complex/dbaccess/DatabaseDocument.java b/dbaccess/qa/complex/dbaccess/DatabaseDocument.java new file mode 100644 index 000000000..5bd28053b --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/DatabaseDocument.java @@ -0,0 +1,995 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.configuration.theDefaultProvider; +import com.sun.star.lang.NotInitializedException; +import com.sun.star.frame.DoubleInitializationException; +import com.sun.star.awt.XTopWindow; +import com.sun.star.beans.PropertyState; +import com.sun.star.document.DocumentEvent; +import com.sun.star.lang.XEventListener; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.script.XStorageBasedLibraryContainer; +import com.sun.star.task.XInteractionRequest; + +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.frame.XStorable; +import com.sun.star.beans.NamedValue; +import com.sun.star.beans.PropertyValue; +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.XNameContainer; +import com.sun.star.container.XSet; +import com.sun.star.document.XDocumentEventListener; +import com.sun.star.document.XEmbeddedScripts; +import com.sun.star.document.XEventsSupplier; +import com.sun.star.lang.XComponent; +import com.sun.star.frame.XComponentLoader; +import com.sun.star.frame.XDispatch; +import com.sun.star.frame.XDispatchProvider; +import com.sun.star.frame.XFrame; +import com.sun.star.frame.XGlobalEventBroadcaster; +import com.sun.star.frame.XLoadable; +import com.sun.star.frame.XModel; +import com.sun.star.frame.XModel2; +import com.sun.star.frame.XTitle; +import com.sun.star.frame.theGlobalEventBroadcaster; +import com.sun.star.lang.EventObject; +import com.sun.star.lang.XServiceInfo; +import com.sun.star.lang.XSingleComponentFactory; +import com.sun.star.lang.XTypeProvider; +import com.sun.star.script.provider.XScriptProviderSupplier; +import com.sun.star.sdb.XDocumentDataSource; + +import com.sun.star.sdb.XFormDocumentsSupplier; +import com.sun.star.sdb.XOfficeDatabaseDocument; +import com.sun.star.sdb.XReportDocumentsSupplier; +import com.sun.star.task.DocumentMacroConfirmationRequest; +import com.sun.star.task.XInteractionApprove; +import com.sun.star.task.XInteractionContinuation; +import com.sun.star.task.XInteractionHandler; +import com.sun.star.uno.XComponentContext; +import com.sun.star.util.CloseVetoException; +import com.sun.star.util.URL; +import com.sun.star.util.XChangesBatch; +import com.sun.star.util.XCloseable; +import com.sun.star.util.XModifiable; +import com.sun.star.util.XURLTransformer; +import java.io.IOException; +import java.util.Iterator; +import java.util.ArrayList; +import java.util.logging.Level; +import java.util.logging.Logger; + +// ---------- junit imports ----------------- +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + + +public class DatabaseDocument extends TestCase implements com.sun.star.document.XDocumentEventListener +{ + + private static final String _BLANK = "_blank"; + private XComponent m_callbackFactory = null; + private final ArrayList m_documentEvents = new ArrayList(); + private final ArrayList m_globalEvents = new ArrayList(); + // for those states, see testDocumentEvents + private static short STATE_NOT_STARTED = 0; + private static short STATE_LOADING_DOC = 1; + private static short STATE_MACRO_EXEC_APPROVED = 2; + private static short STATE_ON_LOAD_RECEIVED = 3; + private short m_loadDocState = STATE_NOT_STARTED; + + + /** a helper class which can be used by the Basic scripts in our test documents + * to notify us of events in this document + */ + private class CallbackComponent implements XDocumentEventListener, XTypeProvider + { + + public void documentEventOccured(DocumentEvent _event) + { + onDocumentEvent(_event); + } + + public void disposing(com.sun.star.lang.EventObject _Event) + { + // not interested in + } + + public Type[] getTypes() + { + final Class interfaces[] = getClass().getInterfaces(); + Type types[] = new Type[interfaces.length]; + for (int i = 0; i < interfaces.length; ++i) + { + types[i] = new Type(interfaces[i]); + } + return types; + } + + public byte[] getImplementationId() + { + return new byte[0]; + } + } + + + private static String getCallbackComponentServiceName() + { + return "org.openoffice.complex.dbaccess.EventCallback"; + } + + + /** a factory for a CallbackComponent + */ + private class CallbackComponentFactory implements XSingleComponentFactory, XServiceInfo, XComponent + { + + private final ArrayList m_eventListeners = new ArrayList(); + + public Object createInstanceWithContext(XComponentContext _context) throws com.sun.star.uno.Exception + { + return new CallbackComponent(); + } + + public Object createInstanceWithArgumentsAndContext(Object[] arg0, XComponentContext _context) throws com.sun.star.uno.Exception + { + return createInstanceWithContext(_context); + } + + public String getImplementationName() + { + return "org.openoffice.complex.dbaccess.CallbackComponent"; + } + + public boolean supportsService(String _service) + { + return _service.equals(getCallbackComponentServiceName()); + } + + public String[] getSupportedServiceNames() + { + return new String[] + { + getCallbackComponentServiceName() + }; + } + + public void dispose() + { + final EventObject event = new EventObject(this); + + final ArrayList eventListenersCopy = (ArrayList)m_eventListeners.clone(); + final Iterator iter = eventListenersCopy.iterator(); + while (iter.hasNext()) + { + iter.next().disposing(event); + } + } + + public void addEventListener(XEventListener _listener) + { + if (_listener != null) + { + m_eventListeners.add(_listener); + } + } + + public void removeEventListener(XEventListener _listener) + { + m_eventListeners.remove(_listener); + } + } + + + private class MacroExecutionApprove implements XInteractionHandler + { + + private XInteractionHandler m_defaultHandler = null; + + MacroExecutionApprove(XMultiServiceFactory _factory) + { + try + { + m_defaultHandler = UnoRuntime.queryInterface(XInteractionHandler.class, _factory.createInstance("com.sun.star.task.InteractionHandler")); + } + catch (Exception ex) + { + Logger.getLogger(DatabaseDocument.class.getName()).log(Level.SEVERE, null, ex); + } + } + + public void handle(XInteractionRequest _request) + { + final Object request = _request.getRequest(); + if (!(request instanceof DocumentMacroConfirmationRequest) && (m_defaultHandler != null)) + { + m_defaultHandler.handle(_request); + return; + } + + assertEquals("interaction handler called in wrong state", STATE_LOADING_DOC, m_loadDocState); + + // auto-approve + final XInteractionContinuation continuations[] = _request.getContinuations(); + for (int i = 0; i < continuations.length; ++i) + { + final XInteractionApprove approve = UnoRuntime.queryInterface(XInteractionApprove.class, continuations[i]); + if (approve != null) + { + approve.select(); + m_loadDocState = STATE_MACRO_EXEC_APPROVED; + break; + } + } + } + } + + + + @Override + @Before + public void before() throws java.lang.Exception + { + super.before(); + + try + { + // at our service factory, insert a new factory for our CallbackComponent + // this will allow the Basic code in our test documents to call back into this test case + // here, by just instantiating this service + final XSet globalFactory = UnoRuntime.queryInterface(XSet.class, getMSF()); + m_callbackFactory = new CallbackComponentFactory(); + globalFactory.insert(m_callbackFactory); + + // register ourself as listener at the global event broadcaster + final XGlobalEventBroadcaster broadcaster + = theGlobalEventBroadcaster.get(getComponentContext()); + broadcaster.addDocumentEventListener(this); + } + catch (Exception e) + { + System.out.println("could not create the test case, error message:\n" + e.getMessage()); + e.printStackTrace(System.err); + fail("failed to create the test case"); + } + } + + + @Override + @After + public void after() throws java.lang.Exception + { + try + { + // dispose our callback factory. This will automatically remove it from our service + // factory + m_callbackFactory.dispose(); + + // revoke ourself as listener at the global event broadcaster + final XGlobalEventBroadcaster broadcaster + = theGlobalEventBroadcaster.get(getComponentContext()); + broadcaster.removeDocumentEventListener(this); + } + catch (Exception e) + { + System.out.println("could not create the test case, error message:\n" + e.getMessage()); + e.printStackTrace(System.err); + fail("failed to close the test case"); + } + + super.after(); + } + + + private static class UnoMethodDescriptor + { + + public Class unoInterfaceClass = null; + public String methodName = null; + + UnoMethodDescriptor(Class _class, String _method) + { + unoInterfaceClass = _class; + methodName = _method; + } + } + + + private void impl_checkDocumentInitState(Object _document, boolean _isInitialized) + { + // things you cannot do with an uninitialized document: + final UnoMethodDescriptor[] unsupportedMethods = new UnoMethodDescriptor[] + { + new UnoMethodDescriptor(XStorable.class, "store"), + new UnoMethodDescriptor(XFormDocumentsSupplier.class, "getFormDocuments"), + new UnoMethodDescriptor(XReportDocumentsSupplier.class, "getReportDocuments"), + new UnoMethodDescriptor(XScriptProviderSupplier.class, "getScriptProvider"), + new UnoMethodDescriptor(XEventsSupplier.class, "getEvents"), + new UnoMethodDescriptor(XTitle.class, "getTitle"), + new UnoMethodDescriptor(XModel2.class, "getControllers") + // (there's much more than this, but we cannot list all methods here, can we ...) + }; + + for (int i = 0; i < unsupportedMethods.length; ++i) + { + assureException( _document, unsupportedMethods[i].unoInterfaceClass, + unsupportedMethods[i].methodName, new Object[]{}, _isInitialized ? null : NotInitializedException.class ); + } + } + + + private XModel impl_createDocument() throws Exception + { + final XModel databaseDoc = UnoRuntime.queryInterface(XModel.class, getMSF().createInstance("com.sun.star.sdb.OfficeDatabaseDocument")); + + // should not be initialized here - we did neither initNew nor load nor storeAsURL it + impl_checkDocumentInitState(databaseDoc, false); + + return databaseDoc; + } + + + private void impl_closeDocument(XModel _databaseDoc) throws CloseVetoException, Exception + { + final XCloseable closeDoc = UnoRuntime.queryInterface(XCloseable.class, _databaseDoc); + closeDoc.close(true); + } + + + private XModel impl_createEmptyEmbeddedHSQLDocument() throws Exception, IOException + { + final XModel databaseDoc = UnoRuntime.queryInterface(XModel.class, getMSF().createInstance("com.sun.star.sdb.OfficeDatabaseDocument")); + final XStorable storeDoc = UnoRuntime.queryInterface(XStorable.class, databaseDoc); + + // verify the document rejects API calls which require it to be initialized + impl_checkDocumentInitState(databaseDoc, false); + + // though the document is not initialized, you can ask for the location, the URL, and the args + final String location = storeDoc.getLocation(); + final String url = databaseDoc.getURL(); + final PropertyValue[] args = databaseDoc.getArgs(); + // they should be all empty at this time + assertEquals("location is expected to be empty here", "", location); + assertEquals("URL is expected to be empty here", "", url); + assertEquals("Args are expected to be empty here", 0, args.length); + + // and, you should be able to set properties at the data source + final XOfficeDatabaseDocument dataSourceAccess = UnoRuntime.queryInterface(XOfficeDatabaseDocument.class, databaseDoc); + final XPropertySet dsProperties = UnoRuntime.queryInterface(XPropertySet.class, dataSourceAccess.getDataSource()); + dsProperties.setPropertyValue("URL", "sdbc:embedded:hsqldb"); + + final String documentURL = createTempFileURL(); + storeDoc.storeAsURL(documentURL, new PropertyValue[0]); + + // now that the document is stored, ... + // ... its URL should be correct + assertEquals("wrong URL after storing the document", documentURL, databaseDoc.getURL()); + // ... it should be initialized + impl_checkDocumentInitState(databaseDoc, true); + + return databaseDoc; + } + + + @Test + public void testLoadable() throws Exception, IOException + { + XModel databaseDoc = impl_createEmptyEmbeddedHSQLDocument(); + String documentURL = databaseDoc.getURL(); + + // there's three methods how you can initialize a database document: + + + // 1. XStorable::storeAsURL + // (this is for compatibility reasons, to not break existing code) + // this test is already made in impl_createEmptyEmbeddedHSQLDocument + + + // 2. XLoadable::load + databaseDoc = UnoRuntime.queryInterface(XModel.class, getMSF().createInstance("com.sun.star.sdb.OfficeDatabaseDocument")); + documentURL = copyToTempFile(documentURL); + // load the doc, and verify it's initialized then, and has the proper URL + XLoadable loadDoc = UnoRuntime.queryInterface(XLoadable.class, databaseDoc); + loadDoc.load(new PropertyValue[] + { + new PropertyValue("URL", 0, documentURL, PropertyState.DIRECT_VALUE) + }); + databaseDoc.attachResource(documentURL, new PropertyValue[0]); + + assertEquals("wrong URL after loading the document", documentURL, databaseDoc.getURL()); + impl_checkDocumentInitState(databaseDoc, true); + + // and while we are here ... initializing the same document again should not be possible + assureException( databaseDoc, XLoadable.class, "initNew", new Object[0], + DoubleInitializationException.class ); + assureException( databaseDoc, XLoadable.class, "load", new Object[] { new PropertyValue[0] }, + DoubleInitializationException.class ); + + + // 3. XLoadable::initNew + impl_closeDocument(databaseDoc); + databaseDoc = impl_createDocument(); + loadDoc = UnoRuntime.queryInterface(XLoadable.class, databaseDoc); + loadDoc.initNew(); + assertEquals("wrong URL after initializing the document", "", databaseDoc.getURL()); + impl_checkDocumentInitState(databaseDoc, true); + + // same as above - initializing the document a second time must fail + assureException( databaseDoc, XLoadable.class, "initNew", new Object[0], + DoubleInitializationException.class ); + assureException( databaseDoc, XLoadable.class, "load", new Object[] { new PropertyValue[0] }, + DoubleInitializationException.class ); + } + + + private PropertyValue[] impl_getMarkerLoadArgs() + { + return new PropertyValue[] + { + new PropertyValue( "PickListEntry", 0, false, PropertyState.DIRECT_VALUE ), + new PropertyValue( "TestCase_Marker", 0, "Yes", PropertyState.DIRECT_VALUE ) + }; + } + + + private boolean impl_hasMarker( final PropertyValue[] _args ) + { + for ( int i=0; i<_args.length; ++i ) + { + if ( _args[i].Name.equals( "TestCase_Marker" ) && _args[i].Value.equals( "Yes" ) ) + { + return true; + } + } + return false; + } + + + private PropertyValue[] impl_getDefaultLoadArgs() + { + return new PropertyValue[] + { + new PropertyValue("PickListEntry", 0, false, PropertyState.DIRECT_VALUE) + }; + } + + + private PropertyValue[] impl_getMacroExecLoadArgs() + { + return new PropertyValue[] + { + new PropertyValue("PickListEntry", 0, false, PropertyState.DIRECT_VALUE), + new PropertyValue("MacroExecutionMode", 0, com.sun.star.document.MacroExecMode.USE_CONFIG, PropertyState.DIRECT_VALUE), + new PropertyValue("InteractionHandler", 0, new MacroExecutionApprove(getMSF()), PropertyState.DIRECT_VALUE) + }; + } + + + private int impl_setMacroSecurityLevel(int _level) throws Exception + { + final XMultiServiceFactory configProvider = theDefaultProvider.get( + getComponentContext()); + + final NamedValue[] args = new NamedValue[] + { + new NamedValue("nodepath", "/org.openoffice.Office.Common/Security/Scripting") + }; + + final XPropertySet securitySettings = UnoRuntime.queryInterface(XPropertySet.class, configProvider.createInstanceWithArguments("com.sun.star.configuration.ConfigurationUpdateAccess", args)); + final int oldValue = ((Integer) securitySettings.getPropertyValue("MacroSecurityLevel")).intValue(); + securitySettings.setPropertyValue("MacroSecurityLevel", Integer.valueOf(_level)); + + final XChangesBatch committer = UnoRuntime.queryInterface(XChangesBatch.class, securitySettings); + committer.commitChanges(); + + return oldValue; + } + + + private XModel impl_loadDocument( final String _documentURL, final PropertyValue[] _loadArgs ) throws Exception + { + final XComponentLoader loader = UnoRuntime.queryInterface(XComponentLoader.class, getMSF().createInstance("com.sun.star.frame.Desktop")); + return UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(_documentURL, _BLANK, 0, _loadArgs)); + } + + + private void impl_storeDocument( final XModel _document ) throws Exception + { + // store the document + FileHelper.getOOoCompatibleFileURL( _document.getURL() ); + final XStorable storeDoc = UnoRuntime.queryInterface(XStorable.class, _document); + storeDoc.store(); + + } + + + private XModel impl_createDocWithMacro( final String _libName, final String _moduleName, final String _code ) throws Exception, IOException + { + // create an empty document + XModel databaseDoc = impl_createEmptyEmbeddedHSQLDocument(); + + // create Basic library/module therein + final XEmbeddedScripts embeddedScripts = UnoRuntime.queryInterface(XEmbeddedScripts.class, databaseDoc); + final XStorageBasedLibraryContainer basicLibs = embeddedScripts.getBasicLibraries(); + final XNameContainer newLib = basicLibs.createLibrary( _libName ); + newLib.insertByName( _moduleName, _code ); + + return databaseDoc; + } + + + /** Tests various aspects of database document "revenants" + * + * Well, I do not really have a good term for this... The point is, database documents are in real + * only *one* aspect of a more complex thing. The second aspect is a data source. Both, in some sense, + * just represent different views on the same thing. For a given database, there's at each time at most + * one data source, and at most one database document. Both have an independent life time, and are + * created when needed. + * In particular, a document can be closed (this is what happens when the last UI window displaying + * this document is closed), and then dies. Now when the other "view", the data source, still exists, + * the underlying document data is not discarded, but kept alive (else the data source would die + * just because the document dies, which is not desired). If the document is loaded, again, then + * it is re-created, using the data of its previous "incarnation". + * + * This method here tests some of those aspects of a document which should survive the death of one + * instance and re-creation as a revenant. + */ + @Test + public void testDocumentRevenants() throws Exception, IOException + { + // create an empty document + XModel databaseDoc = impl_createDocWithMacro( "Lib", "Module", + "Sub Hello\n" + + " MsgBox \"Hello\"\n" + + "End Sub\n" + ); + impl_storeDocument( databaseDoc ); + final String documentURL = databaseDoc.getURL(); + + // at this stage, the marker should not yet be present in the doc's args, else some of the below + // tests become meaningless + assertTrue( "A newly created doc should not have the test case marker", !impl_hasMarker( databaseDoc.getArgs() ) ); + + // obtain the DataSource associated with the document. Keeping this alive + // ensures that the "impl data" of the document is kept alive, too, so when closing + // and re-opening it, this "impl data" must be re-used. + XDocumentDataSource dataSource = UnoRuntime.queryInterface(XDocumentDataSource.class, UnoRuntime.queryInterface(XOfficeDatabaseDocument.class, databaseDoc).getDataSource()); + + // close and reload the doc + impl_closeDocument(databaseDoc); + databaseDoc = impl_loadDocument( documentURL, impl_getMarkerLoadArgs() ); + // since we just put the marker into the load-call, it should be present at the doc + assertTrue( "The test case marker got lost.", impl_hasMarker( databaseDoc.getArgs() ) ); + + // The basic library should have survived + final XEmbeddedScripts embeddedScripts = UnoRuntime.queryInterface(XEmbeddedScripts.class, databaseDoc); + final XStorageBasedLibraryContainer basicLibs = embeddedScripts.getBasicLibraries(); + assertTrue( "Basic lib did not survive reloading a closed document", basicLibs.hasByName( "Lib" ) ); + final XNameContainer lib = UnoRuntime.queryInterface(XNameContainer.class, basicLibs.getByName("Lib")); + assertTrue( "Basic module did not survive reloading a closed document", lib.hasByName( "Module" ) ); + + // now closing the doc, and obtaining it from the data source, should preserve the marker we put into the load + // args + impl_closeDocument( databaseDoc ); + databaseDoc = UnoRuntime.queryInterface(XModel.class, dataSource.getDatabaseDocument()); + assertTrue( "The test case marker did not survive re-retrieval of the doc from the data source.", + impl_hasMarker( databaseDoc.getArgs() ) ); + + // on the other hand, closing and regularly re-loading the doc *without* the marker should indeed + // lose it + impl_closeDocument( databaseDoc ); + databaseDoc = impl_loadDocument( documentURL, impl_getDefaultLoadArgs() ); + assertTrue( "Reloading the document kept the old args, instead of the newly supplied ones.", + !impl_hasMarker( databaseDoc.getArgs() ) ); + + // clean up + impl_closeDocument( databaseDoc ); + } + + + @Test + public void testDocumentEvents() throws Exception, IOException + { + // create an empty document + final String libName = "EventHandlers"; + final String moduleName = "all"; + final String eventHandlerCode = + "Option Explicit\n" + + "\n" + + "Sub OnLoad\n" + + " Dim oCallback as Object\n" + + " oCallback = createUnoService( \"" + getCallbackComponentServiceName() + "\" )\n" + + "\n" + + " ' as long as the Document is not passed to the Basic callbacks, we need to create\n" + + " ' one ourself\n" + + " Dim oEvent as new com.sun.star.document.DocumentEvent\n" + + " oEvent.EventName = \"OnLoad\"\n" + + " oEvent.Source = ThisComponent\n" + + "\n" + + " oCallback.documentEventOccurred( oEvent )\n" + + "End Sub\n"; + XModel databaseDoc = impl_createDocWithMacro( libName, moduleName, eventHandlerCode ); + final String documentURL = databaseDoc.getURL(); + + // bind the macro to the OnLoad event + final String macroURI = "vnd.sun.star.script:" + libName + "." + moduleName + ".OnLoad?language=Basic&location=document"; + final XEventsSupplier eventsSupplier = UnoRuntime.queryInterface(XEventsSupplier.class, databaseDoc); + eventsSupplier.getEvents().replaceByName("OnLoad", new PropertyValue[] + { + new PropertyValue("EventType", 0, "Script", PropertyState.DIRECT_VALUE), + new PropertyValue("Script", 0, macroURI, PropertyState.DIRECT_VALUE) + }); + + // store the document, and close it + impl_storeDocument( databaseDoc ); + impl_closeDocument( databaseDoc ); + + // ensure the macro security configuration is "ask the user for document macro execution" + final int oldSecurityLevel = impl_setMacroSecurityLevel(1); + + // load it, again + m_loadDocState = STATE_LOADING_DOC; + // expected order of states is: + // STATE_LOADING_DOC - initialized here + // STATE_MACRO_EXEC_APPROVED - done in our interaction handler, which auto-approves the execution of macros + // STATE_ON_LOAD_RECEIVED - done in our callback for the document events + // + // In particular, it is important that the interaction handler (which plays the role of the user confirmation + // here) is called before the OnLoad notification is received - since the latter happens from within + // a Basic macro which is bound to the OnLoad event of the document. + + final String context = "OnLoad"; + impl_startObservingEvents(context); + databaseDoc = impl_loadDocument( documentURL, impl_getMacroExecLoadArgs() ); + impl_stopObservingEvents(m_documentEvents, new String[] + { + "OnLoad" + }, context); + + assertEquals("our provided interaction handler was not called", STATE_ON_LOAD_RECEIVED, m_loadDocState); + + // restore macro security level + impl_setMacroSecurityLevel(oldSecurityLevel); + + // close the document + impl_closeDocument(databaseDoc); + } + + + @Test + public void testGlobalEvents() throws Exception, IOException + { + XModel databaseDoc = impl_createEmptyEmbeddedHSQLDocument(); + final XStorable storeDoc = UnoRuntime.queryInterface(XStorable.class, databaseDoc); + + String context, newURL; + + // XStorable.store + final String oldURL = databaseDoc.getURL(); + context = "store"; + impl_startObservingEvents(context); + storeDoc.store(); + assertEquals("store is not expected to change the document URL", databaseDoc.getURL(), oldURL); + impl_stopObservingEvents(m_globalEvents, new String[] + { + "OnSave", "OnSaveDone" + }, context); + + // XStorable.storeToURL + context = "storeToURL"; + impl_startObservingEvents(context); + storeDoc.storeToURL(createTempFileURL(), new PropertyValue[0]); + assertEquals("storetoURL is not expected to change the document URL", databaseDoc.getURL(), oldURL); + impl_stopObservingEvents(m_globalEvents, new String[] + { + "OnSaveTo", "OnSaveToDone" + }, context); + + // XStorable.storeAsURL + newURL = createTempFileURL(); + context = "storeAsURL"; + impl_startObservingEvents(context); + storeDoc.storeAsURL(newURL, new PropertyValue[0]); + assertEquals("storeAsURL is expected to change the document URL", databaseDoc.getURL(), newURL); + impl_stopObservingEvents(m_globalEvents, new String[] + { + "OnSaveAs", "OnSaveAsDone" + }, context); + + // XModifiable.setModified + final XModifiable modifyDoc = UnoRuntime.queryInterface(XModifiable.class, databaseDoc); + context = "setModified"; + impl_startObservingEvents(context); + modifyDoc.setModified(true); + assertEquals("setModified didn't work", modifyDoc.isModified(), true); + impl_stopObservingEvents(m_globalEvents, new String[] + { + "OnModifyChanged" + }, context); + + // XStorable.store, with implicit reset of the "Modified" flag + context = "store (2)"; + impl_startObservingEvents(context); + storeDoc.store(); + assertEquals("'store' should implicitly reset the modified flag", modifyDoc.isModified(), false); + impl_stopObservingEvents(m_globalEvents, new String[] + { + "OnSave", "OnSaveDone", "OnModifyChanged" + }, context); + + // XComponentLoader.loadComponentFromURL + newURL = copyToTempFile(databaseDoc.getURL()); + final XComponentLoader loader = UnoRuntime.queryInterface(XComponentLoader.class, getMSF().createInstance("com.sun.star.frame.Desktop")); + context = "loadComponentFromURL"; + impl_startObservingEvents(context); + databaseDoc = UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(newURL, _BLANK, 0, impl_getDefaultLoadArgs())); + impl_stopObservingEvents(m_globalEvents, + new String[] + { + "OnLoadFinished", "OnViewCreated", "OnFocus", "OnLoad" + }, context); + + // closing a document by API + final XCloseable closeDoc = UnoRuntime.queryInterface(XCloseable.class, databaseDoc); + context = "close (API)"; + impl_startObservingEvents(context); + closeDoc.close(true); + impl_stopObservingEvents(m_globalEvents, + new String[] + { + "OnPrepareUnload", "OnViewClosed", "OnUnload" + }, context); + + // closing a document via UI + context = "close (UI)"; + impl_startObservingEvents("prepare for '" + context + "'"); + databaseDoc = UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(newURL, _BLANK, 0, impl_getDefaultLoadArgs())); + impl_waitForEvent(m_globalEvents, "OnLoad", 5000); + // wait for all events to arrive - OnLoad should be the last one + + final XDispatchProvider dispatchProvider = UnoRuntime.queryInterface(XDispatchProvider.class, databaseDoc.getCurrentController().getFrame()); + final URL url = impl_getURL(".uno:CloseDoc"); + final XDispatch dispatcher = dispatchProvider.queryDispatch(url, "", 0); + impl_startObservingEvents(context); + dispatcher.dispatch(url, new PropertyValue[0]); + impl_stopObservingEvents(m_globalEvents, + new String[] + { + "OnPrepareViewClosing", "OnViewClosed", "OnPrepareUnload", "OnUnload" + }, context); + + // creating a new document + databaseDoc = impl_createDocument(); + final XLoadable loadDoc = UnoRuntime.queryInterface(XLoadable.class, databaseDoc); + context = "initNew"; + impl_startObservingEvents(context); + loadDoc.initNew(); + impl_stopObservingEvents(m_globalEvents, new String[] + { + "OnCreate" + }, context); + + impl_startObservingEvents(context + " (cleanup)"); + impl_closeDocument(databaseDoc); + impl_waitForEvent(m_globalEvents, "OnUnload", 5000); + + // focus changes + context = "activation"; + // for this, load a database document ... + impl_startObservingEvents("prepare for '" + context + "'"); + databaseDoc = UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(newURL, _BLANK, 0, impl_getDefaultLoadArgs())); + final int previousOnLoadEventPos = impl_waitForEvent(m_globalEvents, "OnLoad", 5000); + // ... and another document ... + final String otherURL = copyToTempFile(databaseDoc.getURL()); + final XModel otherDoc = UnoRuntime.queryInterface(XModel.class, loader.loadComponentFromURL(otherURL, _BLANK, 0, impl_getDefaultLoadArgs())); + impl_raise(otherDoc); + impl_waitForEvent(m_globalEvents, "OnLoad", 5000, previousOnLoadEventPos + 1); + + // ... and switch between the two + impl_startObservingEvents(context); + impl_raise(databaseDoc); + impl_stopObservingEvents(m_globalEvents, new String[] + { + "OnUnfocus", "OnFocus" + }, context); + + // cleanup + impl_startObservingEvents("cleanup after '" + context + "'"); + impl_closeDocument(databaseDoc); + impl_closeDocument(otherDoc); + } + + + private URL impl_getURL(String _completeURL) throws Exception + { + final URL[] url = + { + new URL() + }; + url[0].Complete = _completeURL; + final XURLTransformer urlTransformer = UnoRuntime.queryInterface(XURLTransformer.class, getMSF().createInstance("com.sun.star.util.URLTransformer")); + urlTransformer.parseStrict(url); + return url[0]; + } + + + private void impl_raise(XModel _document) + { + final XFrame frame = _document.getCurrentController().getFrame(); + final XTopWindow topWindow = UnoRuntime.queryInterface(XTopWindow.class, frame.getContainerWindow()); + topWindow.toFront(); + } + + + private void impl_startObservingEvents(String _context) + { + System.out.println(" " + _context + " {"); + synchronized (m_documentEvents) + { + m_documentEvents.clear(); + } + synchronized (m_globalEvents) + { + m_globalEvents.clear(); + } + } + + + private void impl_stopObservingEvents(ArrayList _actualEvents, String[] _expectedEvents, String _context) + { + try + { + synchronized (_actualEvents) + { + int actualEventCount = _actualEvents.size(); + while (actualEventCount < _expectedEvents.length) + { + // well, it's possible not all events already arrived, yet - finally, some of them + // are notified asynchronously + // So, wait a few seconds. + try + { + _actualEvents.wait(20000); + } + catch (InterruptedException ex) + { + } + + if (actualEventCount == _actualEvents.size()) + // the above wait was left because of the timeout, *not* because an event + // arrived. Okay, we won't wait any longer, this is a failure. + { + break; + } + actualEventCount = _actualEvents.size(); + } + + assertEquals("wrong event count for '" + _context + "'", + _expectedEvents.length, _actualEvents.size()); + + for (int i = 0; i < _expectedEvents.length; ++i) + { + assertEquals("wrong event at position " + (i + 1) + " for '" + _context + "'", + _expectedEvents[i], _actualEvents.get(i)); + } + } + } + finally + { + System.out.println(" }"); + } + } + + + private int impl_waitForEvent(ArrayList _eventQueue, String _expectedEvent, int _maxMilliseconds) + { + return impl_waitForEvent(_eventQueue, _expectedEvent, _maxMilliseconds, 0); + } + + + private int impl_waitForEvent(ArrayList _eventQueue, String _expectedEvent, int _maxMilliseconds, int _firstQueueElementToCheck) + { + synchronized (_eventQueue) + { + int waitedMilliseconds = 0; + + while (waitedMilliseconds < _maxMilliseconds) + { + for (int i = _firstQueueElementToCheck; i < _eventQueue.size(); ++i) + { + if (_expectedEvent.equals(_eventQueue.get(i))) + // found the event in the queue + { + return i; + } + } + + // wait a little, perhaps the event will still arrive + try + { + _eventQueue.wait(500); + waitedMilliseconds += 500; + } + catch (InterruptedException e) + { + } + } + } + + fail("expected event '" + _expectedEvent + "' did not arrive after " + _maxMilliseconds + " milliseconds"); + return -1; + } + + + private void onDocumentEvent(DocumentEvent _Event) + { + if ("OnTitleChanged".equals(_Event.EventName)) + // OnTitleChanged events are notified too often. This is known, and accepted. + // (the deeper reason is that it's difficult to determine, in the DatabaseDocument implementation, + // when the title actually changed. In particular, when we do a saveAsURL, and then ask for a + // title *before* the TitleHelper got the document's OnSaveAsDone event, then the wrong (old) + // title is obtained. + { + return; + } + + if ((_Event.EventName.equals("OnLoad")) && (m_loadDocState != STATE_NOT_STARTED)) + { + assertEquals("OnLoad event must come *after* invocation of the interaction handler / user!", + m_loadDocState, STATE_MACRO_EXEC_APPROVED); + m_loadDocState = STATE_ON_LOAD_RECEIVED; + } + + synchronized (m_documentEvents) + { + m_documentEvents.add(_Event.EventName); + m_documentEvents.notifyAll(); + } + + System.out.println(" document event: " + _Event.EventName); + } + + + public void documentEventOccured(DocumentEvent _Event) + { + if ("OnTitleChanged".equals(_Event.EventName)) + // ignore. See onDocumentEvent for a justification + { + return; + } + + synchronized (m_globalEvents) + { + m_globalEvents.add(_Event.EventName); + m_globalEvents.notifyAll(); + } + + System.out.println(" global event: " + _Event.EventName); + } + + + public void disposing(EventObject _Event) + { + // not interested in + } +} diff --git a/dbaccess/qa/complex/dbaccess/FileHelper.java b/dbaccess/qa/complex/dbaccess/FileHelper.java new file mode 100644 index 000000000..cae67af00 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/FileHelper.java @@ -0,0 +1,35 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +package complex.dbaccess; + +public class FileHelper +{ + private FileHelper(){} + public static String getOOoCompatibleFileURL( String _javaFileURL ) + { + String returnURL = _javaFileURL; + if ( ( returnURL.indexOf( "file:/" ) == 0 ) && ( returnURL.indexOf( "file:///" ) == -1 ) ) + { + // for some reason, the URLs here in Java start with "file:/" only, instead of "file:///" + // Some of the office code doesn't like this ... + returnURL = "file:///" + returnURL.substring( 6 ); + } + return returnURL; + } +} diff --git a/dbaccess/qa/complex/dbaccess/Parser.java b/dbaccess/qa/complex/dbaccess/Parser.java new file mode 100644 index 000000000..8025e1d37 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/Parser.java @@ -0,0 +1,183 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.XIndexAccess; +import com.sun.star.sdb.XParametersSupplier; +import com.sun.star.sdb.XSingleSelectQueryComposer; +import com.sun.star.sdbc.DataType; +import com.sun.star.sdbc.SQLException; +import com.sun.star.uno.UnoRuntime; + + +// ---------- junit imports ----------------- +import org.junit.Test; +import static org.junit.Assert.*; + + +public class Parser extends CRMBasedTestCase +{ + + @Override + protected void createTestCase() throws Exception + { + super.createTestCase(); + m_database.getDatabase().getDataSource().createQuery( "query products", "SELECT * FROM \"products\"" ); + } + + + @Test + public void checkWhere() throws Exception + { + final XSingleSelectQueryComposer composer = createQueryComposer(); + final String SELECT = "SELECT \"products\".\"Name\" FROM \"products\" WHERE "; + final String[] queries = new String[] + { + "\"ID\" in ( 1,2,3,4)" + ,"not ( \"ID\" in ( 1,2,3,4))" + ,"(1 = 1) is true" + ,"(1 = 1) is not false" + ,"(1 = 1) is not null" + ,"not ( (1 = 1) is not null)" + ,"'a' like 'a%'" + ,"not ( 'a' like 'a%')" + ,"'a' not like 'a%'" + ,"1 between 0 and 2" + ,"not ( 1 between 0 and 2 )" + ,"1 not between 3 and 4" + ,"1 not between ( select \"ID\" from \"categories\") and ( select \"ID\" from \"categories\")" + ,"1 = 1" + ,"0 < 1" + ,"not(0 < 1)" + ,"1 > 0" + ,"not(1 > 0)" + ,"1 <> 0" + ,"(1 <> 0 and 'a' = 'a' and 'c' = 'd') or (1 = 1 and 2 = 2 and 3 = 4)" + ,"not ( 1 <> 0 )" + ,"\"CategoryID\" in ( select \"ID\" from \"categories\")" + ,"not (\"CategoryID\" in ( select \"ID\" from \"categories\"))" + ,"\"CategoryID\" not in ( select \"ID\" from \"categories\")" + }; + for (int i = 0; i < queries.length; i++) + { + composer.setQuery( SELECT + queries[i]); + } + } + + /** verifies that aliases for inner queries work as expected + */ + @Test + public void checkJoinSyntax() throws Exception + { + final XSingleSelectQueryComposer composer = createQueryComposer(); + + // feed the composer with some statements. If any of those cannot be parsed, the composer + // will throw an exception - which is a regression then + composer.setQuery( + "SELECT \"categories\".\"Name\", " + + "\"products\".\"Name\" " + + "FROM \"products\" RIGHT OUTER JOIN \"categories\" AS \"categories\" ON \"products\".\"CategoryID\" = \"categories\".\"ID\"" ); + + composer.setQuery( + "SELECT \"categories\".\"Name\", " + + "\"products\".\"Name\" " + + "FROM \"products\" LEFT OUTER JOIN \"categories\" AS \"categories\" ON \"products\".\"CategoryID\" = \"categories\".\"ID\"" ); + + composer.setQuery( + "SELECT \"categories\".\"Name\", " + + "\"products\".\"Name\" " + + "FROM \"products\" CROSS JOIN \"categories\" AS \"categories\"" ); + + composer.setQuery( + "SELECT \"categories\".\"Name\", " + + "\"products\".\"Name\" " + + "FROM \"products\" INNER JOIN \"categories\" AS \"categories\" ON \"products\".\"CategoryID\" = \"categories\".\"ID\"" ); + + // just to be sure the composer *really* parses upon setting the query: feed it with + // an unparseable statement + boolean caughtExpected = false; + try + { + composer.setQuery( "NONSENSE" ); + } + catch( SQLException e ) + { + caughtExpected = true; + } + assertTrue( "pre-condition not met: parser should except on unparseable statements, else the complete" + + "test is bogus!", caughtExpected ); + } + + + private void impl_checkParameters( final String _statement, final String[] _expectedParameterNames, final int[] _expectedParameterTypes,final String _context ) throws Exception + { + final XSingleSelectQueryComposer composer = createQueryComposer(); + composer.setQuery( _statement ); + + assertEquals( "checkParameterTypes: internal error", _expectedParameterNames.length, _expectedParameterTypes.length ); + + final XParametersSupplier paramSupp = UnoRuntime.queryInterface(XParametersSupplier.class, composer); + final XIndexAccess parameters = paramSupp.getParameters(); + + assertEquals( "(ctx: " + _context + ") unexpected parameter count", _expectedParameterNames.length, parameters.getCount() ); + for ( int i=0; i= :order_date ) " + + " AND ( ( \"Customer Name\" LIKE :customer ) " + + " OR ( \"Product Name\" LIKE ? ) " + + " )", + new String[] { "order_date", "customer", "Product Name" }, + new int[] { DataType.DATE, DataType.VARCHAR, DataType.VARCHAR }, + ">= && LIKE" + ); + + impl_checkParameters( + "SELECT * FROM \"categories\" " + + "WHERE \"ID\" BETWEEN :id_lo AND :id_hi", + new String[] { "id_lo", "id_hi" }, + new int[] { DataType.INTEGER, DataType.INTEGER }, + "BETWEEN" + ); + + impl_checkParameters( + "SELECT CONCAT( :prefix, CONCAT( \"Name\", :suffix ) ) FROM \"customers\"", + new String[] { "prefix", "suffix" }, + new int[] { DataType.VARCHAR, DataType.VARCHAR }, + "CONCAT" + ); + } +} diff --git a/dbaccess/qa/complex/dbaccess/PropertyBag.java b/dbaccess/qa/complex/dbaccess/PropertyBag.java new file mode 100644 index 000000000..6807569ec --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/PropertyBag.java @@ -0,0 +1,302 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +package complex.dbaccess; + +import com.sun.star.beans.NamedValue; +import com.sun.star.beans.PropertyState; +import com.sun.star.beans.PropertyValue; +import com.sun.star.beans.PropertyAttribute; +import com.sun.star.beans.XPropertyAccess; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertyContainer; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.lang.XMultiServiceFactory; + +// ---------- junit imports ----------------- +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.*; + + +public class PropertyBag extends TestCase +{ + private static final String VALUE = "Value"; + private XPropertyContainer m_bag; + private XPropertySet m_set; + private XPropertyAccess m_access; + private XMultiServiceFactory m_orb = null; + + public String getTestObjectName() + { + return "PropertyBag"; + } + + @Before + @Override + public void before() + { + m_orb = getMSF(); + } + + @Test + public void checkBasics() throws Exception + { + createEmptyBag(); + System.out.println("testing the basics"); + + // check whether empty property names are rejected + boolean caughtExpected = false; + try + { + m_bag.addProperty( "", PropertyAttribute.BOUND, Integer.valueOf( 3 ) ); + } + catch(com.sun.star.lang.IllegalArgumentException e) { caughtExpected = true; } + catch(com.sun.star.uno.Exception e) { } + if ( !caughtExpected ) + { + fail("empty property names are not rejected by XPropertyContainer::addProperty"); + } + + // check whether duplicate insertions are rejected + caughtExpected = false; + try + { + m_bag.addProperty( VALUE, PropertyAttribute.BOUND, "" ); + m_bag.addProperty( VALUE, PropertyAttribute.BOUND, "" ); + } + catch(com.sun.star.beans.PropertyExistException e) { caughtExpected = true; } + catch(com.sun.star.uno.Exception e) { } + if ( !caughtExpected ) + { + fail("insertion of duplicate property names is not rejected"); + } + + // try removing the property we just added - this should fail, as it does not have + // the REMOVABLE attribute + caughtExpected = false; + try + { + m_bag.removeProperty( VALUE); + } + catch(com.sun.star.beans.NotRemoveableException e) { caughtExpected = true; } + catch(com.sun.star.uno.Exception e) { } + if ( !caughtExpected ) + { + fail("removing non-removable properties is expected to fail - but it didn't"); + } + + // try removing a non-existent property + caughtExpected = false; + try + { + m_bag.removeProperty( "NonExistent" ); + } + catch(com.sun.star.beans.UnknownPropertyException e) { caughtExpected = true; } + catch(com.sun.star.uno.Exception e) { } + if ( !caughtExpected ) + { + fail("removing non-existent properties is expected to fail - but it didn't"); + } + + // try writing and reading a value for the one property we have so far + final String testValue = "someArbitraryValue"; + m_set.setPropertyValue( VALUE , testValue); + final String currentValue = (String)m_set.getPropertyValue( VALUE); + if ( !currentValue.equals( testValue ) ) + { + fail("set property is not remembered"); + } + + // try setting an illegal value for the property + caughtExpected = false; + try + { + m_set.setPropertyValue( VALUE, Integer.valueOf( 3 ) ); + } + catch(com.sun.star.lang.IllegalArgumentException e) { caughtExpected = true; } + catch(com.sun.star.uno.Exception e) { } + if ( !caughtExpected ) + { + fail("the bag does not respect the property type we declared for the property"); + } + } + + @Test + public void checkSequenceAccess() throws com.sun.star.uno.Exception + { + System.out.println( "checking PropertySetAccess via sequences" ); + createStandardBag( false ); + + + // XPropertyAccess.setPropertyValues + final PropertyValue expectedValues[] = + { + new PropertyValue( "BoolValue", -1, Boolean.FALSE, PropertyState.DIRECT_VALUE ), + new PropertyValue( "StringValue", -1, "some text", PropertyState.DIRECT_VALUE ), + new PropertyValue( "IntegerValue", -1, Integer.valueOf( 3 ), PropertyState.DIRECT_VALUE ), + new PropertyValue( "InterfaceValue", -1, m_bag, PropertyState.DIRECT_VALUE ) + }; + m_access.setPropertyValues( expectedValues ); + + for ( int i=0; i= testPos+1); + assertTrue("testModifyPosition failed on moving to row " + testPos, _resultSet.absolute(testPos)); + UnoRuntime.queryInterface( XRowUpdate.class, _row ).updateString(2, TEST21); + testPosition(_resultSet, _row, testPos, "testModifyPosition"); + UnoRuntime.queryInterface( XResultSetUpdate.class, _resultSet ).cancelRowUpdates(); + } + + + void test3(XResultSet clone, XResultSet _resultSet) throws com.sun.star.uno.Exception + { + final XRow _row = UnoRuntime.queryInterface( XRow.class, _resultSet ); + final XRow cloneRow = UnoRuntime.queryInterface( XRow.class, clone ); + for (int i = 1; i <= MAX_FETCH_ROWS; ++i) + { + final int calcPos = (MAX_TABLE_ROWS % i) + 1; + if (clone.absolute(calcPos)) + { + testPosition(clone, cloneRow, calcPos, "test3"); + testAbsolutePositioning(_resultSet, _row); + testAbsolutePositioning(clone, cloneRow); + } + } + } + + + void test4(XResultSet _resultSet) throws com.sun.star.uno.Exception + { + final XRow _row = UnoRuntime.queryInterface( XRow.class, _resultSet ); + _resultSet.beforeFirst(); + + for (int i = 1; i <= MAX_TABLE_ROWS; ++i) + { + _resultSet.next(); + final XResultSet clone = createClone(); + final XRow cloneRow = UnoRuntime.queryInterface( XRow.class, clone ); + final int calcPos = MAX_TABLE_ROWS - 1; + if (calcPos != 0 && clone.absolute(calcPos)) + { + testPosition(clone, cloneRow, calcPos, "test4: clone"); + testPosition(_resultSet, _row, i, "test4: rowset"); + } + } + } + + + void testConcurrentAccess(XResultSet _resultSet) throws Exception + { + System.out.println("testing Thread"); + + _resultSet.beforeFirst(); + + final int numberOfThreads = 10; + + final Thread threads[] = new Thread[numberOfThreads]; + for (int i = 0; i < numberOfThreads; ++i) + { + threads[i] = new Thread(new ResultSetMovementStress(createClone(), i)); + System.out.println("starting thread " + (i + 1) + " of " + (numberOfThreads)); + threads[i].start(); + } + + for (int i = 0; i < numberOfThreads; ++i) + { + threads[i].join(); + } + synchronized (failedResultSetMovementStressGuard) { + assertEquals("", failedResultSetMovementStressMessages); + } + } + + + @Test + public void testRowSetEvents() throws java.lang.Exception + { + System.out.println("testing RowSet Events"); + createTestCase(true); + + // first we create our RowSet object + final RowSetEventListener pRow = new RowSetEventListener(); + + final XColumnsSupplier colSup = UnoRuntime.queryInterface( XColumnsSupplier.class, m_rowSet ); + final XPropertySet col = UnoRuntime.queryInterface( XPropertySet.class, colSup.getColumns().getByName( "ID" ) ); + col.addPropertyChangeListener("Value", pRow); + m_rowSetProperties.addPropertyChangeListener("IsModified", pRow); + m_rowSetProperties.addPropertyChangeListener("IsNew", pRow); + m_rowSetProperties.addPropertyChangeListener("IsRowCountFinal", pRow); + m_rowSetProperties.addPropertyChangeListener("RowCount", pRow); + + final XRowSetApproveBroadcaster xApBroad = UnoRuntime.queryInterface( XRowSetApproveBroadcaster.class, m_resultSet ); + xApBroad.addRowSetApproveListener(pRow); + m_rowSet.addRowSetListener(pRow); + + // do some movements to check if we got all notifications + final Class cResSet = Class.forName("com.sun.star.sdbc.XResultSet"); + final boolean moves[] = new boolean[9]; + for (int i = 0; i < moves.length; ++i) + { + moves[i] = false; + } + moves[RowSetEventListener.APPROVE_CURSOR_MOVE] = true; + moves[RowSetEventListener.COLUMN_VALUE] = true; + moves[RowSetEventListener.CURSOR_MOVED] = true; + moves[RowSetEventListener.IS_ROW_COUNT_FINAL] = true; + moves[RowSetEventListener.ROW_COUNT] = true; + + testCursorMove(m_resultSet, cResSet.getMethod("afterLast", (Class[]) null), pRow, moves, null); + + moves[RowSetEventListener.IS_ROW_COUNT_FINAL] = false; + moves[RowSetEventListener.ROW_COUNT] = false; + testCursorMove(m_resultSet, cResSet.getMethod(NEXT, (Class[]) null), pRow, moves, null); + testCursorMove(m_resultSet, cResSet.getMethod(NEXT, (Class[]) null), pRow, moves, null); + testCursorMove(m_resultSet, cResSet.getMethod(NEXT, (Class[]) null), pRow, moves, null); + testCursorMove(m_resultSet, cResSet.getMethod("last", (Class[]) null), pRow, moves, null); + testCursorMove(m_resultSet, cResSet.getMethod(NEXT, (Class[]) null), pRow, moves, null); + testCursorMove(m_resultSet, cResSet.getMethod("first", (Class[]) null), pRow, moves, null); + testCursorMove(m_resultSet, cResSet.getMethod("previous", (Class[]) null), pRow, moves, null); + testCursorMove(m_resultSet, cResSet.getMethod(NEXT, (Class[]) null), pRow, moves, null); + moves[RowSetEventListener.IS_MODIFIED] = true; + final XRowUpdate updRow = UnoRuntime.queryInterface( XRowUpdate.class, m_resultSet ); + updRow.updateString(2, TEST21); + testCursorMove(m_resultSet, cResSet.getMethod(NEXT, (Class[]) null), pRow, moves, null); + + moves[RowSetEventListener.IS_MODIFIED] = false; + updRow.updateString(2, m_row.getString(2)); + testCursorMove(m_resultSet, cResSet.getMethod(NEXT, (Class[]) null), pRow, moves, null); + + moves[RowSetEventListener.IS_MODIFIED] = false; + final Class cupd = Class.forName("com.sun.star.sdbc.XResultSetUpdate"); + final XResultSetUpdate upd = UnoRuntime.queryInterface( XResultSetUpdate.class, m_resultSet ); + testCursorMove(upd, cupd.getMethod("moveToInsertRow", (Class[]) null), pRow, moves, null); + + updRow.updateInt(1, MAX_TABLE_ROWS + 2); + updRow.updateString(2, "HHHH"); + moves[RowSetEventListener.APPROVE_CURSOR_MOVE] = false; + moves[RowSetEventListener.CURSOR_MOVED] = false; + moves[RowSetEventListener.IS_MODIFIED] = true; + moves[RowSetEventListener.IS_NEW] = true; + moves[RowSetEventListener.ROW_COUNT] = true; + moves[RowSetEventListener.APPROVE_ROW_CHANGE] = true; + moves[RowSetEventListener.ROW_CHANGED] = true; + testCursorMove(upd, cupd.getMethod("insertRow", (Class[]) null), pRow, moves, null); + + moves[RowSetEventListener.IS_NEW] = false; + moves[RowSetEventListener.ROW_COUNT] = false; + m_resultSet.first(); + updRow.updateInt(1, MAX_TABLE_ROWS + 3); + updRow.updateString(2, "__"); + testCursorMove(upd, cupd.getMethod("updateRow", (Class[]) null), pRow, moves, null); + + moves[RowSetEventListener.IS_NEW] = true; + moves[RowSetEventListener.ROW_COUNT] = true; + m_resultSet.first(); + testCursorMove(upd, cupd.getMethod("deleteRow", (Class[]) null), pRow, moves, null); + + moves[RowSetEventListener.IS_NEW] = false; + moves[RowSetEventListener.COLUMN_VALUE] = true; + moves[RowSetEventListener.ROW_COUNT] = false; + m_resultSet.first(); + updRow.updateString(2, TEST21); + testCursorMove(m_resultSet, cResSet.getMethod("refreshRow", (Class[]) null), pRow, moves, null); + + m_resultSet.first(); + updRow.updateString(2, TEST21); + testCursorMove(upd, cupd.getMethod("cancelRowUpdates", (Class[]) null), pRow, moves, null); + + for (int i = 0; i < moves.length; ++i) + { + moves[i] = false; + } + moves[RowSetEventListener.APPROVE_CURSOR_MOVE] = true; + moves[RowSetEventListener.COLUMN_VALUE] = true; + moves[RowSetEventListener.CURSOR_MOVED] = true; + + final Class cloc = Class.forName("com.sun.star.sdbcx.XRowLocate"); + m_resultSet.first(); + final Object bookmark = m_rowLocate.getBookmark(); + m_resultSet.next(); + final Object temp[] = new Object[1]; + temp[0] = bookmark; + Class ctemp[] = new Class[1]; + ctemp[0] = Object.class; + testCursorMove(m_rowLocate, cloc.getMethod("moveToBookmark", ctemp), pRow, moves, temp); + + final Object temp2[] = new Object[2]; + temp2[0] = bookmark; + temp2[1] = Integer.valueOf(1); + final Class ctemp2[] = new Class[2]; + ctemp2[0] = Object.class; + ctemp2[1] = int.class; + testCursorMove(m_rowLocate, cloc.getMethod("moveRelativeToBookmark", ctemp2), pRow, moves, temp2); + + for (int i = 0; i < moves.length; ++i) + { + moves[i] = false; + } + moves[RowSetEventListener.APPROVE_ROW_CHANGE] = true; + moves[RowSetEventListener.ROW_CHANGED] = true; + moves[RowSetEventListener.ROW_COUNT] = true; + final Class cdelRows = Class.forName("com.sun.star.sdbcx.XDeleteRows"); + ctemp[0] = Object[].class; + final XDeleteRows delRows = UnoRuntime.queryInterface( XDeleteRows.class, m_resultSet ); + final Object bookmarks[] = new Object[5]; + m_resultSet.first(); + for (int i = 0; i < bookmarks.length; ++i) + { + m_resultSet.next(); + bookmarks[i] = m_rowLocate.getBookmark(); + } + + temp[0] = bookmarks; + testCursorMove(delRows, cdelRows.getMethod("deleteRows", ctemp), pRow, moves, temp); + + // now destroy the RowSet + final XComponent xComp = UnoRuntime.queryInterface( XComponent.class, m_resultSet ); + xComp.dispose(); + } + + + private void testCursorMove(Object res, Method _method, RowSetEventListener _evt, boolean _must[], Object args[]) throws java.lang.Exception + { + _evt.clearCalling(); + _method.invoke(res, args); + + System.out.println("testing events for " + _method.getName()); + final int calling[] = _evt.getCalling(); + int pos = 1; + assertTrue("Callings are not in the correct order for APPROVE_CURSOR_MOVE ", + (!_must[RowSetEventListener.APPROVE_CURSOR_MOVE] || calling[RowSetEventListener.APPROVE_CURSOR_MOVE] == -1) || calling[RowSetEventListener.APPROVE_CURSOR_MOVE] == pos++); + assertTrue("Callings are not in the correct order for APPROVE_ROW_CHANGE", + (!_must[RowSetEventListener.APPROVE_ROW_CHANGE] || calling[RowSetEventListener.APPROVE_ROW_CHANGE] == -1) || calling[RowSetEventListener.APPROVE_ROW_CHANGE] == pos++); + assertTrue("Callings are not in the correct order for COLUMN_VALUE", + (!_must[RowSetEventListener.COLUMN_VALUE] || calling[RowSetEventListener.COLUMN_VALUE] == -1) || calling[RowSetEventListener.COLUMN_VALUE] == pos++); + assertTrue("Callings are not in the correct order for CURSOR_MOVED", + (!_must[RowSetEventListener.CURSOR_MOVED] || calling[RowSetEventListener.CURSOR_MOVED] == -1) || calling[RowSetEventListener.CURSOR_MOVED] == pos++); + assertTrue("Callings are not in the correct order for ROW_CHANGED", + (!_must[RowSetEventListener.ROW_CHANGED] || calling[RowSetEventListener.ROW_CHANGED] == -1) || calling[RowSetEventListener.ROW_CHANGED] == pos++); + assertTrue("Callings are not in the correct order for IS_MODIFIED", + (!_must[RowSetEventListener.IS_MODIFIED] || calling[RowSetEventListener.IS_MODIFIED] == -1) || calling[RowSetEventListener.IS_MODIFIED] == pos++); + assertTrue("Callings are not in the correct order for IS_NEW", + (!_must[RowSetEventListener.IS_NEW] || calling[RowSetEventListener.IS_NEW] == -1) || calling[RowSetEventListener.IS_NEW] == pos++); + assertTrue("Callings are not in the correct order for ROW_COUNT", + (!_must[RowSetEventListener.ROW_COUNT] || calling[RowSetEventListener.ROW_COUNT] == -1) || calling[RowSetEventListener.ROW_COUNT] == pos++); + assertTrue("Callings are not in the correct order for IS_ROW_COUNT_FINAL", + (!_must[RowSetEventListener.IS_ROW_COUNT_FINAL] || calling[RowSetEventListener.IS_ROW_COUNT_FINAL] == -1) || calling[RowSetEventListener.IS_ROW_COUNT_FINAL] == pos); + + _evt.clearCalling(); + } + + + /** returns the current row count of the RowSet + */ + private int currentRowCount() throws UnknownPropertyException, WrappedTargetException + { + final Integer rowCount = (Integer) m_rowSetProperties.getPropertyValue("RowCount"); + return rowCount.intValue(); + } + + + /** positions the row set at an arbitrary position between 2 and (current row count - 1) + */ + private int positionRandom() throws SQLException, UnknownPropertyException, WrappedTargetException + { + // note: obviously this should subtract 2 but actually subtract 3 + // because if we have just deleted the current row then + // ORowSetBase::impl_getRowCount() will lie and currentRowCount() + // returns 1 more than the actual number of rows and then + // positionRandom() followed by deleteRow() deletes *last* row + final int position = (new Random()).nextInt(currentRowCount() - 3) + 2; + assertTrue("sub task failed: could not position to row no. " + (Integer.valueOf(position)).toString(), + m_resultSet.absolute(position)); + return m_resultSet.getRow(); + } + + + /** moves the result set to a random record between 2 and (current row count - 1), and deletes this record + * + * After returning from this method, the row set is still positioned at the deleted record + * @return + * the number/position of the record which has been deleted + */ + private int deleteRandom() throws SQLException, UnknownPropertyException, WrappedTargetException + { + // check if the current position and the row count in the result set is changed by a deletion (it should not) + final int positionBefore = positionRandom(); + final int rowCountBefore = currentRowCount(); + + m_resultSetUpdate.deleteRow(); + + final int positionAfter = m_resultSet.getRow(); + final int rowCountAfter = currentRowCount(); + assertTrue("position changed during |deleteRow| (it should not)", positionAfter == positionBefore); + assertTrue("row count changed with a |deleteRow| (it should not)", rowCountBefore == rowCountAfter); + assertTrue("RowSet does not report the current row as deleted after |deleteRow|", m_resultSet.rowDeleted()); + + return positionBefore; + } + + + @Test + public void testDeleteBehavior() throws Exception + { + createTestCase(true); + + // ensure that all records are known + m_resultSet.last(); + final int initialRowCount = currentRowCount(); + + // delete a random row + int deletedRow = deleteRandom(); + + + // asking for the bookmark of a deleted row should fail + boolean caughtException = false; + try + { + m_rowLocate.getBookmark(); + } + catch (SQLException e) + { + caughtException = true; + } + assertTrue("asking for the bookmark of a deleted row should throw an exception", caughtException); + + + // isXXX methods should return |false| on a deleted row + assertTrue("one of the isFoo failed after |deleteRow|", !m_resultSet.isBeforeFirst() && !m_resultSet.isAfterLast() && !m_resultSet.isFirst() && !m_resultSet.isLast()); + // note that we can assume that isFirst / isLast also return |false|, since deleteRandom did + // not position on the first or last record, but inbetween + + + // check if moving away from this row in either direction yields the expected results + assertTrue("|previous| after |deleteRow| failed", m_resultSet.previous()); + final int positionPrevious = m_resultSet.getRow(); + assertTrue("position after |previous| after |deleteRow| is not as expected", positionPrevious == deletedRow - 1); + + deletedRow = deleteRandom(); + assertTrue("|next| after |deleteRow| failed", m_resultSet.next()); + final int positionAfter = m_resultSet.getRow(); + assertTrue("position after |next| after |deleteRow| is not as expected", positionAfter == deletedRow); + // since the deleted record "vanishes" as soon as the cursor is moved away from it, the absolute position does + // not change with a |next| call here + + + // check if the deleted rows really vanished after moving away from them + assertTrue("row count did not change as expected after two deletions", initialRowCount - 2 == currentRowCount()); + + + // check if the deleted row vanishes after moving to the insertion row + final int rowCountBefore = currentRowCount(); + final int deletedPos = deleteRandom(); + m_resultSetUpdate.moveToInsertRow(); + assertTrue("moving to the insertion row immediately after |deleteRow| does not adjust the row count", rowCountBefore == currentRowCount() + 1); + + m_resultSetUpdate.moveToCurrentRow(); + assertTrue("|moveToCurrentRow| after |deleteRow| + |moveToInsertRow| results in unexpected position", + (m_resultSet.getRow() == deletedPos) && !m_resultSet.rowDeleted()); + + // the same, but this time with deleting the first row (which is not covered by deleteRandom) + m_resultSet.last(); + m_resultSetUpdate.deleteRow(); + m_resultSetUpdate.moveToInsertRow(); + m_resultSetUpdate.moveToCurrentRow(); + assertTrue("|last| + |deleteRow| + |moveToInsertRow| + |moveToCurrentRow| results in wrong state", m_resultSet.isAfterLast()); + + + // check if deleting a deleted row fails as expected + deleteRandom(); + caughtException = false; + try + { + m_resultSetUpdate.deleteRow(); + } + catch (SQLException e) + { + caughtException = true; + } + assertTrue("deleting a deleted row succeeded - it shouldn't", caughtException); + + + // check if deleteRows fails if it contains the bookmark of a previously-deleted row + m_resultSet.first(); + final Object firstBookmark = m_rowLocate.getBookmark(); + positionRandom(); + final Object deleteBookmark = m_rowLocate.getBookmark(); + m_resultSetUpdate.deleteRow(); + final XDeleteRows multiDelete = UnoRuntime.queryInterface( XDeleteRows.class, m_resultSet ); + final int[] deleteSuccess = multiDelete.deleteRows(new Object[] + { + firstBookmark, deleteBookmark + }); + assertTrue("XDeleteRows::deleteRows with the bookmark of an already-deleted row failed", + (deleteSuccess.length == 2) && (deleteSuccess[0] != 0) && (deleteSuccess[1] == 0)); + + + // check if refreshing a deleted row fails as expected + deleteRandom(); + caughtException = false; + try + { + m_resultSet.refreshRow(); + } + catch (SQLException e) + { + caughtException = true; + } + assertTrue("refreshing a deleted row succeeded - it shouldn't", caughtException); + + + // rowUpdated/rowDeleted + deleteRandom(); + assertTrue("rowDeleted and/or rowUpdated are wrong on a deleted row", !m_resultSet.rowUpdated() && !m_resultSet.rowInserted()); + + + // updating values in a deleted row should fail + deleteRandom(); + final XRowUpdate rowUpdated = UnoRuntime.queryInterface( XRowUpdate.class, m_resultSet ); + caughtException = false; + try + { + rowUpdated.updateString(2, TEST21); + } + catch (SQLException e) + { + caughtException = true; + } + assertTrue("updating values in a deleted row should not succeed", caughtException); + } + + + /** checks whether deletions on the main RowSet properly interfere (or don't interfere) with the movement + * on a clone of the RowSet + */ + @Test + public void testCloneMovesPlusDeletions() throws Exception + { + createTestCase(true); + // ensure that all records are known + m_resultSet.last(); + + final XResultSet clone = createClone(); + final XRowLocate cloneRowLocate = UnoRuntime.queryInterface( XRowLocate.class, clone ); + + positionRandom(); + + + // move the clone to the same record as the RowSet, and delete this record + cloneRowLocate.moveToBookmark(m_rowLocate.getBookmark()); + final int clonePosition = clone.getRow(); + m_resultSetUpdate.deleteRow(); + + assertTrue("clone doesn't know that its current row has been deleted via the RowSet", clone.rowDeleted()); + assertTrue("clone's position changed somehow during deletion", clonePosition == clone.getRow()); + + + // move the row set away from the deleted record. This should still not touch the state of the clone + m_resultSet.previous(); + + assertTrue("clone doesn't know (anymore) that its current row has been deleted via the RowSet", clone.rowDeleted()); + assertTrue("clone's position changed somehow during deletion and RowSet-movement", clonePosition == clone.getRow()); + + + // move the clone away from the deleted record + clone.next(); + assertTrue("clone still assumes that its row is deleted - but we already moved it", !clone.rowDeleted()); + + + // check whether deleting the extremes (first / last) work + m_resultSet.first(); + cloneRowLocate.moveToBookmark(m_rowLocate.getBookmark()); + m_resultSetUpdate.deleteRow(); + clone.previous(); + assertTrue("deleting the first record left the clone in a strange state (after |previous|)", clone.isBeforeFirst()); + clone.next(); + assertTrue("deleting the first record left the clone in a strange state (after |previous| + |next|)", clone.isFirst()); + + m_resultSet.last(); + cloneRowLocate.moveToBookmark(m_rowLocate.getBookmark()); + m_resultSetUpdate.deleteRow(); + clone.next(); + assertTrue("deleting the last record left the clone in a strange state (after |next|)", clone.isAfterLast()); + clone.previous(); + assertTrue("deleting the first record left the clone in a strange state (after |next| + |previous|)", clone.isLast()); + + + // check whether movements of the clone interfere with movements of the RowSet, if the latter is on a deleted row + final int positionBefore = positionRandom(); + m_resultSetUpdate.deleteRow(); + assertTrue("|deleteRow|, but no |rowDeleted| (this should have been found much earlier!)", m_resultSet.rowDeleted()); + clone.beforeFirst(); + while (clone.next()) {} + assertTrue("row set forgot that the current row is deleted", m_resultSet.rowDeleted()); + + assertTrue("moving to the next record after |deleteRow| and clone moves failed", m_resultSet.next()); + assertTrue("wrong position after |deleteRow| and clone movement", !m_resultSet.isAfterLast() && !m_resultSet.isBeforeFirst()); + assertTrue("wrong absolute position after |deleteRow| and clone movement", m_resultSet.getRow() == positionBefore); + } + + + /** checks whether insertions on the main RowSet properly interfere (or don't interfere) with the movement + * on a clone of the RowSet + */ + @Test + public void testCloneMovesPlusInsertions() throws Exception + { + createTestCase(true); + // ensure that all records are known + m_rowSetProperties.setPropertyValue("FetchSize", Integer.valueOf(10)); + + final XResultSet clone = createClone(); + final XRow cloneRow = UnoRuntime.queryInterface( XRow.class, clone ); + + + // first check the basic scenario without the |moveToInsertRow| |moveToCurrentRow|, to ensure that + // really those are broken, if at all + m_resultSet.last(); + clone.first(); + clone.absolute(11); + clone.first(); + + final int rowValue1 = m_row.getInt(1); + final int rowPos = m_resultSet.getRow(); + final int rowValue2 = m_row.getInt(1); + assertTrue("repeated query for the same column value delivers different values (" + rowValue1 + " and " + rowValue2 + ") on row: " + rowPos, + rowValue1 == rowValue2); + + testPosition(clone, cloneRow, 1, "mixed clone/rowset move: clone check"); + testPosition(m_resultSet, m_row, MAX_TABLE_ROWS, "mixed clone/rowset move: rowset check"); + + + // now the complete scenario + m_resultSet.last(); + m_resultSetUpdate.moveToInsertRow(); + clone.first(); + clone.absolute(11); + clone.first(); + m_resultSetUpdate.moveToCurrentRow(); + + testPosition(clone, cloneRow, 1, "mixed clone/rowset move/insertion: clone check"); + testPosition(m_resultSet, m_row, 100, "mixed clone/rowset move/insertion: rowset check"); + } + + + private void testTableParameters() throws com.sun.star.uno.Exception + { + // for a row set simply based on a table, there should be not parameters at all + createRowSet("products", CommandType.TABLE, false); + verifyParameters(new String[] + { + }, "testTableParameters"); + } + + + private void testParametersAfterNormalExecute() throws com.sun.star.uno.Exception + { + createRowSet("SELECT * FROM \"customers\"", CommandType.COMMAND, true); + m_rowSetProperties.setPropertyValue("Command", "SELECT * FROM \"customers\" WHERE \"City\" = :city"); + final XParameters rowsetParams = UnoRuntime.queryInterface( XParameters.class, m_rowSet ); + rowsetParams.setString(1, "London"); + m_rowSet.execute(); + } + + + private void verifyParameters(String[] _paramNames, String _context) throws com.sun.star.uno.Exception + { + final XIndexAccess params = m_paramsSupplier.getParameters(); + final int expected = _paramNames.length; + final int found = params != null ? params.getCount() : 0; + + assertTrue("wrong number of parameters (expected: " + expected + ", found: " + found + ") in " + _context, + found == expected); + + if (found == 0) + { + return; + } + + for (int i = 0; i < expected; ++i) + { + final XPropertySet parameter = UnoRuntime.queryInterface( XPropertySet.class, params.getByIndex( i ) ); + + final String expectedName = _paramNames[i]; + final String foundName = (String) parameter.getPropertyValue("Name"); + assertTrue("wrong parameter name (expected: " + expectedName + ", found: " + foundName + ") in" + _context, + expectedName.equals(foundName)); + } + } + + + private void testParametrizedQuery() throws com.sun.star.uno.Exception + { + // for a row set based on a parametrized query, those parameters should be properly + // recognized + m_dataSource.createQuery("products like", "SELECT * FROM \"products\" WHERE \"Name\" LIKE :product_name"); + createRowSet("products like", CommandType.QUERY, false); + verifyParameters(new String[] + { + "product_name" + }, "testParametrizedQuery"); + } + + + private void testParametersInteraction() throws com.sun.star.uno.Exception + { + createRowSet("products like", CommandType.QUERY, false); + + // let's fill in a parameter value via XParameters, and see whether it is respected by the parameters container + final XParameters rowsetParams = UnoRuntime.queryInterface(XParameters.class, m_rowSet); + rowsetParams.setString(1, "Apples"); + + XIndexAccess params = m_paramsSupplier.getParameters(); + XPropertySet firstParam = UnoRuntime.queryInterface( XPropertySet.class, params.getByIndex( 0 ) ); + Object firstParamValue = firstParam.getPropertyValue("Value"); + + assertTrue("XParameters and the parameters container do not properly interact", + "Apples".equals(firstParamValue)); + + // let's see whether this also survives an execute of the row set + rowsetParams.setString(1, "Oranges"); + m_rowSet.execute(); + { + // TODO: the following would not be necessary if the parameters container would *survive* + // the execution of the row set. It currently doesn't (though the values it represents do). + // It would be nice, but not strictly necessary, if it would. + params = m_paramsSupplier.getParameters(); + firstParam = UnoRuntime.queryInterface( XPropertySet.class, params.getByIndex( 0 ) ); + } + firstParamValue = firstParam.getPropertyValue("Value"); + assertTrue("XParameters and the parameters container do not properly interact, after the row set has been executed", + "Oranges".equals(firstParamValue)); + } + + + private void testParametersInFilter() throws com.sun.star.uno.Exception + { + createRowSet("SELECT * FROM \"customers\"", CommandType.COMMAND, false); + m_rowSetProperties.setPropertyValue("Filter", "\"City\" = :city"); + + m_rowSetProperties.setPropertyValue("ApplyFilter", Boolean.TRUE); + verifyParameters(new String[] + { + "city" + }, "testParametersInFilter"); + + m_rowSetProperties.setPropertyValue("ApplyFilter", Boolean.FALSE); + verifyParameters(new String[] + { + }, "testParametersInFilter"); + } + + + /** checks the XParametersSupplier functionality of a RowSet + */ + @Test + public void testParameters() throws Exception + { + createTestCase(false); + // use an own RowSet instance, not the one which is also used for the other cases + + testTableParameters(); + testParametrizedQuery(); + testParametersInFilter(); + + testParametersAfterNormalExecute(); + + testParametersInteraction(); + } +} + diff --git a/dbaccess/qa/complex/dbaccess/RowSetEventListener.java b/dbaccess/qa/complex/dbaccess/RowSetEventListener.java new file mode 100644 index 000000000..991dfb7af --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/RowSetEventListener.java @@ -0,0 +1,102 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +package complex.dbaccess; + +import com.sun.star.sdb.XRowSetApproveListener; +import com.sun.star.sdbc.XRowSetListener; +import com.sun.star.sdb.RowChangeEvent; +import com.sun.star.lang.EventObject; +import com.sun.star.beans.XPropertyChangeListener; + +public final class RowSetEventListener implements XRowSetApproveListener,XRowSetListener,XPropertyChangeListener +{ + public static final int APPROVE_CURSOR_MOVE = 0; + public static final int APPROVE_ROW_CHANGE = 1; + public static final int COLUMN_VALUE = 2; + public static final int CURSOR_MOVED = 3; + public static final int ROW_CHANGED = 4; + public static final int IS_MODIFIED = 5; + public static final int IS_NEW = 6; + public static final int ROW_COUNT = 7; + public static final int IS_ROW_COUNT_FINAL = 8; + + private int callPos = 1; + private int calling []; + + RowSetEventListener(){ + calling = new int [9]; + clearCalling(); + } + public int[] getCalling(){ + return calling; + } + public void clearCalling(){ + for(int i = 0 ; i < calling.length; ++i){ + calling[i] = -1; + } + callPos = 1; + } + // XEventListener + public void disposing(com.sun.star.lang.EventObject event) + { + } + // XRowSetApproveBroadcaster + public boolean approveCursorMove(EventObject event) + { + calling[APPROVE_CURSOR_MOVE] = callPos++; + return true; + } + public boolean approveRowChange(RowChangeEvent event) + { + calling[APPROVE_ROW_CHANGE] = callPos++; + return true; + } + public boolean approveRowSetChange(EventObject event) + { + return true; + } + + // XRowSetListener + public void cursorMoved(com.sun.star.lang.EventObject event) + { + calling[CURSOR_MOVED] = callPos++; + } + public void rowChanged(com.sun.star.lang.EventObject event) + { + calling[ROW_CHANGED] = callPos++; + } + public void rowSetChanged(com.sun.star.lang.EventObject event) + { + } + + public void propertyChange(com.sun.star.beans.PropertyChangeEvent propertyChangeEvent) { + if ( "Value".equals(propertyChangeEvent.PropertyName) ){ + calling[COLUMN_VALUE] = callPos++; + } else if ( "IsModified".equals(propertyChangeEvent.PropertyName) ){ + calling[IS_MODIFIED] = callPos++; + } else if ( "IsNew".equals(propertyChangeEvent.PropertyName) ){ + calling[IS_NEW] = callPos++; + } else if ( "RowCount".equals(propertyChangeEvent.PropertyName) ){ + calling[ROW_COUNT] = callPos++; + } else if ( "IsRowCountFinal".equals(propertyChangeEvent.PropertyName) ){ + calling[IS_ROW_COUNT_FINAL] = callPos++; + } + } + +} diff --git a/dbaccess/qa/complex/dbaccess/SingleSelectQueryComposer.java b/dbaccess/qa/complex/dbaccess/SingleSelectQueryComposer.java new file mode 100644 index 000000000..2d05030b7 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/SingleSelectQueryComposer.java @@ -0,0 +1,351 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.beans.PropertyState; +import com.sun.star.sdb.SQLFilterOperator; +import com.sun.star.beans.PropertyAttribute; +import com.sun.star.beans.XPropertySet; +import com.sun.star.beans.XPropertyContainer; +import com.sun.star.beans.NamedValue; +import com.sun.star.container.XNameAccess; +import com.sun.star.sdbcx.XTablesSupplier; +import com.sun.star.sdb.XParametersSupplier; +import com.sun.star.beans.PropertyValue; +import com.sun.star.sdbcx.XColumnsSupplier; +import com.sun.star.container.XIndexAccess; +import com.sun.star.sdb.CommandType; +import com.sun.star.sdb.XSingleSelectQueryComposer; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.sdbc.DataType; +import com.sun.star.sdbc.SQLException; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + + +// ---------- junit imports ----------------- +import org.junit.Test; + +import static org.junit.Assert.*; + + +public class SingleSelectQueryComposer extends CRMBasedTestCase +{ + + private XSingleSelectQueryComposer m_composer = null; + private static final String COMPLEXFILTER = "( \"ID\" = 1 AND \"Postal\" = '4' )" + + " OR ( \"ID\" = 2 AND \"Postal\" = '5' )" + + " OR ( \"ID\" = 3 AND \"Postal\" = '6' AND \"Address\" = '7' )" + + " OR ( \"Address\" = '8' )" + + " OR ( \"Postal\" = '9' )" + + " OR ( NOW( ) = {d '2010-01-01' } )"; + private static final String INNERPRODUCTSQUERY = "products (inner)"; + + + private void createQueries() throws Exception + { + m_database.getDatabase().getDataSource().createQuery(INNERPRODUCTSQUERY, "SELECT * FROM \"products\""); + } + + + @Override + protected void createTestCase() throws Exception + { + super.createTestCase(); + + createQueries(); + + m_composer = createQueryComposer(); + } + + + private void checkAttributeAccess(String _attributeName, String _attributeValue) + { + System.out.println("setting " + _attributeName + " to " + _attributeValue); + String realValue = null; + try + { + final Class composerClass = m_composer.getClass(); + final Method attributeGetter = composerClass.getMethod("get" + _attributeName, new Class[] + { + }); + final Method attributeSetter = composerClass.getMethod("set" + _attributeName, new Class[] + { + String.class + }); + + attributeSetter.invoke(m_composer, new Object[] + { + _attributeValue + }); + realValue = (String) attributeGetter.invoke(m_composer, new Object[] + { + }); + } + catch (NoSuchMethodException e) + { + } + catch (IllegalAccessException e) + { + } + catch (InvocationTargetException e) + { + } + assertTrue("set/get" + _attributeName + " not working as expected (set: " + _attributeValue + ", get: " + (realValue != null ? realValue : "null") + ")", + realValue.equals(_attributeValue)); + System.out.println(" (results in " + m_composer.getQuery() + ")"); + } + + /** tests setCommand of the composer + */ + @Test + public void testSetCommand() throws Exception + { + System.out.println("testing SingleSelectQueryComposer's setCommand"); + + final String table = "SELECT * FROM \"customers\""; + m_composer.setCommand("customers", CommandType.TABLE); + assertTrue("setCommand/getQuery TABLE inconsistent", m_composer.getQuery().equals(table)); + + m_database.getDatabase().getDataSource().createQuery("set command test", "SELECT * FROM \"orders for customer\" \"a\", \"customers\" \"b\" WHERE \"a\".\"Product Name\" = \"b\".\"Name\""); + m_composer.setCommand("set command test", CommandType.QUERY); + assertTrue("setCommand/getQuery QUERY inconsistent", m_composer.getQuery().equals(m_database.getDatabase().getDataSource().getQueryDefinition("set command test").getCommand())); + + final String sql = "SELECT * FROM \"orders for customer\" WHERE \"Product Name\" = 'test'"; + m_composer.setCommand(sql, CommandType.COMMAND); + assertTrue("setCommand/getQuery COMMAND inconsistent", m_composer.getQuery().equals(sql)); + } + + /** tests accessing attributes of the composer (order, filter, group by, having) + */ + @Test + public void testAttributes() throws Exception + { + System.out.println("testing SingleSelectQueryComposer's attributes (order, filter, group by, having)"); + + System.out.println("check setElementaryQuery"); + + final String simpleQuery2 = "SELECT * FROM \"customers\" WHERE \"Name\" = 'oranges'"; + m_composer.setElementaryQuery(simpleQuery2); + assertTrue("setElementaryQuery/getQuery inconsistent", m_composer.getQuery().equals(simpleQuery2)); + + System.out.println("check setQuery"); + final String simpleQuery = "SELECT * FROM \"customers\""; + m_composer.setQuery(simpleQuery); + assertTrue("set/getQuery inconsistent", m_composer.getQuery().equals(simpleQuery)); + + checkAttributeAccess("Filter", "\"Name\" = 'oranges'"); + checkAttributeAccess("Group", "\"City\""); + checkAttributeAccess("Order", "\"Address\""); + checkAttributeAccess("HavingClause", "\"ID\" <> 4"); + + final XIndexAccess orderColumns = m_composer.getOrderColumns(); + assertTrue("Order columns doesn't exist: \"Address\"", + orderColumns != null && orderColumns.getCount() == 1 && orderColumns.getByIndex(0) != null); + + final XIndexAccess groupColumns = m_composer.getGroupColumns(); + assertTrue("Group columns doesn't exist: \"City\"", + groupColumns != null && groupColumns.getCount() == 1 && groupColumns.getByIndex(0) != null); + + // XColumnsSupplier + final XColumnsSupplier xSelectColumns = UnoRuntime.queryInterface(XColumnsSupplier.class, m_composer); + assertTrue("no select columns, or wrong number of select columns", + xSelectColumns != null && xSelectColumns.getColumns() != null && xSelectColumns.getColumns().getElementNames().length == 6); + + // structured filter + m_composer.setQuery("SELECT \"ID\", \"Postal\", \"Address\" FROM \"customers\""); + m_composer.setFilter(COMPLEXFILTER); + final PropertyValue[][] aStructuredFilter = m_composer.getStructuredFilter(); + m_composer.setFilter(""); + m_composer.setStructuredFilter(aStructuredFilter); + if (!m_composer.getFilter().equals(COMPLEXFILTER)) + { + System.out.println(COMPLEXFILTER); + System.out.println(m_composer.getFilter()); + } + assertTrue("Structured Filter not identical", m_composer.getFilter().equals(COMPLEXFILTER)); + + // structured having clause + m_composer.setHavingClause(COMPLEXFILTER); + final PropertyValue[][] aStructuredHaving = m_composer.getStructuredHavingClause(); + m_composer.setHavingClause(""); + m_composer.setStructuredHavingClause(aStructuredHaving); + assertTrue("Structured Having Clause not identical", m_composer.getHavingClause().equals(COMPLEXFILTER)); + } + + /** test various sub query related features ("queries in queries") + */ + @Test + public void testSubQueries() throws Exception + { + m_composer.setQuery("SELECT * from \"" + INNERPRODUCTSQUERY + "\""); + final XTablesSupplier suppTables = UnoRuntime.queryInterface(XTablesSupplier.class, m_composer); + final XNameAccess tables = suppTables.getTables(); + assertTrue("a simple SELECT * FROM could not be parsed", + tables != null && tables.hasByName(INNERPRODUCTSQUERY)); + + final String sInnerCommand = m_database.getDatabase().getDataSource().getQueryDefinition(INNERPRODUCTSQUERY).getCommand(); + final String sExecutableQuery = m_composer.getQueryWithSubstitution(); + assertTrue("simple query containing a sub query improperly parsed to SDBC level statement: \n1. " + sExecutableQuery + "\n2. " + "SELECT * FROM ( " + sInnerCommand + " ) AS \"" + INNERPRODUCTSQUERY + "\"", + sExecutableQuery.equals("SELECT * FROM ( " + sInnerCommand + " ) AS \"" + INNERPRODUCTSQUERY + "\"")); + } + + /** tests the XParametersSupplier functionality + */ + @Test + public void testParameters() throws Exception + { + // "orders for customers" is a query with a named parameter (based on another query) + m_database.getDatabase().getDataSource().createQuery("orders for customer", "SELECT * FROM \"all orders\" WHERE \"Customer Name\" LIKE :cname"); + // "orders for customer and product" is query based on "orders for customers", adding an additional, + // anonymous parameter + m_database.getDatabase().getDataSource().createQuery("orders for customer and product", "SELECT * FROM \"orders for customer\" WHERE \"Product Name\" LIKE ?"); + + m_composer.setQuery(m_database.getDatabase().getDataSource().getQueryDefinition("orders for customer and product").getCommand()); + final XParametersSupplier suppParams = UnoRuntime.queryInterface(XParametersSupplier.class, m_composer); + final XIndexAccess parameters = suppParams.getParameters(); + + final String expectedParamNames[] = + + { + "cname", + "Product Name" + }; + + final int paramCount = parameters.getCount(); + assertTrue("composer did find wrong number of parameters in the nested queries.", + paramCount == expectedParamNames.length); + + for (int i = 0; i < paramCount; ++i) + { + final XPropertySet parameter = UnoRuntime.queryInterface(XPropertySet.class, parameters.getByIndex(i)); + final String paramName = (String) parameter.getPropertyValue("Name"); + assertTrue("wrong parameter name at position " + (i + 1) + " (expected: " + expectedParamNames[i] + ", found: " + paramName + ")", + paramName.equals(expectedParamNames[i])); + + } + } + + @Test + public void testConditionByColumn() throws Exception + { + m_composer.setQuery("SELECT * FROM \"customers\""); + + final Object initArgs[] = + + { + new NamedValue("AutomaticAddition", Boolean.TRUE) + }; + final String serviceName = "com.sun.star.beans.PropertyBag"; + final XPropertyContainer filter = UnoRuntime.queryInterface(XPropertyContainer.class, getMSF().createInstanceWithArguments(serviceName, initArgs)); + filter.addProperty("Name", PropertyAttribute.MAYBEVOID, "Comment"); + filter.addProperty("RealName", PropertyAttribute.MAYBEVOID, "Comment"); + filter.addProperty("TableName", PropertyAttribute.MAYBEVOID, "customers"); + filter.addProperty("Value", PropertyAttribute.MAYBEVOID, "Good one."); + filter.addProperty("Type", PropertyAttribute.MAYBEVOID, Integer.valueOf(DataType.LONGVARCHAR)); + final XPropertySet column = UnoRuntime.queryInterface(XPropertySet.class, filter); + + m_composer.appendFilterByColumn(column, true, SQLFilterOperator.LIKE); + assertTrue("At least one row should exist", m_database.getConnection().createStatement().executeQuery(m_composer.getQuery()).next()); + } + + private void impl_testDisjunctiveNormalForm(String _query, PropertyValue[][] _expectedDNF) throws SQLException + { + m_composer.setQuery(_query); + + final PropertyValue[][] disjunctiveNormalForm = m_composer.getStructuredFilter(); + + assertEquals("DNF: wrong number of rows", _expectedDNF.length, disjunctiveNormalForm.length); + for (int i = 0; i < _expectedDNF.length; ++i) + { + assertEquals("DNF: wrong number of columns in row " + i, _expectedDNF[i].length, disjunctiveNormalForm[i].length); + for (int j = 0; j < _expectedDNF[i].length; ++j) + { + assertEquals("DNF: wrong content in column " + j + ", row " + i, + _expectedDNF[i][j].Name, disjunctiveNormalForm[i][j].Name); + } + } + } + + /** tests the disjunctive normal form functionality, aka the structured filter, + * of the composer + */ + @Test + public void testDisjunctiveNormalForm() throws Exception + { + // a simple case: WHERE clause simply is a combination of predicates knitted with AND + String query = + "SELECT \"customers\".\"Name\", " + + "\"customers\".\"Address\", " + + "\"customers\".\"City\", " + + "\"customers\".\"Postal\", " + + "\"products\".\"Name\" " + + "FROM \"orders\", \"customers\", \"orders_details\", \"products\" " + + "WHERE ( \"orders\".\"CustomerID\" = \"customers\".\"ID\" " + + "AND \"orders_details\".\"OrderID\" = \"orders\".\"ID\" " + + "AND \"orders_details\".\"ProductID\" = \"products\".\"ID\" " + + ") "; + + impl_testDisjunctiveNormalForm(query, new PropertyValue[][] + { + new PropertyValue[] + { + new PropertyValue("CustomerID", SQLFilterOperator.EQUAL, "\"customers\".\"ID\"", PropertyState.DIRECT_VALUE), + new PropertyValue("OrderID", SQLFilterOperator.EQUAL, "\"orders\".\"ID\"", PropertyState.DIRECT_VALUE), + new PropertyValue("ProductID", SQLFilterOperator.EQUAL, "\"products\".\"ID\"", PropertyState.DIRECT_VALUE) + } + }); + + // somewhat more challenging: One of the conjunction terms is a disjunction itself + query = + "SELECT \"customers\".\"Name\", " + + "\"customers\".\"Address\", " + + "\"customers\".\"City\", " + + "\"customers\".\"Postal\", " + + "\"products\".\"Name\" " + + "FROM \"orders\", \"customers\", \"orders_details\", \"products\" " + + "WHERE ( \"orders\".\"CustomerID\" = \"customers\".\"ID\" " + + "AND \"orders_details\".\"OrderID\" = \"orders\".\"ID\" " + + "AND \"orders_details\".\"ProductID\" = \"products\".\"ID\" " + + ") " + + "AND " + + "( \"products\".\"Name\" = 'Apples' " + + "OR \"products\".\"ID\" = 2 " + + ")"; + + impl_testDisjunctiveNormalForm(query, new PropertyValue[][] + { + new PropertyValue[] + { + new PropertyValue("CustomerID", SQLFilterOperator.EQUAL, "\"customers\".\"ID\"", PropertyState.DIRECT_VALUE), + new PropertyValue("OrderID", SQLFilterOperator.EQUAL, "\"orders\".\"ID\"", PropertyState.DIRECT_VALUE), + new PropertyValue("ProductID", SQLFilterOperator.EQUAL, "\"products\".\"ID\"", PropertyState.DIRECT_VALUE), + new PropertyValue("Name", SQLFilterOperator.EQUAL, "Apples", PropertyState.DIRECT_VALUE) + }, + new PropertyValue[] + { + new PropertyValue("CustomerID", SQLFilterOperator.EQUAL, "\"customers\".\"ID\"", PropertyState.DIRECT_VALUE), + new PropertyValue("OrderID", SQLFilterOperator.EQUAL, "\"orders\".\"ID\"", PropertyState.DIRECT_VALUE), + new PropertyValue("ProductID", SQLFilterOperator.EQUAL, "\"products\".\"ID\"", PropertyState.DIRECT_VALUE), + new PropertyValue("ID", SQLFilterOperator.EQUAL, Integer.valueOf(2), PropertyState.DIRECT_VALUE) + } + }); + + } +} diff --git a/dbaccess/qa/complex/dbaccess/TestCase.java b/dbaccess/qa/complex/dbaccess/TestCase.java new file mode 100644 index 000000000..a9768e7b4 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/TestCase.java @@ -0,0 +1,232 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import com.sun.star.beans.PropertyValue; +import com.sun.star.frame.XComponentLoader; +import com.sun.star.frame.XModel; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XComponentContext; +import helper.FileTools; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +// ---------- junit imports ----------------- +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.openoffice.test.OfficeConnection; +import static org.junit.Assert.*; + + + +public abstract class TestCase +{ + + protected final XComponentContext getComponentContext() + { + return connection.getComponentContext(); + } + + + public void before() throws java.lang.Exception + { + } + + + public void after() throws java.lang.Exception + { + } + + + /** returns the URL of a temporary file which can be used during the test. + * + * The file will be deleted when the process exits + * @return the URL of a temporary file + */ + protected final String createTempFileURL() throws IOException + { + final File documentFile = java.io.File.createTempFile( "dbaccess_test", ".odb" ).getAbsoluteFile(); + if ( documentFile.exists() ) + { + documentFile.delete(); + } + return FileHelper.getOOoCompatibleFileURL( documentFile.toURI().toURL().toString() ); + } + + + /** + * copies the file given by URL to a temporary file + * @return + * the URL of the new file + */ + protected final String copyToTempFile( String _sourceURL ) throws IOException + { + final String targetURL = createTempFileURL(); + try + { + FileTools.copyFile( new File( new URI( _sourceURL ) ), new File( new URI( targetURL ) ) ); + } + catch ( URISyntaxException e ) { } + + return FileHelper.getOOoCompatibleFileURL( targetURL ); + } + + + protected final XModel loadDocument( final String _docURL ) throws Exception + { + final XComponentLoader loader = UnoRuntime.queryInterface( XComponentLoader.class, + getMSF().createInstance( "com.sun.star.frame.Desktop" ) ); + return UnoRuntime.queryInterface( XModel.class, + loader.loadComponentFromURL( _docURL, "_blank", 0, new PropertyValue[] {} ) ); + } + + + /** invokes a given method on a given object, and assures a certain exception is caught + * @param _message + * is the message to print when the check fails + * @param _object + * is the object to invoke the method on + * @param _methodName + * is the name of the method to invoke + * @param _methodArgs + * are the arguments to pass to the method. + * @param _argClasses + * are the classes to assume for the arguments of the methods + * @param _expectedExceptionClass + * is the class of the exception to be caught. If this is null, + * it means that no exception must be throw by invoking the method. + */ + private void assureException( final String _message, final Object _object, final String _methodName, + final Class[] _argClasses, final Object[] _methodArgs, final Class _expectedExceptionClass ) + { + Class objectClass = _object.getClass(); + + boolean noExceptionAllowed = ( _expectedExceptionClass == null ); + + boolean caughtExpected = noExceptionAllowed; + try + { + Method method = objectClass.getMethod( _methodName, _argClasses ); + method.invoke(_object, _methodArgs ); + } + catch ( InvocationTargetException e ) + { + caughtExpected = noExceptionAllowed + ? false + : ( e.getTargetException().getClass().equals( _expectedExceptionClass ) ); + } + catch( Exception e ) + { + caughtExpected = false; + } + + assertTrue( _message, caughtExpected ); + } + + /** invokes a given method on a given object, and assures a certain exception is caught + * @param _message is the message to print when the check fails + * @param _object is the object to invoke the method on + * @param _methodName is the name of the method to invoke + * @param _methodArgs are the arguments to pass to the method. Those implicitly define + * the classes of the arguments of the method which is called. + * @param _expectedExceptionClass is the class of the exception to be caught. If this is null, + * it means that no exception must be throw by invoking the method. + */ + private void assureException( final String _message, final Object _object, final String _methodName, + final Object[] _methodArgs, final Class _expectedExceptionClass ) + { + Class[] argClasses = new Class[ _methodArgs.length ]; + for ( int i=0; i<_methodArgs.length; ++i ) + argClasses[i] = _methodArgs[i].getClass(); + assureException( _message, _object, _methodName, argClasses, _methodArgs, _expectedExceptionClass ); + } + + /** invokes a given method on a given object, and assures a certain exception is caught + * @param _object is the object to invoke the method on + * @param _methodName is the name of the method to invoke + * @param _methodArgs are the arguments to pass to the method. Those implicitly define + * the classes of the arguments of the method which is called. + * @param _expectedExceptionClass is the class of the exception to be caught. If this is null, + * it means that no exception must be throw by invoking the method. + */ + private void assureException( final Object _object, final String _methodName, final Object[] _methodArgs, + final Class _expectedExceptionClass ) + { + assureException( + "did not catch the expected exception (" + + ( ( _expectedExceptionClass == null ) ? "none" : _expectedExceptionClass.getName() ) + + ") while calling " + _object.getClass().getName() + "." + _methodName, + _object, _methodName, _methodArgs, _expectedExceptionClass ); + } + + /** invokes a given method on a given object, and assures a certain exception is caught + * @param _object is the object to invoke the method on + * @param _methodName is the name of the method to invoke + * @param _methodArgs are the arguments to pass to the method + * @param _argClasses are the classes to assume for the arguments of the methods + * @param _expectedExceptionClass is the class of the exception to be caught. If this is null, + * it means that no exception must be throw by invoking the method. + */ + protected void assureException( final Object _object, final String _methodName, final Class[] _argClasses, + final Object[] _methodArgs, final Class _expectedExceptionClass ) + { + assureException( + "did not catch the expected exception (" + + ( ( _expectedExceptionClass == null ) ? "none" : _expectedExceptionClass.getName() ) + + ") while calling " + _object.getClass().getName() + "." + _methodName, + _object, _methodName, _argClasses, _methodArgs, _expectedExceptionClass ); + } + + + @SuppressWarnings("unchecked") + protected void assureException( Object _object, Class _unoInterfaceClass, String _methodName, Object[] _methodArgs, + Class _expectedExceptionClass ) + { + assureException( UnoRuntime.queryInterface( _unoInterfaceClass, _object ), _methodName, + _methodArgs, _expectedExceptionClass ); + } + + + protected final XMultiServiceFactory getMSF() + { + return UnoRuntime.queryInterface(XMultiServiceFactory.class, connection.getComponentContext().getServiceManager()); + } + + + // setup and close connections + @BeforeClass + public static void setUpConnection() throws Exception + { + connection.setUp(); + } + + + @AfterClass + public static void tearDownConnection() throws InterruptedException, com.sun.star.uno.Exception + { + connection.tearDown(); + } + + private static final OfficeConnection connection = new OfficeConnection(); + +} diff --git a/dbaccess/qa/complex/dbaccess/UISettings.java b/dbaccess/qa/complex/dbaccess/UISettings.java new file mode 100644 index 000000000..273d6b7a7 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/UISettings.java @@ -0,0 +1,132 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +package complex.dbaccess; + +import com.sun.star.awt.FontSlant; +import com.sun.star.awt.TextAlign; +import com.sun.star.beans.XPropertySet; +import com.sun.star.container.XNameAccess; +import com.sun.star.form.runtime.XFormController; +import com.sun.star.frame.XController; +import com.sun.star.sdb.application.DatabaseObject; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.util.XCloseable; +import connectivity.tools.CRMDatabase; + +// ---------- junit imports ----------------- +import org.junit.Test; +import static org.junit.Assert.*; + + +public class UISettings extends TestCase +{ + + /** verifies that aliases for inner queries work as expected + */ + @Test + public void checkTableFormattingPersistence() throws java.lang.Exception + { + // create, load, and connect a DB doc + CRMDatabase database = new CRMDatabase( getMSF(), true ); + + // display a table + XFormController tableViewController = UnoRuntime.queryInterface( XFormController.class, + database.loadSubComponent( DatabaseObject.TABLE, "customers" ) ); + XPropertySet tableControlModel = UnoRuntime.queryInterface( XPropertySet.class, + tableViewController.getCurrentControl().getModel() ); + + // change the table's formatting + tableControlModel.setPropertyValue( "FontName", "Andale Sans UI" ); + tableControlModel.setPropertyValue( "FontHeight", Float.valueOf( 20 ) ); + tableControlModel.setPropertyValue( "FontSlant", FontSlant.ITALIC ); + + String docURL = database.getDatabase().getModel().getURL(); + + // save close the database document + database.saveAndClose(); + + // load a copy of the document + // normally, it should be sufficient to load the same doc. However, there might be objects in the Java VM + // which are not yet freed, and which effectively hold the document alive. More precise: The document (|doc|) + // is certainly disposed, but other objects might hold a reference to one of the many other components + // around the database document, the data source, the connection, etc. As long as those objects are + // not cleaned up, the "database model impl" - the structure holding all document data - will + // stay alive, and subsequent requests to load the doc will just reuse it, without really loading it. + docURL = copyToTempFile( docURL ); + loadDocument( docURL ); + database = new CRMDatabase( getMSF(), docURL ); + + // display the table, again + tableViewController = UnoRuntime.queryInterface( XFormController.class, + database.loadSubComponent( DatabaseObject.TABLE, "customers" ) ); + tableControlModel = UnoRuntime.queryInterface( XPropertySet.class, + tableViewController.getCurrentControl().getModel() ); + + // verify the properties + assertEquals( "wrong font name", "Andale Sans UI", tableControlModel.getPropertyValue( "FontName" ) ); + assertEquals( "wrong font height", 20, ((Float)tableControlModel.getPropertyValue( "FontHeight" )).floatValue(), 0 ); + assertEquals( "wrong font slant", FontSlant.ITALIC, tableControlModel.getPropertyValue( "FontSlant" ) ); + + // close the doc + database.saveAndClose(); + } + + /** + * checks whether query columns use the settings of the underlying table column, if they do not (yet) have own + * settings + */ + @Test + public void checkTransparentQueryColumnSettings() throws java.lang.Exception + { + // create, load, and connect a DB doc + CRMDatabase database = new CRMDatabase( getMSF(), true ); + + // display a table + XController tableView = database.loadSubComponent( DatabaseObject.TABLE, "customers" ); + XFormController tableViewController = UnoRuntime.queryInterface( XFormController.class, + tableView ); + XNameAccess tableControlModel = UnoRuntime.queryInterface( XNameAccess.class, + tableViewController.getCurrentControl().getModel() ); + + // change the formatting of a table column + XPropertySet idColumn = UnoRuntime.queryInterface( XPropertySet.class, tableControlModel.getByName( "ID" ) ); + assertTrue( "precondition not met: column already centered", + ((Short)idColumn.getPropertyValue( "Align" )).shortValue() != TextAlign.CENTER ); + idColumn.setPropertyValue( "Align", TextAlign.CENTER ); + + // close the table data view + XCloseable closeSubComponent = UnoRuntime.queryInterface( XCloseable.class, tableView.getFrame() ); + closeSubComponent.close( true ); + + // create a query based on that column + database.getDatabase().getDataSource().createQuery( "q_customers", "SELECT * FROM \"customers\"" ); + + // load this query, and verify the table column settings was propagated to the query column + XFormController queryViewController = UnoRuntime.queryInterface( XFormController.class, + database.loadSubComponent( DatabaseObject.QUERY, "q_customers" ) ); + tableControlModel = UnoRuntime.queryInterface( XNameAccess.class, + queryViewController.getCurrentControl().getModel() ); + idColumn = UnoRuntime.queryInterface( XPropertySet.class, tableControlModel.getByName( "ID" ) ); + + assertTrue( "table column alignment was not propagated to the query column", + ((Short)idColumn.getPropertyValue( "Align" )).shortValue() == TextAlign.CENTER ); + + // save close the database document + database.saveAndClose(); + } +} diff --git a/dbaccess/qa/complex/dbaccess/makefile.mk b/dbaccess/qa/complex/dbaccess/makefile.mk new file mode 100644 index 000000000..862a0ffc9 --- /dev/null +++ b/dbaccess/qa/complex/dbaccess/makefile.mk @@ -0,0 +1,93 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this 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 "$(OOO_JUNIT_JAR)" == "" +nothing .PHONY: + @echo ----------------------------------------------------- + @echo - JUnit not available, not building anything + @echo ----------------------------------------------------- +.ELSE + +PRJ = ../../.. +PRJNAME = dbaccess +TARGET = qa_complex_dbaccess +PACKAGE = complex/dbaccess + +# --- Settings ----------------------------------------------------- +.INCLUDE: settings.mk + +#----- compile .java files ----------------------------------------- + +JARFILES = OOoRunner.jar ridl.jar test.jar juh.jar unoil.jar ConnectivityTools.jar +EXTRAJARFILES = $(OOO_JUNIT_JAR) + +#----- create a jar from compiled files ---------------------------- + +JARTARGET = $(TARGET).jar + +#----- Java files -------------------------------------------------- + +# here store only Files which contain a @Test +JAVATESTFILES = \ + ApplicationController.java \ + Beamer.java \ + DataSource.java \ + DatabaseDocument.java \ + Parser.java \ + PropertyBag.java \ + Query.java \ + QueryInQuery.java \ + RowSet.java \ + SingleSelectQueryComposer.java \ + UISettings.java \ + CopyTableWizard.java \ + +# put here all other files +JAVAFILES = $(JAVATESTFILES) \ + CRMBasedTestCase.java \ + CopyTableInterActionHandler.java \ + DatabaseApplication.java \ + FileHelper.java \ + RowSetEventListener.java \ + TestCase.java \ + + +# Sample how to debug +# JAVAIFLAGS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=9003,suspend=y + +# --- Targets ------------------------------------------------------ + +.INCLUDE: target.mk + +ALL : ALLTAR + +# --- subsequent tests --------------------------------------------- + +.IF "$(OOO_SUBSEQUENT_TESTS)" != "" + +.INCLUDE: installationtest.mk + +ALLTAR : javatest + + # Sample how to debug + # JAVAIFLAGS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=9003,suspend=y + +.END # "$(OOO_SUBSEQUENT_TESTS)" == "" + +.END # ELSE "$(OOO_JUNIT_JAR)" != "" + diff --git a/dbaccess/qa/extras/dialog-save.cxx b/dbaccess/qa/extras/dialog-save.cxx new file mode 100644 index 000000000..a336a66e3 --- /dev/null +++ b/dbaccess/qa/extras/dialog-save.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +class DialogSaveTest : public UnoApiTest +{ +public: + DialogSaveTest(); + + void test(); + + CPPUNIT_TEST_SUITE(DialogSaveTest); +// Should we disable this test on MOX and WNT? +// #if !defined(MACOSX) && !defined(_WIN32) + CPPUNIT_TEST(test); +// #endif + CPPUNIT_TEST_SUITE_END(); + +}; + + +DialogSaveTest::DialogSaveTest() + : UnoApiTest("/dbaccess/qa/extras/testdocuments") +{ +} + +void DialogSaveTest::test() +{ + // UnoApiTest::setUp (via InitVCL) puts each test under a locked SolarMutex, + // but at least the below xDocCloseable->close call could lead to a deadlock + // then, and it looks like none of the code here requires the SolarMutex to + // be locked anyway: + SolarMutexReleaser rel; + + const OUString sStandard("Standard"); + const OUString aFileName(m_directories.getURLFromWorkdir("CppunitTest/testDialogSave.odb")); + { + uno::Reference< lang::XComponent > xComponent = loadFromDesktop(aFileName); + CPPUNIT_ASSERT(xComponent.is()); + uno::Reference< frame::XStorable > xDocStorable(xComponent, UNO_QUERY_THROW); + uno::Reference< document::XEmbeddedScripts > xDocScr(xComponent, UNO_QUERY_THROW); + uno::Reference< script::XStorageBasedLibraryContainer > xStorBasLib(xDocScr->getBasicLibraries()); + CPPUNIT_ASSERT(xStorBasLib.is()); + uno::Reference< script::XLibraryContainer > xBasLib(xStorBasLib, UNO_QUERY_THROW); + uno::Reference< script::XStorageBasedLibraryContainer > xStorDlgLib(xDocScr->getDialogLibraries()); + CPPUNIT_ASSERT(xStorDlgLib.is()); + uno::Reference< script::XLibraryContainer > xDlgLib(xStorDlgLib, UNO_QUERY_THROW); + xBasLib->loadLibrary(sStandard); + CPPUNIT_ASSERT(xBasLib->isLibraryLoaded(sStandard)); + // the whole point of this test is to test the "save" operation + // when the Basic library is loaded, but not the Dialog library + CPPUNIT_ASSERT(!xDlgLib->isLibraryLoaded(sStandard)); + + // make some change to enable a save + // uno::Reference< document::XDocumentPropertiesSupplier > xDocPropSuppl(xComponent, UNO_QUERY_THROW); + // uno::Reference< document::XDocumentPropertiesSupplier > xDocProps(xDocPropSuppl->getDocumentProperties()); + // CPPUNIT_ASSERT(xDocProps.is()); + // xDocProps.setTitle(xDocProps.getTitle() + " suffix"); + uno::Reference< util::XModifiable > xDocMod(xComponent, UNO_QUERY_THROW); + xDocMod->setModified(true); + + // now save; the code path to exercise in this test is the "store to same location" + // do *not* change to store(As|To|URL)! + xDocStorable->store(); + + // close + uno::Reference< util::XCloseable > xDocCloseable(xComponent, UNO_QUERY_THROW); + xDocCloseable->close(false); + + // All our uno::References are (should?) be invalid now -> let them go out of scope + } + { + uno::Sequence args(1); + args[0] <<= aFileName; + Reference xHNA(getMultiServiceFactory()->createInstanceWithArguments("com.sun.star.packages.Package", args), UNO_QUERY_THROW); + Reference< beans::XPropertySet > xPS(xHNA->getByHierarchicalName("Dialogs/Standard/Dialog1.xml"), UNO_QUERY_THROW); + sal_Int64 nSize = 0; + CPPUNIT_ASSERT(xPS->getPropertyValue("Size") >>= nSize); + CPPUNIT_ASSERT(nSize != 0); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(DialogSaveTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/extras/empty-stdlib-save.cxx b/dbaccess/qa/extras/empty-stdlib-save.cxx new file mode 100644 index 000000000..cce32ed08 --- /dev/null +++ b/dbaccess/qa/extras/empty-stdlib-save.cxx @@ -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/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +class DialogSaveTest : public UnoApiTest +{ +public: + DialogSaveTest(); + + void test(); + + CPPUNIT_TEST_SUITE(DialogSaveTest); +// Should we disable this test on MOX and WNT? +// #if !defined(MACOSX) && !defined(_WIN32) + CPPUNIT_TEST(test); +// #endif + CPPUNIT_TEST_SUITE_END(); + +}; + + +DialogSaveTest::DialogSaveTest() + : UnoApiTest("/dbaccess/qa/extras/testdocuments") +{ +} + +void DialogSaveTest::test() +{ + // UnoApiTest::setUp (via InitVCL) puts each test under a locked SolarMutex, + // but at least the below xDocCloseable->close call could lead to a deadlock + // then, and it looks like none of the code here requires the SolarMutex to + // be locked anyway: + SolarMutexReleaser rel; + + const OUString sStandard("Standard"); + const OUString aFileName(m_directories.getURLFromWorkdir("CppunitTest/testEmptyStdlibSave.odb")); + { + uno::Reference< lang::XComponent > xComponent = loadFromDesktop(aFileName); + CPPUNIT_ASSERT(xComponent.is()); + uno::Reference< frame::XStorable > xDocStorable(xComponent, UNO_QUERY_THROW); + uno::Reference< document::XEmbeddedScripts > xDocScr(xComponent, UNO_QUERY_THROW); + uno::Reference< script::XStorageBasedLibraryContainer > xStorBasLib(xDocScr->getBasicLibraries()); + CPPUNIT_ASSERT(xStorBasLib.is()); + uno::Reference< script::XLibraryContainer > xBasLib(xStorBasLib, UNO_QUERY_THROW); + uno::Reference< script::XStorageBasedLibraryContainer > xStorDlgLib(xDocScr->getDialogLibraries()); + CPPUNIT_ASSERT(xStorDlgLib.is()); + uno::Reference< script::XLibraryContainer > xDlgLib(xStorDlgLib, UNO_QUERY_THROW); + xBasLib->loadLibrary(sStandard); + xDlgLib->loadLibrary(sStandard); + CPPUNIT_ASSERT(xBasLib->isLibraryLoaded(sStandard)); + CPPUNIT_ASSERT(xDlgLib->isLibraryLoaded(sStandard)); + + Any a; + uno::Reference< container::XNameContainer > xI; + + a = xBasLib->getByName(sStandard); + a >>= xI; + CPPUNIT_ASSERT(xI.is()); + xI->removeByName("Raralix"); + + a = xDlgLib->getByName(sStandard); + a >>= xI; + CPPUNIT_ASSERT(xI.is()); + xI->removeByName("Dialog1"); + + // uno::Reference< util::XModifiable > xDlgMod(xDlgLib, UNO_QUERY_THROW); + // xDlgMod->setModified(sal_True); + + // uno::Reference< util::XModifiable > xScrMod(xDocScr, UNO_QUERY_THROW); + // xScrMod->setModified(sal_True); + + // uno::Reference< util::XModifiable > xDocMod(xComponent, UNO_QUERY_THROW); + // std::cerr << "** Modified: " << static_cast(xDocMod->isModified()) << std::endl; + // xDocMod->setModified(sal_True); + // std::cerr << "** Modified: " << static_cast(xDocMod->isModified()) << std::endl; + // CPPUNIT_ASSERT(xDocMod->isModified()); + + // now save; the code path to exercise in this test is the "store to same location" + // do *not* change to store(As|To|URL)! + xDocStorable->store(); + + // close + uno::Reference< util::XCloseable > xDocCloseable(xComponent, UNO_QUERY_THROW); + xDocCloseable->close(false); + + // All our uno::References are (should?) be invalid now -> let them go out of scope + } + { + uno::Sequence args(1); + args[0] <<= aFileName; + Reference xHNA(getMultiServiceFactory()->createInstanceWithArguments("com.sun.star.packages.Package", args), UNO_QUERY_THROW); + CPPUNIT_ASSERT(!xHNA->hasByHierarchicalName("Basic/Standard")); + CPPUNIT_ASSERT(!xHNA->hasByHierarchicalName("Dialogs/Standard")); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(DialogSaveTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/extras/hsql_schema_import.cxx b/dbaccess/qa/extras/hsql_schema_import.cxx new file mode 100644 index 000000000..89ee74ce0 --- /dev/null +++ b/dbaccess/qa/extras/hsql_schema_import.cxx @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include +#include +#include + +using namespace dbahsql; + +namespace +{ +constexpr std::size_t operator"" _z(unsigned long long n) { return n; } + +const ColumnDefinition* lcl_findByType(const std::vector& columns, + sal_Int32 nType) +{ + for (const auto& column : columns) + { + if (column.getDataType() == nType) + return &column; + } + return nullptr; +} +} + +class HsqlSchemaImportTest : public CppUnit::TestFixture +{ +public: + void testIntegerPrimaryKeyNotNull(); + void testVarcharWithParam(); + void testVarcharWithoutParam(); + void testNumericWithTwoParam(); + void testIntegerAutoincremental(); + void testTimestampWithParam(); + void testDefaultValueNow(); + void testEvilNullColumnName(); + // TODO testForeign, testDecomposer + + CPPUNIT_TEST_SUITE(HsqlSchemaImportTest); + + CPPUNIT_TEST(testIntegerPrimaryKeyNotNull); + CPPUNIT_TEST(testVarcharWithParam); + CPPUNIT_TEST(testVarcharWithoutParam); + CPPUNIT_TEST(testNumericWithTwoParam); + CPPUNIT_TEST(testIntegerAutoincremental); + CPPUNIT_TEST(testTimestampWithParam); + CPPUNIT_TEST(testDefaultValueNow); + CPPUNIT_TEST(testEvilNullColumnName); + + CPPUNIT_TEST_SUITE_END(); +}; + +void HsqlSchemaImportTest::testIntegerPrimaryKeyNotNull() +{ + const OUString sql{ "CREATE CACHED TABLE \"myTable\"(\"id\" INTEGER NOT NULL PRIMARY KEY)" }; + + FbCreateStmtParser aCreateParser; + aCreateParser.parse(sql); + + CPPUNIT_ASSERT_EQUAL(OUString{ "\"myTable\"" }, aCreateParser.getTableName()); + const auto& columns = aCreateParser.getColumnDef(); + CPPUNIT_ASSERT_EQUAL(1_z, columns.size()); + const auto& column = columns.at(0); + CPPUNIT_ASSERT_EQUAL(OUString{ "\"id\"" }, column.getName()); + CPPUNIT_ASSERT_EQUAL(css::sdbc::DataType::INTEGER, column.getDataType()); + CPPUNIT_ASSERT(column.isPrimaryKey()); + CPPUNIT_ASSERT(!column.isNullable()); + CPPUNIT_ASSERT(!column.isAutoIncremental()); +} + +void HsqlSchemaImportTest::testVarcharWithParam() +{ + const OUString sql{ + "CREATE CACHED TABLE \"myTable\"(\"id\" INTEGER NOT NULL PRIMARY KEY, \"myText\" " + "VARCHAR(50))" + }; + + FbCreateStmtParser aCreateParser; + aCreateParser.parse(sql); + + const auto& columns = aCreateParser.getColumnDef(); + CPPUNIT_ASSERT_EQUAL(2_z, columns.size()); + const ColumnDefinition* colVarchar = lcl_findByType(columns, css::sdbc::DataType::VARCHAR); + CPPUNIT_ASSERT(colVarchar != nullptr); + const auto& params = colVarchar->getParams(); + CPPUNIT_ASSERT_EQUAL(1_z, params.size()); + constexpr sal_Int32 nParamExpected = 50; + CPPUNIT_ASSERT_EQUAL(nParamExpected, params.at(0)); // VARCHAR(50) +} + +/** + * Special case: + * HSQLDB might define a column VARCHAR without parameter. With Firebird + * dialect, this is forbidden, so a default parameter has to be appended: + **/ +void HsqlSchemaImportTest::testVarcharWithoutParam() +{ + const OUString sql{ + "CREATE CACHED TABLE \"myTable\"(\"id\" INTEGER NOT NULL PRIMARY KEY, \"myText\" " + "VARCHAR)" + }; + + FbCreateStmtParser aCreateParser; + aCreateParser.parse(sql); + + const auto& columns = aCreateParser.getColumnDef(); + CPPUNIT_ASSERT_EQUAL(2_z, columns.size()); + const ColumnDefinition* colVarchar = lcl_findByType(columns, css::sdbc::DataType::VARCHAR); + CPPUNIT_ASSERT(colVarchar != nullptr); + const auto& params = colVarchar->getParams(); + CPPUNIT_ASSERT_EQUAL(1_z, params.size()); // parameter generated +} + +void HsqlSchemaImportTest::testNumericWithTwoParam() +{ + const OUString sql{ + "CREATE CACHED TABLE \"myTable\"(\"id\" INTEGER NOT NULL PRIMARY KEY, \"Betrag\" " + "NUMERIC(8,2))" + }; + + FbCreateStmtParser aCreateParser; + aCreateParser.parse(sql); + + const auto& columns = aCreateParser.getColumnDef(); + CPPUNIT_ASSERT_EQUAL(2_z, columns.size()); + + const ColumnDefinition* colNumeric = lcl_findByType(columns, css::sdbc::DataType::NUMERIC); + CPPUNIT_ASSERT(colNumeric != nullptr); + const auto& params = colNumeric->getParams(); + CPPUNIT_ASSERT_EQUAL(2_z, params.size()); + + constexpr sal_Int32 nPrecision = 8; + constexpr sal_Int32 nScale = 2; + CPPUNIT_ASSERT_EQUAL(nPrecision, params.at(0)); + CPPUNIT_ASSERT_EQUAL(nScale, params.at(1)); +} + +void HsqlSchemaImportTest::testIntegerAutoincremental() +{ + const OUString sql{ + "CREATE CACHED TABLE \"myTable\"(\"id\" INTEGER NOT NULL PRIMARY KEY GENERATED " + "BY DEFAULT AS IDENTITY(START WITH 0), \"myText\" VARCHAR(50))" + }; + + FbCreateStmtParser aCreateParser; + aCreateParser.parse(sql); + + const auto& columns = aCreateParser.getColumnDef(); + const auto column = columns.at(0); + CPPUNIT_ASSERT_EQUAL(css::sdbc::DataType::INTEGER, column.getDataType()); + CPPUNIT_ASSERT(column.isAutoIncremental()); + CPPUNIT_ASSERT(column.isPrimaryKey()); + CPPUNIT_ASSERT(!column.isNullable()); +} + +/** + * Special case: + * Hsqldb might use one parameter for defining column with type TIMESTAMP. + * With Firebird this is illegal. + */ +void HsqlSchemaImportTest::testTimestampWithParam() +{ + const OUString sql{ + "CREATE CACHED TABLE \"myTable\"(\"id\" INTEGER NOT NULL PRIMARY KEY, \"myText\" " + "TIMESTAMP(0))" + }; + + FbCreateStmtParser aCreateParser; + aCreateParser.parse(sql); + + const auto& columns = aCreateParser.getColumnDef(); + const ColumnDefinition* colTimeStamp = lcl_findByType(columns, css::sdbc::DataType::TIMESTAMP); + + CPPUNIT_ASSERT(colTimeStamp != nullptr); + + // instead of asserting parameter size, look at the deparsed string, + // because it's Firebird specific + OUString fbSql = aCreateParser.compose(); + CPPUNIT_ASSERT(fbSql.indexOf("0") < 0); //does not contain +} + +/** + * Special case: + * HSQLDB uses keyword NOW without quotes. Firebird uses single quotes 'NOW' + */ +void HsqlSchemaImportTest::testDefaultValueNow() +{ + const OUString sql{ + "CREATE CACHED TABLE \"myTable\"(\"id\" INTEGER NOT NULL PRIMARY KEY, \"myDate\" " + "TIMESTAMP DEFAULT NOW)" + }; + + FbCreateStmtParser aCreateParser; + aCreateParser.parse(sql); + + const auto& columns = aCreateParser.getColumnDef(); + const ColumnDefinition* colTimeStamp = lcl_findByType(columns, css::sdbc::DataType::TIMESTAMP); + + CPPUNIT_ASSERT(colTimeStamp != nullptr); + CPPUNIT_ASSERT_EQUAL(OUString{ "NOW" }, colTimeStamp->getDefault()); // parsed NOW + OUString fbSql = aCreateParser.compose(); + CPPUNIT_ASSERT(fbSql.indexOf("\'NOW\'") > 0); // composed 'NOW' +} + +void HsqlSchemaImportTest::testEvilNullColumnName() +{ + const OUString sql{ "CREATE CACHED TABLE \"myTable\"(\"id\" INTEGER NOT NULL PRIMARY KEY, " + "\"myEvilNOT NULLName\" " + "VARCHAR(20))" }; + + FbCreateStmtParser aCreateParser; + aCreateParser.parse(sql); + + const auto& columns = aCreateParser.getColumnDef(); + CPPUNIT_ASSERT_EQUAL(2_z, columns.size()); + const ColumnDefinition* colVarchar = lcl_findByType(columns, css::sdbc::DataType::VARCHAR); + CPPUNIT_ASSERT(colVarchar != nullptr); + CPPUNIT_ASSERT(colVarchar->isNullable()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(HsqlSchemaImportTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/dbaccess/qa/extras/macros-test.cxx b/dbaccess/qa/extras/macros-test.cxx new file mode 100644 index 000000000..d5b7538f9 --- /dev/null +++ b/dbaccess/qa/extras/macros-test.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +#if !defined(MACOSX) && !defined(_WIN32) + +class DBAccessTest : public UnoApiTest +{ +public: + DBAccessTest(); + + void test(); + + CPPUNIT_TEST_SUITE(DBAccessTest); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + +}; + + +DBAccessTest::DBAccessTest() + : UnoApiTest("/dbaccess/qa/extras/testdocuments") +{ +} + +void DBAccessTest::test() +{ + const OUString aFileNameBase("testdb.odb"); + OUString aFileName; + createFileURL(aFileNameBase, aFileName); + uno::Reference< lang::XComponent > xComponent = loadFromDesktop(aFileName); + CPPUNIT_ASSERT(xComponent.is()); + xComponent->dispose(); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(DBAccessTest); + +#endif + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/extras/nolib-save.cxx b/dbaccess/qa/extras/nolib-save.cxx new file mode 100644 index 000000000..b42171ce2 --- /dev/null +++ b/dbaccess/qa/extras/nolib-save.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/. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + + +class DialogSaveTest : public UnoApiTest +{ +public: + DialogSaveTest(); + + void test(); + + CPPUNIT_TEST_SUITE(DialogSaveTest); +// Should we disable this test on MOX and WNT? +// #if !defined(MACOSX) && !defined(_WIN32) + CPPUNIT_TEST(test); +// #endif + CPPUNIT_TEST_SUITE_END(); + +}; + + +DialogSaveTest::DialogSaveTest() + : UnoApiTest("/dbaccess/qa/extras/testdocuments") +{ +} + +void DialogSaveTest::test() +{ + // UnoApiTest::setUp (via InitVCL) puts each test under a locked SolarMutex, + // but at least the below xDocCloseable->close call could lead to a deadlock + // then, and it looks like none of the code here requires the SolarMutex to + // be locked anyway: + SolarMutexReleaser rel; + + const OUString sStandard("Standard"); + const OUString aFileName(m_directories.getURLFromWorkdir("CppunitTest/testNolibSave.odb")); + { + uno::Reference< lang::XComponent > xComponent = loadFromDesktop(aFileName); + CPPUNIT_ASSERT(xComponent.is()); + uno::Reference< frame::XStorable > xDocStorable(xComponent, UNO_QUERY_THROW); + uno::Reference< document::XEmbeddedScripts > xDocScr(xComponent, UNO_QUERY_THROW); + uno::Reference< script::XStorageBasedLibraryContainer > xStorBasLib(xDocScr->getBasicLibraries()); + CPPUNIT_ASSERT(xStorBasLib.is()); + uno::Reference< script::XLibraryContainer > xBasLib(xStorBasLib, UNO_QUERY_THROW); + uno::Reference< script::XStorageBasedLibraryContainer > xStorDlgLib(xDocScr->getDialogLibraries()); + CPPUNIT_ASSERT(xStorDlgLib.is()); + uno::Reference< script::XLibraryContainer > xDlgLib(xStorDlgLib, UNO_QUERY_THROW); + xBasLib->loadLibrary(sStandard); + xDlgLib->loadLibrary(sStandard); + CPPUNIT_ASSERT(xBasLib->isLibraryLoaded(sStandard)); + CPPUNIT_ASSERT(xDlgLib->isLibraryLoaded(sStandard)); + + xBasLib->removeLibrary(sStandard); + xDlgLib->removeLibrary(sStandard); + + // uno::Reference< util::XModifiable > xDlgMod(xDlgLib, UNO_QUERY_THROW); + // xDlgMod->setModified(sal_True); + + // uno::Reference< util::XModifiable > xScrMod(xDocScr, UNO_QUERY_THROW); + // xScrMod->setModified(sal_True); + + // uno::Reference< util::XModifiable > xDocMod(xComponent, UNO_QUERY_THROW); + // std::cerr << "** Modified: " << static_cast(xDocMod->isModified()) << std::endl; + // xDocMod->setModified(sal_True); + // std::cerr << "** Modified: " << static_cast(xDocMod->isModified()) << std::endl; + // CPPUNIT_ASSERT(xDocMod->isModified()); + + // now save; the code path to exercise in this test is the "store to same location" + // do *not* change to store(As|To|URL)! + xDocStorable->store(); + + // close + uno::Reference< util::XCloseable > xDocCloseable(xComponent, UNO_QUERY_THROW); + xDocCloseable->close(false); + + // All our uno::References are (should?) be invalid now -> let them go out of scope + } + { + uno::Sequence args(1); + args[0] <<= aFileName; + Reference xHNA(getMultiServiceFactory()->createInstanceWithArguments("com.sun.star.packages.Package", args), UNO_QUERY_THROW); + CPPUNIT_ASSERT(!xHNA->hasByHierarchicalName("Basic/Standard")); + CPPUNIT_ASSERT(!xHNA->hasByHierarchicalName("Dialogs/Standard")); + } +} + +CPPUNIT_TEST_SUITE_REGISTRATION(DialogSaveTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/extras/rowsetclones.cxx b/dbaccess/qa/extras/rowsetclones.cxx new file mode 100644 index 000000000..f62314205 --- /dev/null +++ b/dbaccess/qa/extras/rowsetclones.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/. + */ + +#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::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; + +class RowSetClones : public UnoApiTest +{ +public: + RowSetClones(); + + void test(); + + CPPUNIT_TEST_SUITE(RowSetClones); + CPPUNIT_TEST(test); + CPPUNIT_TEST_SUITE_END(); + +}; + + +RowSetClones::RowSetClones() + : UnoApiTest("") +{ +} + +void RowSetClones::test() +{ + const OUString sFilePath(m_directories.getURLFromWorkdir("CppunitTest/RowSetClones.odb")); + + uno::Reference< lang::XComponent > xComponent (loadFromDesktop(sFilePath)); + CPPUNIT_ASSERT(xComponent.is()); + + uno::Reference< XOfficeDatabaseDocument > xDocument(xComponent, UNO_QUERY); + CPPUNIT_ASSERT(xDocument.is()); + + uno::Reference< XDataSource > xDataSource = xDocument->getDataSource(); + CPPUNIT_ASSERT(xDataSource.is()); + + uno::Reference< XConnection > xConnection = xDataSource->getConnection("",""); + CPPUNIT_ASSERT(xConnection.is()); + + uno::Reference< XRowSet > xRowSet (getMultiServiceFactory()->createInstance("com.sun.star.sdb.RowSet" ), UNO_QUERY); + CPPUNIT_ASSERT(xRowSet.is()); + uno::Reference< XPropertySet > rowSetProperties ( xRowSet, UNO_QUERY ); + CPPUNIT_ASSERT(rowSetProperties.is()); + rowSetProperties->setPropertyValue("Command", Any(OUString("SELECT * FROM Assets ORDER BY AssetID"))); + rowSetProperties->setPropertyValue("CommandType", Any(CommandType::COMMAND)); + rowSetProperties->setPropertyValue("ActiveConnection", Any(xConnection)); + + xRowSet->execute(); + uno::Reference< XResultSet > xResultSet = xRowSet; + CPPUNIT_ASSERT(xResultSet.is()); + // always starts at BeforeFirst position + CPPUNIT_ASSERT(xResultSet->isBeforeFirst()); + CPPUNIT_ASSERT(xResultSet->next()); + CPPUNIT_ASSERT(xResultSet->isFirst()); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xResultSet->getRow()); + + uno::Reference< XRow > xRow(xResultSet, UNO_QUERY); + CPPUNIT_ASSERT(xRow.is()); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xRow->getInt(1)); + + uno::Reference< XResultSetAccess > xResultSetAccess(xResultSet, UNO_QUERY); + CPPUNIT_ASSERT(xResultSetAccess.is()); + uno::Reference< XResultSet > xResultSetClone = xResultSetAccess->createResultSet(); + CPPUNIT_ASSERT(xResultSetClone.is()); + + uno::Reference< XRow > xRowClone(xResultSetClone, UNO_QUERY); + CPPUNIT_ASSERT(xRowClone.is()); + + // the clone starts at same position as what it is cloned from, + // and does not move its source. + CPPUNIT_ASSERT(xResultSetClone->isFirst()); + CPPUNIT_ASSERT(xResultSet->isFirst()); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xResultSet->getRow()); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xResultSetClone->getRow()); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xRow->getInt(1)); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xRowClone->getInt(1)); + + // if we move the source, the clone does not move + CPPUNIT_ASSERT(xResultSet->next()); + CPPUNIT_ASSERT(xResultSetClone->isFirst()); + CPPUNIT_ASSERT_EQUAL(static_cast(2), xResultSet->getRow()); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xResultSetClone->getRow()); + CPPUNIT_ASSERT_EQUAL(static_cast(2), xRow->getInt(1)); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xRowClone->getInt(1)); + + CPPUNIT_ASSERT(xResultSet->last()); + CPPUNIT_ASSERT(xResultSet->isLast()); + CPPUNIT_ASSERT(xResultSetClone->isFirst()); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xRowClone->getInt(1)); + + // and the other way round + CPPUNIT_ASSERT(xResultSet->first()); + CPPUNIT_ASSERT(xResultSetClone->next()); + CPPUNIT_ASSERT(xResultSet->isFirst()); + CPPUNIT_ASSERT_EQUAL(static_cast(2), xResultSetClone->getRow()); + CPPUNIT_ASSERT_EQUAL(static_cast(2), xRowClone->getInt(1)); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xRow->getInt(1)); + + CPPUNIT_ASSERT(xResultSetClone->last()); + CPPUNIT_ASSERT(xResultSetClone->isLast()); + CPPUNIT_ASSERT(xResultSet->isFirst()); + CPPUNIT_ASSERT_EQUAL(static_cast(1), xRow->getInt(1)); + + closeDocument(uno::Reference(xDocument, uno::UNO_QUERY)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(RowSetClones); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/extras/testdocuments/RowSetClones.odb b/dbaccess/qa/extras/testdocuments/RowSetClones.odb new file mode 100644 index 000000000..91ed328ac Binary files /dev/null and b/dbaccess/qa/extras/testdocuments/RowSetClones.odb differ diff --git a/dbaccess/qa/extras/testdocuments/fdo84315.odb b/dbaccess/qa/extras/testdocuments/fdo84315.odb new file mode 100644 index 000000000..0513ff587 Binary files /dev/null and b/dbaccess/qa/extras/testdocuments/fdo84315.odb differ diff --git a/dbaccess/qa/extras/testdocuments/testDialogSave.odb b/dbaccess/qa/extras/testdocuments/testDialogSave.odb new file mode 100644 index 000000000..d72531253 Binary files /dev/null and b/dbaccess/qa/extras/testdocuments/testDialogSave.odb differ diff --git a/dbaccess/qa/extras/testdocuments/testdb.odb b/dbaccess/qa/extras/testdocuments/testdb.odb new file mode 100644 index 000000000..038e998e6 Binary files /dev/null and b/dbaccess/qa/extras/testdocuments/testdb.odb differ diff --git a/dbaccess/qa/python/fdo84315.py b/dbaccess/qa/python/fdo84315.py new file mode 100644 index 000000000..f58b16f51 --- /dev/null +++ b/dbaccess/qa/python/fdo84315.py @@ -0,0 +1,76 @@ +#! /usr/bin/env python +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import os +import unittest +from collections import deque +import unohelper +from org.libreoffice.unotest import UnoInProcess + +class Fdo84315(unittest.TestCase): + + @classmethod + def setUpClass(cls): + cls._uno = UnoInProcess() + cls._uno.setUp() + workdir = os.environ[ "WORKDIR_FOR_BUILD" ] + cls._xDoc = cls._uno.openDocFromAbsolutePath(workdir + "/CppunitTest/fdo84315.odb") + + @classmethod + def tearDownClass(cls): + cls._uno.tearDown() + + def __test_Query(self, column_name, expected_type, xResultset): + self.assertTrue(xResultset) + xMeta = xResultset.MetaData + self.assertEqual(xMeta.ColumnCount, 1) + self.assertEqual(xResultset.findColumn(column_name), 1) + self.assertEqual(xMeta.getColumnName(1), column_name) + self.assertEqual(xMeta.getColumnType(1), expected_type) + return xMeta + + def __test_ResultSetInteger(self, xResultset, expected_values): + while xResultset.next(): + self.assertEqual(xResultset.getInt(1), expected_values.popleft()) + self.assertEqual(len(expected_values), 0) + + def __test_ResultSetString(self, xResultset, expected_values): + while xResultset.next(): + self.assertEqual(xResultset.getString(1), expected_values.popleft()) + self.assertEqual(len(expected_values), 0) + + def test_fdo84315(self): + xDoc = self.__class__._xDoc + xDataSource = xDoc.DataSource + xCon = xDataSource.getConnection('','') + xStatement = xCon.createStatement() + + NUMERIC = 2 + VAR_CHAR = 12 + INTEGER = 4 + + xResultset = xStatement.executeQuery('SELECT "count" FROM "test_table"') + expected_values = deque([42, 4711]) + xMeta = self.__test_Query('count', NUMERIC, xResultset) + self.__test_ResultSetInteger(xResultset, expected_values) + + xResultset = xStatement.executeQuery('SELECT "name" FROM "test_table"') + expected_values = deque(['foo', 'bar']) + xMeta = self.__test_Query('name', VAR_CHAR, xResultset) + self.__test_ResultSetString(xResultset, expected_values) + + xResultset = xStatement.executeQuery('SELECT "id" FROM "test_table"') + expected_values = deque([0, 1]) + xMeta = self.__test_Query('id', INTEGER, xResultset) + self.__test_ResultSetInteger(xResultset, expected_values) + + xCon.dispose() + +if __name__ == '__main__': + unittest.main() diff --git a/dbaccess/qa/unit/data/dbaccess-dialogs-test.txt b/dbaccess/qa/unit/data/dbaccess-dialogs-test.txt new file mode 100644 index 000000000..d30f9f70e --- /dev/null +++ b/dbaccess/qa/unit/data/dbaccess-dialogs-test.txt @@ -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 contains all dialogs that the unit tests in the module +# will work on if it is in script mode. It will read one-by-one, +# try to open it and create a screenshot that will be saved in +# workdir/screenshots using the pattern of the ui-file name. +# +# Syntax: +# - empty lines are allowed +# - lines starting with '#' are treated as comment +# - all other lines should contain a *.ui filename in the same +# notation as in the dialog constructors (see code) + +# +# The 'known' dialogs which have a hard-coded representation +# in registerKnownDialogsByID/createDialogByID +# + +# No known dialogs in dbaccess for now + +# +# Dialogs without a hard-coded representation. These will +# be visualized using a fallback based on VclBuilder +# + +# currently deactivated, leads to problems and the test to not work +# This is typically a hint that these should be hard-coded in the +# test case since they need some document and model data to work +# dbaccess/ui/joindialog.ui <- not calling ORelationControl::lateInit for +# DlgQryJoin::m_xTableControl member OTableListBoxControl::m_pRC_Tables leaves its +# BrowseBox::mvCols empty, causing "implicit conversion from type 'int' of value -1 (32-bit, +# signed) to type 'sal_uInt16' (aka 'unsigned short') changed the value to 65535 (16-bit, +# unsigned)" when calling +# GetColumnId( static_cast(mvCols.size()) - 1 ); +# in BrowseBox::AutoSizeLastColumn (svtools/source/brwbox/brwbox1.cxx) with Clang +# -fsanitize=implicit-signed-integer-truncation +# dbaccess/ui/relationdialog.ui <- not calling ORelationControl::lateInit for +# ORelationDialog::m_xTableControl member OTableListBoxControl::m_pRC_Tables leaves its +# BrowseBox::mvCols empty, causing "implicit conversion from type 'int' of value -1 (32-bit, +# signed) to type 'sal_uInt16' (aka 'unsigned short') changed the value to 65535 (16-bit, +# unsigned)" when calling +# GetColumnId( static_cast(mvCols.size()) - 1 ); +# in BrowseBox::AutoSizeLastColumn (svtools/source/brwbox/brwbox1.cxx) with Clang +# -fsanitize=implicit-signed-integer-truncation + +dbaccess/ui/advancedsettingsdialog.ui +dbaccess/ui/admindialog.ui +dbaccess/ui/fielddialog.ui +dbaccess/ui/useradmindialog.ui +dbaccess/ui/mysqlnativesettings.ui +dbaccess/ui/textpage.ui +dbaccess/ui/applycolpage.ui +dbaccess/ui/copytablepage.ui +dbaccess/ui/namematchingpage.ui +dbaccess/ui/typeselectpage.ui +dbaccess/ui/specialsettingspage.ui +dbaccess/ui/generatedvaluespage.ui +dbaccess/ui/ldapconnectionpage.ui +dbaccess/ui/dbwizmysqlintropage.ui +dbaccess/ui/dbwizmysqlnativepage.ui +dbaccess/ui/specialjdbcconnectionpage.ui +dbaccess/ui/authentificationpage.ui +dbaccess/ui/finalpagewizard.ui +dbaccess/ui/tablesfilterpage.ui +dbaccess/ui/useradminpage.ui +dbaccess/ui/connectionpage.ui +dbaccess/ui/dbwizconnectionpage.ui +dbaccess/ui/dbwiztextpage.ui +dbaccess/ui/jdbcconnectionpage.ui +dbaccess/ui/dbwizspreadsheetpage.ui +dbaccess/ui/dbasepage.ui +dbaccess/ui/autocharsetpage.ui +dbaccess/ui/odbcpage.ui +dbaccess/ui/userdetailspage.ui +dbaccess/ui/autocharsetpage.ui +dbaccess/ui/generalspecialjdbcdetailspage.ui +dbaccess/ui/mysqlnativepage.ui +dbaccess/ui/ldappage.ui +dbaccess/ui/emptypage.ui +dbaccess/ui/generalpagedialog.ui +dbaccess/ui/generalpagewizard.ui +dbaccess/ui/collectionviewdialog.ui +dbaccess/ui/dbaseindexdialog.ui +dbaccess/ui/directsqldialog.ui +dbaccess/ui/savedialog.ui +dbaccess/ui/savedialog.ui +dbaccess/ui/rowheightdialog.ui +dbaccess/ui/colwidthdialog.ui +dbaccess/ui/choosedatasourcedialog.ui +dbaccess/ui/indexdesigndialog.ui +dbaccess/ui/parametersdialog.ui +dbaccess/ui/queryfilterdialog.ui +dbaccess/ui/sortdialog.ui +dbaccess/ui/querypropertiesdialog.ui +dbaccess/ui/sqlexception.ui +dbaccess/ui/textconnectionsettings.ui +dbaccess/ui/password.ui +dbaccess/ui/tablesfilterdialog.ui +dbaccess/ui/tablesjoindialog.ui +dbaccess/ui/savemodifieddialog.ui +dbaccess/ui/saveindexdialog.ui +dbaccess/ui/designsavemodifieddialog.ui +dbaccess/ui/tabledesignsavemodifieddialog.ui +dbaccess/ui/deleteallrowsdialog.ui diff --git a/dbaccess/qa/unit/data/firebird_empty.odb b/dbaccess/qa/unit/data/firebird_empty.odb new file mode 100644 index 000000000..9aabfd47b Binary files /dev/null and b/dbaccess/qa/unit/data/firebird_empty.odb differ diff --git a/dbaccess/qa/unit/data/firebird_empty_le.odb b/dbaccess/qa/unit/data/firebird_empty_le.odb new file mode 100644 index 000000000..766c17db2 Binary files /dev/null and b/dbaccess/qa/unit/data/firebird_empty_le.odb differ diff --git a/dbaccess/qa/unit/data/firebird_integer_le.odb b/dbaccess/qa/unit/data/firebird_integer_le.odb new file mode 100644 index 000000000..da2ec1499 Binary files /dev/null and b/dbaccess/qa/unit/data/firebird_integer_le.odb differ diff --git a/dbaccess/qa/unit/data/firebird_integer_le_ods12.odb b/dbaccess/qa/unit/data/firebird_integer_le_ods12.odb new file mode 100644 index 000000000..95691ed20 Binary files /dev/null and b/dbaccess/qa/unit/data/firebird_integer_le_ods12.odb differ diff --git a/dbaccess/qa/unit/data/firebird_integer_ods12.odb b/dbaccess/qa/unit/data/firebird_integer_ods12.odb new file mode 100644 index 000000000..642b038dd Binary files /dev/null and b/dbaccess/qa/unit/data/firebird_integer_ods12.odb differ diff --git a/dbaccess/qa/unit/data/hsqldb_empty.odb b/dbaccess/qa/unit/data/hsqldb_empty.odb new file mode 100644 index 000000000..087c26113 Binary files /dev/null and b/dbaccess/qa/unit/data/hsqldb_empty.odb differ diff --git a/dbaccess/qa/unit/data/hsqldb_migration_test.odb b/dbaccess/qa/unit/data/hsqldb_migration_test.odb new file mode 100644 index 000000000..99b6b5d9a Binary files /dev/null and b/dbaccess/qa/unit/data/hsqldb_migration_test.odb differ diff --git a/dbaccess/qa/unit/data/tdf119625.odb b/dbaccess/qa/unit/data/tdf119625.odb new file mode 100644 index 000000000..e7bd69d60 Binary files /dev/null and b/dbaccess/qa/unit/data/tdf119625.odb differ diff --git a/dbaccess/qa/unit/data/tdf126268.odb b/dbaccess/qa/unit/data/tdf126268.odb new file mode 100644 index 000000000..434a4238b Binary files /dev/null and b/dbaccess/qa/unit/data/tdf126268.odb differ diff --git a/dbaccess/qa/unit/dbaccess-dialogs-test.cxx b/dbaccess/qa/unit/dbaccess-dialogs-test.cxx new file mode 100644 index 000000000..49eff86ec --- /dev/null +++ b/dbaccess/qa/unit/dbaccess-dialogs-test.cxx @@ -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/. + */ + +#include +#include +#include + +using namespace ::com::sun::star; + +/// Test opening a dialog in dbaccess +class DbaccessDialogsTest : public ScreenshotTest +{ +private: + /// helper method to populate KnownDialogs, called in setUp(). Needs to be + /// written and has to add entries to KnownDialogs + virtual void registerKnownDialogsByID(mapType& rKnownDialogs) override; + + /// dialog creation for known dialogs by ID. Has to be implemented for + /// each registered known dialog + virtual VclPtr createDialogByID(sal_uInt32 nID) override; + +public: + DbaccessDialogsTest(); + + // try to open a dialog + void openAnyDialog(); + + CPPUNIT_TEST_SUITE(DbaccessDialogsTest); + CPPUNIT_TEST(openAnyDialog); + CPPUNIT_TEST_SUITE_END(); +}; + +DbaccessDialogsTest::DbaccessDialogsTest() {} + +void DbaccessDialogsTest::registerKnownDialogsByID(mapType& /*rKnownDialogs*/) +{ + // fill map of known dialogs +} + +VclPtr DbaccessDialogsTest::createDialogByID(sal_uInt32 /*nID*/) +{ + return nullptr; +} + +void DbaccessDialogsTest::openAnyDialog() +{ + /// process input file containing the UXMLDescriptions of the dialogs to dump + processDialogBatchFile("dbaccess/qa/unit/data/dbaccess-dialogs-test.txt"); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(DbaccessDialogsTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/unit/dbtest_base.cxx b/dbaccess/qa/unit/dbtest_base.cxx new file mode 100644 index 000000000..72f4e9b68 --- /dev/null +++ b/dbaccess/qa/unit/dbtest_base.cxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +class DBTestBase + : public UnoApiTest +{ +public: + DBTestBase() : UnoApiTest("dbaccess/qa/unit/data") {}; + + utl::TempFile createTempCopy(OUString const & pathname); + + uno::Reference< XOfficeDatabaseDocument > + getDocumentForFileName(const OUString &sFileName); + + uno::Reference getDocumentForUrl(OUString const & url); + + uno::Reference< XConnection > + getConnectionForDocument( + uno::Reference< XOfficeDatabaseDocument > const & xDocument); +}; + +utl::TempFile DBTestBase::createTempCopy(OUString const & pathname) { + OUString url; + createFileURL(pathname, url); + utl::TempFile tmp; + tmp.EnableKillingFile(); + auto const e = osl::File::copy(url, tmp.GetURL()); + CPPUNIT_ASSERT_EQUAL_MESSAGE( + (OUStringToOString("<" + url + "> -> <" + tmp.GetURL() + ">", RTL_TEXTENCODING_UTF8) + .getStr()), + osl::FileBase::E_None, e); + return tmp; +} + +uno::Reference< XOfficeDatabaseDocument > + DBTestBase::getDocumentForFileName(const OUString &sFileName) +{ + OUString sFilePath; + createFileURL(sFileName, sFilePath); + return getDocumentForUrl(sFilePath); +} + +uno::Reference DBTestBase::getDocumentForUrl(OUString const & url) { + uno::Reference< lang::XComponent > xComponent (loadFromDesktop(url)); + CPPUNIT_ASSERT(xComponent.is()); + + uno::Reference< XOfficeDatabaseDocument > xDocument(xComponent, UNO_QUERY); + CPPUNIT_ASSERT(xDocument.is()); + + return xDocument; +} + +uno::Reference< XConnection > DBTestBase::getConnectionForDocument( + uno::Reference< XOfficeDatabaseDocument > const & xDocument) +{ + uno::Reference< XDataSource > xDataSource = xDocument->getDataSource(); + CPPUNIT_ASSERT(xDataSource.is()); + + uno::Reference< XConnection > xConnection = xDataSource->getConnection("",""); + CPPUNIT_ASSERT(xConnection.is()); + + return xConnection; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/unit/embeddeddb_performancetest.cxx b/dbaccess/qa/unit/embeddeddb_performancetest.cxx new file mode 100644 index 000000000..0517a9fd1 --- /dev/null +++ b/dbaccess/qa/unit/embeddeddb_performancetest.cxx @@ -0,0 +1,359 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 "dbtest_base.cxx" + +#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::beans; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +static void normaliseTimeValue(TimeValue* pVal) +{ + pVal->Seconds += pVal->Nanosec / 1000000000; + pVal->Nanosec %= 1000000000; +} + +static void getTimeDifference(const TimeValue* pTimeStart, + const TimeValue* pTimeEnd, + TimeValue* pTimeDifference) +{ + // We add 1 second to the nanoseconds to ensure that we get a positive number + // We have to normalise anyway so this doesn't cause any harm. + // (Seconds/Nanosec are both unsigned) + pTimeDifference->Seconds = pTimeEnd->Seconds - pTimeStart->Seconds - 1; + pTimeDifference->Nanosec = 1000000000 + pTimeEnd->Nanosec - pTimeStart->Nanosec; + normaliseTimeValue(pTimeDifference); +} + +static OUString getPrintableTimeValue(const TimeValue* pTimeValue) +{ + return OUString::number( + (sal_uInt64(pTimeValue->Seconds) * SAL_CONST_UINT64(1000000000) + + sal_uInt64(pTimeValue->Nanosec))/ 1000000 + ); +} + +/* + * The recommended way to run this test is: + * 'SAL_LOG="" DBA_PERFTEST=YES make CppunitTest_dbaccess_embeddeddb_performancetest' + * This blocks the unnecessary exception output and show only the performance data. + * + * You also need to create the file dbaccess/qa/unit/data/wordlist, this list cannot + * contain any unescaped apostrophes (since the words are used directly to assemble + * sql statement), apostrophes are escaped using a double apostrophe, i.e. ''. + * one easy way of generating a list is using: + * 'for WORD in $(aspell dump master); do echo ${WORD//\'/\'\'}; done > dbaccess/qa/unit/data/wordlist' + * + * Note that wordlist cannot have more than 220580 lines, this is due to a hard + * limit in our hsqldb version. + * + * Also note that this unit test "fails" when doing performance testing, this is + * since by default unit test output is hidden, and thus there is no way of + * reading the results. + */ +class EmbeddedDBPerformanceTest + : public DBTestBase +{ +private: + static const char our_sEnableTestEnvVar[]; + + // We store the results and print them at the end due to the amount of warning + // noise present which otherwise obscures the results. + OUStringBuffer m_aOutputBuffer; + + void printTimes(const TimeValue* pTime1, const TimeValue* pTime2, const TimeValue* pTime3); + + void doPerformanceTestOnODB(const OUString& rDriverURL, + const OUString& rDBName, + const bool bUsePreparedStatement); + + void setupTestTable(uno::Reference< XConnection > const & xConnection); + + SvFileStream *getWordListStream(); + + // Individual Tests + void performPreparedStatementInsertTest( + uno::Reference< XConnection > const & xConnection, + const OUString& rDBName); + void performStatementInsertTest( + uno::Reference< XConnection > const & xConnection, + const OUString& rDBName); + void performReadTest( + uno::Reference< XConnection > const & xConnection, + const OUString& rDBName); + + // Perform all tests on a given DB. + void testFirebird(); + void testHSQLDB(); + +public: + void testPerformance(); + + CPPUNIT_TEST_SUITE(EmbeddedDBPerformanceTest); + CPPUNIT_TEST(testPerformance); + CPPUNIT_TEST_SUITE_END(); +}; + +SvFileStream* EmbeddedDBPerformanceTest::getWordListStream() +{ + OUString wlPath; + createFileURL("wordlist", wlPath); + return new SvFileStream(wlPath, StreamMode::READ); +} + +void EmbeddedDBPerformanceTest::printTimes( + const TimeValue* pTime1, + const TimeValue* pTime2, + const TimeValue* pTime3) +{ + m_aOutputBuffer + .append(getPrintableTimeValue(pTime1)).append("\t") + .append(getPrintableTimeValue(pTime2)).append("\t") + .append(getPrintableTimeValue(pTime3)).append("\t") + .append("\n"); +} + +const char EmbeddedDBPerformanceTest::our_sEnableTestEnvVar[] = "DBA_PERFTEST"; + +// TODO: we probably should create a document from scratch instead? + +void EmbeddedDBPerformanceTest::testPerformance() +{ + OUString sEnabled; + osl_getEnvironment(OUString(our_sEnableTestEnvVar).pData, &sEnabled.pData); + + if (sEnabled.isEmpty()) + return; + + m_aOutputBuffer.append("---------------------\n"); + testFirebird(); + m_aOutputBuffer.append("---------------------\n"); + testHSQLDB(); + m_aOutputBuffer.append("---------------------\n"); + + fprintf(stdout, "Performance Test Results:\n"); + fprintf(stdout, "%s", + OUStringToOString(m_aOutputBuffer.makeStringAndClear(), + RTL_TEXTENCODING_UTF8) + .getStr() + ); + + // We want the results printed, but unit test output is only printed on failure + // Hence we deliberately fail the test. + CPPUNIT_ASSERT(false); +} + +void EmbeddedDBPerformanceTest::testFirebird() +{ + + m_aOutputBuffer.append("Standard Insert\n"); + doPerformanceTestOnODB("sdbc:embedded:firebird", "Firebird", false); + m_aOutputBuffer.append("PreparedStatement Insert\n"); + doPerformanceTestOnODB("sdbc:embedded:firebird", "Firebird", true); +} + +void EmbeddedDBPerformanceTest::testHSQLDB() +{ + m_aOutputBuffer.append("Standard Insert\n"); + doPerformanceTestOnODB("sdbc:embedded:hsqldb", "HSQLDB", false); + m_aOutputBuffer.append("PreparedStatement Insert\n"); + doPerformanceTestOnODB("sdbc:embedded:hsqldb", "HSQLDB", true); +} + +/** + * Use an existing .odb to do performance tests on. The database cannot have + * a table of the name PFTESTTABLE. + */ +void EmbeddedDBPerformanceTest::doPerformanceTestOnODB( + const OUString& rDriverURL, + const OUString& rDBName, + const bool bUsePreparedStatement) +{ + ::utl::TempFile aFile; + aFile.EnableKillingFile(); + + { + uno::Reference< XOfficeDatabaseDocument > xDocument( + m_xSFactory->createInstance("com.sun.star.sdb.OfficeDatabaseDocument"), + UNO_QUERY_THROW); + uno::Reference< XStorable > xStorable(xDocument, UNO_QUERY_THROW); + + uno::Reference< XDataSource > xDataSource = xDocument->getDataSource(); + uno::Reference< XPropertySet > xPropertySet(xDataSource, UNO_QUERY_THROW); + xPropertySet->setPropertyValue("URL", Any(rDriverURL)); + + xStorable->storeAsURL(aFile.GetURL(), uno::Sequence< beans::PropertyValue >()); + } + + uno::Reference< XOfficeDatabaseDocument > xDocument( + loadFromDesktop(aFile.GetURL()), UNO_QUERY_THROW); + + uno::Reference< XConnection > xConnection = + getConnectionForDocument(xDocument); + + setupTestTable(xConnection); + + if (bUsePreparedStatement) + performPreparedStatementInsertTest(xConnection, rDBName); + else + performStatementInsertTest(xConnection, rDBName); + + performReadTest(xConnection, rDBName); +} + +void EmbeddedDBPerformanceTest::setupTestTable( + uno::Reference< XConnection > const & xConnection) +{ + uno::Reference< XStatement > xStatement = xConnection->createStatement(); + + // Although not strictly necessary we use quoted identifiers to reflect + // the fact that Base always uses quoted identifiers. + xStatement->execute( + "CREATE TABLE \"PFTESTTABLE\" ( \"ID\" INTEGER NOT NULL PRIMARY KEY " + ", \"STRINGCOLUMNA\" VARCHAR (50) " + ")"); + + xConnection->commit(); +} + +void EmbeddedDBPerformanceTest::performPreparedStatementInsertTest( + uno::Reference< XConnection > const & xConnection, + const OUString& rDBName) +{ + uno::Reference< XPreparedStatement > xPreparedStatement = + xConnection->prepareStatement( + "INSERT INTO \"PFTESTTABLE\" ( \"ID\", " + "\"STRINGCOLUMNA\" " + ") VALUES ( ?, ? )" + ); + + uno::Reference< XParameters > xParameters(xPreparedStatement, UNO_QUERY_THROW); + + std::unique_ptr< SvFileStream > pFile(getWordListStream()); + + OUString aWord; + sal_Int32 aID = 0; + + TimeValue aStart, aMiddle, aEnd; + osl_getSystemTime(&aStart); + + while (pFile->ReadByteStringLine(aWord, RTL_TEXTENCODING_UTF8)) + { + xParameters->setInt(1, aID++); + xParameters->setString(2, aWord); + xPreparedStatement->execute(); + } + osl_getSystemTime(&aMiddle); + xConnection->commit(); + osl_getSystemTime(&aEnd); + + + TimeValue aTimeInsert, aTimeCommit, aTimeTotal; + getTimeDifference(&aStart, &aMiddle, &aTimeInsert); + getTimeDifference(&aMiddle, &aEnd, &aTimeCommit); + getTimeDifference(&aStart, &aEnd, &aTimeTotal); + m_aOutputBuffer.append("Insert: ").append(rDBName).append("\n"); + printTimes(&aTimeInsert, &aTimeCommit, &aTimeTotal); + + pFile->Close(); +} + +void EmbeddedDBPerformanceTest::performStatementInsertTest( + uno::Reference< XConnection > const & xConnection, + const OUString& rDBName) +{ + uno::Reference< XStatement > xStatement = + xConnection->createStatement(); + + std::unique_ptr< SvFileStream > pFile(getWordListStream()); + + OUString aWord; + sal_Int32 aID = 0; + + TimeValue aStart, aMiddle, aEnd; + osl_getSystemTime(&aStart); + + while (pFile->ReadByteStringLine(aWord, RTL_TEXTENCODING_UTF8)) + { + xStatement->execute( + "INSERT INTO \"PFTESTTABLE\" ( \"ID\", " + "\"STRINGCOLUMNA\" " + ") VALUES ( " + + OUString::number(aID++) + ", '" + aWord + "' )" + ); + } + osl_getSystemTime(&aMiddle); + xConnection->commit(); + osl_getSystemTime(&aEnd); + + TimeValue aTimeInsert, aTimeCommit, aTimeTotal; + getTimeDifference(&aStart, &aMiddle, &aTimeInsert); + getTimeDifference(&aMiddle, &aEnd, &aTimeCommit); + getTimeDifference(&aStart, &aEnd, &aTimeTotal); + m_aOutputBuffer.append("Insert: ").append(rDBName).append("\n"); + printTimes(&aTimeInsert, &aTimeCommit, &aTimeTotal); + + pFile->Close(); +} + +void EmbeddedDBPerformanceTest::performReadTest( + uno::Reference< XConnection > const & xConnection, + const OUString& rDBName) +{ + uno::Reference< XStatement > xStatement = xConnection->createStatement(); + + TimeValue aStart, aMiddle, aEnd; + osl_getSystemTime(&aStart); + + uno::Reference< XResultSet > xResults = xStatement->executeQuery("SELECT * FROM PFTESTTABLE"); + + osl_getSystemTime(&aMiddle); + + uno::Reference< XRow > xRow(xResults, UNO_QUERY_THROW); + + while (xResults->next()) + { + xRow->getString(2); + } + osl_getSystemTime(&aEnd); + + TimeValue aTimeSelect, aTimeIterate, aTimeTotal; + getTimeDifference(&aStart, &aMiddle, &aTimeSelect); + getTimeDifference(&aMiddle, &aEnd, &aTimeIterate); + getTimeDifference(&aStart, &aEnd, &aTimeTotal); + m_aOutputBuffer.append("Read from: ").append(rDBName).append("\n"); + printTimes(&aTimeSelect, &aTimeIterate, &aTimeTotal); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(EmbeddedDBPerformanceTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/unit/firebird-regression.cxx b/dbaccess/qa/unit/firebird-regression.cxx new file mode 100644 index 000000000..faf0a834b --- /dev/null +++ b/dbaccess/qa/unit/firebird-regression.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/. + */ + +#include "dbtest_base.cxx" + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +class FirebirdTest + : public DBTestBase +{ +public: + void testEmptyDBConnection(); + void testIntegerDatabase(); + + CPPUNIT_TEST_SUITE(FirebirdTest); + CPPUNIT_TEST(testEmptyDBConnection); + CPPUNIT_TEST(testIntegerDatabase); + CPPUNIT_TEST_SUITE_END(); +}; + +/** + * Test the loading of an "empty" file, i.e. the embedded database has not yet + * been initialised (as occurs when a new .odb is created and opened by base). + */ +void FirebirdTest::testEmptyDBConnection() +{ +#ifdef OSL_BIGENDIAN + auto const tmp = createTempCopy("firebird_empty_be.odb"); +#else + auto const tmp = createTempCopy("firebird_empty_le.odb"); +#endif + uno::Reference< XOfficeDatabaseDocument > xDocument = + getDocumentForUrl(tmp.GetURL()); + + getConnectionForDocument(xDocument); + + closeDocument(uno::Reference(xDocument, uno::UNO_QUERY)); +} + +/** + * Test reading of integers from a known .odb to verify that the data + * can still be read on all systems. + */ +void FirebirdTest::testIntegerDatabase() +{ +#ifdef OSL_BIGENDIAN + uno::Reference< XOfficeDatabaseDocument > xDocument = + getDocumentForFileName("firebird_integer_be_ods12.odb"); +#else + uno::Reference< XOfficeDatabaseDocument > xDocument = + getDocumentForFileName("firebird_integer_le_ods12.odb"); +#endif + + uno::Reference< XConnection > xConnection = + getConnectionForDocument(xDocument); + + uno::Reference< XStatement > xStatement = xConnection->createStatement(); + CPPUNIT_ASSERT(xStatement.is()); + + uno::Reference< XResultSet > xResultSet = xStatement->executeQuery( + "SELECT * FROM TESTTABLE"); + CPPUNIT_ASSERT(xResultSet.is()); + CPPUNIT_ASSERT(xResultSet->next()); + + uno::Reference< XRow > xRow(xResultSet, UNO_QUERY); + CPPUNIT_ASSERT(xRow.is()); + uno::Reference< XColumnLocate > xColumnLocate(xRow, UNO_QUERY); + CPPUNIT_ASSERT(xColumnLocate.is()); + + CPPUNIT_ASSERT_EQUAL(sal_Int16(-30000), + xRow->getShort(xColumnLocate->findColumn("_SMALLINT"))); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-2100000000), + xRow->getInt(xColumnLocate->findColumn("_INT"))); + CPPUNIT_ASSERT_EQUAL(SAL_CONST_INT64(-9000000000000000000), + xRow->getLong(xColumnLocate->findColumn("_BIGINT"))); + CPPUNIT_ASSERT_EQUAL(OUString("5"), + xRow->getString(xColumnLocate->findColumn("_CHAR"))); + CPPUNIT_ASSERT_EQUAL(OUString("5"), + xRow->getString(xColumnLocate->findColumn("_VARCHAR"))); + + CPPUNIT_ASSERT(!xResultSet->next()); // Should only be one row + + closeDocument(uno::Reference(xDocument, uno::UNO_QUERY)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(FirebirdTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/unit/firebird.cxx b/dbaccess/qa/unit/firebird.cxx new file mode 100644 index 000000000..955813324 --- /dev/null +++ b/dbaccess/qa/unit/firebird.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/. + */ + +#include "dbtest_base.cxx" + +#include +#include +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +class FirebirdTest + : public DBTestBase +{ +public: + void testEmptyDBConnection(); + void testIntegerDatabase(); + + CPPUNIT_TEST_SUITE(FirebirdTest); + CPPUNIT_TEST(testEmptyDBConnection); + CPPUNIT_TEST(testIntegerDatabase); + CPPUNIT_TEST_SUITE_END(); +}; + +/** + * Test the loading of an "empty" file, i.e. the embedded database has not yet + * been initialised (as occurs when a new .odb is created and opened by base). + */ +void FirebirdTest::testEmptyDBConnection() +{ + auto const tmp = createTempCopy("firebird_empty.odb"); + uno::Reference< XOfficeDatabaseDocument > xDocument = + getDocumentForUrl(tmp.GetURL()); + + getConnectionForDocument(xDocument); + + closeDocument(uno::Reference(xDocument, uno::UNO_QUERY)); +} + +/** + * Test reading of integers from a known .odb to verify that the data + * can still be read on all systems. + */ +void FirebirdTest::testIntegerDatabase() +{ + uno::Reference< XOfficeDatabaseDocument > xDocument = + getDocumentForFileName("firebird_integer_ods12.odb"); + + uno::Reference< XConnection > xConnection = + getConnectionForDocument(xDocument); + + uno::Reference< XStatement > xStatement = xConnection->createStatement(); + CPPUNIT_ASSERT(xStatement.is()); + + uno::Reference< XResultSet > xResultSet = xStatement->executeQuery( + "SELECT * FROM TESTTABLE"); + CPPUNIT_ASSERT(xResultSet.is()); + CPPUNIT_ASSERT(xResultSet->next()); + + uno::Reference< XRow > xRow(xResultSet, UNO_QUERY); + CPPUNIT_ASSERT(xRow.is()); + uno::Reference< XColumnLocate > xColumnLocate(xRow, UNO_QUERY); + CPPUNIT_ASSERT(xColumnLocate.is()); + + CPPUNIT_ASSERT_EQUAL(sal_Int16(-30000), + xRow->getShort(xColumnLocate->findColumn("_SMALLINT"))); + CPPUNIT_ASSERT_EQUAL(sal_Int32(-2100000000), + xRow->getInt(xColumnLocate->findColumn("_INT"))); + CPPUNIT_ASSERT_EQUAL(SAL_CONST_INT64(-9000000000000000000), + xRow->getLong(xColumnLocate->findColumn("_BIGINT"))); + CPPUNIT_ASSERT_EQUAL(OUString("5"), + xRow->getString(xColumnLocate->findColumn("_CHAR"))); + CPPUNIT_ASSERT_EQUAL(OUString("5"), + xRow->getString(xColumnLocate->findColumn("_VARCHAR"))); + + CPPUNIT_ASSERT(!xResultSet->next()); // Should only be one row + + closeDocument(uno::Reference(xDocument, uno::UNO_QUERY)); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(FirebirdTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/unit/hsql_binary_import.cxx b/dbaccess/qa/unit/hsql_binary_import.cxx new file mode 100644 index 000000000..fbf12f929 --- /dev/null +++ b/dbaccess/qa/unit/hsql_binary_import.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/. + */ + +#include "dbtest_base.cxx" + +#include +#include +#include +#include +#include + +class HsqlBinaryImportTest : public DBTestBase +{ +public: + void testBinaryImport(); + + virtual void setUp() override; + + CPPUNIT_TEST_SUITE(HsqlBinaryImportTest); + + CPPUNIT_TEST(testBinaryImport); + + CPPUNIT_TEST_SUITE_END(); +}; + +void HsqlBinaryImportTest::setUp() +{ + DBTestBase::setUp(); + osl_setEnvironment(OUString{ "DBACCESS_HSQL_MIGRATION" }.pData, OUString{ "1" }.pData); +} + +void HsqlBinaryImportTest::testBinaryImport() +{ + SvtMiscOptions aMiscOptions; + bool oldValue = aMiscOptions.IsExperimentalMode(); + + aMiscOptions.SetExperimentalMode(true); + // the migration requires the file to be writable + utl::TempFile const temp(createTempCopy("hsqldb_migration_test.odb")); + uno::Reference const xDocument = getDocumentForUrl(temp.GetURL()); + + uno::Reference xConnection = getConnectionForDocument(xDocument); + // at this point migration is already done + + uno::Reference statement = xConnection->createStatement(); + OUString sql{ "SELECT \"ID\", \"Power_value\", \"Power_name\", \"Retired\", " + "\"Birth_date\" FROM \"TestTable\" ORDER BY \"ID\"" }; + + uno::Reference xRes = statement->executeQuery(sql); + uno::Reference xRow(xRes, UNO_QUERY_THROW); + + // assert first row + CPPUNIT_ASSERT(xRes->next()); + constexpr sal_Int16 idExpected = 1; + CPPUNIT_ASSERT_EQUAL(idExpected, xRow->getShort(1)); + CPPUNIT_ASSERT_EQUAL(OUString{ "45.32" }, xRow->getString(2)); // numeric + CPPUNIT_ASSERT_EQUAL(OUString{ "laser eye" }, xRow->getString(3)); // varchar + CPPUNIT_ASSERT(xRow->getBoolean(4)); // boolean + + css::util::Date date = xRow->getDate(5); + + CPPUNIT_ASSERT_EQUAL(sal_uInt16{ 15 }, date.Day); + CPPUNIT_ASSERT_EQUAL(sal_uInt16{ 1 }, date.Month); + CPPUNIT_ASSERT_EQUAL(sal_Int16{ 1996 }, date.Year); + + // assert second row + CPPUNIT_ASSERT(xRes->next()); + constexpr sal_Int16 secondIdExpected = 2; + CPPUNIT_ASSERT_EQUAL(secondIdExpected, xRow->getShort(1)); // ID + CPPUNIT_ASSERT_EQUAL(OUString{ "54.12" }, xRow->getString(2)); // numeric + CPPUNIT_ASSERT_EQUAL(OUString{ "telekinesis" }, xRow->getString(3)); // varchar + CPPUNIT_ASSERT(!xRow->getBoolean(4)); // boolean + + date = xRow->getDate(5); + CPPUNIT_ASSERT_EQUAL(sal_uInt16{ 26 }, date.Day); + CPPUNIT_ASSERT_EQUAL(sal_uInt16{ 2 }, date.Month); + CPPUNIT_ASSERT_EQUAL(sal_Int16{ 1998 }, date.Year); + + closeDocument(uno::Reference(xDocument, uno::UNO_QUERY)); + if (!oldValue) + aMiscOptions.SetExperimentalMode(false); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(HsqlBinaryImportTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/dbaccess/qa/unit/hsqldb.cxx b/dbaccess/qa/unit/hsqldb.cxx new file mode 100644 index 000000000..5af5dff89 --- /dev/null +++ b/dbaccess/qa/unit/hsqldb.cxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "dbtest_base.cxx" + +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::uno; + +class HSQLDBTest + : public DBTestBase +{ +public: + void testEmptyDBConnection(); + + CPPUNIT_TEST_SUITE(HSQLDBTest); + CPPUNIT_TEST(testEmptyDBConnection); + CPPUNIT_TEST_SUITE_END(); +}; + +/** + * Test the loading of an "empty" file, i.e. the embedded database has not yet + * been initialised (as occurs when a new .odb is created and opened by base). + */ +void HSQLDBTest::testEmptyDBConnection() +{ + uno::Reference< XOfficeDatabaseDocument > xDocument = + getDocumentForFileName("hsqldb_empty.odb"); + + getConnectionForDocument(xDocument); + + css::uno::Reference( + xDocument, css::uno::UNO_QUERY_THROW)->dispose(); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(HSQLDBTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/qa/unit/tdf119625.cxx b/dbaccess/qa/unit/tdf119625.cxx new file mode 100644 index 000000000..8431c5426 --- /dev/null +++ b/dbaccess/qa/unit/tdf119625.cxx @@ -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/. + */ + +#include "dbtest_base.cxx" + +#include +#include +#include +#include +#include +#include + +class Tdf119625Test : public DBTestBase +{ +public: + void testTime(); + + virtual void setUp() override; + + CPPUNIT_TEST_SUITE(Tdf119625Test); + + CPPUNIT_TEST(testTime); + + CPPUNIT_TEST_SUITE_END(); +}; + +void Tdf119625Test::setUp() +{ + DBTestBase::setUp(); + osl_setEnvironment(OUString{ "DBACCESS_HSQL_MIGRATION" }.pData, OUString{ "1" }.pData); +} + +namespace +{ +struct expect_t +{ + sal_Int16 id; + sal_Int16 h, m, s; +}; +} + +/* The values here assume that our results are in UTC. However, + tdf#119675 "Firebird: Migration: User dialog to set treatment of + datetime and time values during migration" is going to change the + final result of migration. If that change is implemented below + the level we are testing, this test will have to allow for or set + the destination timezone. + */ +static const expect_t expect[] + = { { 0, 15, 10, 10 }, { 1, 23, 30, 30 }, { 2, 5, 0, 0 }, { 3, 4, 30, 0 }, + { 4, 3, 15, 10 }, { 5, 5, 0, 0 }, { 6, 3, 22, 22 } }; + +void Tdf119625Test::testTime() +{ + SvtMiscOptions aMiscOptions; + bool oldValue = aMiscOptions.IsExperimentalMode(); + + aMiscOptions.SetExperimentalMode(true); + + // the migration requires the file to be writable + utl::TempFile const temp(createTempCopy("tdf119625.odb")); + uno::Reference const xDocument = getDocumentForUrl(temp.GetURL()); + + uno::Reference xConnection = getConnectionForDocument(xDocument); + // at this point migration is already done + /* In the presence of tdf#119625, terminal already has messages + + *value exceeds the range for a valid time + caused by + 'isc_dsql_execute' + + warn:dbaccess:22435:22435:dbaccess/source/filter/hsqldb/hsqlimport.cxx:373: Error during migration + + In this case, we do not expect anything good from the following + code, but I (tje, 2018-09-04) do not know how to detect this + situation. In particular, the migration has been observed to + create the destination table (but truncated after the first + row), and xConnection.is() returns true. + */ + + // select basically everything from the .odb + uno::Reference statement = xConnection->createStatement(); + const OUString sql{ " SELECT id, tst_dt, tst_d, tst_t " + " FROM tst_data " + "ORDER BY id" }; + + uno::Reference xRes = statement->executeQuery(sql); + uno::Reference xRow(xRes, UNO_QUERY_THROW); + + // check result + for (auto& e : expect) + { + CPPUNIT_ASSERT(xRes->next()); + CPPUNIT_ASSERT_EQUAL(xRow->getShort(1), e.id); + auto time_got = xRow->getTime(4); + auto time_expected = com::sun::star::util::Time(0, e.s, e.m, e.h, false); + auto equal_times = time_got == time_expected; + CPPUNIT_ASSERT(equal_times); + } + CPPUNIT_ASSERT(!xRes->next()); + + closeDocument(uno::Reference(xDocument, uno::UNO_QUERY)); + if (!oldValue) + aMiscOptions.SetExperimentalMode(false); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Tdf119625Test); + +CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/dbaccess/qa/unit/tdf126268.cxx b/dbaccess/qa/unit/tdf126268.cxx new file mode 100644 index 000000000..b0719936f --- /dev/null +++ b/dbaccess/qa/unit/tdf126268.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/. + */ + +#include "dbtest_base.cxx" + +#include +#include +#include +#include +#include + +class Tdf126268Test : public DBTestBase +{ +public: + void testNumbers(); + + virtual void setUp() override; + + CPPUNIT_TEST_SUITE(Tdf126268Test); + + CPPUNIT_TEST(testNumbers); + + CPPUNIT_TEST_SUITE_END(); +}; + +void Tdf126268Test::setUp() +{ + DBTestBase::setUp(); + osl_setEnvironment(OUString{ "DBACCESS_HSQL_MIGRATION" }.pData, OUString{ "1" }.pData); +} + +namespace +{ +struct expect_t +{ + sal_Int16 id; + OUString number; +}; +} + +static const expect_t expect[] = { + { 1, "0.00" }, { 2, "25.00" }, { 3, "26.00" }, { 4, "30.4" }, { 5, "45.8" }, + { 6, "-25.00" }, { 7, "-26.00" }, { 8, "-30.4" }, { 9, "-45.8" }, +}; + +void Tdf126268Test::testNumbers() +{ + SvtMiscOptions aMiscOptions; + bool oldValue = aMiscOptions.IsExperimentalMode(); + + aMiscOptions.SetExperimentalMode(true); + + // the migration requires the file to be writable + utl::TempFile const temp(createTempCopy("tdf126268.odb")); + uno::Reference const xDocument = getDocumentForUrl(temp.GetURL()); + + uno::Reference xConnection = getConnectionForDocument(xDocument); + + // select basically everything from the .odb + uno::Reference statement = xConnection->createStatement(); + const OUString sql{ "SELECT ID, Column1, Column2 FROM tableTest ORDER BY ID" }; + + uno::Reference xRes = statement->executeQuery(sql); + uno::Reference xRow(xRes, UNO_QUERY_THROW); + + // check result + for (auto& e : expect) + { + CPPUNIT_ASSERT(xRes->next()); + CPPUNIT_ASSERT_EQUAL(e.id, xRow->getShort(1)); + CPPUNIT_ASSERT_EQUAL(e.number, xRow->getString(2)); //decimal + CPPUNIT_ASSERT_EQUAL(e.number, xRow->getString(3)); //numeric + } + CPPUNIT_ASSERT(!xRes->next()); + + closeDocument(uno::Reference(xDocument, uno::UNO_QUERY)); + if (!oldValue) + aMiscOptions.SetExperimentalMode(false); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(Tdf126268Test); + +CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/dbaccess/qa/unoapi/dbaccess.props b/dbaccess/qa/unoapi/dbaccess.props new file mode 100644 index 000000000..afad9f038 --- /dev/null +++ b/dbaccess/qa/unoapi/dbaccess.props @@ -0,0 +1,24 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +#properties needed for dbbaccess + +jdbc.url=mysql://unoapi:3306/testDB +jdbc.user=unoapi +jdbc.password=unoapi +mysql.url=sdbc:mysql:jdbc:unoapi:3306/TestDB diff --git a/dbaccess/qa/unoapi/dbaccess.sce b/dbaccess/qa/unoapi/dbaccess.sce new file mode 100644 index 000000000..13fa966ab --- /dev/null +++ b/dbaccess/qa/unoapi/dbaccess.sce @@ -0,0 +1,32 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# +#i84113 -o dbaccess.ConnectionLineAccessibility +-o dbaccess.DBContentLoader +#i84114 -o dbaccess.JoinViewAccessibility +-o dbaccess.OCommandDefinition +-o dbaccess.ODatabaseContext +-o dbaccess.ODatabaseSource +-o dbaccess.ODatasourceAdministrationDialog +#i98007 -o dbaccess.ODatasourceBrowser +-o dbaccess.OInteractionHandler +#i84116 -o dbaccess.OQueryDesign +-o dbaccess.ORowSet +-o dbaccess.OSQLMessageDialog +-o dbaccess.OSingleSelectQueryComposer +#i95611 -o dbaccess.SbaXGridControl +#i84128 -o dbaccess.TableWindowAccessibility diff --git a/dbaccess/qa/unoapi/knownissues.xcl b/dbaccess/qa/unoapi/knownissues.xcl new file mode 100644 index 000000000..8c635d097 --- /dev/null +++ b/dbaccess/qa/unoapi/knownissues.xcl @@ -0,0 +1,80 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +### 114044 ### +dbaccess.ORowSet::com::sun::star::sdbc::XWarningsSupplier + +### i38209 ### +dbaccess.ODatasourceAdministrationDialog::com::sun::star::sdb::DatasourceAdministrationDialog + +### i55579 ### +dbaccess.OQueryDesign::com::sun::star::frame::XController + +### i84113 ### +dbaccess.ConnectionLineAccessibility +# -> disabled in dbaccess.sce + +### i84114 ### +dbaccess.JoinViewAccessibility +# -> disabled in dbaccess.sce + +### i84116 ### +dbaccess.OQueryDesign +# -> disabled in dbaccess.sce + +### i84125 ### +dbaccess.SbaXGridControl::com::sun::star::view::XSelectionSupplier + +### i84127 ### +dbaccess.SbaXGridControl::com::sun::star::awt::XWindow + +### i86990 ### +dbaccess.ODatabaseSource::com::sun::star::beans::XPropertySet +dbaccess.OCommandDefinition::com::sun::star::beans::XPropertySet + +### i84128 ### +dbaccess.TableWindowAccessibility +# -> disabled in dbaccess.sce + +### i87247 ### +dbaccess.DBContentLoader::com::sun::star::frame::XFrameLoader + +### i88646 ### +dbaccess.ODatabaseContext::com::sun::star::uno::XNamingService + +### i90358 ### +dbaccess.SbaXGridControl::com::sun::star::awt::XView + +### i90359 ### +dbaccess.ODatabaseSource::com::sun::star::sdb::DataSource + +### i95611 ### +dbaccess.SbaXGridControl +# -> disabled in dbaccess.sce + +### i95691 ### +dbaccess.ORowSet::com::sun::star::sdbc::XRowUpdate +dbaccess.ORowSet::com::sun::star::sdbc::XRow + +## i97860 ### +dbaccess.ORowSet::com::sun::star::sdbcx::XDeleteRows +dbaccess.ORowSet::com::sun::star::sdbc::XResultSetUpdate + +### i98007 ### +dbaccess.ODatasourceBrowser +# -> disabled in dbaccess.sce \ No newline at end of file diff --git a/dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbf b/dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbf new file mode 100644 index 000000000..c3af1e143 Binary files /dev/null and b/dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbf differ diff --git a/dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbt b/dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbt new file mode 100644 index 000000000..41cb9d24c Binary files /dev/null and b/dbaccess/qa/unoapi/testdocuments/TestDB/testDB.dbt differ diff --git a/dbaccess/source/core/api/BookmarkSet.cxx b/dbaccess/source/core/api/BookmarkSet.cxx new file mode 100644 index 000000000..b21d7cbbb --- /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); + break; + case DataType::BIGINT: + if ( _rValue.isSigned() ) + _xParameter->updateLong(nPos,_rValue); + else + _xParameter->updateString(nPos,_rValue); + break; + case DataType::BIT: + case DataType::BOOLEAN: + _xParameter->updateBoolean(nPos,bool(_rValue)); + break; + case DataType::TINYINT: + if ( _rValue.isSigned() ) + _xParameter->updateByte(nPos,_rValue); + else + _xParameter->updateShort(nPos,_rValue); + break; + case DataType::SMALLINT: + if ( _rValue.isSigned() ) + _xParameter->updateShort(nPos,_rValue); + else + _xParameter->updateInt(nPos,_rValue); + break; + case DataType::INTEGER: + if ( _rValue.isSigned() ) + _xParameter->updateInt(nPos,_rValue); + else + _xParameter->updateLong(nPos,_rValue); + break; + case DataType::FLOAT: + _xParameter->updateFloat(nPos,_rValue); + break; + case DataType::DOUBLE: + case DataType::REAL: + _xParameter->updateDouble(nPos,_rValue); + break; + case DataType::DATE: + _xParameter->updateDate(nPos,_rValue); + break; + case DataType::TIME: + _xParameter->updateTime(nPos,_rValue); + break; + case DataType::TIMESTAMP: + _xParameter->updateTimestamp(nPos,_rValue); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + _xParameter->updateBytes(nPos,_rValue); + break; + case DataType::BLOB: + case DataType::CLOB: + _xParameter->updateObject(nPos,_rValue.getAny()); + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/BookmarkSet.hxx b/dbaccess/source/core/api/BookmarkSet.hxx new file mode 100644 index 000000000..6567d50b7 --- /dev/null +++ b/dbaccess/source/core/api/BookmarkSet.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_BOOKMARKSET_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_BOOKMARKSET_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_BOOKMARKSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/CIndexes.cxx b/dbaccess/source/core/api/CIndexes.cxx new file mode 100644 index 000000000..409d87728 --- /dev/null +++ b/dbaccess/source/core/api/CIndexes.cxx @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "CIndexes.hxx" + + +using namespace connectivity; +using namespace connectivity::sdbcx; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace dbaccess; +using namespace cppu; + + +ObjectType OIndexes::createObject(const OUString& _rName) +{ + ObjectType xRet; + if ( m_xIndexes.is() && m_xIndexes->hasByName(_rName) ) + xRet.set(m_xIndexes->getByName(_rName),UNO_QUERY); + else + xRet = OIndexesHelper::createObject(_rName); + + return xRet; +} + +Reference< XPropertySet > OIndexes::createDescriptor() +{ + Reference 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 000000000..0ee3d5ced --- /dev/null +++ b/dbaccess/source/core/api/CIndexes.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_CINDEXES_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_CINDEXES_HXX + +#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, + const css::uno::Reference< css::container::XNameAccess >& _rxIndexes + ) : connectivity::OIndexesHelper(_pTable,_rMutex,_rVector) + ,m_xIndexes(_rxIndexes) + {} + + virtual void disposing() override; + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_CINDEXES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/CRowSetColumn.cxx b/dbaccess/source/core/api/CRowSetColumn.cxx new file mode 100644 index 000000000..cef90a8e8 --- /dev/null +++ b/dbaccess/source/core/api/CRowSetColumn.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 "CRowSetColumn.hxx" + +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 +{ + BEGIN_PROPERTY_SEQUENCE(21) + + DECL_PROP1( CATALOGNAME, OUString, READONLY ); + DECL_PROP1( DISPLAYSIZE, sal_Int32, READONLY ); + DECL_PROP1_BOOL( ISAUTOINCREMENT, READONLY ); + DECL_PROP1_BOOL( ISCASESENSITIVE, READONLY ); + DECL_PROP1_BOOL( ISCURRENCY, READONLY ); + DECL_PROP1_BOOL( ISDEFINITELYWRITABLE, READONLY ); + DECL_PROP1( ISNULLABLE, sal_Int32, READONLY ); + DECL_PROP1_BOOL( ISREADONLY, BOUND ); + DECL_PROP1_BOOL( ISROWVERSION, READONLY ); + DECL_PROP1_BOOL( ISSEARCHABLE, READONLY ); + DECL_PROP1_BOOL( ISSIGNED, READONLY ); + DECL_PROP1_BOOL( ISWRITABLE, READONLY ); + DECL_PROP1( LABEL, OUString, READONLY ); + DECL_PROP1( PRECISION, sal_Int32, READONLY ); + DECL_PROP1( SCALE, sal_Int32, READONLY ); + DECL_PROP1( SCHEMANAME, OUString, READONLY ); + DECL_PROP1( SERVICENAME, OUString, READONLY ); + DECL_PROP1( TABLENAME, OUString, READONLY ); + DECL_PROP1( TYPE, sal_Int32, READONLY ); + DECL_PROP1( TYPENAME, OUString, READONLY ); + DECL_PROP2( VALUE, Any, READONLY, BOUND ); + + END_PROPERTY_SEQUENCE() + + Sequence< Property > aRegisteredProperties; + describeProperties( aRegisteredProperties ); + + return new ::cppu::OPropertyArrayHelper( ::comphelper::concatSequences( aDescriptor, aRegisteredProperties ), false ); +} + +::cppu::IPropertyArrayHelper& ORowSetColumn::getInfoHelper() +{ + return *static_cast< ::comphelper::OPropertyArrayUsageHelper< ORowSetColumn >* >(this)->getArrayHelper(); +} + +void SAL_CALL ORowSetColumn::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue ) +{ + OSL_ENSURE( nHandle != PROPERTY_ID_VALUE, "ORowSetColumn::setFastPropertyValue_NoBroadcast: hmm? This property is marked as READONLY!" ); + if ( nHandle != PROPERTY_ID_VALUE ) + ORowSetDataColumn::setFastPropertyValue_NoBroadcast( nHandle, rValue ); +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/CRowSetColumn.hxx b/dbaccess/source/core/api/CRowSetColumn.hxx new file mode 100644 index 000000000..25c4b3310 --- /dev/null +++ b/dbaccess/source/core/api/CRowSetColumn.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_CROWSETCOLUMN_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_CROWSETCOLUMN_HXX + +#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; + }; + +} + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_CROWSETCOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/CRowSetDataColumn.cxx b/dbaccess/source/core/api/CRowSetDataColumn.cxx new file mode 100644 index 000000000..f1d845e11 --- /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 + +using namespace dbaccess; +using namespace comphelper; +using namespace connectivity; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using namespace cppu; +using namespace osl; + + +ORowSetDataColumn::ORowSetDataColumn( const Reference < XResultSetMetaData >& _xMetaData, + const Reference < XRow >& _xRow, + const Reference < XRowUpdate >& _xRowUpdate, + sal_Int32 _nPos, + const Reference< XDatabaseMetaData >& _rxDBMeta, + const OUString& _rDescription, + const OUString& i_sLabel, + const std::function &_getValue) + :ODataColumn(_xMetaData,_xRow,_xRowUpdate,_nPos,_rxDBMeta) + ,m_pGetValue(_getValue) + ,m_sLabel(i_sLabel) + ,m_aDescription(_rDescription) +{ + OColumnSettings::registerProperties( *this ); + registerProperty( PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, PropertyAttribute::READONLY, &m_aDescription, cppu::UnoType::get() ); +} + +ORowSetDataColumn::~ORowSetDataColumn() +{ +} + +// comphelper::OPropertyArrayUsageHelper +::cppu::IPropertyArrayHelper* ORowSetDataColumn::createArrayHelper( ) const +{ + BEGIN_PROPERTY_SEQUENCE(21) + + DECL_PROP1( CATALOGNAME, OUString, READONLY ); + DECL_PROP1( DISPLAYSIZE, sal_Int32, READONLY ); + DECL_PROP1_BOOL( ISAUTOINCREMENT, READONLY ); + DECL_PROP1_BOOL( ISCASESENSITIVE, READONLY ); + DECL_PROP1_BOOL( ISCURRENCY, READONLY ); + DECL_PROP1_BOOL( ISDEFINITELYWRITABLE, READONLY ); + DECL_PROP1( ISNULLABLE, sal_Int32, READONLY ); + DECL_PROP1_BOOL( ISREADONLY, BOUND ); + DECL_PROP1_BOOL( ISROWVERSION, READONLY ); + DECL_PROP1_BOOL( ISSEARCHABLE, READONLY ); + DECL_PROP1_BOOL( ISSIGNED, READONLY ); + DECL_PROP1_BOOL( ISWRITABLE, READONLY ); + DECL_PROP1( LABEL, OUString, READONLY ); + DECL_PROP1( PRECISION, sal_Int32, READONLY ); + DECL_PROP1( SCALE, sal_Int32, READONLY ); + DECL_PROP1( SCHEMANAME, OUString, READONLY ); + DECL_PROP1( SERVICENAME, OUString, READONLY ); + DECL_PROP1( TABLENAME, OUString, READONLY ); + DECL_PROP1( TYPE, sal_Int32, READONLY ); + DECL_PROP1( TYPENAME, OUString, READONLY ); + DECL_PROP1( VALUE, Any, BOUND ); + + END_PROPERTY_SEQUENCE() + + 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, + const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns, + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector + ) : connectivity::sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector) + ,m_aColumns(_rColumns) +{ +} + +ORowSetDataColumns::~ORowSetDataColumns() +{ +} + +sdbcx::ObjectType ORowSetDataColumns::createObject(const OUString& _rName) +{ + connectivity::sdbcx::ObjectType xNamed; + + ::comphelper::UStringMixEqual aCase(isCaseSensitive()); + ::connectivity::OSQLColumns::Vector::const_iterator first = ::connectivity::find(m_aColumns->begin(),m_aColumns->end(),_rName,aCase); + if(first != m_aColumns->end()) + xNamed = *first; + + return xNamed; +} + +void ORowSetDataColumns::disposing() +{ + ORowSetDataColumns_BASE::disposing(); + m_aColumns = nullptr; +} + +void ORowSetDataColumns::assign(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,const std::vector< OUString> &_rVector) +{ + m_aColumns = _rColumns; + reFill(_rVector); +} + +void ORowSetDataColumns::impl_refresh() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/CRowSetDataColumn.hxx b/dbaccess/source/core/api/CRowSetDataColumn.hxx new file mode 100644 index 000000000..24863cb0a --- /dev/null +++ b/dbaccess/source/core/api/CRowSetDataColumn.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_CROWSETDATACOLUMN_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_CROWSETDATACOLUMN_HXX + +#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, + const OUString& _rDescription, + const OUString& i_sLabel, + const 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, + const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns, + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector + ); + virtual ~ORowSetDataColumns() override; + // only the name is identical to ::cppu::OComponentHelper + virtual void disposing() override; + void assign(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,const std::vector< OUString> &_rVector); + }; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/CacheSet.cxx b/dbaccess/source/core/api/CacheSet.cxx new file mode 100644 index 000000000..92c1484ed --- /dev/null +++ b/dbaccess/source/core/api/CacheSet.cxx @@ -0,0 +1,579 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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&) + { + SAL_WARN("dbaccess", "Exception occurred"); + } + 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++)) ).append(","); + aValues.append("?,"); + } + + aSql[aSql.getLength() - 1] = ')'; + aValues[aValues.getLength() - 1] = ')'; + + aSql.append(aValues.makeStringAndClear()); + // 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) ).append("?,"); + } + } +} + +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 " ).append( aCondition.makeStringAndClear()); + } + 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 000000000..522d77faf --- /dev/null +++ b/dbaccess/source/core/api/CacheSet.hxx @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_API_CACHESET_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_CACHESET_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_CACHESET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/FilteredContainer.cxx b/dbaccess/source/core/api/FilteredContainer.cxx new file mode 100644 index 000000000..0e8b2926c --- /dev/null +++ b/dbaccess/source/core/api/FilteredContainer.cxx @@ -0,0 +1,467 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 ) + :sComposedName() + ,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(); + + 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(); + + 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( const 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 = _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( _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( 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.realloc( 1 ); + aTableTypeFilter[0] = 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 const char sAll[] = "%"; + 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( 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 ); + } + + const OUString sAll( "%" ); + const OUString sView( "VIEW" ); + const OUString sTable( "TABLE" ); + + switch ( nFilterMode ) + { + default: + SAL_WARN("dbaccess", "OTableContainer::getAllTableTypeFilter: unknown TableTypeFilterMode!" ); + [[fallthrough]]; + case FILTER_MODE_MIX_ALL: + _rFilter.realloc( 3 ); + _rFilter[0] = sView; + _rFilter[1] = sTable; + _rFilter[2] = sAll; + break; + case FILTER_MODE_FIXED: + _rFilter.realloc( 2 ); + _rFilter[0] = sView; + _rFilter[1] = sTable; + break; + case FILTER_MODE_WILDCARD: + _rFilter.realloc( 1 ); + _rFilter[0] = sAll; + break; + case FILTER_MODE_STANDARD: + _rFilter.realloc( 0 ); + break; + } + } + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/HelperCollections.cxx b/dbaccess/source/core/api/HelperCollections.cxx new file mode 100644 index 000000000..dfc18badc --- /dev/null +++ b/dbaccess/source/core/api/HelperCollections.cxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "HelperCollections.hxx" + +#include + +#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(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns, + bool _bCase, + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector, + bool _bUseAsIndex + ) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector,_bUseAsIndex) + ,m_aColumns(_rColumns) + { + } + + std::unique_ptr OPrivateColumns::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 000000000..c2406dc49 --- /dev/null +++ b/dbaccess/source/core/api/HelperCollections.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_HELPERCOLLECTIONS_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_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; + + typedef connectivity::sdbcx::OCollection OPrivateColumns_Base; + class OPrivateColumns : public OPrivateColumns_Base + { + ::rtl::Reference< ::connectivity::OSQLColumns> m_aColumns; + protected: + virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override {} + virtual Reference< XPropertySet > createDescriptor() override + { + return nullptr; + } + public: + OPrivateColumns(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns, + bool _bCase, + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector, + bool _bUseAsIndex = false + ); + + /** creates a columns instance as above, but taking the names from the columns itself + */ + static std::unique_ptr createWithIntrinsicNames( + const ::rtl::Reference< ::connectivity::OSQLColumns >& _rColumns, + bool _bCase, + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex + ); + + virtual void disposing() override; + }; + typedef connectivity::sdbcx::OCollection OPrivateTables_BASE; + + // OPrivateTables + class OPrivateTables : public OPrivateTables_BASE + { + OSQLTables m_aTables; + protected: + virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual void impl_refresh() override {} + virtual Reference< XPropertySet > createDescriptor() override + { + return nullptr; + } + public: + OPrivateTables( const OSQLTables& _rTables, + bool _bCase, + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const std::vector< OUString> &_rVector + ) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector) + ,m_aTables(_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(); + } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_HELPERCOLLECTIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/KeySet.cxx b/dbaccess/source/core/api/KeySet.cxx new file mode 100644 index 000000000..c9f9ac8a3 --- /dev/null +++ b/dbaccess/source/core/api/KeySet.cxx @@ -0,0 +1,1463 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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(const connectivity::OSQLTable& _xTable, + const OUString& _rUpdateTableName, // this can be the alias or the full qualified name + const Reference< XSingleSelectQueryAnalyzer >& _xComposer, + const ORowSetValueVector& _aParameterValueForCache, + sal_Int32 i_nMaxRows, + sal_Int32& o_nRowCount) + :OCacheSet(i_nMaxRows) + ,m_aParameterValueForCache(new ORowSetValueVector(_aParameterValueForCache)) + ,m_xTable(_xTable) + ,m_xComposer(_xComposer) + ,m_sUpdateTableName(_rUpdateTableName) + ,m_rRowCount(o_nRowCount) + ,m_bRowCountFinal(false) +{ +} + +OKeySet::~OKeySet() +{ + tryDispose(m_xSet); + // m_xStatement is necessarily one of those + for (auto & statement : m_vStatements) + { + tryDispose(statement.second); + } + + m_xComposer = nullptr; + +} + +void OKeySet::initColumns() +{ + Reference 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); + for(sal_Int32 i = 0; i< nParaCount;++i) + { + Reference xPara(xQueryParameters->getByIndex(i),UNO_QUERY_THROW); + xPara->getPropertyValue(PROPERTY_REALNAME) >>= aParameterColumns[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( const OUString &tblName, const OUString &colName, const connectivity::ORowSetValue &_rValue, OUStringBuffer &o_buf ) + { + OUString fullName; + if (tblName.isEmpty()) + fullName = colName; + else + fullName = tblName + "." + colName; + if ( _rValue.isNull() ) + { + o_buf.append(fullName).append(" IS NULL "); + } + else + { + o_buf.append(fullName).append(" = ? "); + } + } +} + +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( makeAny(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 makeAny(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 + static OUString aPara(" = ?,"); + OUString aQuote = getIdentifierQuoteString(); + static OUString aAnd(" AND "); + 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(); + sal_Int32 i = 1; + // 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)).append(aPara); + } + ++i; + } + + 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.makeStringAndClear()).append(sIndexCondition.makeStringAndClear()); + } + else if(!sKeyCondition.isEmpty()) + { + aSql.append(sKeyCondition.makeStringAndClear()); + } + else if(!sIndexCondition.isEmpty()) + { + aSql.append(sIndexCondition.makeStringAndClear()); + } + 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(),"",aIndexColumnPositions); +} + +void OKeySet::executeUpdate(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const OUString& i_sSQL,const OUString& 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.isEmpty() || 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.isEmpty() || keyColumnName.second.sTableName == i_sTableName ) + { + setParameter(i++,xParameter,(*_rOriginalRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale); + } + } + if ( !_aIndexColumnPositions.empty() ) + { + // now we have to set the index values + auto aIter = m_pColumnNames->begin(); + for (auto const& indexColumnPosition : _aIndexColumnPositions) + { + setParameter(i++,xParameter,(*_rOriginalRow)[indexColumnPosition],(*_rOriginalRow)[indexColumnPosition].getTypeKind(),aIter->second.nScale); + ++aIter; + } + } + const sal_Int32 nRowsUpdated = xPrep->executeUpdate(); + m_bUpdated = nRowsUpdated > 0; + if(m_bUpdated) + { + const sal_Int32 nBookmark = ::comphelper::getINT32((*_rInsertRow)[0].getAny()); + m_aKeyIter = m_aKeyMap.find(nBookmark); + m_aKeyIter->second.second.first = 2; + m_aKeyIter->second.second.second = xRow; + copyRowValue(_rInsertRow,m_aKeyIter->second.first,nBookmark); + tryRefetch(_rInsertRow,bRefetch); + } +} + +void OKeySet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) +{ + Reference 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)).append(","); + 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.makeStringAndClear()); + // now create,fill and execute the prepared statement + executeInsert(_rInsertRow,aSql.makeStringAndClear(),"",bRefetch); +} + +void OKeySet::executeInsert( const ORowSetRow& _rInsertRow,const OUString& i_sSQL,const OUString& 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.isEmpty() || 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.isEmpty() && !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(").append(::dbtools::quoteName( sQuote,aFind->second.sRealName)).append("),"); + } + } + + if(!sMaxStmt.isEmpty()) + { + sMaxStmt[sMaxStmt.getLength()-1] = ' '; + OUString sStmt = "SELECT " + sMaxStmt.makeStringAndClear() + "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] = makeAny(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(*_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.makeStringAndClear()); + aSql.setLength(aSql.getLength()-5); + + // now create end execute the prepared statement + Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear())); + Reference< XParameters > xParameter(xPrep,UNO_QUERY); + + sal_Int32 i = 1; + for (auto const& keyColumnName : *m_pKeyColumnNames) + { + setParameter(i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale); + } + + // now we have to set the index values + auto aIter = m_pColumnNames->begin(); + for (auto const& indexColumnPosition : aIndexColumnPositions) + { + setParameter(i++,xParameter,(*_rDeleteRow)[indexColumnPosition],(*_rDeleteRow)[indexColumnPosition].getTypeKind(),aIter->second.nScale); + ++aIter; + } + + m_bDeleted = xPrep->executeUpdate() > 0; + + if(m_bDeleted) + { + sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny()); + if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end()) + ++m_aKeyIter; + m_aKeyMap.erase(nBookmark); + m_bDeleted = true; + } +} + +bool OKeySet::next() +{ + m_bInserted = m_bUpdated = m_bDeleted = false; + + if(isAfterLast()) + return false; + ++m_aKeyIter; + if(!m_bRowCountFinal && m_aKeyIter == m_aKeyMap.end()) + { + // not yet all records fetched, but we reached the end of those we fetched + // try to fetch one more row + if (fetchRow()) + { + OSL_ENSURE(!isAfterLast(), "fetchRow succeeded, but isAfterLast()"); + return true; + } + else + { + // nope, we arrived at end of data + m_aKeyIter = m_aKeyMap.end(); + OSL_ENSURE(isAfterLast(), "fetchRow failed, but not end of data"); + } + } + + invalidateRow(); + return !isAfterLast(); +} + +bool OKeySet::isBeforeFirst( ) +{ + return m_aKeyIter == m_aKeyMap.begin(); +} + +bool OKeySet::isAfterLast( ) +{ + return m_bRowCountFinal && m_aKeyIter == m_aKeyMap.end(); +} + +void OKeySet::beforeFirst( ) +{ + m_bInserted = m_bUpdated = m_bDeleted = false; + m_aKeyIter = m_aKeyMap.begin(); + invalidateRow(); +} + +void OKeySet::afterLast( ) +{ + m_bInserted = m_bUpdated = m_bDeleted = false; + fillAllRows(); + m_aKeyIter = m_aKeyMap.end(); + invalidateRow(); +} + +bool OKeySet::first() +{ + m_bInserted = m_bUpdated = m_bDeleted = false; + m_aKeyIter = m_aKeyMap.begin(); + ++m_aKeyIter; + if(m_aKeyIter == m_aKeyMap.end()) + { + if (!fetchRow()) + { + m_aKeyIter = m_aKeyMap.end(); + return false; + } + } + else + invalidateRow(); + return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin(); +} + +bool OKeySet::last( ) +{ + m_bInserted = m_bUpdated = m_bDeleted = false; + bool bFetchedRow = fillAllRows(); + + m_aKeyIter = m_aKeyMap.end(); + --m_aKeyIter; + if ( !bFetchedRow ) + { + invalidateRow(); + } + return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin(); +} + +sal_Int32 OKeySet::getRow( ) +{ + OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!"); + OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!"); + + return std::distance(m_aKeyMap.begin(),m_aKeyIter); +} + +bool OKeySet::absolute( sal_Int32 row ) +{ + m_bInserted = m_bUpdated = m_bDeleted = false; + OSL_ENSURE(row,"absolute(0) isn't allowed!"); + bool bFetchedRow = false; + if(row < 0) + { + if(!m_bRowCountFinal) + bFetchedRow = fillAllRows(); + + row = std::min(std::abs(row), static_cast(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, + const OUString& _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 000000000..417774cae --- /dev/null +++ b/dbaccess/source/core/api/KeySet.hxx @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_KEYSET_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_KEYSET_HXX + +#include "CacheSet.hxx" + +#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, const OUString& _rDefaultValue ) + :sDefaultValue( _rDefaultValue ) + ,nPosition( _nPosition ) + ,nType( _nType ) + ,nScale( _nScale ) + ,bNullable(_bNullable) + { + } + }; + typedef std::map< OUString, SelectColumnDescription, ::comphelper::UStringMixLess > SelectColumnsMetaData; + + // the elements of _rxQueryColumns must have the properties PROPERTY_REALNAME and PROPERTY_TABLENAME + void getColumnPositions(const css::uno::Reference< css::container::XNameAccess >& _rxQueryColumns, + const css::uno::Sequence< OUString >& _rColumnNames, + const OUString& _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, const OUString& i_sTableName,const std::vector& _aIndexColumnPositions = std::vector()); + void executeInsert( const ORowSetRow& _rInsertRow, const OUString& i_sSQL, const OUString& i_sTableName, bool bRefetch = false); + void executeStatement(OUStringBuffer& io_aFilter, css::uno::Reference< css::sdb::XSingleSelectQueryComposer>& io_xAnalyzer); + + virtual ~OKeySet() override; + public: + OKeySet(const connectivity::OSQLTable& _xTable, + const OUString& _rUpdateTableName, + const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer >& _xComposer, + const ORowSetValueVector& _aParameterValueForCache, + sal_Int32 i_nMaxRows, + sal_Int32& o_nRowCount); + + // late ctor which can throw exceptions + virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter) override; + virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) override; + + // css::sdbc::XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + + + virtual bool rowUpdated( ) override; + virtual bool rowInserted( ) override; + virtual bool rowDeleted( ) override; + bool isBeforeFirst( ); + bool isAfterLast( ); + + // css::sdbc::XResultSet + virtual bool next() override; + virtual void beforeFirst( ) override; + virtual void afterLast( ) override; + virtual bool first() override; + virtual bool last( ) override; + virtual sal_Int32 getRow( ) override; + virtual bool absolute( sal_Int32 row ) override; + virtual bool previous( ) override; + /// @throws css::sdbc::SQLException + /// @throws css::uno::RuntimeException + void ensureRowForData( ); + virtual void refreshRow( ) override; + // css::sdbcx::XRowLocate + virtual css::uno::Any getBookmark() override; + + virtual bool moveToBookmark( const css::uno::Any& bookmark ) override; + + virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override; + + virtual bool hasOrderedBookmarks( ) override; + + virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) override; + + // css::sdbc::XResultSetUpdate + virtual void updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) override; + virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override; + virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_KEYSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/OptimisticSet.cxx b/dbaccess/source/core/api/OptimisticSet.cxx new file mode 100644 index 000000000..67fd18aaa --- /dev/null +++ b/dbaccess/source/core/api/OptimisticSet.cxx @@ -0,0 +1,586 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#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,const OUString& 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).append(" = ?"); + } + } + + 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.toString()); + OUStringBuffer& rCondition = aKeyConditions[elem.first]; + if ( !rCondition.isEmpty() ) + sSql.append(" WHERE ").append( rCondition.toString() ); + + 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.toString() + + ") VALUES ( " + aParameter[elem.first].toString() + " )"); + + OUStringBuffer& rCondition = aKeyConditions[elem.first]; + if ( !rCondition.isEmpty() ) + { + OUString sQuery("SELECT " + elem.second.toString() + " FROM " + sComposedTableName + + " WHERE " + rCondition.toString()); + + 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.toString() ); + executeDelete(_rDeleteRow, sSql, keyCondition.first); + } + } +} + +void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,const OUString& i_sTableName) +{ + // now create and execute the prepared statement + Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL)); + Reference< XParameters > xParameter(xPrep,UNO_QUERY); + + sal_Int32 i = 1; + for (auto const& keyColumnName : *m_pKeyColumnNames) + { + if ( keyColumnName.second.sTableName == i_sTableName ) + setParameter(i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale); + } + m_bDeleted = xPrep->executeUpdate() > 0; + + if(m_bDeleted) + { + sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny()); + if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end()) + ++m_aKeyIter; + m_aKeyMap.erase(nBookmark); + m_bDeleted = true; + } +} + +void OptimisticSet::fillJoinedColumns_throw(const std::vector< TNodePair >& i_aJoinColumns) +{ + for (auto const& joinColumn : i_aJoinColumns) + { + OUString sColumnName,sTableName; + m_aSqlIterator.getColumnRange(joinColumn.first,sColumnName,sTableName); + OUString sLeft(sTableName + "." + sColumnName); + m_aSqlIterator.getColumnRange(joinColumn.second,sColumnName,sTableName); + OUString sRight(sTableName + "." + sColumnName); + fillJoinedColumns_throw(sLeft, sRight); + } +} + +void OptimisticSet::fillJoinedColumns_throw(const OUString& i_sLeftColumn,const OUString& i_sRightColumn) +{ + sal_Int32 nLeft = 0,nRight = 0; + SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn); + SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn); + + bool bLeftKey = aLeftIter != m_pKeyColumnNames->end(); + if ( bLeftKey ) + { + nLeft = aLeftIter->second.nPosition; + } + else + { + aLeftIter = m_pColumnNames->find(i_sLeftColumn); + if ( aLeftIter != m_pColumnNames->end() ) + nLeft = aLeftIter->second.nPosition; + } + + bool bRightKey = aRightIter != m_pKeyColumnNames->end(); + if ( bRightKey ) + { + nRight = aRightIter->second.nPosition; + } + else + { + aRightIter = m_pColumnNames->find(i_sRightColumn); + if ( aRightIter != m_pColumnNames->end() ) + nRight = aRightIter->second.nPosition; + } + + if (bLeftKey) + m_aJoinedKeyColumns[nLeft] = nRight; + else + m_aJoinedColumns[nLeft] = nRight; + if (bRightKey) + m_aJoinedKeyColumns[nRight] = nLeft; + else + m_aJoinedColumns[nRight] = nLeft; +} + +bool OptimisticSet::isResultSetChanged() const +{ + bool bOld = m_bResultSetChanged; + m_bResultSetChanged = false; + return bOld; +} + +void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,std::vector& 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.toString() + " FROM " + sComposedTableName + " WHERE " + + rCondition.makeStringAndClear()); + + 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 000000000..db380d071 --- /dev/null +++ b/dbaccess/source/core/api/OptimisticSet.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_OPTIMISTICSET_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_OPTIMISTICSET_HXX + +#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,const OUString& 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; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_OPTIMISTICSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/PrivateRow.cxx b/dbaccess/source/core/api/PrivateRow.cxx new file mode 100644 index 000000000..22adc74f1 --- /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]; + } + sal_Bool SAL_CALL OPrivateRow::getBoolean( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return bool(m_aRow[m_nPos]); + } + ::sal_Int8 SAL_CALL OPrivateRow::getByte( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + ::sal_Int16 SAL_CALL OPrivateRow::getShort( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + ::sal_Int32 SAL_CALL OPrivateRow::getInt( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + ::sal_Int64 SAL_CALL OPrivateRow::getLong( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + float SAL_CALL OPrivateRow::getFloat( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + double SAL_CALL OPrivateRow::getDouble( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + Sequence< ::sal_Int8 > SAL_CALL OPrivateRow::getBytes( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + css::util::Date SAL_CALL OPrivateRow::getDate( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + css::util::Time SAL_CALL OPrivateRow::getTime( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + css::util::DateTime SAL_CALL OPrivateRow::getTimestamp( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos]; + } + Reference< css::io::XInputStream > SAL_CALL OPrivateRow::getBinaryStream( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return Reference< css::io::XInputStream >(m_aRow[m_nPos].makeAny(),UNO_QUERY); + } + Reference< css::io::XInputStream > SAL_CALL OPrivateRow::getCharacterStream( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return Reference< css::io::XInputStream >(m_aRow[m_nPos].makeAny(),UNO_QUERY); + } + Any SAL_CALL OPrivateRow::getObject( ::sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& ) + { + m_nPos = columnIndex; + return m_aRow[m_nPos].makeAny(); + } + Reference< XRef > SAL_CALL OPrivateRow::getRef( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return Reference< XRef >(m_aRow[m_nPos].makeAny(),UNO_QUERY); + } + Reference< XBlob > SAL_CALL OPrivateRow::getBlob( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return Reference< XBlob >(m_aRow[m_nPos].makeAny(),UNO_QUERY); + } + Reference< XClob > SAL_CALL OPrivateRow::getClob( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return Reference< XClob >(m_aRow[m_nPos].makeAny(),UNO_QUERY); + } + Reference< XArray > SAL_CALL OPrivateRow::getArray( ::sal_Int32 columnIndex ) + { + m_nPos = columnIndex; + return Reference< XArray >(m_aRow[m_nPos].makeAny(),UNO_QUERY); + } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/PrivateRow.hxx b/dbaccess/source/core/api/PrivateRow.hxx new file mode 100644 index 000000000..3f8edf0bc --- /dev/null +++ b/dbaccess/source/core/api/PrivateRow.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_PRIVATEROW_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_PRIVATEROW_HXX + +#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(const ORowSetValueVector::Vector& i_aRow) : m_aRow(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 +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_PRIVATEROW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/RowSet.cxx b/dbaccess/source/core/api/RowSet.cxx new file mode 100644 index 000000000..62383ecd5 --- /dev/null +++ b/dbaccess/source/core/api/RowSet.cxx @@ -0,0 +1,2966 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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)); +} + +#define NOTIFY_LISTENERS_CHECK(_rListeners,T,method) \ + std::vector< Reference< XInterface > > aListenerSeq = _rListeners.getElements(); \ + \ + _rGuard.clear(); \ + bool bCheck = std::all_of(aListenerSeq.rbegin(), aListenerSeq.rend(), \ + [&aEvt](Reference& rxItem) { \ + try \ + { \ + return static_cast(static_cast(rxItem.get())->method(aEvt)); \ + } \ + catch( RuntimeException& ) \ + { \ + return true; \ + } \ + }); \ + _rGuard.reset(); + + +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_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() throw() +{ + ORowSet_BASE1::acquire(); +} + +void SAL_CALL ORowSet::release() throw() +{ + ORowSet_BASE1::release(); +} + +// css::XUnoTunnel +sal_Int64 SAL_CALL ORowSet::getSomething( const Sequence< sal_Int8 >& rId ) +{ + if (isUnoTunnelId(rId)) + return reinterpret_cast(this); + + return 0; +} + +Sequence< sal_Int8 > ORowSet::getUnoTunnelId() +{ + static ::cppu::OImplementationId s_Id; + + return s_Id.getImplementationId(); +} + +// 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); + } + // additionals things to set + freeResources( true ); +} + +// comphelper::OPropertyArrayUsageHelper +::cppu::IPropertyArrayHelper* ORowSet::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +// cppu::OPropertySetHelper +::cppu::IPropertyArrayHelper& SAL_CALL ORowSet::getInfoHelper() +{ + return *::comphelper::OPropertyArrayUsageHelper::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,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,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,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,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,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( MOVE_NONE ); + sal_Int32 nDeletePosition = m_pCache->getRow(); + + notifyRowSetAndClonesRowDelete( aBookmarkToDelete ); + + ORowSetRow aOldValues; + if ( m_pCache->m_aMatrixIter != m_pCache->getEnd() && m_pCache->m_aMatrixIter->is() ) + aOldValues = new ORowSetValueVector( *(*(m_pCache->m_aMatrixIter)) ); + + Sequence aChangedBookmarks; + RowsChangeEvent aEvt(*this,RowChangeAction::DELETE,1,aChangedBookmarks); + notifyAllListenersRowBeforeChange(aGuard,aEvt); + + m_pCache->deleteRow(); + notifyRowSetAndClonesRowDeleted( aBookmarkToDelete, nDeletePosition ); + + ORowSetNotifier aNotifier( this ); + // this will call cancelRowModification on the cache if necessary + + // notification order + // - rowChanged + notifyAllListenersRowChanged(aGuard,aEvt); + + // - IsModified + // - IsNew + aNotifier.fire( ); + + // - RowCount/IsRowCountFinal + fireRowcount(); +} + +void ORowSet::implCancelRowUpdates( bool _bNotifyModified ) +{ + ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); + + ::osl::MutexGuard aGuard( *m_pMutex ); + if ( m_bBeforeFirst || m_bAfterLast || rowDeleted() ) + return; // nothing to do so return + + checkCache(); + // cancelRowUpdates is not allowed when: + // - standing on the insert row + // - the concurrency is read only + // - the current row is deleted + if ( m_bNew || m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY ) + throwFunctionSequenceException(*this); + + positionCache( MOVE_NONE ); + + ORowSetRow aOldValues; + if ( !m_bModified && _bNotifyModified && !m_aCurrentRow.isNull() ) + aOldValues = new ORowSetValueVector( *(*m_aCurrentRow) ); + + m_pCache->cancelRowUpdates(); + + m_aBookmark = m_pCache->getBookmark(); + m_aCurrentRow = m_pCache->m_aMatrixIter; + m_bIsInsertRow = false; + + // notification order + // IsModified + if( !m_bModified && _bNotifyModified ) + { + // - column values + ORowSetBase::firePropertyChange(aOldValues); + fireProperty(PROPERTY_ID_ISMODIFIED,false,true); + } +} + +void SAL_CALL ORowSet::cancelRowUpdates( ) +{ + implCancelRowUpdates( true ); +} + +void SAL_CALL ORowSet::addRowSetListener( const Reference< XRowSetListener >& listener ) +{ + ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); + + ::osl::MutexGuard aGuard( m_aColumnsMutex ); + if(listener.is()) + m_aRowsetListeners.addInterface(listener); +} + +void SAL_CALL ORowSet::removeRowSetListener( const Reference< XRowSetListener >& listener ) +{ + ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); + + ::osl::MutexGuard aGuard( m_aColumnsMutex ); + if(listener.is()) + m_aRowsetListeners.removeInterface(listener); +} + +void ORowSet::notifyAllListeners(::osl::ResettableMutexGuard& _rGuard) +{ + EventObject aEvt(*m_pMySelf); + _rGuard.clear(); + m_aRowsetListeners.notifyEach( &XRowSetListener::rowSetChanged, aEvt ); + _rGuard.reset(); +} + +void ORowSet::notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& _rGuard) +{ + EventObject aEvt(*m_pMySelf); + _rGuard.clear(); + m_aRowsetListeners.notifyEach( &XRowSetListener::cursorMoved, aEvt ); + _rGuard.reset(); +} + +void ORowSet::notifyAllListenersRowChanged(::osl::ResettableMutexGuard& _rGuard, const RowsChangeEvent& aEvt) +{ + _rGuard.clear(); + m_aRowsetListeners.notifyEach( &XRowSetListener::rowChanged, static_cast(aEvt) ); + m_aRowsChangeListener.notifyEach( &XRowsChangeListener::rowsChanged, aEvt ); + _rGuard.reset(); +} + +bool ORowSet::notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& _rGuard) +{ + EventObject aEvt(*m_pMySelf); + NOTIFY_LISTENERS_CHECK(m_aApproveListeners,XRowSetApproveListener,approveCursorMove); + return bCheck; +} + +void ORowSet::notifyAllListenersRowBeforeChange(::osl::ResettableMutexGuard& _rGuard,const RowChangeEvent &aEvt) +{ + NOTIFY_LISTENERS_CHECK(m_aApproveListeners,XRowSetApproveListener,approveRowChange); + if ( !bCheck ) + m_aErrors.raiseTypedException( sdb::ErrorCondition::ROW_SET_OPERATION_VETOED, *this, ::cppu::UnoType< RowSetVetoException >::get() ); +} + +void ORowSet::fireRowcount() +{ + sal_Int32 nCurrentRowCount( impl_getRowCount() ); + bool bCurrentRowCountFinal( m_pCache->m_bRowCountFinal ); + + if ( m_nLastKnownRowCount != nCurrentRowCount ) + { + sal_Int32 nHandle = PROPERTY_ID_ROWCOUNT; + Any aNew,aOld; + aNew <<= nCurrentRowCount; aOld <<= m_nLastKnownRowCount; + fire(&nHandle,&aNew,&aOld,1,false); + m_nLastKnownRowCount = nCurrentRowCount; + } + if ( !m_bLastKnownRowCountFinal && ( m_bLastKnownRowCountFinal != bCurrentRowCountFinal ) ) + { + sal_Int32 nHandle = PROPERTY_ID_ISROWCOUNTFINAL; + Any aNew,aOld; + aNew <<= bCurrentRowCountFinal; + aOld <<= m_bLastKnownRowCountFinal; + fire(&nHandle,&aNew,&aOld,1,false); + m_bLastKnownRowCountFinal = bCurrentRowCountFinal; + } +} + +void SAL_CALL ORowSet::moveToInsertRow( ) +{ + ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); + + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + checkPositioningAllowed(); + if ( ( m_pCache->m_nPrivileges & Privilege::INSERT ) != Privilege::INSERT ) + ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_INSERT_PRIVILEGE ), StandardSQLState::GENERAL_ERROR, *this ); + + if ( !notifyAllListenersCursorBeforeMove( aGuard ) ) + return; + + // remember old value for fire + ORowSetRow aOldValues; + if ( rowDeleted() ) + { + positionCache( MOVE_FORWARD ); + m_pCache->next(); + setCurrentRow( true, false, aOldValues, aGuard); + } + else + positionCache( MOVE_NONE ); + + // check before because the resultset could be empty + if ( !m_bBeforeFirst + && !m_bAfterLast + && m_pCache->m_aMatrixIter != m_pCache->getEnd() + && m_pCache->m_aMatrixIter->is() + ) + aOldValues = new ORowSetValueVector( *(*(m_pCache->m_aMatrixIter)) ); + + const bool bNewState = m_bNew; + const bool bModState = m_bModified; + + m_pCache->moveToInsertRow(); + m_aCurrentRow = m_pCache->m_aInsertRow; + m_bIsInsertRow = true; + + // set read-only flag to false + impl_setDataColumnsWriteable_throw(); + + // notification order + // - column values + ORowSetBase::firePropertyChange(aOldValues); + + // - cursorMoved + notifyAllListenersCursorMoved(aGuard); + + // - IsModified + if ( bModState != m_bModified ) + fireProperty( PROPERTY_ID_ISMODIFIED, m_bModified, bModState ); + + // - IsNew + if ( bNewState != m_bNew ) + fireProperty( PROPERTY_ID_ISNEW, m_bNew, bNewState ); + + // - RowCount/IsRowCountFinal + fireRowcount(); +} + +void ORowSet::impl_setDataColumnsWriteable_throw() +{ + impl_restoreDataColumnsWriteable_throw(); + m_aReadOnlyDataColumns.resize(m_aDataColumns.size(),false); + std::vector >::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,makeAny(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, makeAny(readOnlyDataColumn) ); + ++aIter; + } + m_aReadOnlyDataColumns.clear(); +} + +void SAL_CALL ORowSet::moveToCurrentRow( ) +{ + ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed); + + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + checkPositioningAllowed(); + + if ( !m_pCache->m_bNew && !m_bModified ) + // nothing to do if we're not on the insertion row, and not modified otherwise + return; + + if ( rowDeleted() ) + // this would perhaps even justify a RuntimeException... + // if the current row is deleted, then no write access to this row should be possible. So, + // m_bModified should be true. Also, as soon as somebody calls moveToInsertRow, + // our current row should not be deleted anymore. So, we should not have survived the above + // check "if ( !m_pCache->m_bNew && !m_bModified )" + ::dbtools::throwSQLException( DBA_RES( RID_STR_ROW_ALREADY_DELETED ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this ); + + if ( !notifyAllListenersCursorBeforeMove( aGuard ) ) + return; + + positionCache( MOVE_NONE_REFRESH ); + + ORowSetNotifier aNotifier( this ); + + // notification order + // - cursorMoved + notifyAllListenersCursorMoved(aGuard); + + // - IsModified + // - IsNew + aNotifier.fire(); +} + +// XRow +sal_Bool SAL_CALL ORowSet::wasNull( ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + + return ( m_pCache && isInsertRow() ) ? (**m_pCache->m_aInsertRow)[m_nLastColumnIndex].isNull() : ORowSetBase::wasNull(); +} + +const ORowSetValue& ORowSet::getInsertValue(sal_Int32 columnIndex) +{ + checkCache(); + + if ( m_pCache && isInsertRow() ) + { + m_nLastColumnIndex = columnIndex; + return (**m_pCache->m_aInsertRow)[m_nLastColumnIndex]; + } + return getValue(columnIndex); +} + +OUString SAL_CALL ORowSet::getString( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +sal_Bool SAL_CALL ORowSet::getBoolean( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + // the extra cast is to recognise the "true" or "false" strings + return static_cast(getInsertValue(columnIndex)); +} + +sal_Int8 SAL_CALL ORowSet::getByte( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +sal_Int16 SAL_CALL ORowSet::getShort( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +sal_Int32 SAL_CALL ORowSet::getInt( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +sal_Int64 SAL_CALL ORowSet::getLong( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +float SAL_CALL ORowSet::getFloat( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +double SAL_CALL ORowSet::getDouble( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +Sequence< sal_Int8 > SAL_CALL ORowSet::getBytes( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +css::util::Date SAL_CALL ORowSet::getDate( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +css::util::Time SAL_CALL ORowSet::getTime( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +css::util::DateTime SAL_CALL ORowSet::getTimestamp( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getInsertValue(columnIndex); +} + +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.get(); +} + +void ORowSet::approveExecution() +{ + ::osl::MutexGuard aGuard( m_aColumnsMutex ); + EventObject aEvt(*this); + + OInterfaceIteratorHelper2 aApproveIter( m_aApproveListeners ); + while ( aApproveIter.hasMoreElements() ) + { + Reference< XRowSetApproveListener > xListener( static_cast< XRowSetApproveListener* >( aApproveIter.next() ) ); + try + { + if ( xListener.is() && !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, makeAny( nResultSetType ) ); + _rxStatement->setPropertyValue( PROPERTY_RESULTSETCONCURRENCY, makeAny( 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, makeAny( true ) ); + xStatementProps->setPropertyValue( PROPERTY_MAXROWS, makeAny( 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( const SQLException& ) + { + SQLExceptionInfo aError( ::cppu::getCaughtException() ); + OSL_ENSURE( aError.isValid(), "ORowSet::impl_makeNewStatement_throw: caught an SQLException which we cannot analyze!" ); + + // append information about what we were actually going to execute + try + { + OUString sInfo(DBA_RES_PARAM( RID_STR_COMMAND_LEADING_TO_ERROR, "$command$", sCommandToExecute ) ); + aError.append( SQLExceptionInfo::TYPE::SQLContext, sInfo ); + } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + + // propagate + aError.doThrow(); + } +} + +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[] = { + OUString(PROPERTY_ALIGN), OUString(PROPERTY_RELATIVEPOSITION), OUString(PROPERTY_WIDTH), OUString(PROPERTY_HIDDEN), OUString(PROPERTY_CONTROLMODEL), + OUString(PROPERTY_HELPTEXT), OUString(PROPERTY_CONTROLDEFAULT) + }; + for (const auto & aPropertyName : aPropertyNames) + { + if ( xInfo->hasPropertyByName( aPropertyName ) ) + { + _rxRowSetColumn->setPropertyValue( aPropertyName, _rxTemplateColumn->getPropertyValue( aPropertyName ) ); + bHaveAnyColumnSetting = true; + } + } + + // the format key is slightly more complex + sal_Int32 nFormatKey = 0; + if( xInfo->hasPropertyByName( PROPERTY_NUMBERFORMAT ) ) + { + _rxTemplateColumn->getPropertyValue( PROPERTY_NUMBERFORMAT ) >>= nFormatKey; + bHaveAnyColumnSetting = true; + } + if ( !nFormatKey && m_xNumberFormatTypes.is() ) + nFormatKey = ::dbtools::getDefaultNumberFormat( _rxTemplateColumn, m_xNumberFormatTypes, SvtSysLocale().GetLanguageTag().getLocale() ); + _rxRowSetColumn->setPropertyValue( PROPERTY_NUMBERFORMAT, makeAny( 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; + } + ORowSetDataColumn* pColumn = new ORowSetDataColumn( getMetaData(), + this, + this, + i+1, + m_xActiveConnection->getMetaData(), + aDescription, + OUString(), + [this] (sal_Int32 const column) -> ORowSetValue const& { + return this->getInsertValue(column); + }); + aColumnMap.insert(std::make_pair(sName,0)); + aColumns->emplace_back(pColumn); + pColumn->setName(sName); + aNames.push_back(sName); + m_aDataColumns.push_back(pColumn); + + pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ISREADONLY,makeAny(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,makeAny(nFormatKey)); + pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_RELATIVEPOSITION,makeAny(sal_Int32(i+1))); + pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_WIDTH,makeAny(sal_Int32(227))); + pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ALIGN,makeAny(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; + } + ORowSetDataColumn* pColumn = new ORowSetDataColumn( getMetaData(), + this, + this, + i, + m_xActiveConnection->getMetaData(), + aDescription, + sParseLabel, + [this] (sal_Int32 const column) -> ORowSetValue const& { + return this->getInsertValue(column); + }); + aColumns->emplace_back(pColumn); + + pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ISREADONLY,makeAny(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); + + 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()) + { + ORowSetClone* pClone = new ORowSetClone( m_aContext, *this, m_pMutex ); + Reference< XResultSet > xRet(pClone); + m_aClones.emplace_back(xRet); + return xRet; + } + 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) + { + auto pClone = comphelper::getUnoTunnelImplementation(elem.get()); + if(pClone) + pClone->onDeleteRow( _rBookmark ); + } +} + +void ORowSet::notifyRowSetAndClonesRowDeleted( const Any& _rBookmark, sal_Int32 _nPos ) +{ + // notify ourself + onDeletedRow( _rBookmark, _nPos ); + // notify the clones + for (auto const& clone : m_aClones) + { + auto pClone = comphelper::getUnoTunnelImplementation(clone.get()); + if(pClone) + pClone->onDeletedRow( _rBookmark, _nPos ); + } +} + +Reference< XConnection > ORowSet::calcConnection(const Reference< XInteractionHandler >& _rxHandler) +{ + MutexGuard aGuard(m_aMutex); + if (!m_xActiveConnection.is()) + { + Reference< XConnection > xNewConn; + if ( !m_aDataSourceName.isEmpty() ) + { + Reference< XDatabaseContext > xDatabaseContext( DatabaseContext::create(m_aContext) ); + try + { + Reference< XDataSource > xDataSource( xDatabaseContext->getByName( m_aDataSourceName ), UNO_QUERY_THROW ); + + // try connecting with the interaction handler + Reference< XCompletedConnection > xComplConn( xDataSource, UNO_QUERY ); + if ( _rxHandler.is() && xComplConn.is() ) + { + xNewConn = xComplConn->connectWithCompletion( _rxHandler ); + } + else + { + xNewConn = xDataSource->getConnection( m_aUser, m_aPassword ); + } + } + catch ( const SQLException& ) + { + throw; + } + catch ( const Exception& ) + { + Any aError = ::cppu::getCaughtException(); + OUString sMessage = ResourceManager::loadString( RID_NO_SUCH_DATA_SOURCE, + "$name$", m_aDataSourceName, "$error$", extractExceptionMessage( m_aContext, aError ) ); + ::dbtools::throwGenericSQLException( sMessage, *this, aError ); + } + } + setActiveConnection(xNewConn); + m_bOwnConnection = true; + } + return m_xActiveConnection; +} + +Reference< XNameAccess > ORowSet::impl_getTables_throw() +{ + Reference< XNameAccess > xTables; + + Reference< XTablesSupplier > xTablesAccess( m_xActiveConnection, UNO_QUERY ); + if ( xTablesAccess.is() ) + { + xTables.set( xTablesAccess->getTables(), UNO_SET_THROW ); + } + else if ( m_xTables ) + { + xTables = m_xTables.get(); + } + else + { + if ( !m_xActiveConnection.is() ) + throw SQLException(DBA_RES(RID_STR_CONNECTION_INVALID),*this,SQLSTATE_GENERAL,1000,Any() ); + + bool bCase = true; + try + { + Reference xMeta = m_xActiveConnection->getMetaData(); + bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(); + } + catch(SQLException&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_xTables = 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.clear(); +} + +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.get() ); + // 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 || sal_Int32((*m_aCurrentRow)->size()) <= 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, OComponentHelper::rBHelper, _pMutex ) + ,m_pParent(&rParent) + ,m_nFetchDirection(rParent.m_nFetchDirection) + ,m_nFetchSize(rParent.m_nFetchSize) + ,m_bIsBookmarkable(true) +{ + + m_nResultSetType = rParent.m_nResultSetType; + m_nResultSetConcurrency = ResultSetConcurrency::READ_ONLY; + m_pMySelf = this; + m_bClone = true; + m_bBeforeFirst = rParent.m_bBeforeFirst; + m_bAfterLast = rParent.m_bAfterLast; + m_pCache = rParent.m_pCache; + m_aBookmark = rParent.m_aBookmark; + m_aCurrentRow = m_pCache->createIterator(this); + m_xNumberFormatTypes = rParent.m_xNumberFormatTypes; + + m_aOldRow = m_pCache->registerOldRow(); + + ::rtl::Reference< ::connectivity::OSQLColumns> aColumns = new ::connectivity::OSQLColumns(); + std::vector< OUString> aNames; + + OUString aDescription; + Locale aLocale = SvtSysLocale().GetLanguageTag().getLocale(); + + if ( rParent.m_pColumns ) + { + Sequence< OUString> aSeq = rParent.m_pColumns->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + aColumns->reserve(aSeq.getLength()+1); + for(sal_Int32 i=1;pIter != pEnd ;++pIter,++i) + { + Reference 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; + ORowSetColumn* pColumn = new ORowSetColumn( rParent.getMetaData(), + this, + i, + rParent.m_xActiveConnection->getMetaData(), + aDescription, + sParseLabel, + [this] (sal_Int32 const column) -> ORowSetValue const& { + return this->getValue(column); + }); + aColumns->emplace_back(pColumn); + pColumn->setName(*pIter); + aNames.push_back(*pIter); + m_aDataColumns.push_back(pColumn); + + 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,makeAny(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() throw() +{ + OSubComponent::acquire(); +} + +void ORowSetClone::release() throw() +{ + OSubComponent::release(); +} + +// XServiceInfo +OUString ORowSetClone::getImplementationName( ) +{ + return "com.sun.star.sdb.ORowSetClone"; +} + +sal_Bool ORowSetClone::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > ORowSetClone::getSupportedServiceNames( ) +{ + return { SERVICE_SDBC_RESULTSET, SERVICE_SDB_RESULTSET }; +} + +// OComponentHelper +void ORowSetClone::disposing() +{ + MutexGuard aGuard( m_aMutex ); + ORowSetBase::disposing(); + + m_pParent = nullptr; + m_pMutex = &m_aMutex; // this must be done here because someone could hold a ref to us and try to do something + OSubComponent::disposing(); +} + +// XCloseable +void ORowSetClone::close() +{ + { + MutexGuard aGuard( m_aMutex ); + if (OComponentHelper::rBHelper.bDisposed) + throw DisposedException(); + } + dispose(); +} + +// comphelper::OPropertyArrayUsageHelper +::cppu::IPropertyArrayHelper* ORowSetClone::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +// cppu::OPropertySetHelper +::cppu::IPropertyArrayHelper& SAL_CALL ORowSetClone::getInfoHelper() +{ + return *::comphelper::OPropertyArrayUsageHelper::getArrayHelper(); +} + +Sequence< sal_Int8 > ORowSetClone::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +// css::XUnoTunnel +sal_Int64 SAL_CALL ORowSetClone::getSomething( const Sequence< sal_Int8 >& rId ) +{ + if (isUnoTunnelId(rId)) + return reinterpret_cast(this); + + return 0; +} + +void SAL_CALL ORowSetClone::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) +{ + if ( nHandle == PROPERTY_ID_FETCHSIZE ) + { + if ( m_pParent ) + m_pParent->setFastPropertyValue_NoBroadcast( nHandle, rValue ); + } + + OPropertyStateContainer::setFastPropertyValue_NoBroadcast(nHandle,rValue); +} + +void ORowSetClone::doCancelModification( ) +{ +} + +bool ORowSetClone::isModification( ) +{ + return false; +} + +bool ORowSetClone::isModified( ) +{ + return false; +} + +bool ORowSetClone::isNew( ) +{ + return false; +} + +void SAL_CALL ORowSetClone::execute( ) +{ + throwFunctionNotSupportedSQLException( "RowSetClone::XRowSet::execute", *this ); +} + +void SAL_CALL ORowSetClone::addRowSetListener( const Reference< XRowSetListener >& ) +{ + throwFunctionNotSupportedRuntimeException( "RowSetClone::XRowSet", *this ); +} + +void SAL_CALL ORowSetClone::removeRowSetListener( const Reference< XRowSetListener >& ) +{ + throwFunctionNotSupportedRuntimeException( "RowSetClone::XRowSet", *this ); +} + +} // dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/RowSet.hxx b/dbaccess/source/core/api/RowSet.hxx new file mode 100644 index 000000000..effbdb87a --- /dev/null +++ b/dbaccess/source/core/api/RowSet.hxx @@ -0,0 +1,527 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSET_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSET_HXX + +#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::OInterfaceContainerHelper2 m_aRowsetListeners; + ::comphelper::OInterfaceContainerHelper2 m_aApproveListeners; + ::comphelper::OInterfaceContainerHelper2 m_aRowsChangeListener; + + ::dbtools::WarningsContainer m_aWarnings; + + rtl::Reference 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 + + 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() throw() override; + virtual void SAL_CALL release() throw() override; + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + // css::uno::XAggregation + virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& aType ) override; + + // css::lang::XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // css::lang::XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // css::sdbc::XCloseable + virtual void SAL_CALL close( ) override; + + // comphelper::OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + // cppu::OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // css::sdbc::XResultSet + virtual void SAL_CALL refreshRow( ) override; + + // XCompletedExecution + virtual void SAL_CALL executeWithCompletion( const css::uno::Reference< css::task::XInteractionHandler >& handler ) override; + + // XParametersSupplier + virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getParameters( ) override; + + // css::sdbc::XRow + virtual sal_Bool SAL_CALL wasNull( ) override; + virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override; + virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override; + virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override; + virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override; + virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override; + virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override; + virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override; + virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override; + virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override; + virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override; + virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override; + virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override; + virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override; + virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override; + + // css::sdbc::XRowUpdate + virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override; + virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override; + virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override; + virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override; + virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override; + virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override; + virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override; + virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override; + virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override; + virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override; + virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override; + virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override; + + // css::sdbc::XResultSetUpdate + virtual void SAL_CALL insertRow( ) override; + virtual void SAL_CALL updateRow( ) override; + virtual void SAL_CALL deleteRow( ) override; + virtual void SAL_CALL cancelRowUpdates( ) override; + virtual void SAL_CALL moveToInsertRow( ) override; + virtual void SAL_CALL moveToCurrentRow( ) override; + + // css::sdbc::XRowSet + virtual void SAL_CALL execute( ) override; + virtual void SAL_CALL addRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override; + virtual void SAL_CALL removeRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override; + + // css::sdb::XRowSetApproveBroadcaster + virtual void SAL_CALL addRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override; + virtual void SAL_CALL removeRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override; + + // css::sdb::XRowsChangeBroadcaster + virtual void SAL_CALL addRowsChangeListener( const css::uno::Reference< css::sdb::XRowsChangeListener >& listener ) override; + virtual void SAL_CALL removeRowsChangeListener( const css::uno::Reference< css::sdb::XRowsChangeListener >& listener ) override; + + // css::sdb::XResultSetAccess + virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL createResultSet( ) override; + + // css::util::XCancellable + virtual void SAL_CALL cancel( ) override; + + // css::sdbcx::XDeleteRows + virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override; + + // XParameters + virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override; + virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override; + virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override; + virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override; + virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override; + virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override; + virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override; + virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override; + virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override; + virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override; + virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override; + virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override; + virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override; + virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override; + virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override; + virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override; + virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override; + virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override; + virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override; + virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override; + virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override; + virtual void SAL_CALL clearParameters( ) override; + + // XWarningsSupplier + virtual css::uno::Any SAL_CALL getWarnings( ) override; + virtual void SAL_CALL clearWarnings( ) override; + + /** implement the 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() throw() override; + virtual void SAL_CALL release() throw() override; + + // css::lang::XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + // css::sdbc::XCloseable + virtual void SAL_CALL close( ) override; + + // css::beans::XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override + { + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); + } + + // css::sdbc::XRowSet + virtual void SAL_CALL execute( ) override; + virtual void SAL_CALL addRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override; + virtual void SAL_CALL removeRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override; + + // comphelper::OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + // cppu::OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + protected: + using ORowSetBase::doCancelModification; + using ORowSetBase::isModification; + using ORowSetBase::isModified; + using ORowSetBase::isNew; + using ORowSetBase::rowDeleted; + }; + +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/RowSetBase.cxx b/dbaccess/source/core/api/RowSetBase.cxx new file mode 100644 index 000000000..df8c46a72 --- /dev/null +++ b/dbaccess/source/core/api/RowSetBase.cxx @@ -0,0 +1,1437 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "RowSetBase.hxx" +#include "CRowSetDataColumn.hxx" +#include +#include "RowSetCache.hxx" +#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::makeAny(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( MOVE_NONE ); + m_aCurrentRow = m_pCache->m_aMatrixIter; + m_bIsInsertRow = false; + OSL_ENSURE(!m_aCurrentRow.isNull(),"ORowSetBase::getValue: we don't stand on a valid row! Row is null."); + + bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() ); + } + + if ( bValidCurrentRow ) + { +#if OSL_DEBUG_LEVEL > 0 + ORowSetMatrix::const_iterator aCacheEnd; + ORowSetMatrix::iterator aCurrentRow; + aCacheEnd = m_pCache->getEnd(); + aCurrentRow = m_aCurrentRow; + ORowSetCacheMap::const_iterator aCacheIter = m_aCurrentRow.getIter(); + ORowSetCacheIterator_Helper aHelper = aCacheIter->second; + ORowSetMatrix::const_iterator k = aHelper.aIterator; + for (; k != m_pCache->getEnd(); ++k) + { + ORowSetValueVector* pTemp = k->get(); + OSL_ENSURE( pTemp != reinterpret_cast(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); +} + +sal_Bool SAL_CALL ORowSetBase::getBoolean( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return bool(getValue(columnIndex)); +} + +sal_Int8 SAL_CALL ORowSetBase::getByte( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +sal_Int16 SAL_CALL ORowSetBase::getShort( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +sal_Int32 SAL_CALL ORowSetBase::getInt( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +sal_Int64 SAL_CALL ORowSetBase::getLong( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +float SAL_CALL ORowSetBase::getFloat( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +double SAL_CALL ORowSetBase::getDouble( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +Sequence< sal_Int8 > SAL_CALL ORowSetBase::getBytes( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +css::util::Date SAL_CALL ORowSetBase::getDate( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +css::util::Time SAL_CALL ORowSetBase::getTime( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +css::util::DateTime SAL_CALL ORowSetBase::getTimestamp( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + return getValue(columnIndex); +} + +Reference< css::io::XInputStream > SAL_CALL ORowSetBase::getBinaryStream( sal_Int32 columnIndex ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + + if ( m_bBeforeFirst || m_bAfterLast ) + { + SAL_WARN("dbaccess", "ORowSetBase::getBinaryStream: Illegal call here (we're before first or after last)!"); + ::dbtools::throwSQLException( DBA_RES( RID_STR_CURSOR_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf ); + } + + if ( impl_rowDeleted() ) + { + return nullptr; + } + + bool bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() ); + if ( !bValidCurrentRow ) + { + positionCache( MOVE_NONE ); + m_aCurrentRow = m_pCache->m_aMatrixIter; + m_bIsInsertRow = false; + OSL_ENSURE(!m_aCurrentRow.isNull(),"ORowSetBase::getBinaryStream: we don't stand on a valid row! Row is null."); + + bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() ); + } + + if ( bValidCurrentRow ) + { + m_nLastColumnIndex = columnIndex; + return new ::comphelper::SequenceInputStream((**m_aCurrentRow)[m_nLastColumnIndex].getSequence()); + } + + // we should normally never reach this + return Reference< css::io::XInputStream >(); +} + +Reference< css::io::XInputStream > SAL_CALL ORowSetBase::getCharacterStream( sal_Int32 columnIndex ) +{ + return getBinaryStream(columnIndex); +} + +Any SAL_CALL ORowSetBase::getObject( sal_Int32 columnIndex, const Reference< XNameAccess >& /*typeMap*/ ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + + return getValue(columnIndex).makeAny(); +} + +Reference< XRef > SAL_CALL ORowSetBase::getRef( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRef", *m_pMySelf ); + return nullptr; +} + +Reference< XBlob > SAL_CALL ORowSetBase::getBlob( sal_Int32 columnIndex ) +{ + return Reference< XBlob >(getValue(columnIndex).makeAny(),UNO_QUERY); +} + +Reference< XClob > SAL_CALL ORowSetBase::getClob( sal_Int32 columnIndex ) +{ + return Reference< XClob >(getValue(columnIndex).makeAny(),UNO_QUERY); +} + +Reference< XArray > SAL_CALL ORowSetBase::getArray( sal_Int32 /*columnIndex*/ ) +{ + ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getArray", *m_pMySelf ); + return nullptr; +} + +// css::sdbcx::XRowLocate +Any SAL_CALL ORowSetBase::getBookmark( ) +{ + SAL_INFO("dbaccess", "ORowSetBase::getBookmark() Clone = " << m_bClone); + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + + if ( m_bBeforeFirst || m_bAfterLast ) + ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_BOOKMARK_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf ); + + if ( impl_rowDeleted() ) + ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_BOOKMARK_DELETED ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf ); + + OSL_ENSURE( m_aBookmark.hasValue(), "ORowSetBase::getBookmark: bookmark has no value!" ); + return m_aBookmark; +} + +sal_Bool SAL_CALL ORowSetBase::moveToBookmark( const Any& bookmark ) +{ + SAL_INFO("dbaccess", "ORowSetBase::moveToBookmark(Any) Clone = " << m_bClone); + OSL_ENSURE(bookmark.hasValue(),"ORowSetBase::moveToBookmark bookmark has no value!"); + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + + if(!bookmark.hasValue() || m_nResultSetType == ResultSetType::FORWARD_ONLY) + { + if(bookmark.hasValue()) + SAL_WARN("dbaccess", "MoveToBookmark is not possible when we are only forward"); + else + SAL_WARN("dbaccess", "Bookmark is not valid"); + throwFunctionSequenceException(*m_pMySelf); + } + + checkCache(); + + bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) ); + if ( bRet ) + { + // check if we are inserting a row + bool bWasNew = m_pCache->m_bNew || impl_rowDeleted(); + + ORowSetNotifier aNotifier( this ); + // this will call cancelRowModification on the cache if necessary + + ORowSetRow aOldValues = getOldRow(bWasNew); + + bRet = m_pCache->moveToBookmark(bookmark); + doCancelModification( ); + if(bRet) + { + // notification order + // - column values + // - cursorMoved + setCurrentRow( true, true, aOldValues, aGuard ); + } + else + { + movementFailed(); + } + + // - IsModified + // - IsNew + aNotifier.fire( ); + } + SAL_INFO("dbaccess", "ORowSetBase::moveToBookmark(Any) = " << bRet << " Clone = " << m_bClone); + return bRet; +} + +sal_Bool SAL_CALL ORowSetBase::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) +{ + SAL_INFO("dbaccess", "ORowSetBase::moveRelativeToBookmark(Any," << rows << ") Clone = " << m_bClone); + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + + checkPositioningAllowed(); + + bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) ); + if ( bRet ) + { + // check if we are inserting a row + bool bWasNew = m_pCache->m_bNew || rowDeleted(); + + ORowSetNotifier aNotifier( this ); + // this will call cancelRowModification on the cache if necessary + + ORowSetRow aOldValues = getOldRow(bWasNew); + + bRet = m_pCache->moveRelativeToBookmark(bookmark,rows); + doCancelModification( ); + if(bRet) + { + // notification order + // - column values + // - cursorMoved + setCurrentRow( true, true, aOldValues, aGuard ); + } + else + movementFailed(); + + // - IsModified + // - IsNew + aNotifier.fire( ); + + // RowCount/IsRowCountFinal + fireRowcount(); + } + SAL_INFO("dbaccess", "ORowSetBase::moveRelativeToBookmark(Any," << rows << ") = " << bRet << " Clone = " << m_bClone); + return bRet; +} + +sal_Int32 SAL_CALL ORowSetBase::compareBookmarks( const Any& _first, const Any& _second ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + return m_pCache->compareBookmarks(_first,_second); +} + +sal_Bool SAL_CALL ORowSetBase::hasOrderedBookmarks( ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + return m_pCache->hasOrderedBookmarks(); +} + +sal_Int32 SAL_CALL ORowSetBase::hashBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + return m_pCache->hashBookmark(bookmark); +} + +// XResultSetMetaDataSupplier +Reference< XResultSetMetaData > SAL_CALL ORowSetBase::getMetaData( ) +{ + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + + Reference< XResultSetMetaData > xMeta; + if(m_pCache) + xMeta = m_pCache->getMetaData(); + + return xMeta; +} + +// XColumnLocate +sal_Int32 SAL_CALL ORowSetBase::findColumn( const OUString& columnName ) +{ + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + + ::osl::MutexGuard aGuard( m_aColumnsMutex ); + // it is possible to save some time here when we remember the names - position relation in a map + return m_pColumns ? m_pColumns->findColumn(columnName) : sal_Int32(0); +} + +// css::sdbcx::XColumnsSupplier +Reference< XNameAccess > SAL_CALL ORowSetBase::getColumns( ) +{ + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + + ::osl::MutexGuard aGuard( m_aColumnsMutex ); + if(!m_pColumns) + { + if (!m_pEmptyCollection) + m_pEmptyCollection.reset( new OEmptyCollection(*m_pMySelf,m_aColumnsMutex) ); + return m_pEmptyCollection.get(); + } + + return m_pColumns.get(); +} + +// XResultSet +sal_Bool SAL_CALL ORowSetBase::next( ) +{ + SAL_INFO("dbaccess", "ORowSetBase::next() Clone = " << m_bClone); + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + checkCache(); + + bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) ); + if ( bRet ) + { + // check if we are inserting a row + bool bWasNew = m_pCache->m_bNew || impl_rowDeleted(); + + ORowSetNotifier aNotifier( this ); + // this will call cancelRowModification on the cache if necessary + + ORowSetRow aOldValues = getOldRow(bWasNew); + + positionCache( MOVE_FORWARD ); + bool bAfterLast = m_pCache->isAfterLast(); + bRet = m_pCache->next(); + doCancelModification( ); + + // if we were afterLast before next() then we still are, + // i.e. bAfterLast implies m_pCache->isAfterLast() + if (bAfterLast) + assert(m_pCache->isAfterLast()); + // so the only way bAfterLast != m_pCache->isAfterLast() + // would be that we just arrived there, + if (bAfterLast != m_pCache->isAfterLast()) + { + assert(!bAfterLast); + assert(m_pCache->isAfterLast()); + } + // in which case we *did* move the cursor + if ( bRet || bAfterLast != m_pCache->isAfterLast() ) + { + // notification order + // - column values + // - cursorMoved + setCurrentRow( true, true, aOldValues, aGuard ); + OSL_ENSURE(!m_bBeforeFirst,"BeforeFirst is true. I don't know why?"); + } + else + { + // moved after the last row + movementFailed(); + OSL_ENSURE(m_bAfterLast,"AfterLast is false. I don't know why?"); + } + + // - IsModified + // - IsNew + aNotifier.fire(); + + // - RowCount/IsRowCountFinal + fireRowcount(); + } + SAL_INFO("dbaccess", "ORowSetBase::next() = " << bRet << " Clone = " << m_bClone); + return bRet; +} + +sal_Bool SAL_CALL ORowSetBase::isBeforeFirst( ) +{ + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + + SAL_INFO("dbaccess", "ORowSetBase::isBeforeFirst() = " << m_bBeforeFirst << " Clone = " << m_bClone); + + return m_bBeforeFirst; +} + +sal_Bool SAL_CALL ORowSetBase::isAfterLast( ) +{ + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + SAL_INFO("dbaccess", "ORowSetBase::isAfterLast() = " << m_bAfterLast << " Clone = " << m_bClone); + + return m_bAfterLast; +} + +bool ORowSetBase::isOnFirst() +{ + return isFirst(); +} + +sal_Bool SAL_CALL ORowSetBase::isFirst( ) +{ + SAL_INFO("dbaccess", "ORowSetBase::isFirst() Clone = " << m_bClone); + + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + + if ( m_bBeforeFirst || m_bAfterLast ) + return false; + + if ( impl_rowDeleted() ) + return ( m_nDeletedPosition == 1 ); + + positionCache( MOVE_NONE ); + bool bIsFirst = m_pCache->isFirst(); + + SAL_INFO("dbaccess", "ORowSetBase::isFirst() = " << bIsFirst << " Clone = " << m_bClone); + return bIsFirst; +} + +bool ORowSetBase::isOnLast() +{ + return isLast(); +} + +sal_Bool SAL_CALL ORowSetBase::isLast( ) +{ + SAL_INFO("dbaccess", "ORowSetBase::isLast() Clone = " << m_bClone); + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + + if ( m_bBeforeFirst || m_bAfterLast ) + return false; + + if ( impl_rowDeleted() ) + { + if ( !m_pCache->m_bRowCountFinal ) + return false; + else + return ( m_nDeletedPosition == impl_getRowCount() ); + } + + positionCache( MOVE_NONE ); + bool bIsLast = m_pCache->isLast(); + + SAL_INFO("dbaccess", "ORowSetBase::isLast() = " << bIsLast << " Clone = " << m_bClone); + return bIsLast; +} + +void SAL_CALL ORowSetBase::beforeFirst( ) +{ + SAL_INFO("dbaccess", "ORowSetBase::beforeFirst() Clone = " << m_bClone); + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + + checkPositioningAllowed(); + + // check if we are inserting a row + bool bWasNew = m_pCache->m_bNew || impl_rowDeleted(); + + if((bWasNew || !m_bBeforeFirst) && notifyAllListenersCursorBeforeMove(aGuard) ) + { + ORowSetNotifier aNotifier( this ); + // this will call cancelRowModification on the cache if necessary + + if ( !m_bBeforeFirst ) + { + ORowSetRow aOldValues = getOldRow(bWasNew); + m_pCache->beforeFirst(); + doCancelModification( ); + + // notification order + // - column values + // - cursorMoved + setCurrentRow( true, true, aOldValues, aGuard ); + + // - IsModified + // - Isnew + aNotifier.fire(); + + // - RowCount/IsRowCountFinal + fireRowcount(); + } + + // to be done _after_ the notifications! + m_aOldRow->clearRow(); + } + SAL_INFO("dbaccess", "ORowSetBase::beforeFirst() Clone = " << m_bClone); +} + +void SAL_CALL ORowSetBase::afterLast( ) +{ + SAL_INFO("dbaccess", "ORowSetBase::afterLast() Clone = " << m_bClone); + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + checkPositioningAllowed(); + + bool bWasNew = m_pCache->m_bNew || impl_rowDeleted(); + + if((bWasNew || !m_bAfterLast) && notifyAllListenersCursorBeforeMove(aGuard) ) + { + // check if we are inserting a row + ORowSetNotifier aNotifier( this ); + // this will call cancelRowModification on the cache if necessary + + if(!m_bAfterLast) + { + ORowSetRow aOldValues = getOldRow(bWasNew); + + m_pCache->afterLast(); + doCancelModification( ); + + // notification order + // - column values + // - cursorMoved + setCurrentRow( true, true, aOldValues, aGuard ); + + // - IsModified + // - Isnew + aNotifier.fire(); + + // - RowCount/IsRowCountFinal + fireRowcount(); + } + } + SAL_INFO("dbaccess", "ORowSetBase::afterLast() Clone = " << m_bClone); +} + +bool SAL_CALL ORowSetBase::move(std::function 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( MOVE_NONE ); + nPos = m_pCache->getRow(); + } + SAL_INFO("dbaccess", "ORowSetBase::impl_getRow() = " << nPos << " Clone = " << m_bClone); + return nPos; +} + +sal_Bool SAL_CALL ORowSetBase::absolute( sal_Int32 row ) +{ + SAL_INFO("dbaccess", "ORowSetBase::absolute(" << row << ") Clone = " << m_bClone); + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + checkPositioningAllowed(); + + bool bRet = ( row > 0 ) + && notifyAllListenersCursorBeforeMove( aGuard ); + if ( bRet ) + { + // check if we are inserting a row + bool bWasNew = m_pCache->m_bNew || rowDeleted(); + + ORowSetNotifier aNotifier( this ); + // this will call cancelRowModification on the cache if necessary + + ORowSetRow aOldValues = getOldRow(bWasNew); + + bRet = m_pCache->absolute(row); + doCancelModification( ); + + if(bRet) + { + // notification order + // - column values + // - cursorMoved + setCurrentRow( true, true, aOldValues, aGuard ); + } + else + { // absolute movement goes wrong we stand left or right side of the rows + movementFailed(); + } + + // - IsModified + // - IsNew + aNotifier.fire(); + + // - RowCount/IsRowCountFinal + fireRowcount(); + } + SAL_INFO("dbaccess", "ORowSetBase::absolute(" << row << ") = " << bRet << " Clone = " << m_bClone); + return bRet; +} + +sal_Bool SAL_CALL ORowSetBase::relative( sal_Int32 rows ) +{ + SAL_INFO("dbaccess", "ORowSetBase::relative(" << rows << ") Clone = " << m_bClone); + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + + if(!rows) + return true; // in this case do nothing + + checkPositioningAllowed(); + + bool bRet = + ( ( !m_bAfterLast || rows <= 0 ) + && ( !m_bBeforeFirst || rows >= 0 ) + && notifyAllListenersCursorBeforeMove( aGuard ) + ); + + if ( bRet ) + { + // check if we are inserting a row + bool bWasNew = m_pCache->m_bNew || rowDeleted(); + + ORowSetNotifier aNotifier( this ); + // this will call cancelRowModification on the cache if necessary + + ORowSetRow aOldValues = getOldRow(bWasNew); + + positionCache( rows > 0 ? MOVE_FORWARD : MOVE_BACKWARD ); + bRet = m_pCache->relative(rows); + doCancelModification( ); + + if(bRet) + { + // notification order + // - column values + // - cursorMoved + setCurrentRow( true, true, aOldValues, aGuard ); + } + else + { + movementFailed(); + } + + // - IsModified + // - IsNew + aNotifier.fire(); + + // - RowCount/IsRowCountFinal + fireRowcount(); + } + SAL_INFO("dbaccess", "ORowSetBase::relative(" << rows << ") = " << bRet << " Clone = " << m_bClone); + return bRet; +} + +sal_Bool SAL_CALL ORowSetBase::previous( ) +{ + SAL_INFO("dbaccess", "ORowSetBase::previous() Clone = " << m_bClone); + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + ::osl::ResettableMutexGuard aGuard( *m_pMutex ); + + checkPositioningAllowed(); + + bool bRet = !m_bBeforeFirst + && notifyAllListenersCursorBeforeMove(aGuard); + + if ( bRet ) + { + // check if we are inserting a row + bool bWasNew = m_pCache->m_bNew || rowDeleted(); + + ORowSetNotifier aNotifier( this ); + // this will call cancelRowModification on the cache if necessary + + ORowSetRow aOldValues = getOldRow(bWasNew); + + positionCache( MOVE_BACKWARD ); + bRet = m_pCache->previous(); + doCancelModification( ); + + // if m_bBeforeFirst is false and bRet is false then we stood on the first row + if(!m_bBeforeFirst || bRet) + { + // notification order + // - column values + // - cursorMoved + setCurrentRow( true, true, aOldValues, aGuard ); + } + else + { + SAL_WARN("dbaccess", "ORowSetBase::previous: inconsistency!" ); + // we should never reach this place, as we should not get into this whole branch if m_bBeforeFirst + // was |true| from the beginning + movementFailed(); + } + + // - IsModified + // - IsNew + aNotifier.fire(); + + // - RowCount/IsRowCountFinal + fireRowcount(); + } + SAL_INFO("dbaccess", "ORowSetBase::previous() = " << bRet << " Clone = " << m_bClone); + return bRet; +} + +void ORowSetBase::setCurrentRow( bool _bMoved, bool _bDoNotify, const ORowSetRow& _rOldValues, ::osl::ResettableMutexGuard& _rGuard ) +{ + SAL_INFO("dbaccess", "ORowSetBase::setCurrentRow() Clone = " << m_bClone); + m_bBeforeFirst = m_pCache->isBeforeFirst(); + m_bAfterLast = m_pCache->isAfterLast(); + + if(!(m_bBeforeFirst || m_bAfterLast)) + { + m_aBookmark = m_pCache->getBookmark(); + OSL_ENSURE(m_aBookmark.hasValue(),"Bookmark has no value!"); + m_aCurrentRow = m_pCache->m_aMatrixIter; + m_bIsInsertRow = false; + OSL_ENSURE(!m_aCurrentRow.isNull(),"CurrentRow is null!"); + OSL_ENSURE(!m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd(),"Position of matrix iterator isn't valid!"); + OSL_ENSURE(m_aCurrentRow->is(),"Currentrow isn't valid"); + OSL_ENSURE(m_aBookmark.hasValue(),"Bookmark has no value!"); + + m_aCurrentRow = m_pCache->m_aMatrixIter; + m_bIsInsertRow = false; + OSL_ENSURE(!m_aCurrentRow.isNull(),"CurrentRow is nul after positionCache!"); +#if OSL_DEBUG_LEVEL > 0 + ORowSetRow rRow = *m_aCurrentRow; + OSL_ENSURE(rRow.is() ,"Invalid size of vector!"); +#endif + + // notification order + // - column values + if ( _bDoNotify ) + firePropertyChange(_rOldValues); + + } + else + { + m_aOldRow->clearRow(); + m_aCurrentRow = m_pCache->getEnd(); + m_aBookmark = Any(); + } + + // TODO: can this be done before the notifications? + if(!(m_bBeforeFirst || m_bAfterLast) && !m_aCurrentRow.isNull() && m_aCurrentRow->is() && m_aCurrentRow != m_pCache->getEnd()) + m_aOldRow->setRow(new ORowSetValueVector( *(*m_aCurrentRow) )); + + if ( _bMoved && _bDoNotify ) + // - cursorMoved + notifyAllListenersCursorMoved( _rGuard ); + + SAL_INFO("dbaccess", "ORowSetBase::setCurrentRow() Clone = " << m_bClone); +} + +void ORowSetBase::checkPositioningAllowed() +{ + if(!m_pCache || m_nResultSetType == ResultSetType::FORWARD_ONLY) + throwFunctionSequenceException(*m_pMySelf); +} + +Reference< XInterface > ORowSetBase::getStatement() +{ + return nullptr; +} + +void SAL_CALL ORowSetBase::refreshRow( ) +{ + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + if ( impl_rowDeleted() ) + throwSQLException( "The current row is deleted", StandardSQLState::INVALID_CURSOR_STATE, Reference< XRowSet >( this ) ); + + if(!(m_bBeforeFirst || m_bAfterLast)) + { + bool bWasNew = m_pCache->m_bNew || impl_rowDeleted(); + ORowSetRow aOldValues = getOldRow(bWasNew); + positionCache( MOVE_NONE ); + m_pCache->refreshRow(); + firePropertyChange(aOldValues); + } +} + +sal_Bool SAL_CALL ORowSetBase::rowUpdated( ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + + if ( impl_rowDeleted() ) + return false; + + return m_pCache->rowUpdated(); +} + +sal_Bool SAL_CALL ORowSetBase::rowInserted( ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + + checkCache(); + + if ( impl_rowDeleted() ) + return false; + + return m_pCache->rowInserted(); +} + +sal_Bool SAL_CALL ORowSetBase::rowDeleted( ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + checkCache(); + return impl_rowDeleted(); +} + +bool ORowSetBase::impl_rowDeleted( ) +{ + return !m_aBookmark.hasValue() && !m_bBeforeFirst && !m_bAfterLast; +} + +// XWarningsSupplier +Any SAL_CALL ORowSetBase::getWarnings( ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + + if ( m_pCache ) + { + Reference< XWarningsSupplier > xWarnings( m_pCache->m_xSet.get(), UNO_QUERY ); + if ( xWarnings.is() ) + return xWarnings->getWarnings(); + } + + return Any(); +} + +void SAL_CALL ORowSetBase::clearWarnings( ) +{ + ::osl::MutexGuard aGuard( *m_pMutex ); + + if ( m_pCache ) + { + Reference< XWarningsSupplier > xWarnings( m_pCache->m_xSet.get(), UNO_QUERY ); + if ( xWarnings.is() ) + xWarnings->clearWarnings(); + } +} + +void ORowSetBase::firePropertyChange(const ORowSetRow& _rOldRow) +{ + if (!isPropertyChangeNotificationEnabled()) + return; + + SAL_INFO("dbaccess", "ORowSetBase::firePropertyChange" ); + SAL_INFO("dbaccess", "ORowSetBase::firePropertyChange() Clone = " << m_bClone); + OSL_ENSURE(m_pColumns,"Columns can not be NULL here!"); + sal_Int32 i=0; + for (auto const& dataColumn : m_aDataColumns) + { + try + { + dataColumn->fireValueChange(_rOldRow.is() ? (*_rOldRow)[i+1] : ::connectivity::ORowSetValue()); + } + catch (const Exception&) + { + SAL_WARN("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 = css::uno::makeAny( _bNew ); + Any aOld = css::uno::makeAny( _bOld ); + fire( &_nProperty, &aNew, &aOld, 1, false ); +} + +void ORowSetBase::positionCache( CursorMoveDirection _ePrepareForDirection ) +{ + SAL_INFO("dbaccess", "ORowSetBase::positionCache() Clone = " << m_bClone); + + bool bSuccess = false; + if ( m_aBookmark.hasValue() ) + { + if (_ePrepareForDirection == MOVE_NONE_REFRESH || + (m_pCache->isAfterLast() != bool(isAfterLast())) || ( m_pCache->isBeforeFirst() != bool(isBeforeFirst()) ) || + m_pCache->compareBookmarks( m_aBookmark, m_pCache->getBookmark() ) != CompareBookmark::EQUAL ) + bSuccess = m_pCache->moveToBookmark( m_aBookmark ); + else + bSuccess = true; + } + else + { + if ( m_bBeforeFirst ) + { + m_pCache->beforeFirst(); + bSuccess = true; + } + else if ( m_bAfterLast ) + { + m_pCache->afterLast(); + bSuccess = true; + } + else + { + OSL_ENSURE( m_nDeletedPosition >= 1, "ORowSetBase::positionCache: no bookmark, and no valid 'deleted position'!" ); + switch ( _ePrepareForDirection ) + { + case MOVE_FORWARD: + if ( m_nDeletedPosition > 1 ) + bSuccess = m_pCache->absolute( m_nDeletedPosition - 1 ); + else + { + m_pCache->beforeFirst(); + bSuccess = true; + } + break; + + case MOVE_BACKWARD: + if ( m_pCache->m_bRowCountFinal && ( m_nDeletedPosition == impl_getRowCount() ) ) + { + m_pCache->afterLast(); + bSuccess = true; + } + else + bSuccess = m_pCache->absolute( m_nDeletedPosition ); + break; + + case MOVE_NONE: + case MOVE_NONE_REFRESH: + bSuccess = false; // will be asserted below + break; + } + } + } + OSL_ENSURE( bSuccess, "ORowSetBase::positionCache: failed!" ); + + SAL_INFO("dbaccess", "ORowSetBase::positionCache() Clone = " << m_bClone); +} + +void ORowSetBase::checkCache() +{ + ::connectivity::checkDisposed(m_rBHelper.bDisposed); + if(!m_pCache) + throwFunctionSequenceException(*m_pMySelf); +} + +void ORowSetBase::movementFailed() +{ + SAL_INFO("dbaccess", "ORowSetBase::movementFailed() Clone = " << m_bClone); + m_aOldRow->clearRow(); + m_aCurrentRow = m_pCache->getEnd(); + m_bBeforeFirst = m_pCache->isBeforeFirst(); + m_bAfterLast = m_pCache->isAfterLast(); + m_aBookmark = Any(); + OSL_ENSURE(m_bBeforeFirst || m_bAfterLast,"BeforeFirst or AfterLast is wrong!"); + SAL_INFO("dbaccess", "ORowSetBase::movementFailed() Clone = " << m_bClone); +} + +ORowSetRow ORowSetBase::getOldRow(bool _bWasNew) +{ + OSL_ENSURE(m_aOldRow.is(),"RowSetRowHElper isn't valid!"); + ORowSetRow aOldValues; + if ( !_bWasNew && m_aOldRow->getRow().is() ) + aOldValues = new ORowSetValueVector( *(m_aOldRow->getRow())); // remember the old values + return aOldValues; +} + +void ORowSetBase::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const +{ + _rDefault.clear(); +} + +void ORowSetBase::onDeleteRow( const Any& _rBookmark ) +{ + if ( rowDeleted() ) + // not interested in + return; + + ::osl::MutexGuard aGuard( *m_pMutex ); + //OSL_ENSURE( m_aBookmark.hasValue(), "ORowSetBase::onDeleteRow: Bookmark isn't valid!" ); + if ( compareBookmarks( _rBookmark, m_aBookmark ) == CompareBookmark::EQUAL ) + { + positionCache( MOVE_NONE ); + m_nDeletedPosition = m_pCache->getRow(); + } +} + +void ORowSetBase::onDeletedRow( const Any& _rBookmark, sal_Int32 _nPos ) +{ + if ( rowDeleted() ) + { + // if we're a clone, and on a deleted row, and the main RowSet deleted another + // row (only the main RowSet can, clones can't), which is *before* our + // deleted position, then we have to adjust this position + if ( m_bClone && ( _nPos < m_nDeletedPosition ) ) + --m_nDeletedPosition; + return; + } + + ::osl::MutexGuard aGuard( *m_pMutex ); + if ( compareBookmarks( _rBookmark, m_aBookmark ) == CompareBookmark::EQUAL ) + { + m_aOldRow->clearRow(); + m_aCurrentRow = m_pCache->getEnd(); + m_aBookmark = Any(); + } +} + +sal_Int32 ORowSetBase::impl_getRowCount() const +{ + sal_Int32 nRowCount( m_pCache->m_nRowCount ); + if ( const_cast< ORowSetBase* >( this )->rowDeleted() && !m_pCache->m_bNew ) + ++nRowCount; + return nRowCount; +} + +struct ORowSetNotifierImpl +{ + std::vector aChangedColumns; + ORowSetValueVector::Vector aRow; +}; + + +ORowSetNotifier::ORowSetNotifier( ORowSetBase* _pRowSet ) + :m_pRowSet( _pRowSet ) + ,m_bWasNew( false ) + ,m_bWasModified( false ) +{ + + OSL_ENSURE( m_pRowSet, "ORowSetNotifier::ORowSetNotifier: invalid row set. This will crash." ); + + // remember the "inserted" and "modified" state for later firing + m_bWasNew = m_pRowSet->isNew( ORowSetBase::GrantNotifierAccess() ); + m_bWasModified = m_pRowSet->isModified( ORowSetBase::GrantNotifierAccess() ); + + // if the row set is on the insert row, then we need to cancel this + if ( m_pRowSet->isModification( ORowSetBase::GrantNotifierAccess() ) ) + m_pRowSet->doCancelModification( ORowSetBase::GrantNotifierAccess() ); +} + +ORowSetNotifier::ORowSetNotifier( ORowSetBase* _pRowSet,const ORowSetValueVector::Vector& i_aRow ) + :m_pImpl(new ORowSetNotifierImpl) + ,m_pRowSet( _pRowSet ) + ,m_bWasNew( false ) + ,m_bWasModified( false ) +{ + + OSL_ENSURE( m_pRowSet, "ORowSetNotifier::ORowSetNotifier: invalid row set. This will crash." ); + m_pImpl->aRow = 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() const +{ + OSL_ENSURE(m_pImpl, "Illegal CTor call, use the other one!"); + return m_pImpl->aChangedColumns; +} + +void ORowSetNotifier::firePropertyChange() +{ + OSL_ENSURE(m_pImpl, "Illegal CTor call, use the other one!"); + if (m_pImpl) + { + for (auto const& changedColumn : m_pImpl->aChangedColumns) + { + m_pRowSet->firePropertyChange(changedColumn-1 ,m_pImpl->aRow[changedColumn-1], ORowSetBase::GrantNotifierAccess()); + } + if ( !m_pImpl->aChangedColumns.empty() ) + m_pRowSet->fireProperty(PROPERTY_ID_ISMODIFIED,true,false, ORowSetBase::GrantNotifierAccess()); + } +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/RowSetBase.hxx b/dbaccess/source/core/api/RowSetBase.hxx new file mode 100644 index 000000000..1031ed5dc --- /dev/null +++ b/dbaccess/source/core/api/RowSetBase.hxx @@ -0,0 +1,405 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETBASE_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETBASE_HXX + +#include +#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::ImplHelper10< css::sdbcx::XRowLocate, + css::sdbc::XRow, + css::sdbc::XResultSetMetaDataSupplier, + css::sdbc::XWarningsSupplier, + css::sdbc::XColumnLocate, + css::sdbcx::XColumnsSupplier, + css::lang::XServiceInfo, + css::sdbc::XRowSet, + css::sdbc::XCloseable, + css::lang::XUnoTunnel> ORowSetBase_BASE; + + class ORowSetCache; + class ORowSetDataColumns; + class ORowSetCacheIterator; + class ORowSetDataColumn; + class ORowSetBase : public ORowSetBase_BASE, + public ::comphelper::OPropertyStateContainer, + public ::comphelper::OPropertyArrayUsageHelper // 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 CursorMoveDirection + { + /// denotes a cursor move forward + MOVE_FORWARD, + /// denotes a cursor move backwards + MOVE_BACKWARD, + /// denotes no cursor move at all, but move cache to current row (if it is not there already) + MOVE_NONE, + /// denotes no cursor move at all, but force the cache to move to current row (and refresh the row) + MOVE_NONE_REFRESH + }; + /** positions the cache in preparation of a cursor move + + Normally, the cache is simply moved to our bookmark (m_aBookmark). If however the current + row is deleted, then the cache is properly positioned for a following cursor movement in the + given direction. + + @param _ePrepareForDirection + the direction into which the cursor should be moved after the call. If we're currently not on + a deleted row, this parameter is ignored, since in this case the cache is simply moved to + m_aBookmark.
+ 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)

+ */ + struct ORowSetNotifierImpl; + class ORowSetNotifier + { + private: + std::unique_ptr m_pImpl; + ORowSetBase* m_pRowSet; + // not acquired! This is not necessary because this class here is to be used on the stack within + // a method of ORowSetBase (or derivees) + bool m_bWasNew; + bool m_bWasModified; + + public: + /** constructs the object, and cancels the insertion + + @see ORowSetBase::doCancelModification + */ + explicit ORowSetNotifier( ORowSetBase* m_pRowSet ); + + /** use this one to construct a vector for change value notification + */ + ORowSetNotifier( ORowSetBase* m_pRowSet,const 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 inde of the changed column values + */ + std::vector& getChangedColumns() const; + + }; + +} // end of namespace + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETBASE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/RowSetCache.cxx b/dbaccess/source/core/api/RowSetCache.cxx new file mode 100644 index 000000000..21098ccac --- /dev/null +++ b/dbaccess/source/core/api/RowSetCache.cxx @@ -0,0 +1,1714 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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; + +#define CHECK_MATRIX_POS(M) OSL_ENSURE(((M) >= static_cast(0)) && ((M) < static_cast(m_pMatrix->size())),"Position is invalid!") + +// 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; + OptimisticSet* pCursor = new OptimisticSet(m_aContext,xConnection,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount); + m_xCacheSet = pCursor; + try + { + m_xCacheSet->construct(_xRs,i_sRowSetFilter); + if ( pCursor->isReadOnly() ) + m_nPrivileges = Privilege::SELECT; + m_aKeyColumns = pCursor->getJoinedKeyColumns(); + return; + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache"); + } + m_xCacheSet.clear(); + } + else + { + if(!_rUpdateTableName.isEmpty() && xTables->hasByName(_rUpdateTableName)) + xTables->getByName(_rUpdateTableName) >>= m_aUpdateTable; + else if(xTables->getElementNames().hasElements()) + { + aUpdateTableName = xTables->getElementNames()[0]; + xTables->getByName(aUpdateTableName) >>= m_aUpdateTable; + } + Reference xIndexAccess(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() && sal_Int32(aColumnNames.size()) == 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 + } + } + } + + OKeySet* 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 ) + { + CHECK_MATRIX_POS(*aIter); + 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 makeAny(static_cast(i_aValue)); + 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] = makeAny(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 + nStartPosOffet) i.e. [aEnd, aNewEnd): new data of positions < old m_nStartPos + // [nOverlapSize + nStartPosOffet; size()) i.e. [aNewEnd, end()): unused + // Note that nOverlapSize + nStartPosOffet == 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 + nStartPosOffet) i.e. [aEnd, aNewEnd): kept + // [nOverlapSize + nStartPosOffet; 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 + CHECK_MATRIX_POS( (nDist + nStartPosOffset) ); + 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 + CHECK_MATRIX_POS(nRowsInCache); + 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; + CHECK_MATRIX_POS( nNewStartPosInMatrix ); + // 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; + CHECK_MATRIX_POS(nValue); + return ( nValue < 0 || nValue >= static_cast(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 000000000..082b6522c --- /dev/null +++ b/dbaccess/source/core/api/RowSetCache.hxx @@ -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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETCACHE_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETCACHE_HXX + +#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); + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/RowSetCacheIterator.cxx b/dbaccess/source/core/api/RowSetCacheIterator.cxx new file mode 100644 index 000000000..7df7bae6b --- /dev/null +++ b/dbaccess/source/core/api/RowSetCacheIterator.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "RowSetCacheIterator.hxx" +#include "RowSetCache.hxx" +#include "RowSetBase.hxx" + +using namespace dbaccess; + +ORowSetCacheIterator::ORowSetCacheIterator(const ORowSetCacheIterator& _rRH) +: m_aIter(_rRH.m_aIter) +, m_pCache(_rRH.m_pCache) +,m_pRowSet(_rRH.m_pRowSet) +{ +} + +ORowSetCacheIterator::operator ORowSetMatrix::iterator const &() +{ + return m_aIter->second.aIterator; +} + +ORowSetCacheIterator& ORowSetCacheIterator::operator =(const ORowSetCacheIterator& _rRH) +{ + if(this == &_rRH) + return *this; + + m_pCache = _rRH.m_pCache; + m_aIter = _rRH.m_aIter; + m_pRowSet = _rRH.m_pRowSet; + + return *this; +} + +ORowSetCacheIterator& ORowSetCacheIterator::operator =(const ORowSetMatrix::iterator& _rIter) +{ + m_aIter->second.aIterator = _rIter; + return *this; +} + +ORowSetRow& ORowSetCacheIterator::operator *() +{ + return *m_aIter->second.aIterator; +} + +ORowSetMatrix::iterator& ORowSetCacheIterator::operator ->() +{ + return m_aIter->second.aIterator; +} + +bool ORowSetCacheIterator::operator <(const ORowSetMatrix::iterator& _rRH) const +{ + return m_aIter->second.aIterator < _rRH; +} + +bool ORowSetCacheIterator::operator !=(const ORowSetMatrix::iterator& _rRH) const +{ + return m_aIter->second.aIterator != _rRH; +} + +bool ORowSetCacheIterator::isNull() const +{ + bool bRet = !m_pCache || !m_pRowSet || m_aIter == m_pCache->m_aCacheIterators.end(); + if ( !bRet ) + { + bRet = ( m_pRowSet->isInsertRow() + ? + m_aIter->second.aIterator == m_pCache->m_pInsertMatrix->end() + : + m_aIter->second.aIterator == m_pCache->m_pMatrix->end() + ); + } + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/RowSetCacheIterator.hxx b/dbaccess/source/core/api/RowSetCacheIterator.hxx new file mode 100644 index 000000000..39f139c27 --- /dev/null +++ b/dbaccess/source/core/api/RowSetCacheIterator.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETCACHEITERATOR_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETCACHEITERATOR_HXX + +#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(const ORowSetCacheMap::iterator& _rIter,ORowSetCache* _pCache,ORowSetBase* _pRowSet) + : m_aIter(_rIter) + ,m_pCache(_pCache) + ,m_pRowSet(_pRowSet) + { + } + public: + ORowSetCacheIterator() :m_aIter(),m_pCache(nullptr),m_pRowSet(nullptr){} + ORowSetCacheIterator(const ORowSetCacheIterator& _rRH); + ORowSetCacheIterator& operator =(const ORowSetCacheIterator&); + + bool isNull() const; + ORowSetCacheIterator& operator =(const ORowSetMatrix::iterator&); + operator ORowSetMatrix::iterator const &(); + + ORowSetRow& operator *(); + + ORowSetMatrix::iterator& operator ->(); + + bool operator <(const ORowSetMatrix::iterator& _rRH) const; + bool operator !=(const ORowSetMatrix::iterator& _rRH) const; + + const ORowSetCacheMap::iterator& getIter() const { return m_aIter; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETCACHEITERATOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/RowSetRow.hxx b/dbaccess/source/core/api/RowSetRow.hxx new file mode 100644 index 000000000..11337dec7 --- /dev/null +++ b/dbaccess/source/core/api/RowSetRow.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETROW_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETROW_HXX + +#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(const ORowSetRow& _rRow) + : m_aRow(_rRow) + {} + + const ORowSetRow& getRow() const { return m_aRow; } + void clearRow() { m_aRow = nullptr; } + void setRow(const ORowSetRow& _rRow) { m_aRow = _rRow; } + }; + + typedef ::rtl::Reference< ORowSetOldRowHelper > TORowSetOldRowHelperRef; + +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_ROWSETROW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/SingleSelectQueryComposer.cxx b/dbaccess/source/core/api/SingleSelectQueryComposer.cxx new file mode 100644 index 000000000..9f96f8429 --- /dev/null +++ b/dbaccess/source/core/api/SingleSelectQueryComposer.cxx @@ -0,0 +1,1881 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "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 + +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; +} + +#define STR_SELECT "SELECT " +#define STR_FROM " FROM " +#define STR_WHERE " WHERE " +#define STR_GROUP_BY " GROUP BY " +#define STR_HAVING " HAVING " +#define STR_ORDER_BY " ORDER BY " +#define STR_AND " AND " +#define STR_OR " OR " +#define STR_LIKE OUString(" LIKE ") +#define L_BRACKET "(" +#define R_BRACKET ")" +#define COMMA "," + +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, makeAny( aError2 ) ); + throw SQLException(_rParser.getContext().getErrorMessage(OParseContext::ErrorCode::General),_rxContext,sSQLStateGeneralError,1000,makeAny(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, makeAny( 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,const OUString& i_sValue,OUStringBuffer& o_sRet) + { + switch( i_nFilterOperator ) + { + case SQLFilterOperator::EQUAL: + o_sRet.append(" = " ).append( i_sValue); + break; + case SQLFilterOperator::NOT_EQUAL: + o_sRet.append(" <> " ).append( i_sValue); + break; + case SQLFilterOperator::LESS: + o_sRet.append(" < " ).append( i_sValue); + break; + case SQLFilterOperator::GREATER: + o_sRet.append(" > " ).append( i_sValue); + break; + case SQLFilterOperator::LESS_EQUAL: + o_sRet.append(" <= " ).append( i_sValue); + break; + case SQLFilterOperator::GREATER_EQUAL: + o_sRet.append(" >= " ).append( i_sValue); + break; + case SQLFilterOperator::LIKE: + o_sRet.append(" LIKE " ).append( i_sValue); + break; + case SQLFilterOperator::NOT_LIKE: + o_sRet.append(" NOT LIKE " ).append( 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_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,static_cast (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) +IMPLEMENT_SERVICE_INFO1(OSingleSelectQueryComposer,"org.openoffice.comp.dba.OSingleSelectQueryComposer",SERVICE_NAME_SINGLESELECTQUERYCOMPOSER) + +css::uno::Sequence OSingleSelectQueryComposer::getImplementationId() +{ + return css::uno::Sequence(); +} + +IMPLEMENT_GETTYPES3(OSingleSelectQueryComposer,OSubComponent,OSingleSelectQueryComposer_BASE,OPropertyContainer) +IMPLEMENT_PROPERTYCONTAINER_DEFAULTS(OSingleSelectQueryComposer) + +// 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,makeAny(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 aCatlog,aSchema,aTable; + ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatlog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation); + sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation ); + } + else if (!sTableName.isEmpty()) + sTableName = ::dbtools::quoteName(aQuote,sTableName); + + if(sTableName.isEmpty()) + aNewName = ::dbtools::quoteName(aQuote,sRealName); + else + aNewName = sTableName + "." + ::dbtools::quoteName(aQuote,sRealName); + } + } + else + aNewName = ::dbtools::quoteName(aQuote,aName); + } + else + aNewName = getTableAlias(column) + ::dbtools::quoteName(aQuote,aName); + return aNewName; +} + +OUString OSingleSelectQueryComposer::impl_getColumnNameOrderBy_throw(const Reference< XPropertySet >& column) +{ + ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed); + + getColumns(); + if ( !column.is() + || !m_aCurrentColumns[SelectColumns] + || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME) + ) + { + OUString sError(DBA_RES(RID_STR_COLUMN_UNKNOWN_PROP)); + SQLException aErr(sError.replaceAll("%value", PROPERTY_NAME),*this,SQLSTATE_GENERAL,1000,Any() ); + throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,makeAny(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, const OUString& _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,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 ( " ).append( sOriginalWhereClause ).append( " ) " ); + } + + 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, makeAny( 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; + + ::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,aComposedName,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 + { + 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, const OUString& rQuoteString) + { + const sal_Int32 nQuoteLength = rQuoteString.getLength(); + OUString sName = rComposedName.trim(); + OUString sColumnName; + sal_Int32 nPos, nRPos = 0; + + for (;;) + { + nPos = sName.indexOf( rQuoteString, nRPos ); + if ( nPos >= 0 ) + { + nRPos = sName.indexOf( rQuoteString, nPos + nQuoteLength ); + if ( nRPos > nPos ) + { + if ( nRPos + nQuoteLength < sName.getLength() ) + { + nRPos += nQuoteLength; // -1 + 1 skip dot + } + else + { + sColumnName = sName.copy( nPos + nQuoteLength, nRPos - nPos - nQuoteLength ); + break; + } + } + else + break; + } + else + break; + } + return sColumnName.isEmpty() ? rComposedName : sColumnName; + } + + OUString lcl_getCondition(const Sequence< Sequence< PropertyValue > >& filter, + const OPredicateInputController& i_aPredicateInputController, + const Reference< XNameAccess >& i_xSelectColumns, + const OUString& rQuoteString) + { + OUStringBuffer sRet; + const Sequence< PropertyValue >* pOrIter = filter.getConstArray(); + const Sequence< PropertyValue >* pOrEnd = pOrIter + filter.getLength(); + while ( pOrIter != pOrEnd ) + { + if ( pOrIter->hasElements() ) + { + sRet.append(L_BRACKET); + const PropertyValue* pAndIter = pOrIter->getConstArray(); + const PropertyValue* pAndEnd = pAndIter + pOrIter->getLength(); + while ( pAndIter != pAndEnd ) + { + sRet.append(pAndIter->Name); + OUString sValue; + pAndIter->Value >>= sValue; + const OUString sColumnName = lcl_getDecomposedColumnName( pAndIter->Name, rQuoteString ); + if ( i_xSelectColumns.is() && i_xSelectColumns->hasByName(sColumnName) ) + { + Reference 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 aCatlog,aSchema,aTable; + ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatlog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation); + sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation ); + } + else + sTableName = ::dbtools::quoteName(aQuote,sTableName); + + if ( !::comphelper::getBOOL(xColumn->getPropertyValue("Function")) ) + { + aSQL = sTableName + "." + ::dbtools::quoteName( aQuote, sRealName ); + } + else + aSQL = sRealName; + } + else + { + aSQL = getTableAlias( column ) + ::dbtools::quoteName( aQuote, aName ); + } + + if ( aValue.hasValue() ) + { + if( !m_xTypeConverter.is() ) + m_xTypeConverter.set( Converter::create(m_aContext) ); + OSL_ENSURE(m_xTypeConverter.is(),"NO typeconverter!"); + + if ( nType != DataType::BOOLEAN && DataType::BIT != nType ) + { + lcl_addFilterCriteria_throw(filterOperator,"",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("'").append(xClob->getSubString(1,static_cast(nLength))).append("'"); + } + } + 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,"",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 ? OUStringLiteral(STR_AND) : OUStringLiteral(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 000000000..0a5bd2c2d --- /dev/null +++ b/dbaccess/source/core/api/StaticSet.cxx @@ -0,0 +1,282 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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 makeAny(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]); + } + 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]); + } + 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(row >= static_cast(m_aSet.size())) + { + if(!m_bEnd) + { + bool bNext = true; + for(sal_Int32 i=m_aSet.size()-1;i < row && bNext;++i) + bNext = fetchRow(); + } + + if(row > static_cast(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 t; + m_aSet.swap(t); + } + m_aSetIter = m_aSet.end(); + m_bEnd = false; + m_aSet.emplace_back(nullptr); // this is the beforefirst record +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/StaticSet.hxx b/dbaccess/source/core/api/StaticSet.hxx new file mode 100644 index 000000000..8c466d29e --- /dev/null +++ b/dbaccess/source/core/api/StaticSet.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_STATICSET_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_STATICSET_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_STATICSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/TableDeco.cxx b/dbaccess/source/core/api/TableDeco.cxx new file mode 100644 index 000000000..b8a8da273 --- /dev/null +++ b/dbaccess/source/core/api/TableDeco.cxx @@ -0,0 +1,622 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 ::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 : 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 +IMPLEMENT_SERVICE_INFO1(ODBTableDecorator, "com.sun.star.sdb.dbaccess.ODBTableDecorator", 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 (isUnoTunnelId(rId)) + return reinterpret_cast(this); + + sal_Int64 nRet = 0; + Reference xTunnel(m_xTable,UNO_QUERY); + if(xTunnel.is()) + nRet = xTunnel->getSomething(rId); + return nRet; +} + +Sequence< sal_Int8 > ODBTableDecorator::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +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()) + { + Sequence< OUString> aNames = xNames->getElementNames(); + const OUString* pIter = aNames.getConstArray(); + const OUString* pEnd = pIter + aNames.getLength(); + for(;pIter != pEnd;++pIter) + aVector.push_back(*pIter); + } + } + 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); + OContainerMediator* pMediator = new OContainerMediator( pCol, m_xColumnDefinitions ); + m_xColumnMediator = pMediator; + pCol->setMediator( pMediator ); + m_pColumns.reset(pCol); + } + else + m_pColumns->reFill(aVector); +} + +OColumn* ODBTableDecorator::createColumn(const OUString& _rName) const +{ + OColumn* pReturn = nullptr; + + Reference xNames; + if ( m_xTable.is() ) + { + xNames = m_xTable->getColumns(); + + if ( xNames.is() && xNames->hasByName(_rName) ) + { + Reference xProp(xNames->getByName(_rName),UNO_QUERY); + + Reference xColumnDefintion; + if ( m_xColumnDefinitions.is() && m_xColumnDefinitions->hasByName(_rName)) + xColumnDefintion.set(m_xColumnDefinitions->getByName(_rName),UNO_QUERY); + + pReturn = new OTableColumnWrapper( xProp, xColumnDefintion, 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() throw() +{ + OTableDescriptor_BASE::acquire(); +} + +void SAL_CALL ODBTableDecorator::release() throw() +{ + OTableDescriptor_BASE::release(); +} + +void SAL_CALL ODBTableDecorator::setName( const OUString& /*aName*/ ) +{ + throwFunctionNotSupportedRuntimeException( "XNamed::setName", *this ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/View.cxx b/dbaccess/source/core/api/View.cxx new file mode 100644 index 000000000..c52c4885c --- /dev/null +++ b/dbaccess/source/core/api/View.cxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 000000000..a0999e5f3 --- /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 makeAny(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); + break; + case DataType::BIGINT: + if ( _rValue.isSigned() ) + _xParameter->updateLong(nPos,_rValue); + else + _xParameter->updateString(nPos,_rValue); + break; + case DataType::BIT: + case DataType::BOOLEAN: + _xParameter->updateBoolean(nPos,static_cast(_rValue)); + break; + case DataType::TINYINT: + if ( _rValue.isSigned() ) + _xParameter->updateByte(nPos,_rValue); + else + _xParameter->updateShort(nPos,_rValue); + break; + case DataType::SMALLINT: + if ( _rValue.isSigned() ) + _xParameter->updateShort(nPos,_rValue); + else + _xParameter->updateInt(nPos,_rValue); + break; + case DataType::INTEGER: + if ( _rValue.isSigned() ) + _xParameter->updateInt(nPos,_rValue); + else + _xParameter->updateLong(nPos,_rValue); + break; + case DataType::FLOAT: + _xParameter->updateFloat(nPos,_rValue); + break; + case DataType::DOUBLE: + case DataType::REAL: + _xParameter->updateDouble(nPos,_rValue); + break; + case DataType::DATE: + _xParameter->updateDate(nPos,_rValue); + break; + case DataType::TIME: + _xParameter->updateTime(nPos,_rValue); + break; + case DataType::TIMESTAMP: + _xParameter->updateTimestamp(nPos,_rValue); + break; + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + _xParameter->updateBytes(nPos,_rValue); + break; + case DataType::BLOB: + case DataType::CLOB: + _xParameter->updateObject(nPos,_rValue.getAny()); + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/WrappedResultSet.hxx b/dbaccess/source/core/api/WrappedResultSet.hxx new file mode 100644 index 000000000..8f0b07953 --- /dev/null +++ b/dbaccess/source/core/api/WrappedResultSet.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_WRAPPEDRESULTSET_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_WRAPPEDRESULTSET_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_WRAPPEDRESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/callablestatement.cxx b/dbaccess/source/core/api/callablestatement.cxx new file mode 100644 index 000000000..cfddeac19 --- /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() throw () +{ + OPreparedStatement::acquire(); +} + +void OCallableStatement::release() throw () +{ + OPreparedStatement::release(); +} + +// XServiceInfo +OUString OCallableStatement::getImplementationName( ) +{ + return "com.sun.star.sdb.OCallableStatement"; +} + +Sequence< OUString > OCallableStatement::getSupportedServiceNames( ) +{ + return { SERVICE_SDBC_CALLABLESTATEMENT, SERVICE_SDB_CALLABLESTATEMENT }; +} + +// XOutParameters +void SAL_CALL OCallableStatement::registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) +{ + MutexGuard aGuard(m_aMutex); + + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + Reference< XOutParameters >(m_xAggregateAsSet, UNO_QUERY_THROW)->registerOutParameter( parameterIndex, sqlType, typeName ); +} + +void SAL_CALL OCallableStatement::registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + Reference< XOutParameters >(m_xAggregateAsSet, UNO_QUERY_THROW)->registerNumericOutParameter( parameterIndex, sqlType, scale ); +} + +// XRow +sal_Bool SAL_CALL OCallableStatement::wasNull( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->wasNull(); +} + +OUString SAL_CALL OCallableStatement::getString( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getString( columnIndex ); +} + +sal_Bool SAL_CALL OCallableStatement::getBoolean( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBoolean( columnIndex ); +} + +sal_Int8 SAL_CALL OCallableStatement::getByte( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getByte( columnIndex ); +} + +sal_Int16 SAL_CALL OCallableStatement::getShort( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getShort( columnIndex ); +} + +sal_Int32 SAL_CALL OCallableStatement::getInt( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getInt( columnIndex ); +} + +sal_Int64 SAL_CALL OCallableStatement::getLong( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getLong( columnIndex ); +} + +float SAL_CALL OCallableStatement::getFloat( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getFloat( columnIndex ); +} + +double SAL_CALL OCallableStatement::getDouble( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getDouble( columnIndex ); +} + +Sequence< sal_Int8 > SAL_CALL OCallableStatement::getBytes( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBytes( columnIndex ); +} + +css::util::Date SAL_CALL OCallableStatement::getDate( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getDate( columnIndex ); +} + +css::util::Time SAL_CALL OCallableStatement::getTime( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getTime( columnIndex ); +} + +css::util::DateTime SAL_CALL OCallableStatement::getTimestamp( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getTimestamp( columnIndex ); +} + +Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getBinaryStream( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBinaryStream( columnIndex ); +} + +Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getCharacterStream( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getCharacterStream( columnIndex ); +} + +Any SAL_CALL OCallableStatement::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getObject( columnIndex, typeMap ); +} + +Reference< XRef > SAL_CALL OCallableStatement::getRef( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getRef( columnIndex ); +} + +Reference< XBlob > SAL_CALL OCallableStatement::getBlob( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBlob( columnIndex ); +} + +Reference< XClob > SAL_CALL OCallableStatement::getClob( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getClob( columnIndex ); +} + +Reference< XArray > SAL_CALL OCallableStatement::getArray( sal_Int32 columnIndex ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getArray( columnIndex ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/column.cxx b/dbaccess/source/core/api/column.cxx new file mode 100644 index 000000000..5bc70affb --- /dev/null +++ b/dbaccess/source/core/api/column.cxx @@ -0,0 +1,411 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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, + const css::uno::Reference< css::container::XNameAccess >& _rxDrvColumns, + bool _bCaseSensitive,const std::vector< OUString> &_rVector, + IColumnFactory* _pColFactory, + ::connectivity::sdbcx::IRefreshableColumns* _pRefresh, + bool _bAddColumn, + bool _bDropColumn, + bool _bUseHardRef) + : OColumns_BASE(_rParent,_bCaseSensitive,_rMutex,_rVector,_bUseHardRef) + ,m_pMediator(nullptr) + ,m_xDrvColumns(_rxDrvColumns) + ,m_pColFactoryImpl(_pColFactory) + ,m_pRefreshColumns(_pRefresh) + ,m_bInitialized(false) + ,m_bAddColumn(_bAddColumn) + ,m_bDropColumn(_bDropColumn) +{ +} + +OColumns::~OColumns() +{ +} + +// XServiceInfo +OUString OColumns::getImplementationName( ) +{ + return "com.sun.star.sdb.OColumns"; +} + +sal_Bool OColumns::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > OColumns::getSupportedServiceNames( ) +{ + return { SERVICE_SDBCX_CONTAINER }; +} + +void OColumns::append( const OUString& _rName, OColumn* _pColumn ) +{ + MutexGuard aGuard(m_rMutex); + + OSL_ENSURE( _pColumn, "OColumns::append: invalid column!" ); + OSL_ENSURE( !m_pElements->exists( _rName ),"OColumns::append: Column already exists"); + + _pColumn->m_sName = _rName; + + // now really insert the column + insertElement( _rName, _pColumn ); +} + +void OColumns::clearColumns() +{ + MutexGuard aGuard(m_rMutex); + disposing(); +} + +void OColumns::disposing() +{ + MutexGuard aGuard(m_rMutex); + m_xDrvColumns = nullptr; + m_pMediator = nullptr; + m_pColFactoryImpl = nullptr; + OColumns_BASE::disposing(); +} + +void OColumns::impl_refresh() +{ + if (m_pRefreshColumns) + m_pRefreshColumns->refreshColumns(); +} + +connectivity::sdbcx::ObjectType OColumns::createObject(const OUString& _rName) +{ + OSL_ENSURE(m_pColFactoryImpl, "OColumns::createObject: no column factory!"); + + connectivity::sdbcx::ObjectType xRet; + if ( m_pColFactoryImpl ) + { + xRet = m_pColFactoryImpl->createColumn(_rName); + Reference xChild(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 000000000..3f62a5a69 --- /dev/null +++ b/dbaccess/source/core/api/columnsettings.cxx @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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[] = + { + { OUString(PROPERTY_ALIGN), PROPERTY_ID_ALIGN }, + { OUString(PROPERTY_NUMBERFORMAT), PROPERTY_ID_NUMBERFORMAT }, + { OUString(PROPERTY_RELATIVEPOSITION), PROPERTY_ID_RELATIVEPOSITION }, + { OUString(PROPERTY_WIDTH), PROPERTY_ID_WIDTH }, + { OUString(PROPERTY_HELPTEXT), PROPERTY_ID_HELPTEXT }, + { OUString(PROPERTY_CONTROLDEFAULT), PROPERTY_ID_CONTROLDEFAULT }, + { OUString(PROPERTY_CONTROLMODEL), PROPERTY_ID_CONTROLMODEL }, + { OUString(PROPERTY_HIDDEN), PROPERTY_ID_HIDDEN } + }; + + for (const auto & aProp : aProps) + { + if ( xPSI->hasPropertyByName( aProp.sName ) ) + if ( !isDefaulted( aProp.nHandle, _rxColumn->getPropertyValue( aProp.sName ) ) ) + return false; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return true; + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/datacolumn.cxx b/dbaccess/source/core/api/datacolumn.cxx new file mode 100644 index 000000000..c597a4064 --- /dev/null +++ b/dbaccess/source/core/api/datacolumn.cxx @@ -0,0 +1,396 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "datacolumn.hxx" +#include +#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 000000000..fa40e0765 --- /dev/null +++ b/dbaccess/source/core/api/datacolumn.hxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_DATACOLUMN_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_DATACOLUMN_HXX + +#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() throw() override { OResultColumn::acquire(); } + virtual void SAL_CALL release() throw() 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; + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_DATACOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/datasettings.cxx b/dbaccess/source/core/api/datasettings.cxx new file mode 100644 index 000000000..281671844 --- /dev/null +++ b/dbaccess/source/core/api/datasettings.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 + +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) + ,ODataSettings_Base() + ,m_bQuery(_bQuery) +{ +} + +ODataSettings_Base::ODataSettings_Base() + :m_bApplyFilter(false) + ,m_bAutoGrow(false) + ,m_aFont(::comphelper::getDefaultFont()) + ,m_nFontEmphasis(css::awt::FontEmphasisMark::NONE) + ,m_nFontRelief(css::awt::FontRelief::NONE) +{ +} + +ODataSettings_Base::~ODataSettings_Base() +{ +} + +void ODataSettings::getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _rDefault ) const +{ + static css::awt::FontDescriptor aFD = ::comphelper::getDefaultFont(); + switch( _nHandle ) + { + case PROPERTY_ID_HAVING_CLAUSE: + case PROPERTY_ID_GROUP_BY: + case PROPERTY_ID_FILTER: + case PROPERTY_ID_ORDER: + _rDefault <<= OUString(); + break; + case PROPERTY_ID_FONT: + _rDefault <<= ::comphelper::getDefaultFont(); + break; + case PROPERTY_ID_APPLYFILTER: + _rDefault <<= false; + break; + case PROPERTY_ID_TEXTRELIEF: + _rDefault <<= css::awt::FontRelief::NONE; + break; + case PROPERTY_ID_TEXTEMPHASIS: + _rDefault <<= css::awt::FontEmphasisMark::NONE; + break; + case PROPERTY_ID_FONTNAME: + _rDefault <<= aFD.Name; + break; + case PROPERTY_ID_FONTHEIGHT: + _rDefault <<= aFD.Height; + break; + case PROPERTY_ID_FONTWIDTH: + _rDefault <<= aFD.Width; + break; + case PROPERTY_ID_FONTSTYLENAME: + _rDefault <<= aFD.StyleName; + break; + case PROPERTY_ID_FONTFAMILY: + _rDefault <<= aFD.Family; + break; + case PROPERTY_ID_FONTCHARSET: + _rDefault <<= aFD.CharSet; + break; + case PROPERTY_ID_FONTPITCH: + _rDefault <<= aFD.Pitch; + break; + case PROPERTY_ID_FONTCHARWIDTH: + _rDefault <<= aFD.CharacterWidth; + break; + case PROPERTY_ID_FONTWEIGHT: + _rDefault <<= aFD.Weight; + break; + case PROPERTY_ID_FONTSLANT: + _rDefault <<= aFD.Slant; + break; + case PROPERTY_ID_FONTUNDERLINE: + _rDefault <<= aFD.Underline; + break; + case PROPERTY_ID_FONTSTRIKEOUT: + _rDefault <<= aFD.Strikeout; + break; + case PROPERTY_ID_FONTORIENTATION: + _rDefault <<= aFD.Orientation; + break; + case PROPERTY_ID_FONTKERNING: + _rDefault <<= aFD.Kerning; + break; + case PROPERTY_ID_FONTWORDLINEMODE: + _rDefault <<= aFD.WordLineMode; + break; + case PROPERTY_ID_FONTTYPE: + _rDefault <<= aFD.Type; + break; + } +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/definitioncolumn.cxx b/dbaccess/source/core/api/definitioncolumn.cxx new file mode 100644 index 000000000..84d1197bd --- /dev/null +++ b/dbaccess/source/core/api/definitioncolumn.cxx @@ -0,0 +1,608 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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::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? OUString(SERVICE_SDBCX_COLUMNDESCRIPTOR) : OUString(SERVICE_SDBCX_COLUMN), + SERVICE_SDB_COLUMNSETTINGS }; +} + +// comphelper::OPropertyArrayUsageHelper +::cppu::IPropertyArrayHelper* OTableColumnDescriptor::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper( aProps ); +} + +// cppu::OPropertySetHelper +::cppu::IPropertyArrayHelper& OTableColumnDescriptor::getInfoHelper() +{ + return *static_cast< ::comphelper::OPropertyArrayUsageHelper< OTableColumnDescriptor >* >(this)->getArrayHelper(); +} + +void OTableColumnDescriptor::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) +{ + OColumn::setFastPropertyValue_NoBroadcast( nHandle, rValue ); + ::dbaccess::notifyDataSourceModified( m_xParent ); +} + +Reference< XInterface > SAL_CALL OTableColumnDescriptor::getParent( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + return m_xParent; +} + +void SAL_CALL OTableColumnDescriptor::setParent( const Reference< XInterface >& _xParent ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + m_xParent = _xParent; +} + +// OTableColumn + +OTableColumn::OTableColumn( const OUString& _rName ) + :OTableColumnDescriptor( false /* do not act as descriptor */ ) +{ + m_sName = _rName; +} + +OTableColumn::~OTableColumn() +{ +} + +IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumn ) + +OUString OTableColumn::getImplementationName( ) +{ + return "com.sun.star.sdb.OTableColumn"; +} + +::cppu::IPropertyArrayHelper& SAL_CALL OTableColumn::getInfoHelper() +{ + return *OTableColumn_PBase::getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* OTableColumn::createArrayHelper( ) const +{ + return OTableColumnDescriptor::createArrayHelper(); +} + +// OQueryColumn + +OQueryColumn::OQueryColumn( const Reference< XPropertySet >& _rxParserColumn, const Reference< XConnection >& _rxConnection, const OUString &i_sLabel ) + :OTableColumnDescriptor( false /* do not act as descriptor */ ) + ,m_sLabel(i_sLabel) +{ + const sal_Int32 nPropAttr = PropertyAttribute::READONLY; + registerProperty( PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, nPropAttr, &m_sCatalogName, cppu::UnoType::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[] = + { + { OUString(PROPERTY_CATALOGNAME), PROPERTY_ID_CATALOGNAME }, + { OUString(PROPERTY_SCHEMANAME), PROPERTY_ID_SCHEMANAME }, + { OUString(PROPERTY_TABLENAME), PROPERTY_ID_TABLENAME }, + { OUString(PROPERTY_REALNAME), PROPERTY_ID_REALNAME } + }; + for (const auto & aProp : aProps) + { + if ( xPSI->hasPropertyByName( aProp.sName ) ) + setFastPropertyValue_NoBroadcast( aProp.nHandle, _rxParserColumn->getPropertyValue( aProp.sName ) ); + } + + // determine the table column we're based on + osl_atomic_increment( &m_refCount ); + { + m_xOriginalTableColumn = impl_determineOriginalTableColumn( _rxConnection ); + } + osl_atomic_decrement( &m_refCount ); +} + +OQueryColumn::~OQueryColumn() +{ +} + +Reference< XPropertySet > OQueryColumn::impl_determineOriginalTableColumn( const Reference< XConnection >& _rxConnection ) +{ + OSL_PRECOND( _rxConnection.is(), "OQueryColumn::impl_determineOriginalTableColumn: illegal connection!" ); + if ( !_rxConnection.is() ) + return nullptr; + + Reference< XPropertySet > xOriginalTableColumn; + try + { + // determine the composed table name, plus the column name, as indicated by the + // respective properties + OUString sCatalog, sSchema, sTable; + if( ! (getPropertyValue( PROPERTY_CATALOGNAME ) >>= sCatalog) ) + SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_CATALOGNAME); + if( ! (getPropertyValue( PROPERTY_SCHEMANAME ) >>= sSchema) ) + SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_SCHEMANAME); + if( ! (getPropertyValue( PROPERTY_TABLENAME ) >>= sTable) ) + SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_TABLENAME); + if ( sCatalog.isEmpty() && sSchema.isEmpty() && sTable.isEmpty() ) + return nullptr; + + OUString sComposedTableName = ::dbtools::composeTableName( + _rxConnection->getMetaData(), sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::Complete ); + + // retrieve the table in question + Reference< XTablesSupplier > xSuppTables( _rxConnection, UNO_QUERY_THROW ); + Reference< XNameAccess > xTables( xSuppTables->getTables(), UNO_SET_THROW ); + if ( !xTables->hasByName( sComposedTableName ) ) + return nullptr; + + Reference< XColumnsSupplier > xSuppCols( xTables->getByName( sComposedTableName ), UNO_QUERY_THROW ); + Reference< XNameAccess > xColumns( xSuppCols->getColumns(), UNO_SET_THROW ); + + OUString sColumn; + if( ! (getPropertyValue( PROPERTY_REALNAME ) >>= sColumn) ) + SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_REALNAME); + if ( !xColumns->hasByName( sColumn ) ) + return nullptr; + + xOriginalTableColumn.set( xColumns->getByName( sColumn ), UNO_QUERY ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xOriginalTableColumn; +} + +IMPLEMENT_GET_IMPLEMENTATION_ID( OQueryColumn ) + +OUString SAL_CALL OQueryColumn::getImplementationName( ) +{ + return "org.openoffice.comp.dbaccess.OQueryColumn"; +} + +::cppu::IPropertyArrayHelper& SAL_CALL OQueryColumn::getInfoHelper() +{ + return *OQueryColumn_PBase::getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* OQueryColumn::createArrayHelper() const +{ + return OTableColumnDescriptor::createArrayHelper(); +} + +void SAL_CALL OQueryColumn::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const +{ + OTableColumnDescriptor::getFastPropertyValue( _rValue, _nHandle ); + + // special treatment for column settings: + if ( !OColumnSettings::isColumnSettingProperty( _nHandle ) ) + return; + + // If the setting has its default value, then try to obtain the value from the table column which + // this query column is based on + if ( !OColumnSettings::isDefaulted( _nHandle, _rValue ) ) + return; + + if ( !m_xOriginalTableColumn.is() ) + return; + + try + { + // determine original property name + OUString sPropName; + sal_Int16 nAttributes( 0 ); + const_cast< OQueryColumn* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName, &nAttributes, _nHandle ); + OSL_ENSURE( !sPropName.isEmpty(), "OColumnWrapper::impl_getPropertyNameFromHandle: property not found!" ); + + _rValue = m_xOriginalTableColumn->getPropertyValue( sPropName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +// OColumnWrapper + +OColumnWrapper::OColumnWrapper( const Reference< XPropertySet > & rCol, const bool _bNameIsReadOnly ) + :OColumn( _bNameIsReadOnly ) + ,m_xAggregate(rCol) + ,m_nColTypeID(-1) +{ + // which type of aggregate property do we have? + // we distinguish the properties by the containment of optional properties + m_nColTypeID = 0; + if ( !m_xAggregate.is() ) + return; + + Reference 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()); + + BEGIN_PROPERTY_SEQUENCE( nHaveAlways + nHaveOptionally ) + + DECL_PROP0_BOOL( ISAUTOINCREMENT ); + DECL_PROP0_BOOL( ISCURRENCY ); + DECL_PROP0( ISNULLABLE, sal_Int32 ); + DECL_PROP0( PRECISION, sal_Int32 ); + DECL_PROP0( SCALE, sal_Int32 ); + DECL_PROP0( TYPE, sal_Int32 ); + DECL_PROP0( TYPENAME, OUString ); + + if ( nId & HAS_AUTOINCREMENT_CREATION ) + { + DECL_PROP1( AUTOINCREMENTCREATION, OUString, MAYBEVOID ); + } + if ( nId & HAS_DEFAULTVALUE ) + { + DECL_PROP0( DEFAULTVALUE, OUString ); + } + if ( nId & HAS_DESCRIPTION ) + { + DECL_PROP0( DESCRIPTION, OUString ); + } + if ( nId & HAS_ROWVERSION ) + { + DECL_PROP0_BOOL( ISROWVERSION ); + } + if ( nId & HAS_CATALOGNAME ) + { + DECL_PROP0( CATALOGNAME, OUString ); + } + if ( nId & HAS_SCHEMANAME ) + { + DECL_PROP0( SCHEMANAME, OUString ); + } + if ( nId & HAS_TABLENAME ) + { + DECL_PROP0( TABLENAME, OUString ); + } + + END_PROPERTY_SEQUENCE() + + if ( !m_bIsDescriptor ) + { + for ( auto & prop : 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 >& _xColDefintion, + const bool _bPureWrap ) + :OTableColumnDescriptorWrapper( rCol, _bPureWrap, false ) +{ + osl_atomic_increment( &m_refCount ); + if ( _xColDefintion.is() ) + { + try + { + ::comphelper::copyProperties( _xColDefintion, this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + osl_atomic_decrement( &m_refCount ); +} + +OTableColumnWrapper::~OTableColumnWrapper() +{ +} + +IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumnWrapper ) + +OUString OTableColumnWrapper::getImplementationName( ) +{ + return "com.sun.star.sdb.OTableColumnWrapper"; +} + +Sequence< OUString > OTableColumnWrapper::getSupportedServiceNames( ) +{ + return { SERVICE_SDBCX_COLUMN, SERVICE_SDB_COLUMNSETTINGS }; +} + +::cppu::IPropertyArrayHelper& OTableColumnWrapper::getInfoHelper() +{ + return *static_cast< OIdPropertyArrayUsageHelper< OTableColumnWrapper >* >(this)->getArrayHelper(m_nColTypeID); +} + +// comphelper::OPropertyArrayUsageHelper +::cppu::IPropertyArrayHelper* OTableColumnWrapper::createArrayHelper( sal_Int32 nId ) const +{ + return OTableColumnDescriptorWrapper::createArrayHelper( nId ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/preparedstatement.cxx b/dbaccess/source/core/api/preparedstatement.cxx new file mode 100644 index 000000000..d65ea616d --- /dev/null +++ b/dbaccess/source/core/api/preparedstatement.cxx @@ -0,0 +1,411 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#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() throw () +{ + OStatementBase::acquire(); +} + +void OPreparedStatement::release() throw () +{ + OStatementBase::release(); +} + +// XServiceInfo +OUString OPreparedStatement::getImplementationName( ) +{ + return "com.sun.star.sdb.OPreparedStatement"; +} + +sal_Bool OPreparedStatement::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > OPreparedStatement::getSupportedServiceNames( ) +{ + return { SERVICE_SDBC_PREPAREDSTATEMENT, SERVICE_SDB_PREPAREDSTATMENT }; +} + +// OComponentHelper +void OPreparedStatement::disposing() +{ + { + MutexGuard aGuard(m_aMutex); + m_pColumns->disposing(); + m_xAggregateAsParameters = nullptr; + } + OStatementBase::disposing(); +} + +// css::sdbcx::XColumnsSupplier +Reference< css::container::XNameAccess > OPreparedStatement::getColumns() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + // do we have to populate the columns + if (!m_pColumns->isInitialized()) + { + try + { + Reference< XResultSetMetaDataSupplier > xSuppMeta( m_xAggregateAsSet, UNO_QUERY_THROW ); + Reference< XResultSetMetaData > xMetaData( xSuppMeta->getMetaData(), UNO_SET_THROW ); + + Reference< XConnection > xConn( getConnection(), UNO_SET_THROW ); + Reference< XDatabaseMetaData > xDBMeta( xConn->getMetaData(), UNO_SET_THROW ); + + for (sal_Int32 i = 0, nCount = xMetaData->getColumnCount(); i < nCount; ++i) + { + // retrieve the name of the column + OUString aName = xMetaData->getColumnName(i + 1); + OResultColumn* pColumn = new OResultColumn(xMetaData, i + 1, xDBMeta); + // don't silently assume that the name is unique - preparedStatement implementations + // are allowed to return duplicate names, but we are required to have + // unique column names + if ( m_pColumns->hasByName( aName ) ) + aName = ::dbtools::createUniqueName( m_pColumns.get(), aName ); + + m_pColumns->append(aName, pColumn); + } + } + catch (const SQLException& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_pColumns->setInitialized(); + } + return m_pColumns.get(); +} + +// XResultSetMetaDataSupplier +Reference< XResultSetMetaData > OPreparedStatement::getMetaData() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + return Reference< XResultSetMetaDataSupplier >( m_xAggregateAsSet, UNO_QUERY_THROW )->getMetaData(); +} + +// XPreparedStatement +Reference< XResultSet > OPreparedStatement::executeQuery() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + disposeResultSet(); + + Reference< XResultSet > xResultSet; + Reference< XResultSet > xDrvResultSet = Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->executeQuery(); + if (xDrvResultSet.is()) + { + xResultSet = new OResultSet(xDrvResultSet, *this, m_pColumns->isCaseSensitive()); + + // keep the resultset weak + m_aResultSet = xResultSet; + } + return xResultSet; +} + +sal_Int32 OPreparedStatement::executeUpdate() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + disposeResultSet(); + + return Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->executeUpdate(); +} + +sal_Bool OPreparedStatement::execute() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + disposeResultSet(); + + return Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->execute(); +} + +Reference< XConnection > OPreparedStatement::getConnection() +{ + return Reference< XConnection > (m_xParent, UNO_QUERY); +} + +// XParameters +void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setNull(parameterIndex, sqlType); +} + +void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setObjectNull(parameterIndex, sqlType, typeName); +} + +void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setBoolean(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setByte(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setShort(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setInt(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setLong(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setFloat(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setDouble(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setString(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setBytes(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const css::util::Date& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setDate(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setTime(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setTimestamp(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setBinaryStream(parameterIndex, x, length); +} + +void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setCharacterStream(parameterIndex, x, length); +} + +void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setObject(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setObjectWithInfo(parameterIndex, x, targetSqlType, scale); +} + +void SAL_CALL OPreparedStatement::setRef( sal_Int32 parameterIndex, const Reference< XRef >& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setRef(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setBlob(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setClob(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::setArray( sal_Int32 parameterIndex, const Reference< XArray >& x ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->setArray(parameterIndex, x); +} + +void SAL_CALL OPreparedStatement::clearParameters( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + m_xAggregateAsParameters->clearParameters(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/query.cxx b/dbaccess/source/core/api/query.cxx new file mode 100644 index 000000000..051c11148 --- /dev/null +++ b/dbaccess/source/core/api/query.cxx @@ -0,0 +1,359 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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(); +} + +IMPLEMENT_GETTYPES3(OQuery,OQueryDescriptor_Base,ODataSettings,OContentHelper); +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; + } + OQueryColumn* pColumn = new OQueryColumn( xSource, m_xConnection, sLabel); + Reference< XChild > xChild( *pColumn, UNO_QUERY_THROW ); + xChild->setParent( *this ); + + implAppendColumn( rName, pColumn ); + 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 +IMPLEMENT_SERVICE_INFO3(OQuery, "com.sun.star.sdb.dbaccess.OQuery", 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); +} + +OColumn* 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 000000000..7a7b8c2fc --- /dev/null +++ b/dbaccess/source/core/api/query.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_QUERY_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_QUERY_HXX + +#include "querydescriptor.hxx" +#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 OColumn* createColumn(const OUString& _rName) const override; + + virtual void rebuildColumns( ) override; + + // OContentHelper overridables + virtual OUString determineContentType() const override; + +private: + void registerProperties(); +}; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_QUERY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/querycomposer.cxx b/dbaccess/source/core/api/querycomposer.cxx new file mode 100644 index 000000000..043b0c083 --- /dev/null +++ b/dbaccess/source/core/api/querycomposer.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 +#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() throw() +{ + OSubComponent::acquire(); +} + +void SAL_CALL OQueryComposer::release() throw() +{ + OSubComponent::release(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/querycontainer.cxx b/dbaccess/source/core/api/querycontainer.cxx new file mode 100644 index 000000000..27ecf51ef --- /dev/null +++ b/dbaccess/source/core/api/querycontainer.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 "query.hxx" +#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 +IMPLEMENT_SERVICE_INFO2(OQueryContainer, "com.sun.star.sdb.dbaccess.OQueryContainer", 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, makeAny(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,makeAny(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,makeAny(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 + { + OQuery* pNewObject = new OQuery( Reference< XPropertySet >( _rxCommandDesc, UNO_QUERY ), m_xConnection, m_aContext ); + xReturn = pNewObject; + + pNewObject->setWarningsContainer( m_pWarnings ); +// pNewObject->getColumns(); + // Why? This is expensive. If you comment this in 'cause you really need it, be sure to run the + // QueryInQuery test in dbaccess/qa/complex/dbaccess ... + } + + return xReturn; +} + +Reference< XContent > OQueryContainer::createObject( const OUString& _rName) +{ + return implCreateWrapper(_rName); +} + +bool OQueryContainer::checkExistence(const OUString& _rName) +{ + bool bRet = false; + if ( !m_bInPropertyChange ) + { + bRet = m_xCommandDefinitions->hasByName(_rName); + Documents::const_iterator aFind = m_aDocumentMap.find(_rName); + if ( !bRet && aFind != m_aDocumentMap.end() ) + { + m_aDocuments.erase( std::find(m_aDocuments.begin(),m_aDocuments.end(),aFind)); + m_aDocumentMap.erase(aFind); + } + else if ( bRet && aFind == m_aDocumentMap.end() ) + { + implAppend(_rName,nullptr); + } + } + return bRet; +} + +sal_Bool SAL_CALL OQueryContainer::hasElements( ) +{ + MutexGuard aGuard(m_aMutex); + return m_xCommandDefinitions->hasElements(); +} + +sal_Int32 SAL_CALL OQueryContainer::getCount( ) +{ + MutexGuard aGuard(m_aMutex); + return Reference(m_xCommandDefinitions,UNO_QUERY_THROW)->getCount(); +} + +Sequence< OUString > SAL_CALL OQueryContainer::getElementNames( ) +{ + MutexGuard aGuard(m_aMutex); + + return m_xCommandDefinitions->getElementNames(); +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/querydescriptor.cxx b/dbaccess/source/core/api/querydescriptor.cxx new file mode 100644 index 000000000..c52febb5d --- /dev/null +++ b/dbaccess/source/core/api/querydescriptor.cxx @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#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(); +} + +IMPLEMENT_GETTYPES2(OQueryDescriptor,OQueryDescriptor_Base,ODataSettings); +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(); +} + +sal_Int64 SAL_CALL OQueryDescriptor_Base::getSomething( const Sequence< sal_Int8 >& _rIdentifier ) +{ + if (isUnoTunnelId(_rIdentifier)) + return reinterpret_cast(this); + + return 0; +} + +css::uno::Sequence OQueryDescriptor_Base::getUnoTunnelId() +{ + static cppu::OImplementationId aId; + return aId.getImplementationId(); +} + +css::uno::Sequence OQueryDescriptor_Base::getImplementationId() +{ + return css::uno::Sequence(); +} + +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(); +} + +OColumn* OQueryDescriptor_Base::createColumn( const OUString& /*_rName*/ ) const +{ + // creating a column/descriptor for a query/descriptor does not make sense at all + return nullptr; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/querydescriptor.hxx b/dbaccess/source/core/api/querydescriptor.hxx new file mode 100644 index 000000000..077792906 --- /dev/null +++ b/dbaccess/source/core/api/querydescriptor.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_QUERYDESCRIPTOR_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_QUERYDESCRIPTOR_HXX + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace dbaccess +{ + +// OQueryDescriptor_Base - a query descriptor (as the name suggests :) +typedef ::cppu::ImplHelper3< + css::sdbcx::XColumnsSupplier, + css::lang::XUnoTunnel, + css::lang::XServiceInfo > OQueryDescriptor_BASE; + +class OQueryDescriptor_Base + :public OQueryDescriptor_BASE + ,public OCommandBase + ,public IColumnFactory + ,public ::connectivity::sdbcx::IRefreshableColumns +{ +private: + bool m_bColumnsOutOfDate : 1; // the columns have to be rebuild on the next getColumns ? + ::osl::Mutex& m_rMutex; + +protected: + std::unique_ptr m_pColumns; // our column descriptions + OUString m_sElementName; + virtual ~OQueryDescriptor_Base(); + + void setColumnsOutOfDate( bool _bOutOfDate = true ); + + sal_Int32 getColumnCount() const { return m_pColumns ? m_pColumns->getCount() : 0; } + void clearColumns( ); + + void implAppendColumn( const OUString& _rName, OColumn* _pColumn ); + +public: + OQueryDescriptor_Base(::osl::Mutex& _rMutex,::cppu::OWeakObject& _rMySelf); + /** constructs the object with a UNO QueryDescriptor. If you use this ctor, the resulting object + won't have any column information (the column container will be empty) + */ + OQueryDescriptor_Base(const OQueryDescriptor_Base& _rSource,::cppu::OWeakObject& _rMySelf); + +// css::sdbcx::XColumnsSupplier + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override; + +// css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + +// css::lang::XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + +protected: + +// IColumnFactory + virtual OColumn* createColumn(const OUString& _rName) const override; + virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override; + virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override; + virtual void columnDropped(const OUString& _sName) override; + + /** rebuild our columns set + + clearColumns has already been called before, do 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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_QUERYDESCRIPTOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/resultcolumn.cxx b/dbaccess/source/core/api/resultcolumn.cxx new file mode 100644 index 000000000..afb2e3f57 --- /dev/null +++ b/dbaccess/source/core/api/resultcolumn.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 "resultcolumn.hxx" +#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( + makeAny( 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 +{ + BEGIN_PROPERTY_HELPER(21) + DECL_PROP1(CATALOGNAME, OUString, READONLY); + DECL_PROP1(DISPLAYSIZE, sal_Int32, READONLY); + DECL_PROP1_BOOL(ISAUTOINCREMENT, READONLY); + DECL_PROP1_BOOL(ISCASESENSITIVE, READONLY); + DECL_PROP1_BOOL(ISCURRENCY, READONLY); + DECL_PROP1_BOOL(ISDEFINITELYWRITABLE, READONLY); + DECL_PROP1(ISNULLABLE, sal_Int32, READONLY); + DECL_PROP1_BOOL(ISREADONLY, READONLY); + DECL_PROP1_BOOL(ISROWVERSION, READONLY); + DECL_PROP1_BOOL(ISSEARCHABLE, READONLY); + DECL_PROP1_BOOL(ISSIGNED, READONLY); + DECL_PROP1_BOOL(ISWRITABLE, READONLY); + DECL_PROP1(LABEL, OUString, READONLY); + DECL_PROP1(NAME, OUString, READONLY); + DECL_PROP1(PRECISION, sal_Int32, READONLY); + DECL_PROP1(SCALE, sal_Int32, READONLY); + DECL_PROP1(SCHEMANAME, OUString, READONLY); + DECL_PROP1(SERVICENAME, OUString, READONLY); + DECL_PROP1(TABLENAME, OUString, READONLY); + DECL_PROP1(TYPE, sal_Int32, READONLY); + DECL_PROP1(TYPENAME, OUString, READONLY); + END_PROPERTY_HELPER(); +} + +// cppu::OPropertySetHelper +::cppu::IPropertyArrayHelper& OResultColumn::getInfoHelper() +{ + return *static_cast< ::comphelper::OPropertyArrayUsageHelper< OResultColumn >* >(this)->getArrayHelper(); +} + +namespace +{ + template< typename T > + void obtain( Any& _out_rValue, ::std::optional< T > & _rCache, const sal_Int32 _nPos, const Reference < XResultSetMetaData >& _rxResultMeta, T (SAL_CALL XResultSetMetaData::*Getter)( sal_Int32 ) ) + { + if ( !_rCache ) + _rCache = (_rxResultMeta.get()->*Getter)(_nPos); + _out_rValue <<= *_rCache; + } +} + +void OResultColumn::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + try + { + if ( OColumn::isRegisteredProperty( nHandle ) ) + { + OColumn::getFastPropertyValue( rValue, nHandle ); + } + else + { + switch (nHandle) + { + case PROPERTY_ID_ISROWVERSION: + const_cast< OResultColumn* >( this )->impl_determineIsRowVersion_nothrow(); + rValue = m_aIsRowVersion; + break; + case PROPERTY_ID_TABLENAME: + rValue <<= m_xMetaData->getTableName(m_nPos); + break; + case PROPERTY_ID_SCHEMANAME: + rValue <<= m_xMetaData->getSchemaName(m_nPos); + break; + case PROPERTY_ID_CATALOGNAME: + rValue <<= m_xMetaData->getCatalogName(m_nPos); + break; + case PROPERTY_ID_ISSIGNED: + obtain( rValue, m_isSigned, m_nPos, m_xMetaData, &XResultSetMetaData::isSigned ); + break; + case PROPERTY_ID_ISCURRENCY: + obtain( rValue, m_isCurrency, m_nPos, m_xMetaData, &XResultSetMetaData::isCurrency ); + break; + case PROPERTY_ID_ISSEARCHABLE: + obtain( rValue, m_bSearchable, m_nPos, m_xMetaData, &XResultSetMetaData::isSearchable ); + break; + case PROPERTY_ID_ISCASESENSITIVE: + obtain( rValue, m_isCaseSensitive, m_nPos, m_xMetaData, &XResultSetMetaData::isCaseSensitive ); + break; + case PROPERTY_ID_ISREADONLY: + obtain( rValue, m_isReadOnly, m_nPos, m_xMetaData, &XResultSetMetaData::isReadOnly ); + break; + case PROPERTY_ID_ISWRITABLE: + obtain( rValue, m_isWritable, m_nPos, m_xMetaData, &XResultSetMetaData::isWritable ); + break; + case PROPERTY_ID_ISDEFINITELYWRITABLE: + obtain( rValue, m_isDefinitelyWritable, m_nPos, m_xMetaData, &XResultSetMetaData::isDefinitelyWritable ); + break; + case PROPERTY_ID_ISAUTOINCREMENT: + obtain( rValue, m_isAutoIncrement, m_nPos, m_xMetaData, &XResultSetMetaData::isAutoIncrement ); + break; + case PROPERTY_ID_SERVICENAME: + rValue <<= m_xMetaData->getColumnServiceName(m_nPos); + break; + case PROPERTY_ID_LABEL: + obtain( rValue, m_sColumnLabel, m_nPos, m_xMetaData, &XResultSetMetaData::getColumnLabel ); + break; + case PROPERTY_ID_DISPLAYSIZE: + obtain( rValue, m_nColumnDisplaySize, m_nPos, m_xMetaData, &XResultSetMetaData::getColumnDisplaySize ); + break; + case PROPERTY_ID_TYPE: + obtain( rValue, m_nColumnType, m_nPos, m_xMetaData, &XResultSetMetaData::getColumnType ); + break; + case PROPERTY_ID_PRECISION: + obtain( rValue, m_nPrecision, m_nPos, m_xMetaData, &XResultSetMetaData::getPrecision ); + break; + case PROPERTY_ID_SCALE: + obtain( rValue, m_nScale, m_nPos, m_xMetaData, &XResultSetMetaData::getScale ); + break; + case PROPERTY_ID_ISNULLABLE: + obtain( rValue, m_isNullable, m_nPos, m_xMetaData, &XResultSetMetaData::isNullable ); + break; + case PROPERTY_ID_TYPENAME: + rValue <<= m_xMetaData->getColumnTypeName(m_nPos); + break; + default: + OSL_FAIL( "OResultColumn::getFastPropertyValue: unknown property handle!" ); + break; + } + } + } + catch (SQLException& ) + { + // default handling if we caught an exception + switch (nHandle) + { + case PROPERTY_ID_LABEL: + case PROPERTY_ID_TYPENAME: + case PROPERTY_ID_SERVICENAME: + case PROPERTY_ID_TABLENAME: + case PROPERTY_ID_SCHEMANAME: + case PROPERTY_ID_CATALOGNAME: + // empty string'S + rValue <<= OUString(); + break; + case PROPERTY_ID_ISROWVERSION: + case PROPERTY_ID_ISAUTOINCREMENT: + case PROPERTY_ID_ISWRITABLE: + case PROPERTY_ID_ISDEFINITELYWRITABLE: + case PROPERTY_ID_ISCASESENSITIVE: + case PROPERTY_ID_ISSEARCHABLE: + case PROPERTY_ID_ISCURRENCY: + case PROPERTY_ID_ISSIGNED: + { + rValue <<= false; + } break; + case PROPERTY_ID_ISREADONLY: + { + rValue <<= true; + } break; + case PROPERTY_ID_SCALE: + case PROPERTY_ID_PRECISION: + case PROPERTY_ID_DISPLAYSIZE: + rValue <<= sal_Int32(0); + break; + case PROPERTY_ID_TYPE: + rValue <<= sal_Int32(DataType::SQLNULL); + break; + case PROPERTY_ID_ISNULLABLE: + rValue <<= ColumnValue::NULLABLE_UNKNOWN; + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/resultcolumn.hxx b/dbaccess/source/core/api/resultcolumn.hxx new file mode 100644 index 000000000..f5b150eaa --- /dev/null +++ b/dbaccess/source/core/api/resultcolumn.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_API_RESULTCOLUMN_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_RESULTCOLUMN_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_RESULTCOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/resultset.cxx b/dbaccess/source/core/api/resultset.cxx new file mode 100644 index 000000000..ee93aa42a --- /dev/null +++ b/dbaccess/source/core/api/resultset.cxx @@ -0,0 +1,990 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "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() throw () +{ + OResultSetBase::acquire(); +} + +void OResultSet::release() throw () +{ + 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 +{ + BEGIN_PROPERTY_HELPER(6) + DECL_PROP1(CURSORNAME, OUString, READONLY); + DECL_PROP0(FETCHDIRECTION, sal_Int32); + DECL_PROP0(FETCHSIZE, sal_Int32); + DECL_PROP1_BOOL(ISBOOKMARKABLE, READONLY); + DECL_PROP1(RESULTSETCONCURRENCY, sal_Int32, READONLY); + DECL_PROP1(RESULTSETTYPE, sal_Int32, READONLY); + END_PROPERTY_HELPER(); +} + +// 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); + ODataColumn* pColumn = new ODataColumn(xMetaData, m_xDelegatorRow, m_xDelegatorRowUpdate, i + 1, xDBMetaData); + + // don't silently assume that the name is unique - result set implementations + // are allowed to return duplicate names, but we are required to have + // unique column names + if ( m_pColumns->hasByName( sName ) ) + sName = ::dbtools::createUniqueName( m_pColumns.get(), sName ); + + m_pColumns->append( sName, pColumn ); + } + } + catch ( const SQLException& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_pColumns->setInitialized(); + + #if OSL_DEBUG_LEVEL > 0 + // some sanity checks. Especially in case we auto-adjusted the column names above, + // this might be reasonable + try + { + const Reference< XNameAccess > xColNames( static_cast< XNameAccess* >( m_pColumns.get() ), UNO_SET_THROW ); + const Sequence< OUString > aNames( xColNames->getElementNames() ); + SAL_WARN_IF( aNames.getLength() != nColCount, "dbaccess", + "OResultSet::getColumns: invalid column count!" ); + for ( auto const & name : aNames ) + { + Reference< XPropertySet > xColProps( xColNames->getByName( name ), UNO_QUERY_THROW ); + OUString sName; + OSL_VERIFY( xColProps->getPropertyValue( PROPERTY_NAME ) >>= sName ); + SAL_WARN_IF( sName != name, "dbaccess", "OResultSet::getColumns: invalid column name!" ); + } + + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + #endif + } + return m_pColumns.get(); +} + +// css::sdbc::XRow +sal_Bool OResultSet::wasNull() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->wasNull(); +} + +OUString OResultSet::getString(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getString(columnIndex); +} + +sal_Bool OResultSet::getBoolean(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getBoolean(columnIndex); +} + +sal_Int8 OResultSet::getByte(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getByte(columnIndex); +} + +sal_Int16 OResultSet::getShort(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getShort(columnIndex); +} + +sal_Int32 OResultSet::getInt(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getInt(columnIndex); +} + +sal_Int64 OResultSet::getLong(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getLong(columnIndex); +} + +float OResultSet::getFloat(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getFloat(columnIndex); +} + +double OResultSet::getDouble(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getDouble(columnIndex); +} + +Sequence< sal_Int8 > OResultSet::getBytes(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getBytes(columnIndex); +} + +css::util::Date OResultSet::getDate(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getDate(columnIndex); +} + +css::util::Time OResultSet::getTime(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getTime(columnIndex); +} + +css::util::DateTime OResultSet::getTimestamp(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getTimestamp(columnIndex); +} + +Reference< css::io::XInputStream > OResultSet::getBinaryStream(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getBinaryStream(columnIndex); +} + +Reference< css::io::XInputStream > OResultSet::getCharacterStream(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getCharacterStream(columnIndex); +} + +Any OResultSet::getObject(sal_Int32 columnIndex, const Reference< css::container::XNameAccess > & typeMap) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getObject(columnIndex, typeMap); +} + +Reference< XRef > OResultSet::getRef(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getRef(columnIndex); +} + +Reference< XBlob > OResultSet::getBlob(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getBlob(columnIndex); +} + +Reference< XClob > OResultSet::getClob(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getClob(columnIndex); +} + +Reference< XArray > OResultSet::getArray(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorRow->getArray(columnIndex); +} + +// css::sdbc::XRowUpdate +void OResultSet::updateNull(sal_Int32 columnIndex) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateNull(columnIndex); +} + +void OResultSet::updateBoolean(sal_Int32 columnIndex, sal_Bool x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateBoolean(columnIndex, x); +} + +void OResultSet::updateByte(sal_Int32 columnIndex, sal_Int8 x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateByte(columnIndex, x); +} + +void OResultSet::updateShort(sal_Int32 columnIndex, sal_Int16 x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateShort(columnIndex, x); +} + +void OResultSet::updateInt(sal_Int32 columnIndex, sal_Int32 x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateInt(columnIndex, x); +} + +void OResultSet::updateLong(sal_Int32 columnIndex, sal_Int64 x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateLong(columnIndex, x); +} + +void OResultSet::updateFloat(sal_Int32 columnIndex, float x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateFloat(columnIndex, x); +} + +void OResultSet::updateDouble(sal_Int32 columnIndex, double x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateDouble(columnIndex, x); +} + +void OResultSet::updateString(sal_Int32 columnIndex, const OUString& x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateString(columnIndex, x); +} + +void OResultSet::updateBytes(sal_Int32 columnIndex, const Sequence< sal_Int8 >& x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateBytes(columnIndex, x); +} + +void OResultSet::updateDate(sal_Int32 columnIndex, const css::util::Date& x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateDate(columnIndex, x); +} + +void OResultSet::updateTime(sal_Int32 columnIndex, const css::util::Time& x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateTime(columnIndex, x); +} + +void OResultSet::updateTimestamp(sal_Int32 columnIndex, const css::util::DateTime& x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateTimestamp(columnIndex, x); +} + +void OResultSet::updateBinaryStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream > & x, sal_Int32 length) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateBinaryStream(columnIndex, x, length); +} + +void OResultSet::updateCharacterStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream > & x, sal_Int32 length) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateCharacterStream(columnIndex, x, length); +} + +void OResultSet::updateNumericObject(sal_Int32 columnIndex, const Any& x, sal_Int32 scale) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateNumericObject(columnIndex, x, scale); +} + +void OResultSet::updateObject(sal_Int32 columnIndex, const Any& x) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorRowUpdate->updateObject(columnIndex, x); +} + +// css::sdbc::XResultSet +sal_Bool OResultSet::next() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->next(); +} + +sal_Bool OResultSet::isBeforeFirst() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->isBeforeFirst(); +} + +sal_Bool OResultSet::isAfterLast() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->isAfterLast(); +} + +sal_Bool OResultSet::isFirst() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->isFirst(); +} + +sal_Bool OResultSet::isLast() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->isLast(); +} + +void OResultSet::beforeFirst() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + m_xDelegatorResultSet->beforeFirst(); +} + +void OResultSet::afterLast() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + m_xDelegatorResultSet->afterLast(); +} + +sal_Bool OResultSet::first() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->first(); +} + +sal_Bool OResultSet::last() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->last(); +} + +sal_Int32 OResultSet::getRow() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->getRow(); +} + +sal_Bool OResultSet::absolute(sal_Int32 row) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->absolute(row); +} + +sal_Bool OResultSet::relative(sal_Int32 rows) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->relative(rows); +} + +sal_Bool OResultSet::previous() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->previous(); +} + +void OResultSet::refreshRow() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + m_xDelegatorResultSet->refreshRow(); +} + +sal_Bool OResultSet::rowUpdated() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->rowUpdated(); +} + +sal_Bool OResultSet::rowInserted() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->rowInserted(); +} + +sal_Bool OResultSet::rowDeleted() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_xDelegatorResultSet->rowDeleted(); +} + +Reference< XInterface > OResultSet::getStatement() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + return m_aStatement; +} + +// css::sdbcx::XRowLocate +Any OResultSet::getBookmark() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkBookmarkable(); + + return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->getBookmark(); +} + +sal_Bool OResultSet::moveToBookmark(const Any& bookmark) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkBookmarkable(); + + return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->moveToBookmark(bookmark); +} + +sal_Bool OResultSet::moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkBookmarkable(); + + return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->moveRelativeToBookmark(bookmark, rows); +} + +sal_Int32 OResultSet::compareBookmarks(const Any& _first, const Any& _second) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkBookmarkable(); + + return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->compareBookmarks(_first, _second); +} + +sal_Bool OResultSet::hasOrderedBookmarks() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkBookmarkable(); + + return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->hasOrderedBookmarks(); +} + +sal_Int32 OResultSet::hashBookmark(const Any& bookmark) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkBookmarkable(); + + return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->hashBookmark(bookmark); +} + +// css::sdbc::XResultSetUpdate +void OResultSet::insertRow() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorResultSetUpdate->insertRow(); +} + +void OResultSet::updateRow() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorResultSetUpdate->updateRow(); +} + +void OResultSet::deleteRow() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorResultSetUpdate->deleteRow(); +} + +void OResultSet::cancelRowUpdates() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorResultSetUpdate->cancelRowUpdates(); +} + +void OResultSet::moveToInsertRow() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorResultSetUpdate->moveToInsertRow(); +} + +void OResultSet::moveToCurrentRow() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed); + + checkReadOnly(); + + m_xDelegatorResultSetUpdate->moveToCurrentRow(); +} + +void OResultSet::checkReadOnly() const +{ + if ( ( m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY ) + || !m_xDelegatorResultSetUpdate.is() + ) + throwSQLException( "The result set is read-only.", StandardSQLState::GENERAL_ERROR, *const_cast< OResultSet* >( this ) ); +} + +void OResultSet::checkBookmarkable() const +{ + if ( !m_bIsBookmarkable ) + throwSQLException( "The result set does not have bookmark support.", StandardSQLState::GENERAL_ERROR, *const_cast< OResultSet* >( this ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/resultset.hxx b/dbaccess/source/core/api/resultset.hxx new file mode 100644 index 000000000..34f13a14d --- /dev/null +++ b/dbaccess/source/core/api/resultset.hxx @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_API_RESULTSET_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_API_RESULTSET_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::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() throw() override; + virtual void SAL_CALL release() throw() 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_API_RESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/statement.cxx b/dbaccess/source/core/api/statement.cxx new file mode 100644 index 000000000..812d91c64 --- /dev/null +++ b/dbaccess/source/core/api/statement.cxx @@ -0,0 +1,586 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "resultset.hxx" +#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(OComponentHelper::rBHelper) + ,m_bUseBookmarks( false ) + ,m_bEscapeProcessing( true ) + +{ + OSL_ENSURE(_xStatement.is() ,"Statement is NULL!"); + m_xAggregateAsSet.set(_xStatement,UNO_QUERY); + m_xAggregateAsCancellable.set(m_xAggregateAsSet, UNO_QUERY); +} + +OStatementBase::~OStatementBase() +{ +} + +// css::lang::XTypeProvider +Sequence< Type > OStatementBase::getTypes() +{ + OTypeCollection aTypes(cppu::UnoType::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() throw () +{ + OSubComponent::acquire(); +} + +void OStatementBase::release() throw () +{ + 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 = nullptr; +} + +// OComponentHelper +void OStatementBase::disposing() +{ + OPropertySetHelper::disposing(); + + MutexGuard aGuard(m_aMutex); + + // free pending results + disposeResultSet(); + + // free the original statement + { + MutexGuard aCancelGuard(m_aCancelMutex); + m_xAggregateAsCancellable = nullptr; + } + + if ( m_xAggregateAsSet.is() ) + { + try + { + Reference< XCloseable > (m_xAggregateAsSet, UNO_QUERY_THROW)->close(); + } + catch(RuntimeException& ) + {// don't care for anymore + } + } + m_xAggregateAsSet = nullptr; + + // free the parent at last + OSubComponent::disposing(); +} + +// XCloseable +void OStatementBase::close() +{ + { + MutexGuard aGuard( m_aMutex ); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + } + dispose(); +} + +// OPropertySetHelper +Reference< XPropertySetInfo > OStatementBase::getPropertySetInfo() +{ + return createPropertySetInfo( getInfoHelper() ) ; +} + +// comphelper::OPropertyArrayUsageHelper +::cppu::IPropertyArrayHelper* OStatementBase::createArrayHelper( ) const +{ + BEGIN_PROPERTY_HELPER(10) + DECL_PROP0(CURSORNAME, OUString); + DECL_PROP0_BOOL(ESCAPE_PROCESSING); + DECL_PROP0(FETCHDIRECTION, sal_Int32); + DECL_PROP0(FETCHSIZE, sal_Int32); + DECL_PROP0(MAXFIELDSIZE, sal_Int32); + DECL_PROP0(MAXROWS, sal_Int32); + DECL_PROP0(QUERYTIMEOUT, sal_Int32); + DECL_PROP0(RESULTSETCONCURRENCY, sal_Int32); + DECL_PROP0(RESULTSETTYPE, sal_Int32); + DECL_PROP0_BOOL(USEBOOKMARKS); + END_PROPERTY_HELPER(); +} + +// cppu::OPropertySetHelper +::cppu::IPropertyArrayHelper& OStatementBase::getInfoHelper() +{ + return *getArrayHelper(); +} + +sal_Bool OStatementBase::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) +{ + bool bModified(false); + switch (nHandle) + { + case PROPERTY_ID_USEBOOKMARKS: + bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bUseBookmarks ); + break; + + case PROPERTY_ID_ESCAPE_PROCESSING: + bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bEscapeProcessing ); + break; + + default: + if ( m_xAggregateAsSet.is() ) + { + // get the property name + OUString sPropName; + getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle ); + + // now set the value + Any aCurrentValue = m_xAggregateAsSet->getPropertyValue( sPropName ); + if ( aCurrentValue != rValue ) + { + rOldValue = aCurrentValue; + rConvertedValue = rValue; + bModified = true; + } + } + break; + } + return bModified; +} + +void OStatementBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) +{ + switch ( nHandle ) + { + case PROPERTY_ID_USEBOOKMARKS: + { + m_bUseBookmarks = ::comphelper::getBOOL( rValue ); + if ( m_xAggregateAsSet.is() && m_xAggregateAsSet->getPropertySetInfo()->hasPropertyByName( PROPERTY_USEBOOKMARKS ) ) + m_xAggregateAsSet->setPropertyValue( PROPERTY_USEBOOKMARKS, rValue ); + } + break; + + case PROPERTY_ID_ESCAPE_PROCESSING: + m_bEscapeProcessing = ::comphelper::getBOOL( rValue ); + if ( m_xAggregateAsSet.is() ) + m_xAggregateAsSet->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, rValue ); + break; + + default: + if ( m_xAggregateAsSet.is() ) + { + OUString sPropName; + getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle ); + m_xAggregateAsSet->setPropertyValue( sPropName, rValue ); + } + break; + } +} + +void OStatementBase::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const +{ + switch (nHandle) + { + case PROPERTY_ID_USEBOOKMARKS: + rValue <<= m_bUseBookmarks; + break; + + case PROPERTY_ID_ESCAPE_PROCESSING: + // don't rely on our aggregate - if it implements this wrong, and always returns + // TRUE here, then we would loop in impl_doEscapeProcessing_nothrow + rValue <<= m_bEscapeProcessing; + break; + + default: + if ( m_xAggregateAsSet.is() ) + { + OUString sPropName; + const_cast< OStatementBase* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle ); + rValue = m_xAggregateAsSet->getPropertyValue( sPropName ); + } + break; + } +} + +// XWarningsSupplier +Any OStatementBase::getWarnings() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + return Reference< XWarningsSupplier >(m_xAggregateAsSet, UNO_QUERY_THROW)->getWarnings(); +} + +void OStatementBase::clearWarnings() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + Reference< XWarningsSupplier >(m_xAggregateAsSet, UNO_QUERY_THROW)->clearWarnings(); +} + +// css::util::XCancellable +void OStatementBase::cancel() +{ + // no blocking as cancel is typically called from a different thread + MutexGuard aCancelGuard(m_aCancelMutex); + if (m_xAggregateAsCancellable.is()) + m_xAggregateAsCancellable->cancel(); + // else do nothing +} + +// XMultipleResults +Reference< XResultSet > SAL_CALL OStatementBase::getResultSet( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + // first check the meta data + Reference xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData(); + if (!xMeta.is() || !xMeta->supportsMultipleResultSets()) + throwFunctionSequenceException(*this); + + return Reference< XMultipleResults >(m_xAggregateAsSet, UNO_QUERY_THROW)->getResultSet(); +} + +sal_Int32 SAL_CALL OStatementBase::getUpdateCount( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + // first check the meta data + Reference xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData(); + if (!xMeta.is() || !xMeta->supportsMultipleResultSets()) + throwFunctionSequenceException(*this); + + return Reference< XMultipleResults >(m_xAggregateAsSet, UNO_QUERY_THROW)->getUpdateCount(); +} + +sal_Bool SAL_CALL OStatementBase::getMoreResults( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + // first check the meta data + Reference xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData(); + if (!xMeta.is() || !xMeta->supportsMultipleResultSets()) + throwFunctionSequenceException(*this); + + // free the previous results + disposeResultSet(); + + return Reference< XMultipleResults >(m_xAggregateAsSet, UNO_QUERY_THROW)->getMoreResults(); +} + +// XPreparedBatchExecution +void SAL_CALL OStatementBase::addBatch( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + // first check the meta data + Reference xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData(); + if (!xMeta.is() || !xMeta->supportsBatchUpdates()) + throwFunctionSequenceException(*this); + + Reference< XPreparedBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->addBatch(); +} + +void SAL_CALL OStatementBase::clearBatch( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + // first check the meta data + Reference xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData(); + if (!xMeta.is() || !xMeta->supportsBatchUpdates()) + throwFunctionSequenceException(*this); + + Reference< XPreparedBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->clearBatch(); +} + +Sequence< sal_Int32 > SAL_CALL OStatementBase::executeBatch( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + // first check the meta data + Reference xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData(); + if (!xMeta.is() || !xMeta->supportsBatchUpdates()) + throwFunctionSequenceException(*this); + + // free the previous results + disposeResultSet(); + + return Reference< XPreparedBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->executeBatch(); +} + +Reference< XResultSet > SAL_CALL OStatementBase::getGeneratedValues( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + Reference< XGeneratedResultSet > xGRes(m_xAggregateAsSet, UNO_QUERY); + + if ( xGRes.is() ) + return xGRes->getGeneratedValues( ); + return Reference< XResultSet >(); +} + + +// OStatement + +OStatement::OStatement( const Reference< XConnection >& _xConn, const Reference< XInterface > & _xStatement ) + :OStatementBase( _xConn, _xStatement ) + ,m_bAttemptedComposerCreation( false ) +{ + m_xAggregateStatement.set( _xStatement, UNO_QUERY_THROW ); +} + +IMPLEMENT_FORWARD_XINTERFACE2( OStatement, OStatementBase, OStatement_IFACE ); +IMPLEMENT_FORWARD_XTYPEPROVIDER2( OStatement, OStatementBase, OStatement_IFACE ); + +// XServiceInfo +OUString OStatement::getImplementationName( ) +{ + return "com.sun.star.sdb.OStatement"; +} + +sal_Bool OStatement::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > OStatement::getSupportedServiceNames( ) +{ + return { SERVICE_SDBC_STATEMENT }; +} + +// XStatement +Reference< XResultSet > OStatement::executeQuery( const OUString& _rSQL ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + disposeResultSet(); + Reference< XResultSet > xResultSet; + + OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) ); + + Reference< XResultSet > xInnerResultSet = m_xAggregateStatement->executeQuery( sSQL ); + Reference< XConnection > xConnection( m_xParent, UNO_QUERY_THROW ); + + if ( xInnerResultSet.is() ) + { + Reference< XDatabaseMetaData > xMeta = xConnection->getMetaData(); + bool bCaseSensitive = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(); + xResultSet = new OResultSet( xInnerResultSet, *this, bCaseSensitive ); + + // keep the resultset weak + m_aResultSet = xResultSet; + } + + return xResultSet; +} + +sal_Int32 OStatement::executeUpdate( const OUString& _rSQL ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + disposeResultSet(); + + OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) ); + return m_xAggregateStatement->executeUpdate( sSQL ); +} + +sal_Bool OStatement::execute( const OUString& _rSQL ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + disposeResultSet(); + + OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) ); + return m_xAggregateStatement->execute( sSQL ); +} + +void OStatement::addBatch( const OUString& _rSQL ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + + // first check the meta data + Reference xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData(); + if (!xMeta.is() || !xMeta->supportsBatchUpdates()) + throwFunctionSequenceException(*this); + + OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) ); + Reference< XBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->addBatch( sSQL ); +} + +void OStatement::clearBatch( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + // first check the meta data + Reference xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData(); + if (!xMeta.is() || !xMeta->supportsBatchUpdates()) + throwFunctionSequenceException(*this); + + Reference< XBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->clearBatch(); +} + +Sequence< sal_Int32 > OStatement::executeBatch( ) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed); + // first check the meta data + Reference xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData(); + if (!xMeta.is() || !xMeta->supportsBatchUpdates()) + throwFunctionSequenceException(*this); + return Reference< XBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->executeBatch( ); +} + + +Reference< XConnection > OStatement::getConnection() +{ + return Reference< XConnection >( m_xParent, UNO_QUERY ); +} + +void SAL_CALL OStatement::disposing() +{ + OStatementBase::disposing(); + m_xComposer.clear(); + m_xAggregateStatement.clear(); +} + +OUString OStatement::impl_doEscapeProcessing_nothrow( const OUString& _rSQL ) const +{ + if ( !m_bEscapeProcessing ) + return _rSQL; + try + { + if ( !impl_ensureComposer_nothrow() ) + return _rSQL; + + bool bParseable = false; + try { m_xComposer->setQuery( _rSQL ); bParseable = true; } + catch( const SQLException& ) { } + + if ( !bParseable ) + // if we cannot parse it, silently accept this. The driver is probably able to cope with it then + return _rSQL; + + OUString sLowLevelSQL = m_xComposer->getQueryWithSubstitution(); + return sLowLevelSQL; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return _rSQL; +} + +bool OStatement::impl_ensureComposer_nothrow() const +{ + if ( m_bAttemptedComposerCreation ) + return m_xComposer.is(); + + const_cast< OStatement* >( this )->m_bAttemptedComposerCreation = true; + try + { + Reference< XMultiServiceFactory > xFactory( m_xParent, UNO_QUERY_THROW ); + const_cast< OStatement* >( this )->m_xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return m_xComposer.is(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/table.cxx b/dbaccess/source/core/api/table.cxx new file mode 100644 index 000000000..d9b8f4484 --- /dev/null +++ b/dbaccess/source/core/api/table.cxx @@ -0,0 +1,347 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include "CIndexes.hxx" + +#include +#include +#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() +{ +} + +OColumn* ODBTable::createColumn(const OUString& _rName) const +{ + OColumn* pReturn = nullptr; + + 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 xColumnDefintion; + if ( m_xColumnDefinitions.is() && m_xColumnDefinitions->hasByName(_rName) ) + xColumnDefintion.set(m_xColumnDefinitions->getByName(_rName),UNO_QUERY); + pReturn = new OTableColumnWrapper( xProp, xColumnDefintion, false ); + + return pReturn; +} + +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 : 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 +IMPLEMENT_SERVICE_INFO1(ODBTable, "com.sun.star.sdb.dbaccess.ODBTable", 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(); +} + +sal_Int64 SAL_CALL ODBTable::getSomething( const Sequence< sal_Int8 >& rId ) +{ + sal_Int64 nRet(0); + if (isUnoTunnelId(rId)) + nRet = reinterpret_cast(this); + else + nRet = OTable_Base::getSomething(rId); + + return nRet; +} + +Sequence< sal_Int8 > ODBTable::getUnoTunnelId() +{ + static ::cppu::OImplementationId s_Id; + + return s_Id.getImplementationId(); +} + +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 000000000..bc32774fd --- /dev/null +++ b/dbaccess/source/core/api/tablecontainer.cxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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.is() ) + { + 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&) + { + SAL_WARN("dbaccess", "lcl_isPropertySetDefaulted: Exception caught!" ); + } + } + return ( pIter == pEnd ); + } + return false; + } +} + +// 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 +IMPLEMENT_SERVICE_INFO2(OTableContainer, "com.sun.star.sdb.dbaccess.OTableContainer", SERVICE_SDBCX_CONTAINER, SERVICE_SDBCX_TABLES) + +namespace +{ +void lcl_createDefintionObject(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,makeAny(_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_createDefintionObject(_rName,m_xTableDefinitions,xTableDefinition,xColumnDefinitions); + + if ( xSup.is() ) + { + ODBTableDecorator* pTable = new ODBTableDecorator( m_xConnection, xSup, ::dbtools::getNumberFormats( m_xConnection ) ,xColumnDefinitions); + xRet = pTable; + pTable->construct(); + } + else + { + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_xMetaData, + _rName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + Any aCatalog; + if(!sCatalog.isEmpty()) + aCatalog <<= sCatalog; + OUString sType,sDescription; + Sequence< OUString> aTypeFilter; + getAllTableTypeFilter( aTypeFilter ); + + Reference< XResultSet > xRes; + if ( m_xMetaData.is() ) + xRes = m_xMetaData->getTables(aCatalog,sSchema,sTable,aTypeFilter); + if(xRes.is() && xRes->next()) + { + Reference< XRow > xRow(xRes,UNO_QUERY); + if(xRow.is()) + { + sType = xRow->getString(4); + sDescription = xRow->getString(5); + } + } + ::comphelper::disposeComponent(xRes); + ODBTable* 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.get() ); + 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 ); + ODBTableDecorator* pTable = new ODBTableDecorator( m_xConnection, xMasterColumnsSup, ::dbtools::getNumberFormats( m_xConnection ) ,nullptr); + xRet = pTable; + pTable->construct(); + } + else + { + ODBTable* pTable = new ODBTable(this, m_xConnection); + xRet = pTable; + pTable->construct(); + } + return xRet; +} + +// XAppend +ObjectType OTableContainer::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor ) +{ + // append the new table with a create stmt + OUString aName = getString(descriptor->getPropertyValue(PROPERTY_NAME)); + if(m_xMasterContainer.is() && m_xMasterContainer->hasByName(aName)) + { + OUString sMessage(DBA_RES(RID_STR_TABLE_IS_FILTERED)); + throw SQLException(sMessage.replaceAll("$name$", aName),static_cast(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_createDefintionObject(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 sCatalog,sSchema,sTable,sComposedName; + + bool bIsView = false; + Reference xTable(getObject(_nPos),UNO_QUERY); + if ( xTable.is() && m_xMetaData.is() ) + { + 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), makeAny(sName), makeAny(xName), Any()); + m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent ); + } + } +} + +void SAL_CALL OTableContainer::elementRemoved( const ContainerEvent& /*Event*/ ) +{ +} + +void SAL_CALL OTableContainer::elementReplaced( const ContainerEvent& Event ) +{ + // create a new config entry + OUString sOldComposedName,sNewComposedName; + Event.ReplacedElement >>= sOldComposedName; + Event.Accessor >>= sNewComposedName; + + renameObject(sOldComposedName,sNewComposedName); +} + +void OTableContainer::disposing() +{ + OFilteredContainer::disposing(); + // say goodbye to our listeners + m_xTableDefinitions = nullptr; + m_pTableMediator = nullptr; +} + +void SAL_CALL OTableContainer::disposing( const css::lang::EventObject& /*Source*/ ) +{ +} + +void OTableContainer::addMasterContainerListener() +{ + try + { + Reference< XContainer > xCont( m_xMasterContainer, UNO_QUERY_THROW ); + xCont->addContainerListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/api/viewcontainer.cxx b/dbaccess/source/core/api/viewcontainer.cxx new file mode 100644 index 000000000..690df7139 --- /dev/null +++ b/dbaccess/source/core/api/viewcontainer.cxx @@ -0,0 +1,236 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 +IMPLEMENT_SERVICE_INFO2(OViewContainer, "com.sun.star.sdb.dbaccess.OViewContainer", 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 sCatalog,sSchema,sTable,sComposedName; + + Reference xTable(getObject(_nPos),UNO_QUERY); + if ( xTable.is() ) + { + 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 000000000..a6110bdb2 --- /dev/null +++ b/dbaccess/source/core/dataaccess/ComponentDefinition.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 "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(); +} + +IMPLEMENT_GETTYPES3(OComponentDefinition,ODataSettings,OContentHelper,OComponentDefinition_BASE); +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(); +} + +OColumn* OComponentDefinition::createColumn(const OUString& _rName) const +{ + const OComponentDefinition_Impl& rDefinition( getDefinition() ); + OComponentDefinition_Impl::const_iterator aFind = rDefinition.find( _rName ); + if ( aFind != rDefinition.end() ) + { + aFind->second->addPropertyChangeListener(OUString(),m_xColumnPropertyListener.get()); + 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 000000000..02e40390e --- /dev/null +++ b/dbaccess/source/core/dataaccess/ComponentDefinition.hxx @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_COMPONENTDEFINITION_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_COMPONENTDEFINITION_HXX + +#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 OColumn* createColumn(const OUString& _rName) const override; + virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override; + virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override; + virtual void columnDropped(const OUString& _sName) override; + using OContentHelper::notifyDataSourceModified; + +protected: +// OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue) override; + + // OContentHelper overridables + virtual OUString determineContentType() const override; + +private: + void registerProperties(); +}; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_COMPONENTDEFINITION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/ContentHelper.cxx b/dbaccess/source/core/dataaccess/ContentHelper.cxx new file mode 100644 index 000000000..7ad1d22ba --- /dev/null +++ b/dbaccess/source/core/dataaccess/ContentHelper.cxx @@ -0,0 +1,610 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 + ,const TContentPtr& _pImpl) + : OContentHelper_COMPBASE(m_aMutex) + ,m_aContentListeners(m_aMutex) + ,m_aPropertyChangeListeners(m_aMutex) + ,m_xParentContainer( _xParentContainer ) + ,m_aContext( _xORB ) + ,m_pImpl(_pImpl) + ,m_nCommandId(0) +{ +} + +void SAL_CALL OContentHelper::disposing() +{ + ::osl::MutexGuard aGuard(m_aMutex); + + // say goodbye to our listeners + EventObject aEvt(*this); + m_aContentListeners.disposeAndClear(aEvt); + + m_xParentContainer = nullptr; +} + +IMPLEMENT_SERVICE_INFO1(OContentHelper,"com.sun.star.comp.sdb.Content","com.sun.star.ucb.Content"); + +css::uno::Sequence OContentHelper::getUnoTunnelId() +{ + static cppu::OImplementationId aId; + return aId.getImplementationId(); +} + +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 ).append( "/" ).append( 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( + makeAny( 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( + makeAny( IllegalArgumentException( + OUString(), + static_cast< cppu::OWeakObject * >( this ), + -1 ) ), + Environment ); + // Unreachable + } + + if ( !aProperties.hasElements() ) + { + OSL_FAIL( "No properties!" ); + ucbhelper::cancelCommandExecution( + makeAny( 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( + makeAny( 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() ); + 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! + aRet[ 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& ) + { + OSL_FAIL( "OContentHelper::setPropertyValues('Title'): caught an exception while renaming!" ); + } + } + else + { + // Old value equals new value. No error! + } + } + else + { + aRet[ n ] <<= IllegalTypeException("Property value has wrong type!", + static_cast< cppu::OWeakObject * >( this ) ); + } + } + + else + { + aRet[ 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 Reference< XRow >( xRow.get() ); +} + +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. + OInterfaceContainerHelper* pAllPropsContainer = m_aPropertyChangeListeners.getContainer( OUString() ); + if ( pAllPropsContainer ) + { + OInterfaceIteratorHelper aIter( *pAllPropsContainer ); + while ( aIter.hasMoreElements() ) + { + // Propagate event. + Reference< XPropertiesChangeListener > xListener( aIter.next(), UNO_QUERY ); + if ( xListener.is() ) + xListener->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; + + OInterfaceContainerHelper* pPropsContainer = m_aPropertyChangeListeners.getContainer( rName ); + if ( pPropsContainer ) + { + OInterfaceIteratorHelper aIter( *pPropsContainer ); + while ( aIter.hasMoreElements() ) + { + Sequence< PropertyChangeEvent >* propertyEvents; + + XPropertiesChangeListener* pListener = static_cast< XPropertiesChangeListener * >( aIter.next() ); + 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)[n] = rEvent; + } + } + } + + // Notify listeners. + for (auto & rPair : aListeners) + { + XPropertiesChangeListener* pListener = rPair.first; + Sequence< PropertyChangeEvent >& rSeq = rPair.second; + + // Propagate event. + pListener->propertiesChange( rSeq ); + } +} + +// css::lang::XUnoTunnel +sal_Int64 OContentHelper::getSomething( const Sequence< sal_Int8 > & rId ) +{ + if (isUnoTunnelId(rId)) + return reinterpret_cast(this); + + return 0; +} + +Reference< XInterface > SAL_CALL OContentHelper::getParent( ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + return m_xParentContainer; +} + +void SAL_CALL OContentHelper::setParent( const Reference< XInterface >& _xParent ) +{ + ::osl::MutexGuard aGuard(m_aMutex); + m_xParentContainer = _xParent; +} + +void OContentHelper::impl_rename_throw(const OUString& _sNewName,bool _bNotify ) +{ + osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex); + if ( _sNewName == m_pImpl->m_aProps.aTitle ) + return; + try + { + Sequence< PropertyChangeEvent > aChanges( 1 ); + + aChanges[0].Source = static_cast< cppu::OWeakObject * >( this ); + aChanges[0].Further = false; + aChanges[0].PropertyName = PROPERTY_NAME; + aChanges[0].PropertyHandle = PROPERTY_ID_NAME; + aChanges[0].OldValue <<= m_pImpl->m_aProps.aTitle; + aChanges[0].NewValue <<= _sNewName; + + aGuard.clear(); + + m_pImpl->m_aProps.aTitle = _sNewName; + if ( _bNotify ) + notifyPropertiesChange( aChanges ); + notifyDataSourceModified(); + } + catch(const PropertyVetoException&) + { + throw ElementExistException(_sNewName,*this); + } +} + +void SAL_CALL OContentHelper::rename( const OUString& newName ) +{ + + impl_rename_throw(newName); + +} + +void OContentHelper::notifyDataSourceModified() +{ + ::dbaccess::notifyDataSourceModified(m_xParentContainer); +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/ModelImpl.cxx b/dbaccess/source/core/dataaccess/ModelImpl.cxx new file mode 100644 index 000000000..9aa56fe53 --- /dev/null +++ b/dbaccess/source/core/dataaccess/ModelImpl.cxx @@ -0,0 +1,1440 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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_xModel() + ,m_xDataSource() + ,m_aContainer(4) + ,m_aMacroMode( *this ) + ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE ) + ,m_rDBContext( _rDBContext ) + ,m_refCount(0) + ,m_aEmbeddedMacros() + ,m_bModificationLock( false ) + ,m_bDocumentInitialized( false ) + ,m_nScriptingSignatureState(SignatureState::UNKNOWN) + ,m_aContext( _rxContext ) + ,m_nLoginTimeout(0) + ,m_bReadOnly(false) + ,m_bPasswordRequired(false) + ,m_bSuppressVersionColumns(true) + ,m_bModified(false) + ,m_bDocumentReadOnly(false) + ,m_bMacroCallsSeenWhileLoading(false) + ,m_pSharedConnectionManager(nullptr) + ,m_nControllerLockCount(0) +{ + // some kind of default + m_sConnectURL = "jdbc:"; + m_aTableFilter.realloc(1); + m_aTableFilter[0] = "%"; + impl_construct_nothrow(); +} + +ODatabaseModelImpl::ODatabaseModelImpl( + const OUString& _rRegistrationName, + const Reference< XComponentContext >& _rxContext, + ODatabaseContext& _rDBContext + ) + :m_xModel() + ,m_xDataSource() + ,m_aContainer(4) + ,m_aMacroMode( *this ) + ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE ) + ,m_rDBContext( _rDBContext ) + ,m_refCount(0) + ,m_aEmbeddedMacros() + ,m_bModificationLock( false ) + ,m_bDocumentInitialized( false ) + ,m_nScriptingSignatureState(SignatureState::UNKNOWN) + ,m_aContext( _rxContext ) + ,m_sName(_rRegistrationName) + ,m_nLoginTimeout(0) + ,m_bReadOnly(false) + ,m_bPasswordRequired(false) + ,m_bSuppressVersionColumns(true) + ,m_bModified(false) + ,m_bDocumentReadOnly(false) + ,m_bMacroCallsSeenWhileLoading(false) + ,m_pSharedConnectionManager(nullptr) + ,m_nControllerLockCount(0) +{ + impl_construct_nothrow(); +} + +ODatabaseModelImpl::~ODatabaseModelImpl() +{ +} + +void ODatabaseModelImpl::impl_construct_nothrow() +{ + // create the property bag to hold the settings (also known as "Info" property) + try + { + // the set of property value types in the bag is limited: + Sequence< Type > aAllowedTypes({ + cppu::UnoType::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( makeAny( aProperty ) ); + } + else + { + xContainer->addProperty( + OUString::createFromAscii( pSettings->AsciiName ), + PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT, + pSettings->DefaultValue + ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_rDBContext.appendAtTerminateListener(*this); +} + +namespace +{ + OUString lcl_getContainerStorageName_throw( ODatabaseModelImpl::ObjectType _eType ) + { + const char* pAsciiName( nullptr ); + switch ( _eType ) + { + case ODatabaseModelImpl::E_FORM: pAsciiName = "forms"; break; + case ODatabaseModelImpl::E_REPORT: pAsciiName = "reports"; break; + case ODatabaseModelImpl::E_QUERY: pAsciiName = "queries"; break; + case ODatabaseModelImpl::E_TABLE: pAsciiName = "tables"; break; + default: + throw RuntimeException(); + } + return OUString::createFromAscii( pAsciiName ); + } + + bool lcl_hasObjectWithMacros_throw( const ODefinitionContainer_Impl& _rObjectDefinitions, const Reference< XStorage >& _rxContainerStorage ) + { + bool bSomeDocHasMacros = false; + + for (auto const& objectDefinition : _rObjectDefinitions) + { + const TContentPtr& rDefinition( objectDefinition.second ); + const OUString& rPersistentName( rDefinition->m_aProps.sPersistentName ); + + if ( rPersistentName.isEmpty() ) + { // it's a logical sub folder used to organize the real objects + const ODefinitionContainer_Impl& rSubFoldersObjectDefinitions( dynamic_cast< const ODefinitionContainer_Impl& >( *rDefinition ) ); + bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rSubFoldersObjectDefinitions, _rxContainerStorage ); + if (bSomeDocHasMacros) + break; + continue; + } + + bSomeDocHasMacros = ODatabaseModelImpl::objectHasMacros( _rxContainerStorage, rPersistentName ); + if (bSomeDocHasMacros) + break; + } + return bSomeDocHasMacros; + } + + bool lcl_hasObjectsWithMacros_nothrow( ODatabaseModelImpl& _rModel, const ODatabaseModelImpl::ObjectType _eType ) + { + bool bSomeDocHasMacros = false; + + const OContentHelper_Impl& rContainerData( *_rModel.getObjectContainer( _eType ) ); + const ODefinitionContainer_Impl& rObjectDefinitions = dynamic_cast< const ODefinitionContainer_Impl& >( rContainerData ); + + try + { + Reference< XStorage > xContainerStorage( _rModel.getStorage( _eType ) ); + // note the READWRITE here: If the storage already existed before, then the OpenMode will + // be ignored, anyway. + // If the storage did not yet exist, then it will be created. If the database document + // is read-only, the OpenMode will be automatically downgraded to READ. Otherwise, + // the storage will in fact be created as READWRITE. While this is not strictly necessary + // for this particular use case here, it is required since the storage is *cached*, and + // later use cases will need the READWRITE mode. + + if ( xContainerStorage.is() ) + bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rObjectDefinitions, xContainerStorage ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + // be on the safe side: If we can't reliably determine whether there are macros, + // assume there actually are. Better this way, than the other way round. + bSomeDocHasMacros = true; + } + + return bSomeDocHasMacros; + } +} + +bool ODatabaseModelImpl::objectHasMacros( const Reference< XStorage >& _rxContainerStorage, const OUString& _rPersistentName ) +{ + OSL_PRECOND( _rxContainerStorage.is(), "ODatabaseModelImpl::objectHasMacros: this will crash!" ); + + bool bHasMacros = true; + try + { + if ( !_rxContainerStorage->hasByName( _rPersistentName ) ) + return false; + + Reference< XStorage > xObjectStor( _rxContainerStorage->openStorageElement( + _rPersistentName, ElementModes::READ ) ); + + bHasMacros = ::sfx2::DocumentMacroMode::storageHasMacros( xObjectStor ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bHasMacros; +} + +void ODatabaseModelImpl::reset() +{ + m_bReadOnly = false; + std::vector< TContentPtr > aEmptyContainers( 4 ); + m_aContainer.swap( aEmptyContainers ); + + 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_pSharedConnectionManager = nullptr; + m_xSharedConnectionManager = nullptr; +} + +void ODatabaseModelImpl::dispose() +{ + // dispose the data source and the model + try + { + Reference< XDataSource > xDS( m_xDataSource ); + ::comphelper::disposeComponent( xDS ); + + Reference< XModel > xModel( m_xModel ); + ::comphelper::disposeComponent( xModel ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + m_xDataSource = WeakReference(); + m_xModel = WeakReference< XModel >(); + + for (auto const& elem : m_aContainer) + { + if ( elem ) + elem->m_pDataSource = nullptr; + } + m_aContainer.clear(); + + clearConnections(); + + m_xNumberFormatsSupplier = nullptr; + + try + { + bool bCouldStore = commitEmbeddedStorage( true ); + // "true" means that committing the embedded storage should not trigger committing the root + // storage. This is because we are going to commit the root storage ourself, anyway + disposeStorages(); + if ( bCouldStore ) + commitRootStorage(); + + impl_switchToStorage_throw( nullptr ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( m_pStorageAccess.is() ) + { + m_pStorageAccess->dispose(); + m_pStorageAccess.clear(); + } +} + +const Reference< XNumberFormatsSupplier > & ODatabaseModelImpl::getNumberFormatsSupplier() +{ + if (!m_xNumberFormatsSupplier.is()) + { + // the arguments : the work locale of the current user + Locale aLocale( LanguageTag::convertToLocale( utl::ConfigManager::getWorkLocale(), false)); + + m_xNumberFormatsSupplier.set( NumberFormatsSupplier::createWithLocale( m_aContext, aLocale ) ); + } + return m_xNumberFormatsSupplier; +} + +void ODatabaseModelImpl::setDocFileLocation( const OUString& i_rLoadedFrom ) +{ + ENSURE_OR_THROW( !i_rLoadedFrom.isEmpty(), "invalid URL" ); + m_sDocFileLocation = i_rLoadedFrom; +} + +void ODatabaseModelImpl::setResource( const OUString& i_rDocumentURL, const Sequence< PropertyValue >& _rArgs ) +{ + ENSURE_OR_THROW( !i_rDocumentURL.isEmpty(), "invalid URL" ); + + ::comphelper::NamedValueCollection aMediaDescriptor( _rArgs ); +#if OSL_DEBUG_LEVEL > 0 + if ( aMediaDescriptor.has( "SalvagedFile" ) ) + { + OUString sSalvagedFile( aMediaDescriptor.getOrDefault( "SalvagedFile", OUString() ) ); + // If SalvagedFile is an empty string, this indicates "the document is being recovered, but i_rDocumentURL already + // is the real document URL, not the temporary document location" + if ( sSalvagedFile.isEmpty() ) + sSalvagedFile = i_rDocumentURL; + + OSL_ENSURE( sSalvagedFile == i_rDocumentURL, "ODatabaseModelImpl::setResource: inconsistency!" ); + // nowadays, setResource should only be called with the logical URL of the document + } +#endif + + m_aMediaDescriptor = stripLoadArguments( aMediaDescriptor ); + + impl_switchToLogicalURL( i_rDocumentURL ); +} + +::comphelper::NamedValueCollection ODatabaseModelImpl::stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments ) +{ + OSL_ENSURE( !_rArguments.has( "Model" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (1)!" ); + OSL_ENSURE( !_rArguments.has( "ViewName" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (2)!" ); + + ::comphelper::NamedValueCollection aMutableArgs( _rArguments ); + aMutableArgs.remove( "Model" ); + aMutableArgs.remove( "ViewName" ); + return aMutableArgs; +} + +void ODatabaseModelImpl::disposeStorages() +{ + getDocumentStorageAccess()->disposeStorages(); +} + +Reference< XSingleServiceFactory > ODatabaseModelImpl::createStorageFactory() const +{ + return StorageFactory::create( m_aContext ); +} + +void ODatabaseModelImpl::commitRootStorage() +{ + Reference< XStorage > xStorage( getOrCreateRootStorage() ); + bool bSuccess = commitStorageIfWriteable_ignoreErrors( xStorage ); + SAL_WARN_IF(!bSuccess && xStorage.is(), "dbaccess", + "ODatabaseModelImpl::commitRootStorage: could not commit the storage!"); +} + +Reference< XStorage > const & ODatabaseModelImpl::getOrCreateRootStorage() +{ + if ( !m_xDocumentStorage.is() ) + { + Reference< XSingleServiceFactory> xStorageFactory = StorageFactory::create( m_aContext ); + Any aSource = m_aMediaDescriptor.get( "Stream" ); + if ( !aSource.hasValue() ) + aSource = m_aMediaDescriptor.get( "InputStream" ); + if ( !aSource.hasValue() && !m_sDocFileLocation.isEmpty() ) + aSource <<= m_sDocFileLocation; + // TODO: shouldn't we also check URL? + + OSL_ENSURE( aSource.hasValue(), "ODatabaseModelImpl::getOrCreateRootStorage: no source to create the storage from!" ); + + if ( aSource.hasValue() ) + { + Sequence< Any > aStorageCreationArgs(2); + aStorageCreationArgs[0] = aSource; + aStorageCreationArgs[1] <<= 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[1] <<= ElementModes::READ; + try + { + xDocumentStorage.set( xStorageFactory->createInstanceWithArguments( aStorageCreationArgs ), UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + + impl_switchToStorage_throw( xDocumentStorage ); + } + } + return m_xDocumentStorage.getTyped(); +} + +DocumentStorageAccess* ODatabaseModelImpl::getDocumentStorageAccess() +{ + if ( !m_pStorageAccess.is() ) + { + m_pStorageAccess = new DocumentStorageAccess( *this ); + } + return m_pStorageAccess.get(); +} + +void ODatabaseModelImpl::modelIsDisposing( const bool _wasInitialized, ResetModelAccess ) +{ + m_xModel.clear(); + + // Basic libraries and Dialog libraries are a model facet, though held at this impl class. + // They automatically dispose themself when the model they belong to is being disposed. + // So, to not be tempted to do anything with them, again, we reset them. + m_xBasicLibraries.clear(); + m_xDialogLibraries.clear(); + + m_bDocumentInitialized = _wasInitialized; +} + +Reference< XDocumentSubStorageSupplier > ODatabaseModelImpl::getDocumentSubStorageSupplier() +{ + return getDocumentStorageAccess(); +} + +bool ODatabaseModelImpl::commitEmbeddedStorage( bool _bPreventRootCommits ) +{ + return getDocumentStorageAccess()->commitEmbeddedStorage( _bPreventRootCommits ); +} + +bool ODatabaseModelImpl::commitStorageIfWriteable_ignoreErrors( const Reference< XStorage >& _rxStorage ) +{ + bool bTryToPreserveScriptSignature = false; + utl::TempFile aTempFile; + aTempFile.EnableKillingFile(); + OUString m_sTmpFileUrl = aTempFile.GetURL(); + SignatureState aSignatureState = getScriptingSignatureState(); + if (aSignatureState == SignatureState::OK + || aSignatureState == SignatureState::NOTVALIDATED + || aSignatureState == SignatureState::INVALID) + { + 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(getDocFileLocation(), m_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, m_sTmpFileUrl, ElementModes::READ); + if (!xReadOrig.is()) + throw uno::RuntimeException("Could not read " + m_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->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( makeAny( 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", makeAny( OUString() ) ), + AsciiPropertyValue( "JavaDriverClassPath", makeAny( OUString() ) ), + AsciiPropertyValue( "IgnoreCurrency", makeAny( false ) ), + // known settings for file-based drivers + AsciiPropertyValue( "Extension", makeAny( OUString() ) ), + AsciiPropertyValue( "CharSet", makeAny( OUString() ) ), + AsciiPropertyValue( "HeaderLine", makeAny( true ) ), + AsciiPropertyValue( "FieldDelimiter", makeAny( OUString( "," ) ) ), + AsciiPropertyValue( "StringDelimiter", makeAny( OUString( "\"" ) ) ), + AsciiPropertyValue( "DecimalDelimiter", makeAny( OUString( "." ) ) ), + AsciiPropertyValue( "ThousandDelimiter", makeAny( OUString() ) ), + AsciiPropertyValue( "ShowDeleted", makeAny( false ) ), + // known ODBC settings + AsciiPropertyValue( "SystemDriverSettings", makeAny( OUString() ) ), + AsciiPropertyValue( "UseCatalog", makeAny( false ) ), + AsciiPropertyValue( "TypeInfoSettings", makeAny( Sequence< Any >()) ), + // settings related to auto increment handling + AsciiPropertyValue( "AutoIncrementCreation", makeAny( OUString() ) ), + AsciiPropertyValue( "AutoRetrievingStatement", makeAny( OUString() ) ), + AsciiPropertyValue( "IsAutoRetrievingEnabled", makeAny( false ) ), + // known LDAP driver settings + AsciiPropertyValue( "HostName", makeAny( OUString() ) ), + AsciiPropertyValue( "PortNumber", makeAny( sal_Int32(389) ) ), + AsciiPropertyValue( "BaseDN", makeAny( OUString() ) ), + AsciiPropertyValue( "MaxRowCount", makeAny( sal_Int32(100) ) ), + // known MySQLNative driver settings + AsciiPropertyValue( "LocalSocket", makeAny( OUString() ) ), + AsciiPropertyValue( "NamedPipe", makeAny( OUString() ) ), + // misc known driver settings + AsciiPropertyValue( "ParameterNameSubstitution", makeAny( false ) ), + AsciiPropertyValue( "AddIndexAppendix", makeAny( true ) ), + AsciiPropertyValue( "IgnoreDriverPrivileges", makeAny( true ) ), + AsciiPropertyValue( "ImplicitCatalogRestriction", ::cppu::UnoType< OUString >::get() ), + AsciiPropertyValue( "ImplicitSchemaRestriction", ::cppu::UnoType< OUString >::get() ), + AsciiPropertyValue( "PrimaryKeySupport", ::cppu::UnoType< sal_Bool >::get() ), + AsciiPropertyValue( "ShowColumnDescription", makeAny( false ) ), + // known SDB level settings + AsciiPropertyValue( "NoNameLengthLimit", makeAny( false ) ), + AsciiPropertyValue( "AppendTableAliasName", makeAny( false ) ), + AsciiPropertyValue( "GenerateASBeforeCorrelationName", makeAny( false ) ), + AsciiPropertyValue( "ColumnAliasInOrderBy", makeAny( true ) ), + AsciiPropertyValue( "EnableSQL92Check", makeAny( false ) ), + AsciiPropertyValue( "BooleanComparisonMode", makeAny( BooleanComparisonMode::EQUAL_INTEGER ) ), + AsciiPropertyValue( "TableTypeFilterMode", makeAny( sal_Int32(3) ) ), + AsciiPropertyValue( "RespectDriverResultSetType", makeAny( false ) ), + AsciiPropertyValue( "UseSchemaInSelect", makeAny( true ) ), + AsciiPropertyValue( "UseCatalogInSelect", makeAny( true ) ), + AsciiPropertyValue( "EnableOuterJoinEscape", makeAny( true ) ), + AsciiPropertyValue( "PreferDosLikeLineEnds", makeAny( false ) ), + AsciiPropertyValue( "FormsCheckRequiredFields", makeAny( true ) ), + AsciiPropertyValue( "EscapeDateTime", makeAny( true ) ), + + // known services to handle database tasks + AsciiPropertyValue( "TableAlterationServiceName", makeAny( OUString() ) ), + AsciiPropertyValue( "TableRenameServiceName", makeAny( OUString() ) ), + AsciiPropertyValue( "ViewAlterationServiceName", makeAny( OUString() ) ), + AsciiPropertyValue( "ViewAccessServiceName", makeAny( OUString() ) ), + AsciiPropertyValue( "CommandDefinitions", makeAny( OUString() ) ), + AsciiPropertyValue( "Forms", makeAny( OUString() ) ), + AsciiPropertyValue( "Reports", makeAny( OUString() ) ), + AsciiPropertyValue( "KeyAlterationServiceName", makeAny( OUString() ) ), + AsciiPropertyValue( "IndexAlterationServiceName", makeAny( OUString() ) ), + + AsciiPropertyValue() + }; + return aKnownSettings; +} + +TContentPtr& ODatabaseModelImpl::getObjectContainer( ObjectType _eType ) +{ + OSL_PRECOND( _eType >= E_FORM && _eType <= E_TABLE, "ODatabaseModelImpl::getObjectContainer: illegal index!" ); + TContentPtr& rContentPtr = m_aContainer[ _eType ]; + + if ( !rContentPtr ) + { + rContentPtr = std::make_shared(); + rContentPtr->m_pDataSource = this; + rContentPtr->m_aProps.aTitle = lcl_getContainerStorageName_throw( _eType ); + } + return rContentPtr; +} + +bool ODatabaseModelImpl::adjustMacroMode_AutoReject() +{ + return m_aMacroMode.adjustMacroMode( nullptr ); +} + +bool ODatabaseModelImpl::checkMacrosOnLoading() +{ + Reference< XInteractionHandler > xInteraction; + xInteraction = m_aMediaDescriptor.getOrDefault( "InteractionHandler", xInteraction ); + return m_aMacroMode.checkMacrosOnLoading( xInteraction ); +} + +void ODatabaseModelImpl::resetMacroExecutionMode() +{ + m_aMacroMode = ::sfx2::DocumentMacroMode( *this ); +} + +Reference< XStorageBasedLibraryContainer > ODatabaseModelImpl::getLibraryContainer( bool _bScript ) +{ + Reference< XStorageBasedLibraryContainer >& rxContainer( _bScript ? m_xBasicLibraries : m_xDialogLibraries ); + if ( rxContainer.is() ) + return rxContainer; + + Reference< XStorageBasedDocument > xDocument( getModel_noCreate(), UNO_QUERY_THROW ); + // this is only to be called if there already exists a document model - in fact, it is + // to be called by the document model only + + try + { + Reference< XStorageBasedLibraryContainer > (*Factory)( const Reference< XComponentContext >&, const Reference< XStorageBasedDocument >&) + = _bScript ? &DocumentScriptLibraryContainer::create : &DocumentDialogLibraryContainer::create; + + rxContainer.set( + (*Factory)( m_aContext, xDocument ), + UNO_SET_THROW + ); + } + catch( const RuntimeException& ) + { + throw; + } + catch( const Exception& ) + { + throw WrappedTargetRuntimeException( + OUString(), + xDocument, + ::cppu::getCaughtException() + ); + } + return rxContainer; +} + +void ODatabaseModelImpl::storeLibraryContainersTo( const Reference< XStorage >& _rxToRootStorage ) +{ + if ( m_xBasicLibraries.is() ) + m_xBasicLibraries->storeLibrariesToStorage( _rxToRootStorage ); + + if ( m_xDialogLibraries.is() ) + m_xDialogLibraries->storeLibrariesToStorage( _rxToRootStorage ); +} + +Reference< XStorage > ODatabaseModelImpl::switchToStorage( const Reference< XStorage >& _rxNewRootStorage ) +{ + if ( !_rxNewRootStorage.is() ) + throw IllegalArgumentException(); + + return impl_switchToStorage_throw( _rxNewRootStorage ); +} + +namespace +{ + void lcl_modifyListening( ::sfx2::IModifiableDocument& _rDocument, + const Reference< XStorage >& _rxStorage, ::rtl::Reference< ::sfx2::DocumentStorageModifyListener >& _inout_rListener, + comphelper::SolarMutex& _rMutex, bool _bListen ) + { + Reference< XModifiable > xModify( _rxStorage, UNO_QUERY ); + OSL_ENSURE( xModify.is() || !_rxStorage.is(), "lcl_modifyListening: storage can't notify us!" ); + + if ( xModify.is() && !_bListen && _inout_rListener.is() ) + { + xModify->removeModifyListener( _inout_rListener.get() ); + } + + 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.get() ); + } + } +} + +namespace +{ + void lcl_rebaseScriptStorage_throw( const Reference< XStorageBasedLibraryContainer >& _rxContainer, + const Reference< XStorage >& _rxNewRootStorage ) + { + if ( _rxContainer.is() ) + { + if ( _rxNewRootStorage.is() ) + _rxContainer->setRootStorage( _rxNewRootStorage ); +// else + // TODO: what to do here? dispose the container? + } + } +} + +Reference< XStorage > const & ODatabaseModelImpl::impl_switchToStorage_throw( const Reference< XStorage >& _rxNewRootStorage ) +{ + // stop listening for modifications at the old storage + lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, Application::GetSolarMutex(), false ); + + // set new storage + m_xDocumentStorage.reset( _rxNewRootStorage, SharedStorage::TakeOwnership ); + + // start listening for modifications + lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, Application::GetSolarMutex(), true ); + + // forward new storage to Basic and Dialog library containers + lcl_rebaseScriptStorage_throw( m_xBasicLibraries, m_xDocumentStorage.getTyped() ); + lcl_rebaseScriptStorage_throw( m_xDialogLibraries, m_xDocumentStorage.getTyped() ); + + m_bReadOnly = !tools::stor::storageIsWritable_nothrow( m_xDocumentStorage.getTyped() ); + // TODO: our data source, if it exists, must broadcast the change of its ReadOnly property + + return m_xDocumentStorage.getTyped(); +} + +void ODatabaseModelImpl::impl_switchToLogicalURL( const OUString& i_rDocumentURL ) +{ + if ( i_rDocumentURL == m_sDocumentURL ) + return; + + const OUString sOldURL( m_sDocumentURL ); + // update our name, if necessary + if ( ( m_sName == m_sDocumentURL ) // our name is our old URL + || ( m_sName.isEmpty() ) // we do not have a name, yet (i.e. are not registered at the database context) + ) + { + INetURLObject aURL( i_rDocumentURL ); + if ( aURL.GetProtocol() != INetProtocol::NotValid ) + { + m_sName = i_rDocumentURL; + // TODO: our data source must broadcast the change of the Name property + } + } + + // remember URL + m_sDocumentURL = i_rDocumentURL; + + // update our location, if necessary + if ( m_sDocFileLocation.isEmpty() ) + m_sDocFileLocation = m_sDocumentURL; + + // register at the database context, or change registration + if (!sOldURL.isEmpty()) + m_rDBContext.databaseDocumentURLChange( sOldURL, m_sDocumentURL ); + else + m_rDBContext.registerDatabaseDocument( *this ); +} + +OUString ODatabaseModelImpl::getObjectContainerStorageName( const ObjectType _eType ) +{ + return lcl_getContainerStorageName_throw( _eType ); +} + +sal_Int16 ODatabaseModelImpl::getCurrentMacroExecMode() const +{ + sal_Int16 nCurrentMode = MacroExecMode::NEVER_EXECUTE; + try + { + nCurrentMode = m_aMediaDescriptor.getOrDefault( "MacroExecutionMode", nCurrentMode ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return nCurrentMode; +} + +void ODatabaseModelImpl::setCurrentMacroExecMode( sal_uInt16 nMacroMode ) +{ + m_aMediaDescriptor.put( "MacroExecutionMode", nMacroMode ); +} + +OUString ODatabaseModelImpl::getDocumentLocation() const +{ + return getURL(); + // formerly, we returned getDocFileLocation here, which is the location of the file from which we + // recovered the "real" document. + // However, during CWS autorecovery evolving, we clarified (with MAV/MT) the role of XModel::getURL and + // XStorable::getLocation. In this course, we agreed that for a macro security check, the *document URL* + // (not the recovery file URL) is to be used: The recovery file lies in the backup folder, and by definition, + // this folder is considered to be secure. So, the document URL needs to be used to decide about the security. +} + +ODatabaseModelImpl::EmbeddedMacros ODatabaseModelImpl::determineEmbeddedMacros() +{ + if ( !m_aEmbeddedMacros ) + { + if ( ::sfx2::DocumentMacroMode::storageHasMacros( getOrCreateRootStorage() ) ) + { + m_aEmbeddedMacros = eDocumentWideMacros; + } + else if ( lcl_hasObjectsWithMacros_nothrow( *this, E_FORM ) + || lcl_hasObjectsWithMacros_nothrow( *this, E_REPORT ) + ) + { + m_aEmbeddedMacros = eSubDocumentMacros; + } + else + { + m_aEmbeddedMacros = eNoMacros; + } + } + return *m_aEmbeddedMacros; +} + +bool ODatabaseModelImpl::documentStorageHasMacros() const +{ + const_cast< ODatabaseModelImpl* >( this )->determineEmbeddedMacros(); + return ( *m_aEmbeddedMacros != eNoMacros ); +} + +bool ODatabaseModelImpl::macroCallsSeenWhileLoading() const +{ + return m_bMacroCallsSeenWhileLoading; +} + +Reference< XEmbeddedScripts > ODatabaseModelImpl::getEmbeddedDocumentScripts() const +{ + return Reference< XEmbeddedScripts >( getModel_noCreate(), UNO_QUERY ); +} + +SignatureState ODatabaseModelImpl::getScriptingSignatureState() +{ + return m_nScriptingSignatureState; +} + +bool ODatabaseModelImpl::hasTrustedScriptingSignature(bool bAllowUIToAddAuthor) +{ + bool bResult = false; + + try + { + // Don't use m_xDocumentStorage, that somehow has an incomplete storage representation + // which leads to signatures not being found + Reference xStorage = 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)); + 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 && bAllowUIToAddAuthor) + { + Reference xInteraction; + xInteraction = m_aMediaDescriptor.getOrDefault("InteractionHandler", xInteraction); + if (xInteraction.is()) + { + task::DocumentMacroConfirmationRequest aRequest; + aRequest.DocumentURL = m_sDocFileLocation; + aRequest.DocumentStorage = xStorage; + aRequest.DocumentSignatureInformation = aInfo; + aRequest.DocumentVersion = aODFVersion; + aRequest.Classification = task::InteractionClassification_QUERY; + bResult = SfxMedium::CallApproveHandler(xInteraction, uno::makeAny(aRequest), true); + } + } + } + catch (uno::Exception&) + { + } + + return bResult; +} + +void ODatabaseModelImpl::storageIsModified() +{ + setModified( true ); +} + +ModelDependentComponent::ModelDependentComponent( const ::rtl::Reference< ODatabaseModelImpl >& _model ) + :m_pImpl( _model ) +{ +} + +ModelDependentComponent::~ModelDependentComponent() +{ +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/SharedConnection.cxx b/dbaccess/source/core/dataaccess/SharedConnection.cxx new file mode 100644 index 000000000..93bd17ff7 --- /dev/null +++ b/dbaccess/source/core/dataaccess/SharedConnection.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 "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< XAggregation >& _rxProxyConnection) + : OSharedConnection_BASE(m_aMutex) +{ + setDelegation(_rxProxyConnection,m_refCount); +} + +OSharedConnection::~OSharedConnection() +{ +} + +void SAL_CALL OSharedConnection::disposing() +{ + OSharedConnection_BASE::disposing(); + OConnectionWrapper::disposing(); +} + +Reference< XStatement > SAL_CALL OSharedConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->createStatement(); +} + +Reference< XPreparedStatement > SAL_CALL OSharedConnection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->prepareStatement(sql); +} + +Reference< XPreparedStatement > SAL_CALL OSharedConnection::prepareCall( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->prepareCall(sql); +} + +OUString SAL_CALL OSharedConnection::nativeSQL( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->nativeSQL(sql); +} + +sal_Bool SAL_CALL OSharedConnection::getAutoCommit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->getAutoCommit(); +} + +void SAL_CALL OSharedConnection::commit( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + m_xConnection->commit(); +} + +void SAL_CALL OSharedConnection::rollback( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + m_xConnection->rollback(); +} + +sal_Bool SAL_CALL OSharedConnection::isClosed( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xConnection.is() ) + return true; + + return m_xConnection->isClosed(); +} + +Reference< XDatabaseMetaData > SAL_CALL OSharedConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + + return m_xConnection->getMetaData(); +} + +sal_Bool SAL_CALL OSharedConnection::isReadOnly( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->isReadOnly(); +} + +OUString SAL_CALL OSharedConnection::getCatalog( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->getCatalog(); +} + +sal_Int32 SAL_CALL OSharedConnection::getTransactionIsolation( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->getTransactionIsolation(); +} + +Reference< css::container::XNameAccess > SAL_CALL OSharedConnection::getTypeMap( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(rBHelper.bDisposed); + + return m_xConnection->getTypeMap(); +} + +IMPLEMENT_GET_IMPLEMENTATION_ID( OSharedConnection ) + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/SharedConnection.hxx b/dbaccess/source/core/dataaccess/SharedConnection.hxx new file mode 100644 index 000000000..6121d3d37 --- /dev/null +++ b/dbaccess/source/core/dataaccess/SharedConnection.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_SHAREDCONNECTION_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_SHAREDCONNECTION_HXX + +#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; + typedef ::connectivity::OConnectionWrapper OSharedConnection_BASE2; + + class OSharedConnection : public ::cppu::BaseMutex + , public OSharedConnection_BASE + , public OSharedConnection_BASE2 + { + protected: + virtual void SAL_CALL disposing() override; + virtual ~OSharedConnection() override; + public: + explicit OSharedConnection(css::uno::Reference< css::uno::XAggregation >& _rxProxyConnection); + + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + virtual void SAL_CALL acquire() throw() override { OSharedConnection_BASE::acquire(); } + virtual void SAL_CALL release() throw() override { OSharedConnection_BASE::release(); } + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override + { + return ::comphelper::concatSequences( + OSharedConnection_BASE::getTypes(), + OSharedConnection_BASE2::getTypes() + ); + } + + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& _rType ) override + { + css::uno::Any aReturn = OSharedConnection_BASE::queryInterface(_rType); + if ( !aReturn.hasValue() ) + aReturn = OSharedConnection_BASE2::queryInterface(_rType); + return aReturn; + } + + // XCloseable + virtual void SAL_CALL close( ) override + { + { + ::osl::MutexGuard aGuard( m_aMutex ); + ::connectivity::checkDisposed(rBHelper.bDisposed); + } + dispose(); + } + + // XConnection + virtual void SAL_CALL setAutoCommit( sal_Bool /*autoCommit*/ ) override + { + throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any()); + } + virtual void SAL_CALL setReadOnly( sal_Bool /*readOnly*/ ) override + { + throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any()); + } + virtual void SAL_CALL setCatalog( const OUString& /*catalog*/ ) override + { + throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any()); + } + virtual void SAL_CALL setTransactionIsolation( sal_Int32 /*level*/ ) override + { + throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any()); + } + virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& /*typeMap*/ ) override + { + throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any()); + } + // XConnection + virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override; + virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override; + virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override; + virtual sal_Bool SAL_CALL getAutoCommit( ) override; + virtual void SAL_CALL commit( ) override; + virtual void SAL_CALL rollback( ) override; + virtual sal_Bool SAL_CALL isClosed( ) override; + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override; + virtual sal_Bool SAL_CALL isReadOnly( ) override; + virtual OUString SAL_CALL getCatalog( ) override; + virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override; + virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override; + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_SHAREDCONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx b/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx new file mode 100644 index 000000000..647aaf557 --- /dev/null +++ b/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx @@ -0,0 +1,307 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 ::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( ) throw() +{ + m_rParent.acquire(); +} + +void SAL_CALL OBookmarkContainer::release( ) throw() +{ + 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, makeAny(_rName), makeAny(sNewLink), Any()); + OInterfaceIteratorHelper2 aListenerIterator(m_aContainerListeners); + while (aListenerIterator.hasMoreElements()) + static_cast< XContainerListener* >(aListenerIterator.next())->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, makeAny(_rName), makeAny(sOldBookmark), Any()); + OInterfaceIteratorHelper2 aListenerIterator(m_aContainerListeners); + while (aListenerIterator.hasMoreElements()) + static_cast< XContainerListener* >(aListenerIterator.next())->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, makeAny(_rName), makeAny(sNewLink), makeAny(sOldLink)); + OInterfaceIteratorHelper2 aListenerIterator(m_aContainerListeners); + while (aListenerIterator.hasMoreElements()) + static_cast< XContainerListener* >(aListenerIterator.next())->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( ) +{ + MutexGuard aGuard(m_rMutex); + 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) || (_nIndex >= static_cast(m_aBookmarksIndexed.size()))) + throw IndexOutOfBoundsException(); + + return makeAny(m_aBookmarksIndexed[_nIndex]->second); +} + +Any SAL_CALL OBookmarkContainer::getByName( const OUString& _rName ) +{ + MutexGuard aGuard(m_rMutex); + + if (!checkExistence(_rName)) + throw NoSuchElementException(); + + return makeAny(m_aBookmarks[_rName]); +} + +Sequence< OUString > SAL_CALL OBookmarkContainer::getElementNames( ) +{ + MutexGuard aGuard(m_rMutex); + + Sequence< OUString > aNames(m_aBookmarks.size()); + OUString* pNames = aNames.getArray(); + + for (auto const& bookmarkIndexed : m_aBookmarksIndexed) + { + *pNames = bookmarkIndexed->first; + ++pNames; + } + + return aNames; +} + +sal_Bool SAL_CALL OBookmarkContainer::hasByName( const OUString& _rName ) +{ + MutexGuard aGuard(m_rMutex); + + return checkExistence(_rName); +} + +void OBookmarkContainer::implRemove(const OUString& _rName) +{ + MutexGuard aGuard(m_rMutex); + + // look for the name in the index access vector + MapString2String::const_iterator aMapPos = m_aBookmarks.end(); + auto aSearch = std::find_if(m_aBookmarksIndexed.begin(), m_aBookmarksIndexed.end(), + [&_rName](const MapString2String::iterator& rIter) { return rIter->first == _rName; }); + if (aSearch != m_aBookmarksIndexed.end()) + { + aMapPos = *aSearch; + m_aBookmarksIndexed.erase(aSearch); + } + + if (m_aBookmarks.end() == aMapPos) + { + OSL_FAIL("OBookmarkContainer::implRemove: inconsistence!"); + return; + } + + // remove the map entries + m_aBookmarks.erase(aMapPos); +} + +void OBookmarkContainer::implAppend(const OUString& _rName, const OUString& _rDocumentLocation) +{ + MutexGuard aGuard(m_rMutex); + + OSL_ENSURE(m_aBookmarks.find(_rName) == m_aBookmarks.end(),"Bookmark already known!"); + m_aBookmarksIndexed.push_back(m_aBookmarks.emplace( _rName,_rDocumentLocation).first); +} + +void OBookmarkContainer::implReplace(const OUString& _rName, const OUString& _rNewLink) +{ + MutexGuard aGuard(m_rMutex); + OSL_ENSURE(checkExistence(_rName), "OBookmarkContainer::implReplace : invalid name !"); + + m_aBookmarks[_rName] = _rNewLink; +} + +Reference< XInterface > SAL_CALL OBookmarkContainer::getParent( ) +{ + return m_rParent; +} + +void SAL_CALL OBookmarkContainer::setParent( const Reference< XInterface >& /*Parent*/ ) +{ + throw NoSupportException(); +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/commandcontainer.cxx b/dbaccess/source/core/dataaccess/commandcontainer.cxx new file mode 100644 index 000000000..55087272b --- /dev/null +++ b/dbaccess/source/core/dataaccess/commandcontainer.cxx @@ -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 . + */ + +#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) +IMPLEMENT_GETTYPES2(OCommandContainer,ODefinitionContainer,OCommandContainer_BASE); + +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 000000000..d0a1deca8 --- /dev/null +++ b/dbaccess/source/core/dataaccess/commandcontainer.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_COMMANDCONTAINER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_COMMANDCONTAINER_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_COMMANDCONTAINER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/commanddefinition.cxx b/dbaccess/source/core/dataaccess/commanddefinition.cxx new file mode 100644 index 000000000..41ce139a8 --- /dev/null +++ b/dbaccess/source/core/dataaccess/commanddefinition.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 "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(); +} + +IMPLEMENT_GETTYPES2(OCommandDefinition,OCommandDefinition_Base,OComponentDefinition); +IMPLEMENT_FORWARD_XINTERFACE2( OCommandDefinition,OComponentDefinition,OCommandDefinition_Base) +IMPLEMENT_PROPERTYCONTAINER_DEFAULTS2(OCommandDefinition,OCommandDefinition_PROP) + +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 = makeAny(m_pImpl->m_aProps.aTitle); + aGuard.clear(); + Any aNew = makeAny(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 000000000..112a0eaa2 --- /dev/null +++ b/dbaccess/source/core/dataaccess/commanddefinition.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_COMMANDDEFINITION_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_COMMANDDEFINITION_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_COMMANDDEFINITION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/connection.cxx b/dbaccess/source/core/dataaccess/connection.cxx new file mode 100644 index 000000000..2754a2c7d --- /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 + +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[ 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.get()); + 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() throw () +{ + // include this one when you want to see who calls it (call graph) + OSubComponent::acquire(); +} + +void OConnection::release() throw () +{ + // 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() ) + { + Sequence aArgs(1); + Reference xMy(this); + aArgs[0] <<= NamedValue("ActiveConnection",makeAny(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() ); + Sequence< OUString > aTableNames( xTables->getElementNames() ); + std::set< OUString > aSortedTableNames( aTableNames.begin(), aTableNames.end() ); + + Reference< XNameAccess > xQueries( getQueries() ); + const Sequence< OUString > aQueryNames( xQueries->getElementNames() ); + + for ( auto const & queryName : aQueryNames ) + { + if ( aSortedTableNames.find( queryName ) != aSortedTableNames.end() ) + { + OUString sConflictWarning( DBA_RES( RID_STR_CONFLICTING_NAMES ) ); + m_aWarnings.appendWarning( sConflictWarning, "01SB0", *this ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +Reference< XGraphic > SAL_CALL OConnection::getTableIcon( const OUString& TableName, ::sal_Int32 ColorMode ) +{ + Reference< XGraphic > xReturn; + + // ask our aggregate + if ( m_xTableUIProvider.is() ) + xReturn = m_xTableUIProvider->getTableIcon( TableName, ColorMode ); + + // ask ourself + // well, we don't have own functionality here ... + // In the future, we might decide to delegate the complete handling to this interface. + // In this case, we would need to load the icon here. + + return xReturn; +} + +Reference< XInterface > SAL_CALL OConnection::getTableEditor( const Reference< XDatabaseDocumentUI >& DocumentUI, const OUString& TableName ) +{ + Reference< XInterface > xReturn; + + // ask our aggregate + if ( m_xTableUIProvider.is() ) + xReturn = m_xTableUIProvider->getTableEditor( DocumentUI, TableName ); + + // ask ourself + // well, we don't have own functionality here ... + // In the future, we might decide to delegate the complete handling to this interface. + // In this case, we would need to instantiate a css.sdb.TableDesign here. + + return xReturn; +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/connection.hxx b/dbaccess/source/core/dataaccess/connection.hxx new file mode 100644 index 000000000..e5537da68 --- /dev/null +++ b/dbaccess/source/core/dataaccess/connection.hxx @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_CONNECTION_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_CONNECTION_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 + +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() throw( ) override; + virtual void SAL_CALL release() throw( ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_CONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx b/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx new file mode 100644 index 000000000..d35d6ac00 --- /dev/null +++ b/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx @@ -0,0 +1,261 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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; + // + }; + +#define REGISTER_PROPERTY( propname, member ) \ + registerProperty( PROPERTY_##propname, PROPERTY_ID_##propname, PropertyAttribute::BOUND, &member, cppu::UnoType::get() ) + + DataAccessDescriptor::DataAccessDescriptor() + :DataAccessDescriptor_MutexBase() + ,DataAccessDescriptor_TypeBase() + ,DataAccessDescriptor_PropertyBase( m_aBHelper ) + ,m_sDataSourceName() + ,m_sDatabaseLocation() + ,m_sConnectionResource() + ,m_aConnectionInfo() + ,m_xActiveConnection() + ,m_sCommand() + ,m_nCommandType( CommandType::COMMAND ) + ,m_sFilter() + ,m_sOrder() + ,m_sHavingClause() + ,m_sGroupBy() + ,m_bEscapeProcessing( true ) + ,m_xResultSet() + ,m_aSelection() + ,m_bBookmarkSelection( true ) + ,m_sColumnName() + ,m_xColumn() + { + REGISTER_PROPERTY( DATASOURCENAME, m_sDataSourceName ); + REGISTER_PROPERTY( DATABASE_LOCATION, m_sDatabaseLocation ); + REGISTER_PROPERTY( CONNECTION_RESOURCE, m_sConnectionResource ); + REGISTER_PROPERTY( CONNECTION_INFO, m_aConnectionInfo ); + REGISTER_PROPERTY( ACTIVE_CONNECTION, m_xActiveConnection ); + REGISTER_PROPERTY( COMMAND, m_sCommand ); + REGISTER_PROPERTY( COMMAND_TYPE, m_nCommandType ); + REGISTER_PROPERTY( FILTER, m_sFilter ); + REGISTER_PROPERTY( ORDER, m_sOrder ); + REGISTER_PROPERTY( HAVING_CLAUSE, m_sHavingClause ); + REGISTER_PROPERTY( GROUP_BY, m_sGroupBy ); + REGISTER_PROPERTY( ESCAPE_PROCESSING, m_bEscapeProcessing ); + REGISTER_PROPERTY( RESULT_SET, m_xResultSet ); + REGISTER_PROPERTY( SELECTION, m_aSelection ); + REGISTER_PROPERTY( BOOKMARK_SELECTION, m_bBookmarkSelection ); + REGISTER_PROPERTY( COLUMN_NAME, m_sColumnName ); + REGISTER_PROPERTY( COLUMN, m_xColumn ); + } + + 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(); + } + +struct Instance { + explicit Instance(): + instance(new DataAccessDescriptorFactory()) + {} + + rtl::Reference instance; +}; + +struct Singleton: + public rtl::Static +{}; + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_dba_DataAccessDescriptorFactory( + css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(Singleton::get().instance.get()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databasecontext.cxx b/dbaccess/source/core/dataaccess/databasecontext.cxx new file mode 100644 index 000000000..c2c347698 --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasecontext.cxx @@ -0,0 +1,764 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "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 + +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_xDBRegistrationAggregate.set( createDataSourceRegistrations( m_aContext ), UNO_SET_THROW ); + m_xDatabaseRegistrations.set( m_xDBRegistrationAggregate, UNO_QUERY_THROW ); + + m_xDBRegistrationAggregate->setDelegator( *this ); + } + osl_atomic_decrement( &m_refCount ); +} + +ODatabaseContext::~ODatabaseContext() +{ +#if HAVE_FEATURE_SCRIPTING + ::basic::BasicManagerRepository::revokeCreationListener( *this ); +#endif + + m_xDatabaseDocumentLoader.clear(); + m_xDBRegistrationAggregate->setDelegator( nullptr ); + m_xDBRegistrationAggregate.clear(); + m_xDatabaseRegistrations.clear(); +} + +// Helper +OUString ODatabaseContext::getImplementationName_static() +{ + return "com.sun.star.comp.dba.ODatabaseContext"; +} + +Reference< XInterface > ODatabaseContext::Create(const Reference< XComponentContext >& _rxContext) +{ + return *( new ODatabaseContext( _rxContext ) ); +} + +Sequence< OUString > ODatabaseContext::getSupportedServiceNames_static() +{ + Sequence aSNS { "com.sun.star.sdb.DatabaseContext" }; + return aSNS; +} + +// XServiceInfo +OUString ODatabaseContext::getImplementationName( ) +{ + return getImplementationName_static(); +} + +sal_Bool ODatabaseContext::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Sequence< OUString > ODatabaseContext::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_static(); +} + +Reference< XInterface > ODatabaseContext::impl_createNewDataSource() +{ + ::rtl::Reference pImpl( new ODatabaseModelImpl( m_aContext, *this ) ); + Reference< XDataSource > xDataSource( pImpl->getOrCreateDataSource() ); + + return xDataSource.get(); +} + +Reference< XInterface > SAL_CALL ODatabaseContext::createInstance( ) +{ + // for convenience of the API user, we ensure the document is fully initialized (effectively: XLoadable::initNew + // has been called at the DatabaseDocument). + return impl_createNewDataSource(); +} + +Reference< XInterface > SAL_CALL ODatabaseContext::createInstanceWithArguments( const Sequence< Any >& _rArguments ) +{ + ::comphelper::NamedValueCollection aArgs( _rArguments ); + OUString sURL = aArgs.getOrDefault( INFO_POOLURL, OUString() ); + + Reference< XInterface > xDataSource; + if ( !sURL.isEmpty() ) + xDataSource = getObject( sURL ); + + if ( !xDataSource.is() ) + xDataSource = impl_createNewDataSource(); + + return xDataSource; +} + +// DatabaseAccessContext_Base +void ODatabaseContext::disposing() +{ + // notify our listener + css::lang::EventObject aDisposeEvent(static_cast< XContainer* >(this)); + m_aContainerListeners.disposeAndClear(aDisposeEvent); + + // dispose the data sources + // disposing seems to remove elements, so work on copy for valid iterators + ObjectCache objCopy; + objCopy.swap(m_aDatabaseObjects); + for (auto const& elem : objCopy) + { + rtl::Reference< ODatabaseModelImpl > obj(elem.second); + // make sure obj is acquired and does not delete itself from within + // dispose() + obj->dispose(); + } +} + +// XNamingService +Reference< XInterface > ODatabaseContext::getRegisteredObject(const OUString& _rName) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + + OUString sURL( getDatabaseLocation( _rName ) ); + + if ( sURL.isEmpty() ) + // there is a registration for this name, but no URL + throw IllegalArgumentException(); + + // check if URL is already loaded + Reference< XInterface > xExistent = getObject( sURL ); + if ( xExistent.is() ) + return xExistent; + + return loadObjectFromURL( _rName, sURL ); +} + +Reference< XInterface > ODatabaseContext::loadObjectFromURL(const OUString& _rName,const OUString& _sURL) +{ + INetURLObject aURL( _sURL ); + + if ( aURL.GetProtocol() == INetProtocol::NotValid ) + throw NoSuchElementException( _rName, *this ); + + bool bEmbeddedDataSource = aURL.isSchemeEqualTo(INetProtocol::VndSunStarPkg); + try + { + if (!bEmbeddedDataSource) + { + ::ucbhelper::Content aContent( _sURL, nullptr, comphelper::getProcessComponentContext() ); + if ( !aContent.isDocument() ) + throw InteractiveIOException( + _sURL, *this, InteractionClassification_ERROR, IOErrorCode_NO_FILE + ); + } + } + catch ( const InteractiveIOException& e ) + { + if ( ( e.Code == IOErrorCode_NO_FILE ) + || ( e.Code == IOErrorCode_NOT_EXISTING ) + || ( e.Code == IOErrorCode_NOT_EXISTING_PATH ) + ) + { + // #i40463# #i39187# + OUString sErrorMessage( DBA_RES( RID_STR_FILE_DOES_NOT_EXIST ) ); + ::svt::OFileNotation aTransformer( _sURL ); + + SQLException aError; + aError.Message = sErrorMessage.replaceAll( "$file$", aTransformer.get( ::svt::OFileNotation::N_SYSTEM ) ); + + throw WrappedTargetException( _sURL, *this, makeAny( 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().get(); +} + +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), makeAny(_rName), makeAny(_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, makeAny( _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 makeAny( 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 makeAny( xExistent ); + } + catch (const NoSuchElementException&) + { // let these exceptions through + throw; + } + catch (const WrappedTargetException&) + { // let these exceptions through + throw; + } + catch (const RuntimeException&) + { // let these exceptions through + throw; + } + catch (const Exception&) + { // exceptions other than the specified ones -> wrap + Any aError = ::cppu::getCaughtException(); + throw WrappedTargetException(_rName, *this, aError ); + } +} + +Sequence< OUString > ODatabaseContext::getElementNames() +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + + return getRegistrationNames(); +} + +sal_Bool ODatabaseContext::hasByName(const OUString& _rName) +{ + MutexGuard aGuard(m_aMutex); + ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed); + + return hasRegisteredDatabase( _rName ); +} + +Reference< XInterface > ODatabaseContext::getObject( const OUString& _rURL ) +{ + ObjectCache::const_iterator aFind = m_aDatabaseObjects.find( _rURL ); + Reference< XInterface > xExistent; + if ( aFind != m_aDatabaseObjects.end() ) + xExistent = aFind->second->getOrCreateDataSource(); + return xExistent; +} + +void ODatabaseContext::registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl ) +{ + OUString sURL( _rModelImpl.getURL() ); + SAL_INFO("dbaccess.core", "DatabaseContext: registering " << sURL); + if ( m_aDatabaseObjects.find( sURL ) == m_aDatabaseObjects.end() ) + { + m_aDatabaseObjects[ sURL ] = &_rModelImpl; + setTransientProperties( sURL, _rModelImpl ); + } + else + OSL_FAIL( "ODatabaseContext::registerDatabaseDocument: already have an object registered for this URL!" ); +} + +void ODatabaseContext::revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl ) +{ + const OUString& sURL( _rModelImpl.getURL() ); + SAL_INFO("dbaccess.core", "DatabaseContext: deregistering " << sURL); + m_aDatabaseObjects.erase( sURL ); +} + +void ODatabaseContext::databaseDocumentURLChange( const OUString& _rOldURL, const OUString& _rNewURL ) +{ + SAL_INFO("dbaccess.core", "DatabaseContext: changing registrations from " << _rOldURL << + " to " << _rNewURL); + ObjectCache::const_iterator oldPos = m_aDatabaseObjects.find( _rOldURL ); + ENSURE_OR_THROW( oldPos != m_aDatabaseObjects.end(), "illegal old database document URL" ); + ObjectCache::const_iterator newPos = m_aDatabaseObjects.find( _rNewURL ); + ENSURE_OR_THROW( newPos == m_aDatabaseObjects.end(), "illegal new database document URL" ); + + m_aDatabaseObjects[ _rNewURL ] = oldPos->second; + m_aDatabaseObjects.erase( oldPos ); +} + +sal_Int64 SAL_CALL ODatabaseContext::getSomething( const Sequence< sal_Int8 >& rId ) +{ + if (isUnoTunnelId(rId)) + return reinterpret_cast(this); + + return 0; +} + +Sequence< sal_Int8 > ODatabaseContext::getUnoTunnelId() +{ + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); +} + +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", makeAny( xDatabaseDocument ) ); +#endif +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databasedocument.cxx b/dbaccess/source/core/dataaccess/databasedocument.cxx new file mode 100644 index 000000000..6811ae332 --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasedocument.cxx @@ -0,0 +1,2218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#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(); + + Any aReturn = ODatabaseDocument_OfficeDocument::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ODatabaseDocument_Title::queryInterface(_rType); + return aReturn; +} + +void SAL_CALL ODatabaseDocument::acquire( ) throw () +{ + ODatabaseDocument_OfficeDocument::acquire(); +} + +void SAL_CALL ODatabaseDocument::release( ) throw () +{ + ODatabaseDocument_OfficeDocument::release(); +} + +Sequence< Type > SAL_CALL ODatabaseDocument::getTypes( ) +{ + Sequence< Type > aTypes = ::comphelper::concatSequences( + ODatabaseDocument_OfficeDocument::getTypes(), + ODatabaseDocument_Title::getTypes() + ); + + // strip XEmbeddedScripts and XScriptInvocationContext if we have any form/report + // which already contains macros. In this case, the database document itself is not + // allowed to contain macros, too. + if ( !m_bAllowDocumentScripting ) + { + auto newEnd = std::remove_if( aTypes.begin(), aTypes.end(), + [](const Type& t) + { return t == cppu::UnoType::get() || + t == cppu::UnoType::get();} ); + aTypes.realloc( std::distance(aTypes.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[ 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[ nLength ] <<= _rxStatusIndicator; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + Sequence< PropertyValue > lcl_appendFileNameToDescriptor( const ::comphelper::NamedValueCollection& _rDescriptor, const OUString& _rURL ) + { + ::comphelper::NamedValueCollection aMutableDescriptor( _rDescriptor ); + if ( !_rURL.isEmpty() ) + { + aMutableDescriptor.put( "FileName", _rURL ); + aMutableDescriptor.put( "URL", _rURL ); + } + return aMutableDescriptor.getPropertyValues(); + } +} + +static const char sPictures[] = "Pictures"; + +// base documents seem to have a different behaviour to other documents, the +// root storage contents at least seem to be re-used over different saves, thus if there is a +// top level Picture directory it is never cleared. +// If we delete the 'Pictures' directory then the dialog library storage which does store +// any embed images will not work properly. ( this is due to the fact it will +// try to load the dialog which will try and access the embed images, if those images are not cached in +// memory it will try to read them from the Picture directory which is now gone, so... we have to use this +// inglorious hack below which basically will +// +// a) create a temp storage +// +// b) introspect any dialogs for any embed graphics and grab the associate URL(s) +// +// c) populate the temp storage with the associated embed images ( will be stored in a 'Pictures' folder ) +// +// d) delete the 'Picture' element from the root storage +// +// e) copy the Pictures element of the temp storage to the root storage +// +// this assumes that we don't use the Pictures folder in the root of the base +// document for anything, I believe this is a valid assumption ( as much as +// I could check anyway ) + +/// @throws RuntimeException +static void lcl_uglyHackToStoreDialogeEmbedImages( const Reference< XStorageBasedLibraryContainer >& xDlgCont, const Reference< XStorage >& xStorage, const Reference< XModel >& rxModel, const Reference& 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}, + { OUString(), 0, css::uno::Type(), 0, 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::makeAny(sBaseURI)); + xInfoSet->setPropertyValue("StreamName", uno::makeAny(OUString("content.xml"))); + + const sal_Int32 nCount = aFilterCreationArgs.getLength(); + aFilterCreationArgs.realloc(nCount + 1); + aFilterCreationArgs[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::eSubDocumentMacros ); + + _rDocGuard.clear(); + // <- SYNCHRONIZED + m_aEventNotifier.notifyDocumentEvent( "OnLoadFinished" ); + } + + return true; +} + +OUString SAL_CALL ODatabaseDocument::getURL( ) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + return m_pImpl->getURL(); +} + +Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getArgs( ) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + return m_pImpl->getMediaDescriptor().getPropertyValues(); +} + +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, OUString() ); + } +} + +void ODatabaseDocument::impl_throwIOExceptionCausedBySave_throw( const Any& i_rError, const OUString& 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, makeAny( _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, makeAny( _rURL ) ); + throw; + } + catch( const RuntimeException& ) + { + if ( !bIsInitializationProcess ) + m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveFailed" : "OnSaveAsFailed", nullptr, makeAny( _rURL ) ); + throw; + } + catch( const Exception& ) + { + Any aError = ::cppu::getCaughtException(); + + // notify the failure + if ( !bIsInitializationProcess ) + m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveFailed" : "OnSaveAsFailed", nullptr, makeAny( _rURL ) ); + + impl_throwIOExceptionCausedBySave_throw( aError, _rURL ); + } + + // notify the document event + if ( !bIsInitializationProcess ) + m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveDone" : "OnSaveAsDone", nullptr, makeAny( _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(2); + aParam[0] <<= xStream; + aParam[1] <<= 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, makeAny( _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, makeAny( _rURL ) ); +} + +// XModifyBroadcaster +void SAL_CALL ODatabaseDocument::addModifyListener( const Reference< XModifyListener >& _xListener ) +{ + DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod); + m_aModifyListeners.addInterface(_xListener); +} + +void SAL_CALL ODatabaseDocument::removeModifyListener( const Reference< XModifyListener >& _xListener ) +{ + DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod); + m_aModifyListeners.removeInterface(_xListener); +} + +// XModifiable +sal_Bool SAL_CALL ODatabaseDocument::isModified( ) +{ + DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod); + + return m_pImpl->m_bModified; +} + +void SAL_CALL ODatabaseDocument::setModified( sal_Bool _bModified ) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit ); + if ( impl_isInitialized() ) + impl_setModified_nothrow( _bModified, aGuard ); + // it's allowed to call setModified without the document being initialized already. In this case, + // we simply ignore the call - when the initialization is finished, the respective code will set + // a proper "modified" flag +} + +void ODatabaseDocument::impl_setModified_nothrow( bool _bModified, DocumentGuard& _rGuard ) +{ + // SYNCHRONIZED -> + bool bModifiedChanged = ( m_pImpl->m_bModified != _bModified ) && ( !m_pImpl->isModifyLocked() ); + + if ( bModifiedChanged ) + { + m_pImpl->m_bModified = _bModified; + m_aEventNotifier.notifyDocumentEventAsync( "OnModifyChanged" ); + } + _rGuard.clear(); + // <- SYNCHRONIZED + + if ( bModifiedChanged ) + { + lang::EventObject aEvent( *this ); + m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent ); + } +} + +// css::document::XEventBroadcaster +void SAL_CALL ODatabaseDocument::addEventListener(const uno::Reference< document::XEventListener >& Listener ) +{ + m_aEventNotifier.addLegacyEventListener( Listener ); +} + +void SAL_CALL ODatabaseDocument::removeEventListener( const uno::Reference< document::XEventListener >& Listener ) +{ + m_aEventNotifier.removeLegacyEventListener( Listener ); +} + +void SAL_CALL ODatabaseDocument::addDocumentEventListener( const Reference< XDocumentEventListener >& Listener ) +{ + m_aEventNotifier.addDocumentEventListener( Listener ); +} + +void SAL_CALL ODatabaseDocument::removeDocumentEventListener( const Reference< XDocumentEventListener >& Listener ) +{ + m_aEventNotifier.removeDocumentEventListener( Listener ); +} + +void SAL_CALL ODatabaseDocument::notifyDocumentEvent( const OUString& EventName, const Reference< XController2 >& ViewController, const Any& Supplement ) +{ + if ( EventName.isEmpty() ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + // SYNCHRONIZED -> + DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod); + + if ( !DocumentEvents::needsSynchronousNotification( EventName ) ) + { + m_aEventNotifier.notifyDocumentEventAsync( EventName, ViewController, Supplement ); + return; + } + aGuard.clear(); + // <- SYNCHRONIZED + + m_aEventNotifier.notifyDocumentEvent( EventName, ViewController, Supplement ); +} + +Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getPrinter( ) +{ + OSL_FAIL( "ODatabaseDocument::getPrinter: not supported!" ); + return Sequence< PropertyValue >(); +} + +void SAL_CALL ODatabaseDocument::setPrinter( const Sequence< PropertyValue >& /*aPrinter*/ ) +{ + OSL_FAIL( "ODatabaseDocument::setPrinter: not supported!" ); +} + +void SAL_CALL ODatabaseDocument::print( const Sequence< PropertyValue >& /*xOptions*/ ) +{ + OSL_FAIL( "ODatabaseDocument::print: not supported!" ); +} + +void ODatabaseDocument::impl_reparent_nothrow( const WeakReference< XNameAccess >& _rxContainer ) +{ + Reference< XChild > xChild( _rxContainer.get(), UNO_QUERY ); + if ( xChild.is() ) + xChild->setParent( *this ); +} + +void ODatabaseDocument::clearObjectContainer( WeakReference< XNameAccess >& _rxContainer) +{ + Reference< XNameAccess > xContainer = _rxContainer; + ::comphelper::disposeComponent( xContainer ); + + Reference< XChild > xChild( _rxContainer.get(),UNO_QUERY ); + if ( xChild.is() ) + xChild->setParent( nullptr ); + _rxContainer.clear(); +} + +Reference< XNameAccess > ODatabaseDocument::impl_getDocumentContainer_throw( ODatabaseModelImpl::ObjectType _eType ) +{ + if ( ( _eType != ODatabaseModelImpl::E_FORM ) && ( _eType != ODatabaseModelImpl::E_REPORT ) ) + throw IllegalArgumentException(); + + bool bFormsContainer = _eType == ODatabaseModelImpl::E_FORM; + + WeakReference< XNameAccess >& rContainerRef( bFormsContainer ? m_xForms : m_xReports ); + Reference< XNameAccess > xContainer = rContainerRef; + if ( !xContainer.is() ) + { + Any aValue; + css::uno::Reference< css::uno::XInterface > xMy(*this); + if ( dbtools::getDataSourceSetting(xMy,bFormsContainer ? "Forms" : "Reports",aValue) ) + { + OUString sSupportService; + aValue >>= sSupportService; + if ( !sSupportService.isEmpty() ) + { + Sequence aArgs(1); + aArgs[0] <<= NamedValue("DatabaseDocument",makeAny(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< XCloseListener >( + [&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::E_FORM ); +} + +Reference< XNameAccess > SAL_CALL ODatabaseDocument::getReportDocuments( ) +{ + DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit ); + return impl_getDocumentContainer_throw( ODatabaseModelImpl::E_REPORT ); +} + +void ODatabaseDocument::WriteThroughComponent( const Reference< XComponent >& xComponent, const char* pStreamName, + const char* pServiceName, const Sequence< Any >& _rArguments, const Sequence< PropertyValue >& rMediaDesc, + const Reference& _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, makeAny( OUString( "text/xml" ) ) ); + xStreamProp->setPropertyValue( "Compressed", makeAny( 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() ); + aArgs[0] <<= xSaxWriter; + for ( sal_Int32 i = 0; i < _rArguments.getLength(); ++i ) + aArgs[ 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 ) ) ); + + SvtSaveOptions aSaveOpt; + xInfoSet->setPropertyValue("UsePrettyPrinting", uno::makeAny(aSaveOpt.IsPrettyPrinting())); + if ( aSaveOpt.IsSaveRelFSys() ) + { + OUString sBaseURI = _rMediaDescriptor.getOrDefault("BaseURI", OUString()); + if (sBaseURI.isEmpty()) + sBaseURI = _rMediaDescriptor.getOrDefault("URL",OUString()); + xInfoSet->setPropertyValue("BaseURI", uno::makeAny(sBaseURI)); + } + + // Set TargetStorage, so it doesn't have to be re-constructed based on possibly empty URL. + xInfoSet->setPropertyValue("TargetStorage", uno::makeAny(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::makeAny(sStreamRelPath)); + + sal_Int32 nArgsLen = aDelegatorArguments.getLength(); + aDelegatorArguments.realloc(nArgsLen+1); + aDelegatorArguments[nArgsLen++] <<= xInfoSet; + + Reference< XPropertySet > xProp( _rxTargetStorage, UNO_QUERY_THROW ); + xProp->setPropertyValue( INFO_MEDIATYPE, makeAny( OUString(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII) ) ); + + OUString aVersion; + SvtSaveOptions::ODFSaneDefaultVersion const nDefVersion = + aSaveOpt.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::makeAny(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::makeAny(OUString("settings.xml"))); + WriteThroughComponent( xComponent, "settings.xml", "com.sun.star.comp.sdb.XMLSettingsExporter", + aDelegatorArguments, aMediaDescriptor, _rxTargetStorage ); + + xInfoSet->setPropertyValue("StreamName", uno::makeAny(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< XStorageChangeListener >( + [&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(); +} + +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}, + {OUString(), 0, css::uno::Type(), 0, 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))); + comphelper::NamedValueCollection aDescriptor(rMediaDescriptor); + xInfoSet->setPropertyValue("StreamRelPath", uno::makeAny(aDescriptor.getOrDefault("HierarchicalDocumentName", OUString()))); + xInfoSet->setPropertyValue("StreamName", uno::makeAny(OUString("content.xml"))); + xInfoSet->setPropertyValue("SourceStorage", uno::makeAny(xStorage)); + + uno::Sequence aFilterCreationArgs(1); + aFilterCreationArgs[0] <<= 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 makeAny(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); + + ::framework::TitleHelper* pHelper = new ::framework::TitleHelper(m_pImpl->m_aContext); + m_xTitleHelper.set(static_cast< ::cppu::OWeakObject* >(pHelper), uno::UNO_QUERY_THROW); + pHelper->setOwner (xThis ); + pHelper->connectWithUntitledNumbers (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; + try + { + sModuleId = m_xModuleManager->identify( _xComponent ); + } + catch(const uno::Exception&) + { + } + uno::Reference< frame::XUntitledNumbers > xNumberedControllers; + + TNumberedController::const_iterator aFind = m_aNumberedControllers.find(sModuleId); + if ( aFind == m_aNumberedControllers.end() ) + { + uno::Reference< frame::XModel > xThis(static_cast< frame::XModel* >(this), uno::UNO_QUERY_THROW); + ::comphelper::NumberedCollection* pHelper = new ::comphelper::NumberedCollection(); + xNumberedControllers.set(static_cast< ::cppu::OWeakObject* >(pHelper), uno::UNO_QUERY_THROW); + + pHelper->setOwner (xThis); + + 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); + dbaccess::ODatabaseContext* pContext = reinterpret_cast( + xDBContextTunnel->getSomething( + dbaccess::ODatabaseContext::getUnoTunnelId())); + + 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 000000000..8adb30c54 --- /dev/null +++ b/dbaccess/source/core/dataaccess/databasedocument.hxx @@ -0,0 +1,751 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DATABASEDOCUMENT_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DATABASEDOCUMENT_HXX + +#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 + +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::XModel2 + , css::util::XModifiable + , css::frame::XStorable + , css::document::XEventBroadcaster + , css::document::XDocumentEventBroadcaster + , css::view::XPrintable + , css::util::XCloseable + , css::lang::XServiceInfo + , css::sdb::XOfficeDatabaseDocument + , css::ui::XUIConfigurationManagerSupplier + , css::document::XStorageBasedDocument + , css::document::XEmbeddedScripts + , css::document::XScriptInvocationContext + , css::script::provider::XScriptProviderSupplier + , css::document::XEventsSupplier + , css::frame::XLoadable + , css::document::XDocumentRecovery + > ODatabaseDocument_OfficeDocument; + +typedef ::cppu::ImplHelper3< css::frame::XTitle + , css::frame::XTitleChangeBroadcaster + , css::frame::XUntitledNumbers + > ODatabaseDocument_Title; + +class ODatabaseDocument :public ModelDependentComponent // ModelDependentComponent must be first! + ,public ODatabaseDocument_OfficeDocument + ,public ODatabaseDocument_Title +{ + enum InitState + { + NotInitialized, + Initializing, + Initialized + }; + + typedef std::map< OUString, css::uno::Reference< css::frame::XUntitledNumbers > > TNumberedController; + css::uno::Reference< css::ui::XUIConfigurationManager2> m_xUIConfigurationManager; + + ::comphelper::OInterfaceContainerHelper2 m_aModifyListeners; + ::comphelper::OInterfaceContainerHelper2 m_aCloseListener; + ::comphelper::OInterfaceContainerHelper2 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 ODatabaseDocument* 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; + virtual void SAL_CALL acquire( ) throw () override; + virtual void SAL_CALL release( ) throw () 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; + + // 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, + const OUString& 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 +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DATABASEDOCUMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databaseregistrations.cxx b/dbaccess/source/core/dataaccess/databaseregistrations.cxx new file mode 100644 index 000000000..c147f99ec --- /dev/null +++ b/dbaccess/source/core/dataaccess/databaseregistrations.cxx @@ -0,0 +1,370 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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::makeAny; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::container::NoSuchElementException; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::lang::IllegalAccessException; + using ::com::sun::star::container::ElementExistException; + using ::com::sun::star::sdb::XDatabaseRegistrations; + using ::com::sun::star::sdb::XDatabaseRegistrationsListener; + using ::com::sun::star::sdb::DatabaseRegistrationEvent; + using ::com::sun::star::uno::XAggregation; + + static OUString getConfigurationRootPath() + { + return "org.openoffice.Office.DataAccess/RegisteredNames"; + } + + static OUString getLocationNodeName() + { + return "Location"; + } + + static OUString getNameNodeName() + { + return "Name"; + } + + // DatabaseRegistrations - declaration + typedef ::cppu::WeakAggImplHelper1 < XDatabaseRegistrations + > DatabaseRegistrations_Base; + + namespace { + + class DatabaseRegistrations :public ::cppu::BaseMutex + ,public DatabaseRegistrations_Base + { + public: + explicit DatabaseRegistrations( const Reference& _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(const OUString& _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( const OUString& _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(const OUString& _rName); + + private: + Reference m_aContext; + ::utl::OConfigurationTreeRoot m_aConfigurationRoot; + ::comphelper::OInterfaceContainerHelper2 m_aRegistrationListeners; + }; + + } + + // DatabaseRegistrations - implementation + DatabaseRegistrations::DatabaseRegistrations( const Reference & _rxContext ) + :m_aContext( _rxContext ) + ,m_aConfigurationRoot() + ,m_aRegistrationListeners( m_aMutex ) + { + m_aConfigurationRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext( + m_aContext, getConfigurationRootPath() ); + } + + DatabaseRegistrations::~DatabaseRegistrations() + { + } + + ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_nothrow( const OUString& _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(), makeAny( _rName ) ); + return aNewNode; + } + + void DatabaseRegistrations::impl_checkValidName_common(const OUString& _rName) + { + if ( !m_aConfigurationRoot.isValid() ) + throw RuntimeException( OUString(), *this ); + + if ( _rName.isEmpty() ) + 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( const OUString& _rLocation ) + { + if ( _rLocation.isEmpty() ) + 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(), makeAny( 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(), makeAny( NewLocation ) ); + m_aConfigurationRoot.commit(); + + // notify + DatabaseRegistrationEvent aEvent( *this, Name, sOldLocation, NewLocation ); + aGuard.clear(); + m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::changedDatabaseLocation, aEvent ); + } + + sal_Bool SAL_CALL DatabaseRegistrations::isDatabaseRegistrationReadOnly( const OUString& Name ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_exist(Name); + return aDataSourceRegistration.isReadonly(); + } + + void SAL_CALL DatabaseRegistrations::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) + { + if ( Listener.is() ) + m_aRegistrationListeners.addInterface( Listener ); + } + + void SAL_CALL DatabaseRegistrations::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) + { + if ( Listener.is() ) + m_aRegistrationListeners.removeInterface( Listener ); + } + + // DatabaseRegistrations - factory + Reference< XAggregation > createDataSourceRegistrations( const Reference & _rxContext ) + { + return new DatabaseRegistrations( _rxContext ); + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/databaseregistrations.hxx b/dbaccess/source/core/dataaccess/databaseregistrations.hxx new file mode 100644 index 000000000..5e6680cc3 --- /dev/null +++ b/dbaccess/source/core/dataaccess/databaseregistrations.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DATABASEREGISTRATIONS_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DATABASEREGISTRATIONS_HXX + +#include +#include + +namespace dbaccess +{ + + css::uno::Reference< css::uno::XAggregation > + createDataSourceRegistrations( const css::uno::Reference< css::uno::XComponentContext >& _rxContext ); + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DATABASEREGISTRATIONS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/datasource.cxx b/dbaccess/source/core/dataaccess/datasource.cxx new file mode 100644 index 000000000..002d01b21 --- /dev/null +++ b/dbaccess/source/core/dataaccess/datasource.cxx @@ -0,0 +1,1430 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "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 + +#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_bRemberPassword(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 ) +{ + Sequence< RememberAuthentication > aReturn(1); + _reDefault = aReturn[0] = RememberAuthentication_SESSION; + return aReturn; +} + +void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember ) +{ + m_bRemberPassword = (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 ) +{ + Sequence < RememberAuthentication > aReturn(1); + aReturn[0] = RememberAuthentication_NO; + _reDefault = RememberAuthentication_NO; + return aReturn; +} + +void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ ) +{ + SAL_WARN("dbaccess","OAuthenticationContinuation::setRememberAccount: not supported!"); +} + +namespace { + +/** The class OSharedConnectionManager implements a structure to share connections. + It owns the master connections which will be disposed when the last connection proxy is gone. +*/ +// need to hold the digest +struct TDigestHolder +{ + sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1]; + TDigestHolder() + { + m_pBuffer[0] = 0; + } + +}; + +} + +class OSharedConnectionManager : public ::cppu::WeakImplHelper< XEventListener > +{ + + // contains the currently used master connections + struct TConnectionHolder + { + Reference< XConnection > xMasterConnection; + oslInterlockedCount nALiveCount; + }; + + // the less-compare functor, used for the stl::map + struct TDigestLess + { + bool operator() (const TDigestHolder& x, const TDigestHolder& y) const + { + sal_uInt32 i; + for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i) + ; + return i < RTL_DIGEST_LENGTH_SHA1; + } + }; + + typedef std::map< TDigestHolder,TConnectionHolder,TDigestLess> TConnectionMap; // holds the master connections + typedef std::map< Reference< XConnection >,TConnectionMap::iterator> TSharedConnectionMap;// holds the shared connections + + ::osl::Mutex m_aMutex; + TConnectionMap m_aConnections; // remember the master connection in conjunction with the digest + TSharedConnectionMap m_aSharedConnection; // the shared connections with conjunction with an iterator into the connections map + Reference< XProxyFactory > m_xProxyFactory; + +protected: + virtual ~OSharedConnectionManager() override; + +public: + explicit OSharedConnectionManager(const Reference< XComponentContext >& _rxContext); + + void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + Reference getConnection( const OUString& url, + const OUString& user, + const OUString& password, + const Sequence< PropertyValue >& _aInfo, + ODatabaseSource* _pDataSource); + void addEventListener(const Reference& _rxConnection, TConnectionMap::iterator const & _rIter); +}; + +OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext) +{ + m_xProxyFactory.set( ProxyFactory::create( _rxContext ) ); +} + +OSharedConnectionManager::~OSharedConnectionManager() +{ +} + +void SAL_CALL OSharedConnectionManager::disposing( const css::lang::EventObject& Source ) +{ + MutexGuard aGuard(m_aMutex); + Reference xConnection(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 ); + aInfoCopy[nPos].Name = "TableFilter"; + aInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter; + aInfoCopy[nPos].Name = "TableTypeFilter"; + aInfoCopy[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.get()); + 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() throw () +{ + ODatabaseSource_Base::acquire(); +} + +void ODatabaseSource::release() throw () +{ + 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 aArgs( xModel->getArgs() ); + aArgs.get("IgnoreFirebirdMigration") >>= bIgnoreMigration; + } + else + { + //ignore when we don't have a model. E.g. Mailmerge, data sources, fields... + bIgnoreMigration = true; + } + SvtMiscOptions aMiscOptions; + + if (!aMiscOptions.IsExperimentalMode()) + 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 + constexpr char BACKUP_XML_NAME[] = "content_before_migration.xml"; + try + { + if(xRootStorage->isStreamElement(BACKUP_XML_NAME)) + xRootStorage->removeElement(BACKUP_XML_NAME); + } + catch (NoSuchElementException&) + { + SAL_INFO("dbaccess", "No file content_before_migration.xml found" ); + } + xRootStorage->copyElementTo("content.xml", xRootStorage, + BACKUP_XML_NAME); + + m_pImpl->m_sConnectURL = "sdbc:embedded:firebird"; + } + } +#endif + + try { + xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW ); + } catch( const Exception& ) { } + if ( !xManager.is() ) + // no connection pool installed, fall back to driver manager + xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW ); + + OUString sUser(_rUid); + OUString sPwd(_rPwd); + if ((sUser.isEmpty()) && (sPwd.isEmpty()) && (!m_pImpl->m_sUser.isEmpty())) + { // ease the usage of this method. data source which are intended to have a user automatically + // fill in the user/password combination if the caller of this method does not specify otherwise + sUser = m_pImpl->m_sUser; + if (!m_pImpl->m_aPassword.isEmpty()) + sPwd = m_pImpl->m_aPassword; + } + + const char* pExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED; + if (xManager.is()) + { + sal_Int32 nAdditionalArgs(0); + if (!sUser.isEmpty()) ++nAdditionalArgs; + if (!sPwd.isEmpty()) ++nAdditionalArgs; + + Sequence< PropertyValue > aUserPwd(nAdditionalArgs); + sal_Int32 nArgPos = 0; + if (!sUser.isEmpty()) + { + aUserPwd[ nArgPos ].Name = "user"; + aUserPwd[ nArgPos ].Value <<= sUser; + ++nArgPos; + } + if (!sPwd.isEmpty()) + { + aUserPwd[ nArgPos ].Name = "password"; + aUserPwd[ 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 ); + + aDriverInfo[nCount].Name = "URL"; + aDriverInfo[nCount++].Value <<= m_pImpl->getURL(); + + aDriverInfo[nCount].Name = "Storage"; + Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() ); + aDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE); + + aDriverInfo[nCount].Name = "Document"; + aDriverInfo[nCount++].Value <<= getDatabaseDocument(); + } + if (nAdditionalArgs) + xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo)); + else + xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo); + + if ( m_pImpl->isEmbeddedDatabase() ) + { + // see ODatabaseSource::flushed for comment on why we register as FlushListener + // at the connection + Reference< XFlushable > xFlushable( xReturn, UNO_QUERY ); + if ( xFlushable.is() ) + FlushNotificationAdapter::installAdapter( xFlushable, this ); + } + } + } + else + pExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER; + + if ( !xReturn.is() ) + { + OUString sMessage = DBA_RES(pExceptionMessageId) + .replaceAll("$name$", m_pImpl->m_sConnectURL); + + SQLContext aContext; + aContext.Message = DBA_RES(RID_STR_CONNECTION_REQUEST). + replaceFirst("$name$", m_pImpl->m_sConnectURL); + + throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), makeAny( 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 +{ + BEGIN_PROPERTY_HELPER(13) + DECL_PROP1(INFO, Sequence< PropertyValue >, BOUND); + DECL_PROP1_BOOL(ISPASSWORDREQUIRED, BOUND); + DECL_PROP1_BOOL(ISREADONLY, READONLY); + DECL_PROP1(LAYOUTINFORMATION, Sequence< PropertyValue >, BOUND); + DECL_PROP1(NAME, OUString, READONLY); + DECL_PROP2_IFACE(NUMBERFORMATSSUPPLIER, XNumberFormatsSupplier, READONLY, TRANSIENT); + DECL_PROP1(PASSWORD, OUString, TRANSIENT); + DECL_PROP2_IFACE(SETTINGS, XPropertySet, BOUND, READONLY); + DECL_PROP1_BOOL(SUPPRESSVERSIONCL, BOUND); + DECL_PROP1(TABLEFILTER, Sequence< OUString >,BOUND); + DECL_PROP1(TABLETYPEFILTER, Sequence< OUString >,BOUND); + DECL_PROP1(URL, OUString, BOUND); + DECL_PROP1(USER, OUString, BOUND); + END_PROPERTY_HELPER(); +} + +// 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 != aValues.end() ; ++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() ); + const PropertyValue* pCopyEnd = std::remove_copy_if( + aValues.begin(), + aValues.end(), + aNonDefaultOrUserDefined.getArray(), + IsDefaultAndNotRemoveable( aPropertyAttributes ) + ); + aNonDefaultOrUserDefined.realloc( pCopyEnd - aNonDefaultOrUserDefined.getArray() ); + 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) + OInteractionAbort* pAbort = new OInteractionAbort; + OAuthenticationContinuation* pAuthenticate = new OAuthenticationContinuation; + + // the name which should be referred in the login dialog + OUString sServerName( m_pImpl->m_sName ); + INetURLObject aURLCheck( sServerName ); + if ( aURLCheck.GetProtocol() != INetProtocol::NotValid ) + sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous ); + + // the request + AuthenticationRequest aRequest; + aRequest.ServerName = sServerName; + aRequest.HasRealm = aRequest.HasAccount = false; + aRequest.HasUserName = aRequest.HasPassword = true; + aRequest.UserName = m_pImpl->m_sUser; + aRequest.Password = m_pImpl->m_sFailedPassword.isEmpty() ? m_pImpl->m_aPassword : m_pImpl->m_sFailedPassword; + OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest)); + Reference< XInteractionRequest > xRequest(pRequest); + // some knittings + pRequest->addContinuation(pAbort); + pRequest->addContinuation(pAuthenticate); + + // handle the request + try + { + _rxHandler->handle(xRequest); + } + 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_pSharedConnectionManager = new OSharedConnectionManager( m_pImpl->m_aContext ); + m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager; + } + xConn = m_pImpl->m_pSharedConnectionManager->getConnection( + m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this ); + } + + if ( xConn.is() ) + { + Reference< XComponent> xComp(xConn,UNO_QUERY); + if ( xComp.is() ) + xComp->addEventListener( static_cast< XContainerListener* >( this ) ); + m_pImpl->m_aConnections.emplace_back(xConn); + } + + return xConn; +} + +Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( ) +{ + ModelMethodGuard aGuard( *this ); + // tdf#114596 this may look nutty but see OBookmarkContainer::acquire() + return static_cast(&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(1); + aArgs[0] <<= NamedValue("DataSource",makeAny(xMy)); + xContainer.set( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext), UNO_QUERY); + } + } + if ( !xContainer.is() ) + { + TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) ); + xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, false ); + } + m_pImpl->m_xCommandDefinitions = xContainer; + } + return xContainer; +} + +// XTablesSupplier +Reference< XNameAccess > ODatabaseSource::getTables() +{ + ModelMethodGuard aGuard( *this ); + + Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions; + if ( !xContainer.is() ) + { + TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) ); + xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, true ); + m_pImpl->m_xTableDefinitions = xContainer; + } + return xContainer; +} + +void SAL_CALL ODatabaseSource::flush( ) +{ + try + { + // SYNCHRONIZED -> + { + ModelMethodGuard aGuard( *this ); + + typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel; + SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership ); + + if ( !xModel.is() ) + xModel.reset( m_pImpl->createNewModel_deliverOwnership(), SharedModel::TakeOwnership ); + + Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW ); + xStorable->store(); + } + // <- SYNCHRONIZED + + css::lang::EventObject aFlushedEvent(*this); + m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ ) +{ + ModelMethodGuard aGuard( *this ); + + // Okay, this is some hack. + // + // In general, we have the problem that embedded databases write into their underlying storage, which + // logically is one of our sub storage, and practically is a temporary file maintained by the + // package implementation. As long as we did not commit this storage and our main storage, + // the changes made by the embedded database engine are not really reflected in the database document + // file. This is Bad (TM) for a "real" database application - imagine somebody entering some + // data, and then crashing: For a database application, you would expect that the data still is present + // when you connect to the database next time. + // + // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot* + // provide the desired functionality as long as we do not have a package format which allows O(1) writes), + // we cannot completely fix this. However, we can relax the problem by committing more often - often + // enough so that data loss is more seldom, and seldom enough so that there's no noticeable performance + // decrease. + // + // For this, we introduced a few places which XFlushable::flush their connections, and register as + // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality). + // Then, when the connection is flushed, we commit both the database storage and our main storage. + // + // #i55274# + + OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" ); + bool bWasModified = m_pImpl->m_bModified; + m_pImpl->commitEmbeddedStorage(); + m_pImpl->setModified( bWasModified ); +} + +void SAL_CALL ODatabaseSource::addFlushListener( const Reference< css::util::XFlushListener >& _xListener ) +{ + m_aFlushListeners.addInterface(_xListener); +} + +void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< css::util::XFlushListener >& _xListener ) +{ + m_aFlushListeners.removeInterface(_xListener); +} + +void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ ) +{ + ModelMethodGuard aGuard( *this ); + if ( m_pImpl.is() ) + m_pImpl->setModified(true); +} + +void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ ) +{ + ModelMethodGuard aGuard( *this ); + if ( m_pImpl.is() ) + m_pImpl->setModified(true); +} + +void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ ) +{ + ModelMethodGuard aGuard( *this ); + if ( m_pImpl.is() ) + m_pImpl->setModified(true); +} + +// XDocumentDataSource +Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument() +{ + ModelMethodGuard aGuard( *this ); + + Reference< XModel > xModel( m_pImpl->getModel_noCreate() ); + if ( !xModel.is() ) + xModel = m_pImpl->createNewModel_deliverOwnership(); + + return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW ); +} + +void SAL_CALL ODatabaseSource::initialize( css::uno::Sequence< css::uno::Any > const & rArguments) +{ + ::comphelper::NamedValueCollection aProperties( rArguments ); + if (aProperties.has("ParentWindow")) + aProperties.get("ParentWindow") >>= m_pImpl->m_xDialogParent; +} + +Reference< XInterface > ODatabaseSource::getThis() const +{ + return *const_cast< ODatabaseSource* >( this ); +} + +} // namespace dbaccess + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_dba_ODatabaseSource(css::uno::XComponentContext* context, + css::uno::Sequence 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 000000000..b9d8e8bbf --- /dev/null +++ b/dbaccess/source/core/dataaccess/datasource.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DATASOURCE_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_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 + +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::OInterfaceContainerHelper2 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() throw( ) override; + virtual void SAL_CALL release() throw( ) 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 + +#endif // _DBA_COREDATAACCESS_DATALINK_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/definitioncontainer.cxx b/dbaccess/source/core/dataaccess/definitioncontainer.cxx new file mode 100644 index 000000000..dd099c81f --- /dev/null +++ b/dbaccess/source/core/dataaccess/definitioncontainer.cxx @@ -0,0 +1,671 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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) +IMPLEMENT_GETTYPES2(ODefinitionContainer,OContentHelper,ODefinitionContainer_Base); + +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.get(), 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, makeAny( _rName ), makeAny( _xNewElement ), makeAny( _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) || (_nIndex >= static_cast(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 makeAny(xProp); +} + +Any SAL_CALL ODefinitionContainer::getByName( const OUString& _rName ) +{ + MutexGuard aGuard(m_aMutex); + + return makeAny( 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 = comphelper::getUnoTunnelImplementation( _rxNewObject ); + if ( pContent.is() ) + { + TContentPtr pImpl = pContent->getImpl(); + rDefinitions.erase( pImpl ); + pImpl->m_aProps.aTitle = _rName; + rDefinitions.insert( _rName, pImpl ); + } + } + + m_aDocuments.push_back(m_aDocumentMap.emplace(_rName,_rxNewObject).first); + notifyDataSourceModified(); + // now update our structures + if ( _rxNewObject.is() ) + addObjectListener(_rxNewObject); + } + catch(Exception&) + { + OSL_FAIL("ODefinitionContainer::implAppend: caught something !"); + } +} + +void ODefinitionContainer::implReplace(const OUString& _rName, const Reference< XContent >& _rxNewObject) +{ + OSL_ENSURE(checkExistence(_rName), "ODefinitionContainer::implReplace : invalid name !"); + + Documents::iterator aFind = m_aDocumentMap.find(_rName); + removeObjectListener(aFind->second); + aFind->second = _rxNewObject; + addObjectListener(aFind->second); +} + +void ODefinitionContainer::approveNewObject(const OUString& _sName,const Reference< XContent >& _rxObject) const +{ + // check the arguments + if ( _sName.isEmpty() ) + throw IllegalArgumentException( + DBA_RES( RID_STR_NAME_MUST_NOT_BE_EMPTY ), + *this, + 0 ); + + if ( m_bCheckSlash && _sName.indexOf( '/' ) != -1 ) + throw IllegalArgumentException( + m_aErrorHelper.getErrorMessage( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES ), + *this, + 0 ); + + if ( !_rxObject.is() ) + throw IllegalArgumentException( + DBA_RES( RID_STR_NO_NULL_OBJECTS_IN_CONTAINER ), + *this, + 0 ); + + const ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + if ( rDefinitions.find( _sName ) != rDefinitions.end() ) + throw ElementExistException( + DBA_RES( RID_STR_NAME_ALREADY_USED ), + *this ); + + ::rtl::Reference< OContentHelper > pContent( comphelper::getUnoTunnelImplementation( _rxObject ) ); + if ( !pContent.is() ) + throw IllegalArgumentException( + DBA_RES( RID_STR_OBJECT_CONTAINER_MISMATCH ), + *this, + 1 ); + + if ( rDefinitions.find( pContent->getImpl() ) != rDefinitions.end() ) + throw ElementExistException( + DBA_RES( RID_STR_OBJECT_ALREADY_CONTAINED ), + *this ); +} + +// XPropertyChangeListener +void SAL_CALL ODefinitionContainer::propertyChange( const PropertyChangeEvent& evt ) +{ + MutexGuard aGuard(m_aMutex); + if( !(evt.PropertyName == PROPERTY_NAME || evt.PropertyName == "Title") ) + return; + + 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 000000000..9d88d2722 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentcontainer.cxx @@ -0,0 +1,737 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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(); +} + +IMPLEMENT_GETTYPES3(ODocumentContainer,ODefinitionContainer,OPropertyStateContainer,ODocumentContainer_Base); +IMPLEMENT_SERVICE_INFO_IMPLNAME(ODocumentContainer, "com.sun.star.comp.dba.ODocumentContainer"); +IMPLEMENT_SERVICE_INFO_SUPPORTS(ODocumentContainer); +IMPLEMENT_PROPERTYCONTAINER_DEFAULTS(ODocumentContainer) + +Sequence< OUString > SAL_CALL ODocumentContainer::getSupportedServiceNames( ) +{ + return { m_bFormsContainer ? OUString(SERVICE_NAME_FORM_COLLECTION) : OUString(SERVICE_NAME_REPORT_COLLECTION) }; +} + +OUString ODocumentContainer::determineContentType() const +{ + return OUString(); +} + +Reference< XContent > ODocumentContainer::createObject( const OUString& _rName) +{ + const ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( _rName ); + OSL_ENSURE( aFind != rDefinitions.end(), "ODocumentContainer::createObject:Invalid entry in map!" ); + if ( aFind->second->m_aProps.bIsFolder ) + return new ODocumentContainer( m_aContext, *this, aFind->second, m_bFormsContainer ); + return new ODocumentDefinition( *this, m_aContext, aFind->second, m_bFormsContainer ); +} + +Reference< XInterface > SAL_CALL ODocumentContainer::createInstance( const OUString& aServiceSpecifier ) +{ + return createInstanceWithArguments( aServiceSpecifier, Sequence< Any >() ); +} + +namespace +{ + template< class TYPE > + void lcl_extractAndRemove( ::comphelper::NamedValueCollection& io_rArguments, const OUString& i_rName, TYPE& o_rValue ) + { + if ( io_rArguments.has( i_rName ) ) + { + io_rArguments.get_ensureType( i_rName, o_rValue ); + io_rArguments.remove( i_rName ); + } + } +} + +Reference< XInterface > SAL_CALL ODocumentContainer::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& _aArguments ) +{ + Reference< XInterface > xRet; + Reference< XContent > xContent; + if ( ServiceSpecifier == SERVICE_SDB_DOCUMENTDEFINITION ) + { + MutexGuard aGuard(m_aMutex); + + // extract known arguments + OUString sName, sPersistentName, sURL, sMediaType, sDocServiceName; + Reference< XCommandProcessor > xCopyFrom; + Reference< XConnection > xConnection; + bool bAsTemplate( false ); + Sequence< sal_Int8 > aClassID; + + ::comphelper::NamedValueCollection aArgs( _aArguments ); + lcl_extractAndRemove( aArgs, PROPERTY_NAME, sName ); + lcl_extractAndRemove( aArgs, PROPERTY_PERSISTENT_NAME, sPersistentName ); + lcl_extractAndRemove( aArgs, PROPERTY_URL, sURL ); + lcl_extractAndRemove( aArgs, PROPERTY_EMBEDDEDOBJECT, xCopyFrom ); + lcl_extractAndRemove( aArgs, PROPERTY_ACTIVE_CONNECTION, xConnection ); + lcl_extractAndRemove( aArgs, PROPERTY_AS_TEMPLATE, bAsTemplate ); + lcl_extractAndRemove( aArgs, INFO_MEDIATYPE, sMediaType ); + lcl_extractAndRemove( aArgs, "DocumentServiceName" , sDocServiceName ); + + // ClassID has two allowed types, so a special treatment here + Any aClassIDArg = aArgs.get( "ClassID" ); + if ( aClassIDArg.hasValue() ) + { + if ( !( aClassIDArg >>= aClassID ) ) + { + // Extended for usage also with a string + OUString sClassIDString; + if ( !( aClassIDArg >>= sClassIDString ) ) + throw IllegalArgumentException( OUString(), *this, 2 ); + + aClassID = ::comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation( sClassIDString ); + } + +#if OSL_DEBUG_LEVEL > 0 + OUString sClassIDString = ::comphelper::MimeConfigurationHelper::GetStringClassIDRepresentation( aClassID ); + (void)sClassIDString; +#endif + aArgs.remove( "ClassID" ); + } + // Everything which now is still present in the arguments is passed to the embedded object + const Sequence< PropertyValue > aCreationArgs( aArgs.getPropertyValues() ); + + const ODefinitionContainer_Impl& rDefinitions( getDefinitions() ); + bool bNew = sPersistentName.isEmpty(); + if ( bNew ) + { + sPersistentName = "Obj" + OUString::number(rDefinitions.size() + 1); + Reference xElements = getContainerStorage(); + if ( xElements.is() ) + sPersistentName = ::dbtools::createUniqueName(xElements,sPersistentName); + + const bool bNeedClassID = !aClassID.hasElements() && sURL.isEmpty() ; + if ( xCopyFrom.is() ) + { + Sequence aIni(2); + aIni[0] <<= getContainerStorage(); + aIni[1] <<= 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(2); + aIni[0] <<= 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,makeAny(xNew)); + } + } + } + } + xRet = xContent; + return xRet; +} + +Sequence< OUString > SAL_CALL ODocumentContainer::getAvailableServiceNames( ) +{ + Sequence< OUString > aSe(3); + aSe[0] = SERVICE_SDB_DOCUMENTDEFINITION; + aSe[1] = SERVICE_NAME_FORM_COLLECTION; + aSe[2] = SERVICE_NAME_REPORT_COLLECTION; + return aSe; +} + +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( + makeAny( 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( + makeAny( 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( + makeAny( 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(const OUString& _sName,Reference< XNameContainer >& _xNameContainer,Any& _rRet,OUString& _sSimpleName) + { + sal_Int32 nIndex = 0; + OUString sName = _sName.getToken(0,'/',nIndex); + bool bRet = _xNameContainer->hasByName(sName); + if ( bRet ) + { + _sSimpleName = sName; + _rRet = _xNameContainer->getByName(_sSimpleName); + while ( nIndex != -1 && bRet ) + { + sName = _sName.getToken(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$", + _sName.getToken(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 = comphelper::getUnoTunnelImplementation(const_cast(this)->implGetByName( _sName, true )); + } + catch(const Exception&) + { + } + return pContent; +} + +void ODocumentContainer::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const +{ + _rDefault.clear(); +} + +void SAL_CALL ODocumentContainer::commit( ) +{ + MutexGuard aGuard(m_aMutex); + for (auto const& elem : m_aDocumentMap) + { + Reference 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::E_FORM : ODatabaseModelImpl::E_REPORT ) + : Reference< XStorage>(); +} + +void SAL_CALL ODocumentContainer::removeByName( const OUString& _rName ) +{ + ResettableMutexGuard aGuard(m_aMutex); + + // check the arguments + if (_rName.isEmpty()) + throw IllegalArgumentException(); + + if (!checkExistence(_rName)) + throw NoSuchElementException(_rName,*this); + + Reference< XCommandProcessor > xContent( implGetByName( _rName, true ), UNO_QUERY ); + if ( xContent.is() ) + { + Command aCommand; + + aCommand.Name = "delete"; + xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >()); + } + + // do the removal + implRemove(_rName); + + notifyByName( aGuard, _rName, nullptr, nullptr, E_REMOVED, ContainerListemers ); +} + +void SAL_CALL ODocumentContainer::rename( const OUString& newName ) +{ + try + { + osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex); + if ( newName == m_pImpl->m_aProps.aTitle ) + return; + + sal_Int32 nHandle = PROPERTY_ID_NAME; + Any aOld = makeAny(m_pImpl->m_aProps.aTitle); + Any aNew = makeAny(newName); + + aGuard.clear(); + fire(&nHandle, &aNew, &aOld, 1, true ); + m_pImpl->m_aProps.aTitle = newName; + fire(&nHandle, &aNew, &aOld, 1, false ); + } + catch(const PropertyVetoException&) + { + throw ElementExistException(newName,*this); + } +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentcontainer.hxx b/dbaccess/source/core/dataaccess/documentcontainer.hxx new file mode 100644 index 000000000..cec13d1f1 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentcontainer.hxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTCONTAINER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTCONTAINER_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTCONTAINER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentdefinition.cxx b/dbaccess/source/core/dataaccess/documentdefinition.cxx new file mode 100644 index 000000000..40fddc4de --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentdefinition.cxx @@ -0,0 +1,2106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "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 + +using namespace ::com::sun::star; +using namespace view; +using namespace uno; +using namespace util; +using namespace ucb; +using namespace beans; +using namespace lang; +using namespace awt; +using namespace embed; +using namespace frame; +using namespace document; +using namespace sdbc; +using namespace sdb; +using namespace io; +using namespace container; +using namespace datatransfer; +using namespace task; +using namespace form; +using namespace drawing; +using namespace ::osl; +using namespace ::comphelper; +using namespace ::cppu; + +using sdb::application::XDatabaseDocumentUI; +namespace DatabaseObject = sdb::application::DatabaseObject; + +#define DEFAULT_WIDTH 10000 +#define DEFAULT_HEIGHT 7500 + +namespace dbaccess +{ + + typedef ::std::optional< bool > optional_bool; + + // helper + namespace + { + OUString lcl_determineContentType_nothrow( const Reference< XStorage >& _rxContainerStorage, + const OUString& _rEntityName ) + { + OUString sContentType; + try + { + ::utl::SharedUNOComponent< XPropertySet > xStorageProps( + _rxContainerStorage->openStorageElement( _rEntityName, ElementModes::READ ), UNO_QUERY_THROW ); + OSL_VERIFY( xStorageProps->getPropertyValue( INFO_MEDIATYPE ) >>= sContentType ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return sContentType; + } + } + + // OEmbedObjectHolder + typedef ::cppu::WeakComponentImplHelper< embed::XStateChangeListener > TEmbedObjectHolder; + + namespace { + + class OEmbedObjectHolder : public ::cppu::BaseMutex + ,public TEmbedObjectHolder + { + Reference< XEmbeddedObject > m_xBroadCaster; + ODocumentDefinition* m_pDefinition; + bool m_bInStateChange; + protected: + virtual void SAL_CALL disposing() override; + public: + OEmbedObjectHolder(const Reference< XEmbeddedObject >& _xBroadCaster,ODocumentDefinition* _pDefinition) + : TEmbedObjectHolder(m_aMutex) + ,m_xBroadCaster(_xBroadCaster) + ,m_pDefinition(_pDefinition) + ,m_bInStateChange(false) + { + osl_atomic_increment( &m_refCount ); + { + if ( m_xBroadCaster.is() ) + m_xBroadCaster->addStateChangeListener(this); + } + osl_atomic_decrement( &m_refCount ); + } + + virtual void SAL_CALL changingState( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override; + virtual void SAL_CALL stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override; + virtual void SAL_CALL disposing( const lang::EventObject& Source ) override; + }; + + } + + void SAL_CALL OEmbedObjectHolder::disposing() + { + if ( m_xBroadCaster.is() ) + m_xBroadCaster->removeStateChangeListener(this); + m_xBroadCaster = nullptr; + m_pDefinition = nullptr; + } + + void SAL_CALL OEmbedObjectHolder::changingState( const lang::EventObject& /*aEvent*/, ::sal_Int32 /*nOldState*/, ::sal_Int32 /*nNewState*/ ) + { + } + + void SAL_CALL OEmbedObjectHolder::stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) + { + if ( !m_bInStateChange && nNewState == EmbedStates::RUNNING && nOldState == EmbedStates::ACTIVE && m_pDefinition ) + { + m_bInStateChange = true; + Reference 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(); +} + +IMPLEMENT_GETTYPES3(ODocumentDefinition,OContentHelper,OPropertyStateContainer,ODocumentDefinition_Base); +IMPLEMENT_FORWARD_XINTERFACE3( ODocumentDefinition,OContentHelper,OPropertyStateContainer,ODocumentDefinition_Base) + +void ODocumentDefinition::registerProperties() +{ +#define REGISTER_PROPERTY( name, location ) \ + registerProperty( PROPERTY_##name, PROPERTY_ID_##name, PropertyAttribute::READONLY, &location, cppu::UnoType::get() ); + +#define REGISTER_PROPERTY_BV( name, location ) \ + registerProperty( PROPERTY_##name, PROPERTY_ID_##name, PropertyAttribute::CONSTRAINED | PropertyAttribute::BOUND | PropertyAttribute::READONLY, &location, cppu::UnoType::get() ); + + REGISTER_PROPERTY_BV( NAME, m_pImpl->m_aProps.aTitle ); + REGISTER_PROPERTY ( AS_TEMPLATE, m_pImpl->m_aProps.bAsTemplate ); + REGISTER_PROPERTY ( PERSISTENT_NAME, m_pImpl->m_aProps.sPersistentName ); + REGISTER_PROPERTY ( IS_FORM, m_bForm ); +} + +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() ) + { + OUStringBuffer aBuffer; + aBuffer.append( ODatabaseModelImpl::getObjectContainerStorageName( m_bForm ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT ) ); + aBuffer.append( '/' ); + aBuffer.append( m_pImpl->m_aProps.sPersistentName ); + sPersistentPath = aBuffer.makeStringAndClear(); + } + 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( 1 ); + aManualProps[0].Name = PROPERTY_PERSISTENT_PATH; + aManualProps[0].Handle = PROPERTY_ID_PERSISTENT_PATH; + aManualProps[0].Type = ::cppu::UnoType::get(); + aManualProps[0].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.get() ); + + // 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",makeAny(true)); + xViewSettings->setPropertyValue("ShowVertRuler",makeAny(true)); + xViewSettings->setPropertyValue("ShowHoriRuler",makeAny(true)); + xViewSettings->setPropertyValue("IsRasterVisible",makeAny(true)); + xViewSettings->setPropertyValue("IsSnapToRaster",makeAny(true)); + xViewSettings->setPropertyValue("ShowOnlineLayout",makeAny(true)); + xViewSettings->setPropertyValue("RasterSubdivisionX",makeAny(sal_Int32(5))); + xViewSettings->setPropertyValue("RasterSubdivisionY",makeAny(sal_Int32(5))); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void ODocumentDefinition::impl_showOrHideComponent_throw( const bool i_bShow ) +{ + const sal_Int32 nCurrentState = m_xEmbeddedObject.is() ? m_xEmbeddedObject->getCurrentState() : EmbedStates::LOADED; + switch ( nCurrentState ) + { + default: + case EmbedStates::LOADED: + throw embed::WrongStateException( OUString(), *this ); + + case EmbedStates::RUNNING: + if ( !i_bShow ) + // fine, a running (and not yet active) object is never visible + return; + { + LockModifiable aLockModify( impl_getComponent_throw() ); + m_xEmbeddedObject->changeState( EmbedStates::ACTIVE ); + impl_onActivateEmbeddedObject_nothrow( false ); + } + break; + + case EmbedStates::ACTIVE: + { + Reference< XModel > xEmbeddedDoc( impl_getComponent_throw(), UNO_QUERY_THROW ); + Reference< XController > xEmbeddedController( xEmbeddedDoc->getCurrentController(), UNO_SET_THROW ); + Reference< XFrame > xEmbeddedFrame( xEmbeddedController->getFrame(), UNO_SET_THROW ); + Reference< XWindow > xEmbeddedWindow( xEmbeddedFrame->getContainerWindow(), UNO_SET_THROW ); + xEmbeddedWindow->setVisible( i_bShow ); + } + break; + } +} + +Any ODocumentDefinition::onCommandOpenSomething( const Any& _rOpenArgument, const bool _bActivate, + const Reference< XCommandEnvironment >& _rxEnvironment ) +{ + OExecuteImpl aExecuteGuard( m_bInExecute ); + + Reference< XConnection > xConnection; + sal_Int32 nOpenMode = OpenMode::DOCUMENT; + + ::comphelper::NamedValueCollection aDocumentArgs; + + // for the document, default to the interaction handler as used for loading the DB doc + // This might be overwritten below, when examining _rOpenArgument. + const ::comphelper::NamedValueCollection& aDBDocArgs( m_pImpl->m_pDataSource->getMediaDescriptor() ); + Reference< XInteractionHandler > xHandler( aDBDocArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) ); + if ( xHandler.is() ) + aDocumentArgs.put( "InteractionHandler", xHandler ); + + ::std::optional< sal_Int16 > aDocumentMacroMode; + + if ( !lcl_extractOpenMode( _rOpenArgument, nOpenMode ) ) + { + Sequence< PropertyValue > aArguments; + if ( _rOpenArgument >>= aArguments ) + { + const PropertyValue* pIter = aArguments.getConstArray(); + const PropertyValue* pEnd = pIter + aArguments.getLength(); + for ( ;pIter != pEnd; ++pIter ) + { + if ( pIter->Name == PROPERTY_ACTIVE_CONNECTION ) + { + xConnection.set( pIter->Value, UNO_QUERY ); + continue; + } + + if ( lcl_extractOpenMode( pIter->Value, nOpenMode ) ) + continue; + + if ( pIter->Name == "MacroExecutionMode" ) + { + sal_Int16 nMacroExecMode( !aDocumentMacroMode ? MacroExecMode::USE_CONFIG : *aDocumentMacroMode ); + OSL_VERIFY( pIter->Value >>= nMacroExecMode ); + aDocumentMacroMode = nMacroExecMode; + continue; + } + + // unknown argument -> pass to the loaded document + aDocumentArgs.put( pIter->Name, pIter->Value ); + } + } + } + + bool bExecuteDBDocMacros = m_pImpl->m_pDataSource->checkMacrosOnLoading(); + // Note that this call implies the user might be asked for the macro execution mode. + // Normally, this would happen when the database document is loaded, and subsequent calls + // will simply use the user's decision from this point in time. + // However, it is possible to programmatically load forms/reports, without actually + // loading the database document into a frame. In this case, the user will be asked + // here and now. + // #i87741# + + // allow the command arguments to downgrade the macro execution mode, but not to upgrade + // it + if ( ( m_pImpl->m_pDataSource->getImposedMacroExecMode() == MacroExecMode::USE_CONFIG ) + && bExecuteDBDocMacros + ) + { + // while loading the whole database document, USE_CONFIG, was passed. + // Additionally, *by now* executing macros from the DB doc is allowed (this is what bExecuteDBDocMacros + // indicates). This means either one of: + // 1. The DB doc or one of the sub docs contained macros and + // 1a. the user explicitly allowed executing them + // 1b. the configuration allows executing them without asking the user + // 2. Neither the DB doc nor the sub docs contained macros, thus macro + // execution was silently enabled, assuming that any macro will be a + // user-created macro + // + // The problem with this: If the to-be-opened sub document has macros embedded in + // the content.xml (which is valid ODF, but normally not produced by OOo itself), + // then this has not been detected while loading the database document - it would + // be too expensive, as it effectively would require loading all forms/reports. + // + // So, in such a case, and with 2. above, we would silently execute those macros, + // regardless of the global security settings - which would be a security issue, of + // course. + if ( m_pImpl->m_pDataSource->determineEmbeddedMacros() == ODatabaseModelImpl::eNoMacros ) + { + // this is case 2. from above + // So, pass a USE_CONFIG to the to-be-loaded document. This means that + // the user will be prompted with a security message upon opening this + // sub document, in case the settings require this, *and* the document + // contains scripts in the content.xml. But this is better than the security + // issue we had before ... + aDocumentMacroMode = MacroExecMode::USE_CONFIG; + } + } + + if ( !aDocumentMacroMode ) + { + // nobody so far felt responsible for setting it + // => use the DBDoc-wide macro exec mode for the document, too + aDocumentMacroMode = bExecuteDBDocMacros ? MacroExecMode::ALWAYS_EXECUTE_NO_WARN + : MacroExecMode::NEVER_EXECUTE; + } + aDocumentArgs.put( "MacroExecutionMode", *aDocumentMacroMode ); + + if ( ( nOpenMode == OpenMode::ALL ) + || ( nOpenMode == OpenMode::FOLDERS ) + || ( nOpenMode == OpenMode::DOCUMENTS ) + || ( nOpenMode == OpenMode::DOCUMENT_SHARE_DENY_NONE ) + || ( nOpenMode == OpenMode::DOCUMENT_SHARE_DENY_WRITE ) + ) + { + // not supported + ucbhelper::cancelCommandExecution( + makeAny( 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 makeAny( xReportEngine->createDocumentModel() ); + return makeAny( 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.get() ); + } + + if ( !m_bForm && m_pImpl->m_aProps.bAsTemplate && !m_bOpenInDesign ) + ODocumentDefinition::fillReportData( m_aContext, getComponent(), xConnection ); + + return makeAny( 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 makeAny( 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( + makeAny( 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( + makeAny( 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, makeAny( 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( + makeAny( 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,aMediaDesc(1); + aMediaDesc[0].Name = PROPERTY_URL; + aMediaDesc[0].Value <<= _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); + OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest)); + Reference< XInteractionRequest > xRequest(pRequest); + // some knittings + // two continuations allowed: OK and Cancel + ODocumentSaveContinuation* pDocuSave = nullptr; + + if ( m_pImpl->m_aProps.aTitle.isEmpty() ) + { + pDocuSave = new ODocumentSaveContinuation; + pRequest->addContinuation(pDocuSave); + } + if ( _bApprove ) + { + OInteraction< XInteractionApprove >* pApprove = new OInteraction< XInteractionApprove >; + pRequest->addContinuation(pApprove); + } + + OInteraction< XInteractionDisapprove >* pDisApprove = new OInteraction< XInteractionDisapprove >; + pRequest->addContinuation(pDisApprove); + + OInteractionAbort* 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(xRequest); + + 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(),makeAny(xContent)); + + updateDocumentTitle(); + } + } + + ::osl::MutexGuard aGuard(m_aMutex); + Reference xPersist(m_xEmbeddedObject,UNO_QUERY); + if ( xPersist.is() ) + { + xPersist->storeOwn(); + notifyDataSourceModified(); + } + } + catch(const Exception&) + { + OSL_FAIL("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); + OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aRequest)); + Reference< XInteractionRequest > xRequest(pRequest); + // some knittings + // two continuations allowed: OK and Cancel + ODocumentSaveContinuation* pDocuSave = new ODocumentSaveContinuation; + pRequest->addContinuation(pDocuSave); + OInteraction< XInteractionDisapprove >* pDisApprove = new OInteraction< XInteractionDisapprove >; + pRequest->addContinuation(pDisApprove); + OInteractionAbort* pAbort = new OInteractionAbort; + pRequest->addContinuation(pAbort); + + // create the handler, let it handle the request + Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(m_aContext, nullptr) ); + xHandler->handle(xRequest); + + 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, makeAny( xComponent ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + Reference xPersist(m_xEmbeddedObject,UNO_QUERY); + if ( xPersist.is() ) + { + xPersist->storeOwn(); + notifyDataSourceModified(); + } + } + } + } + catch(const Exception&) + { + OSL_FAIL("ODocumentDefinition::save: caught an Exception (tried to let the InteractionHandler handle it)!"); + } +} + +namespace +{ + void lcl_putLoadArgs( ::comphelper::NamedValueCollection& _io_rArgs, const optional_bool& _bSuppressMacros, const optional_bool& _bReadOnly ) + { + if ( !!_bSuppressMacros ) + { + if ( *_bSuppressMacros ) + { + // if we're to suppress macros, do exactly this + _io_rArgs.put( "MacroExecutionMode", MacroExecMode::NEVER_EXECUTE ); + } + else + { + // otherwise, put the setting only if not already present + if ( !_io_rArgs.has( "MacroExecutionMode" ) ) + { + _io_rArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); + } + } + } + + if ( !!_bReadOnly ) + _io_rArgs.put( "ReadOnly", *_bReadOnly ); + } +} + +namespace +{ + Reference< XFrame > lcl_getDatabaseDocumentFrame( ODatabaseModelImpl const & _rImpl ) + { + Reference< XModel > xDatabaseDocumentModel( _rImpl.getModel_noCreate() ); + + Reference< XController > xDatabaseDocumentController; + if ( xDatabaseDocumentModel.is() ) + xDatabaseDocumentController = xDatabaseDocumentModel->getCurrentController(); + + Reference< XFrame > xFrame; + if ( xDatabaseDocumentController.is() ) + xFrame = xDatabaseDocumentController->getFrame(); + + return xFrame; + } +} + +bool ODocumentDefinition::objectSupportsEmbeddedScripts() const +{ + bool bAllowDocumentMacros = !m_pImpl->m_pDataSource + || ( m_pImpl->m_pDataSource->determineEmbeddedMacros() == ODatabaseModelImpl::eSubDocumentMacros ); + + // if *any* of the objects of the database document already has macros, we + // continue to allow it to have them, until the user does a migration. + // If there are no macros, we don't allow them to be created. + + return bAllowDocumentMacros; +} + +OUString ODocumentDefinition::determineContentType() const +{ + return lcl_determineContentType_nothrow( getContainerStorage(), m_pImpl->m_aProps.sPersistentName ); +} + +void ODocumentDefinition::separateOpenCommandArguments( const Sequence< PropertyValue >& i_rOpenCommandArguments, + ::comphelper::NamedValueCollection& o_rDocumentLoadArgs, ::comphelper::NamedValueCollection& o_rEmbeddedObjectDescriptor ) +{ + ::comphelper::NamedValueCollection aOpenCommandArguments( i_rOpenCommandArguments ); + + const char* const pObjectDescriptorArgs[] = + { + "RecoveryStorage" + }; + for (const char* pObjectDescriptorArg : pObjectDescriptorArgs) + { + if ( aOpenCommandArguments.has( pObjectDescriptorArg ) ) + { + o_rEmbeddedObjectDescriptor.put( pObjectDescriptorArg, aOpenCommandArguments.get( pObjectDescriptorArg ) ); + aOpenCommandArguments.remove( pObjectDescriptorArg ); + } + } + + 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.get(); + + ::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() ) + { + css::io::WrongFormatException aWFE; + aWFE.Message = DBA_RES( RID_STR_MISSING_EXTENSION ); + throw aWFE; + } + } + if ( !aClassID.hasElements() ) + { + if ( m_bForm ) + aClassID = MimeConfigurationHelper::GetSequenceClassID(SO3_SW_CLASSID); + else + { + aClassID = MimeConfigurationHelper::GetSequenceClassID(SO3_RPT_CLASSID_90); + } + } + } + + OSL_ENSURE( aClassID.hasElements(),"No Class ID" ); + + Sequence< PropertyValue > aEmbeddedObjectDescriptor; + Sequence< PropertyValue > aLoadArgs( fillLoadArgs( + i_rConnection, _bSuppressMacros, _bReadOnly, i_rOpenCommandArguments, aEmbeddedObjectDescriptor ) ); + + m_xEmbeddedObject.set(xEmbedFactory->createInstanceUserInit(aClassID + ,sDocumentService + ,xStorage + ,m_pImpl->m_aProps.sPersistentName + ,nEntryConnectionMode + ,aLoadArgs + ,aEmbeddedObjectDescriptor + ),UNO_QUERY); + if ( m_xEmbeddedObject.is() ) + { + if ( !m_pClientHelper.is() ) + { + m_pClientHelper = new OEmbeddedClientHelper; + } + Reference xClient = m_pClientHelper.get(); + m_xEmbeddedObject->setClientSite(xClient); + 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; + } + Reference xClient = m_pClientHelper.get(); + m_xEmbeddedObject->setClientSite(xClient); + + 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 ) +{ + OUStringBuffer aBuffer; + aBuffer.append( getHierarchicalName() ); + aBuffer.append( '/' ); + aBuffer.append( i_rRelativeName ); + return aBuffer.makeStringAndClear(); +} + +void SAL_CALL ODocumentDefinition::rename( const OUString& _rNewName ) +{ + try + { + ::osl::ResettableMutexGuard aGuard(m_aMutex); + if ( _rNewName == m_pImpl->m_aProps.aTitle ) + return; + + // document definitions are organized in a hierarchical way, so reject names + // which contain a /, as this is reserved for hierarchy level separation + if ( _rNewName.indexOf( '/' ) != -1 ) + m_aErrorHelper.raiseException( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES, *this ); + + NameChangeNotifier aNameChangeAndNotify( *this, _rNewName, aGuard ); + m_pImpl->m_aProps.aTitle = _rNewName; + + if ( m_xEmbeddedObject.is() && m_xEmbeddedObject->getCurrentState() == EmbedStates::ACTIVE ) + updateDocumentTitle(); + } + catch(const PropertyVetoException&) + { + throw ElementExistException(_rNewName,*this); + } +} + +Reference< XStorage> ODocumentDefinition::getContainerStorage() const +{ + return m_pImpl->m_pDataSource + ? m_pImpl->m_pDataSource->getStorage( m_bForm ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT ) + : Reference< XStorage>(); +} + +bool ODocumentDefinition::isModified() +{ + osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex); + bool bRet = false; + if ( m_xEmbeddedObject.is() ) + { + Reference 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 > xExecuteable( + _rContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.wizards.report.CallReportWizard", aArgs, _rContext), UNO_QUERY_THROW ); + xExecuteable->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( makeAny( i_rDocumentDefinition.getCurrentName() ) ) + ,m_aNewValue( makeAny( i_rNewName ) ) + ,m_rClearForNotify( i_rClearForNotify ) +{ + impl_fireEvent_throw( true ); +} + +NameChangeNotifier::~NameChangeNotifier() +{ + impl_fireEvent_throw( false ); +} + +void NameChangeNotifier::impl_fireEvent_throw( const bool i_bVetoable ) +{ + m_rClearForNotify.clear(); + m_rDocumentDefinition.firePropertyChange( + PROPERTY_ID_NAME, m_aNewValue, m_aOldValue, i_bVetoable, ODocumentDefinition::NotifierAccess() ); + m_rClearForNotify.reset(); +} + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentdefinition.hxx b/dbaccess/source/core/dataaccess/documentdefinition.hxx new file mode 100644 index 000000000..9910d61d8 --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentdefinition.hxx @@ -0,0 +1,359 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTDEFINITION_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTDEFINITION_HXX + +#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 >& _rContxt, + 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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTDEFINITION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documenteventexecutor.cxx b/dbaccess/source/core/dataaccess/documenteventexecutor.cxx new file mode 100644 index 000000000..3d16ee6eb --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventexecutor.cxx @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "documenteventexecutor.hxx" + +#include +#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; + + // DocumentEventExecutor_Data + struct DocumentEventExecutor_Data + { + WeakReference< XEventsSupplier > xDocument; + Reference< XURLTransformer > xURLTransformer; + + explicit DocumentEventExecutor_Data( const Reference< XEventsSupplier >& _rxDocument ) + :xDocument( _rxDocument ) + { + } + }; + + namespace + { + void lcl_dispatchScriptURL_throw( DocumentEventExecutor_Data const & _rDocExecData, + const OUString& _rScriptURL, const DocumentEvent& _rTrigger ) + { + Reference< XModel > xDocument( _rDocExecData.xDocument.get(), UNO_QUERY_THROW ); + + Reference< XController > xController( xDocument->getCurrentController() ); + Reference< XDispatchProvider > xDispProv; + if ( xController.is() ) + xDispProv.set( xController->getFrame(), UNO_QUERY ); + if ( !xDispProv.is() ) + { + OSL_FAIL( "lcl_dispatchScriptURL_throw: no controller/frame? How should I dispatch?" ); + return; + } + + URL aScriptURL; + aScriptURL.Complete = _rScriptURL; + if ( _rDocExecData.xURLTransformer.is() ) + _rDocExecData.xURLTransformer->parseStrict( aScriptURL ); + + // unfortunately, executing a script can trigger all kind of complex stuff, and unfortunately, not + // every component involved into this properly cares for thread safety. To be on the safe side, + // we lock the solar mutex here. + SolarMutexGuard aSolarGuard; + + Reference< XDispatch > xDispatch( xDispProv->queryDispatch( aScriptURL, OUString(), 0 ) ); + if ( !xDispatch.is() ) + { + OSL_FAIL( "lcl_dispatchScriptURL_throw: no dispatcher for the script URL!" ); + return; + } + + PropertyValue aEventParam; + aEventParam.Value <<= _rTrigger; + Sequence< PropertyValue > aDispatchArgs( &aEventParam, 1 ); + xDispatch->dispatch( aScriptURL, aDispatchArgs ); + } + } + + // DocumentEventExecutor + DocumentEventExecutor::DocumentEventExecutor( const Reference & _rContext, + const Reference< XEventsSupplier >& _rxDocument ) + :m_pData( new DocumentEventExecutor_Data( _rxDocument ) ) + { + Reference< XDocumentEventBroadcaster > xBroadcaster( _rxDocument, UNO_QUERY_THROW ); + + osl_atomic_increment( &m_refCount ); + { + xBroadcaster->addDocumentEventListener( this ); + } + osl_atomic_decrement( &m_refCount ); + + try + { + m_pData->xURLTransformer = URLTransformer::create(_rContext); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + DocumentEventExecutor::~DocumentEventExecutor() + { + } + + void SAL_CALL DocumentEventExecutor::documentEventOccured( const DocumentEvent& Event ) + { + Reference< XEventsSupplier > xEventsSupplier( m_pData->xDocument.get(), UNO_QUERY ); + if ( !xEventsSupplier.is() ) + { + OSL_FAIL( "DocumentEventExecutor::documentEventOccurred: no document anymore, but still being notified?" ); + return; + } + + Reference< XModel > xDocument( xEventsSupplier, UNO_QUERY_THROW ); + + try + { + Reference< XNameAccess > xDocEvents( xEventsSupplier->getEvents(), UNO_SET_THROW ); + if ( !xDocEvents->hasByName( Event.EventName ) ) + { + // this is worth an assertion: We are listener at the very same document which we just asked + // for its events. So when EventName is fired, why isn't it supported by xDocEvents? + OSL_FAIL( "DocumentEventExecutor::documentEventOccurred: an unsupported event is notified!" ); + return; + } + + const ::comphelper::NamedValueCollection aScriptDescriptor( xDocEvents->getByName( Event.EventName ) ); + + OUString sEventType; + bool bScriptAssigned = aScriptDescriptor.get_ensureType( "EventType", sEventType ); + + OUString sScript; + bScriptAssigned = bScriptAssigned && aScriptDescriptor.get_ensureType( "Script", sScript ); + + if ( !bScriptAssigned ) + // no script is assigned to this event + return; + + bool bDispatchScriptURL = ( sEventType == "Script" || sEventType == "Service" ); + bool bNonEmptyScript = !sScript.isEmpty(); + + OSL_ENSURE( bDispatchScriptURL && bNonEmptyScript, + "DocumentEventExecutor::documentEventOccurred: invalid/unsupported script descriptor" ); + + if ( bDispatchScriptURL && bNonEmptyScript ) + { + lcl_dispatchScriptURL_throw( *m_pData, sScript, Event ); + } + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void SAL_CALL DocumentEventExecutor::disposing( const lang::EventObject& /*_Source*/ ) + { + // not interested in + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documenteventexecutor.hxx b/dbaccess/source/core/dataaccess/documenteventexecutor.hxx new file mode 100644 index 000000000..5246984ce --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventexecutor.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTEVENTEXECUTOR_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTEVENTEXECUTOR_HXX + +#include +#include + +#include + +#include + +namespace com::sun::star::uno { class XComponentContext; } + +namespace dbaccess +{ + + struct DocumentEventExecutor_Data; + // DocumentEventExecutor + typedef ::cppu::WeakImplHelper < css::document::XDocumentEventListener + > DocumentEventExecutor_Base; + class DocumentEventExecutor : public DocumentEventExecutor_Base + { + public: + DocumentEventExecutor( + const css::uno::Reference< css::uno::XComponentContext >& _rContext, + const css::uno::Reference< css::document::XEventsSupplier >& _rxDocument ); + + protected: + virtual ~DocumentEventExecutor() override; + + // css.document.XDocumentEventListener + virtual void SAL_CALL documentEventOccured( const css::document::DocumentEvent& Event ) override; + // css.lang.XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + private: + std::unique_ptr< DocumentEventExecutor_Data > m_pData; + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTEVENTEXECUTOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documenteventnotifier.cxx b/dbaccess/source/core/dataaccess/documenteventnotifier.cxx new file mode 100644 index 000000000..16b46ad6d --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventnotifier.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 "documenteventnotifier.hxx" + +#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::OInterfaceContainerHelper2 m_aLegacyEventListeners; + ::comphelper::OInterfaceContainerHelper2 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() throw () override; + virtual void SAL_CALL release() throw () 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() throw () + { + osl_atomic_increment( &m_refCount ); + } + + void SAL_CALL DocumentEventNotifier_Impl::release() throw () + { + 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(); + //TODO: a protocol is missing how to join with the thread before + // exit(3), to ensure the thread is no longer relying on any + // infrastructure while that infrastructure is being shut down + // in atexit handlers; simply calling join here leads to + // deadlock, as this thread holds the solar mutex while the + // other thread is typically blocked waiting for the solar mutex + // For now, use newAutoJoinAsyncEventNotifier which is + // better than nothing. + m_pEventBroadcaster.reset(); + } + + lang::EventObject aEvent( m_rDocument ); + aGuard.clear(); + // <-- SYNCHRONIZED + + m_aLegacyEventListeners.disposeAndClear( aEvent ); + m_aDocumentEventListeners.disposeAndClear( aEvent ); + + // SYNCHRONIZED -> + aGuard.reset(); + m_bDisposed = true; + // <-- SYNCHRONIZED + } + + void DocumentEventNotifier_Impl::onDocumentInitialized() + { + if ( m_bInitialized ) + throw DoubleInitializationException(); + + m_bInitialized = true; + if (m_pEventBroadcaster) + { + // there are already pending asynchronous events + ::comphelper::AsyncEventNotifierAutoJoin::launch(m_pEventBroadcaster); + } + } + + void DocumentEventNotifier_Impl::impl_notifyEvent_nothrow( const DocumentEvent& _rEvent ) + { + OSL_PRECOND( m_bInitialized, + "DocumentEventNotifier_Impl::impl_notifyEvent_nothrow: only to be called when the document is already initialized!" ); + try + { + document::EventObject aLegacyEvent( _rEvent.Source, _rEvent.EventName ); + m_aLegacyEventListeners.notifyEach( &document::XEventListener::notifyEvent, aLegacyEvent ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + try + { + m_aDocumentEventListeners.notifyEach( &XDocumentEventListener::documentEventOccured, _rEvent ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void DocumentEventNotifier_Impl::impl_notifyEventAsync_nothrow( const DocumentEvent& _rEvent ) + { + if (!m_pEventBroadcaster) + { + m_pEventBroadcaster = ::comphelper::AsyncEventNotifierAutoJoin + ::newAsyncEventNotifierAutoJoin("DocumentEventNotifier"); + if ( m_bInitialized ) + { + // start processing the events if and only if we (our document, respectively) are + // already initialized + ::comphelper::AsyncEventNotifierAutoJoin::launch(m_pEventBroadcaster); + } + } + m_pEventBroadcaster->addEvent( new DocumentEventHolder( _rEvent ), this ); + } + + void DocumentEventNotifier_Impl::processEvent( const ::comphelper::AnyEvent& _rEvent ) + { + // beware, this is called from the notification thread + { + ::osl::MutexGuard aGuard( m_rMutex ); + if ( m_bDisposed ) + return; + } + const DocumentEventHolder& rEventHolder = dynamic_cast< const DocumentEventHolder& >( _rEvent ); + impl_notifyEvent_nothrow( rEventHolder.getEventObject() ); + } + + // DocumentEventNotifier + DocumentEventNotifier::DocumentEventNotifier( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex ) + :m_pImpl( new DocumentEventNotifier_Impl( _rBroadcasterDocument, _rMutex ) ) + { + } + + DocumentEventNotifier::~DocumentEventNotifier() + { + } + + void DocumentEventNotifier::disposing() + { + m_pImpl->disposing(); + } + + void DocumentEventNotifier::onDocumentInitialized() + { + m_pImpl->onDocumentInitialized(); + } + + void DocumentEventNotifier::addLegacyEventListener( const Reference< document::XEventListener >& Listener ) + { + m_pImpl->addLegacyEventListener( Listener ); + } + + void DocumentEventNotifier::removeLegacyEventListener( const Reference< document::XEventListener >& Listener ) + { + m_pImpl->removeLegacyEventListener( Listener ); + } + + void DocumentEventNotifier::addDocumentEventListener( const Reference< XDocumentEventListener >& Listener ) + { + m_pImpl->addDocumentEventListener( Listener ); + } + + void DocumentEventNotifier::removeDocumentEventListener( const Reference< XDocumentEventListener >& Listener ) + { + m_pImpl->removeDocumentEventListener( Listener ); + } + + void DocumentEventNotifier::notifyDocumentEvent( const OUString& EventName, + const Reference< XController2 >& ViewController, const Any& Supplement ) + { + m_pImpl->notifyDocumentEvent( EventName, ViewController, Supplement ); + } + + void DocumentEventNotifier::notifyDocumentEventAsync( const OUString& EventName, + const Reference< XController2 >& ViewController, const Any& Supplement ) + { + m_pImpl->notifyDocumentEventAsync( EventName, ViewController, Supplement ); + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documenteventnotifier.hxx b/dbaccess/source/core/dataaccess/documenteventnotifier.hxx new file mode 100644 index 000000000..cc655268f --- /dev/null +++ b/dbaccess/source/core/dataaccess/documenteventnotifier.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTEVENTNOTIFIER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTEVENTNOTIFIER_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_DOCUMENTEVENTNOTIFIER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/documentevents.cxx b/dbaccess/source/core/dataaccess/documentevents.cxx new file mode 100644 index 000000000..d3c6a03ce --- /dev/null +++ b/dbaccess/source/core/dataaccess/documentevents.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 + +namespace dbaccess +{ + + using ::com::sun::star::uno::Any; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::container::NoSuchElementException; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Type; + + // DocumentEvents_Data + struct DocumentEvents_Data + { + ::cppu::OWeakObject& rParent; + ::osl::Mutex& rMutex; + DocumentEventsData& rEventsData; + + DocumentEvents_Data( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData ) + :rParent( _rParent ) + ,rMutex( _rMutex ) + ,rEventsData( _rEventsData ) + { + } + DocumentEvents_Data(const DocumentEvents_Data&) = delete; + const DocumentEvents_Data& operator=(const DocumentEvents_Data&) = delete; + }; + + namespace { + + // helper + struct DocumentEventData + { + const char* pAsciiEventName; + bool bNeedsSyncNotify; + }; + + const DocumentEventData* lcl_getDocumentEventData() + { + static const DocumentEventData s_aData[] = { + { "OnCreate", true }, + { "OnLoadFinished", true }, + { "OnNew", false }, // compatibility, see https://bz.apache.org/ooo/show_bug.cgi?id=46484 + { "OnLoad", false }, // compatibility, see https://bz.apache.org/ooo/show_bug.cgi?id=46484 + { "OnSaveAs", true }, + { "OnSaveAsDone", false }, + { "OnSaveAsFailed", false }, + { "OnSave", true }, + { "OnSaveDone", false }, + { "OnSaveFailed", false }, + { "OnSaveTo", true }, + { "OnSaveToDone", false }, + { "OnSaveToFailed", false }, + { "OnPrepareUnload", true }, + { "OnUnload", true }, + { "OnFocus", false }, + { "OnUnfocus", false }, + { "OnModifyChanged", false }, + { "OnViewCreated", false }, + { "OnPrepareViewClosing", true }, + { "OnViewClosed", false }, + { "OnTitleChanged", false }, + { "OnSubComponentOpened", false }, + { "OnSubComponentClosed", false }, + { nullptr, false } + }; + return s_aData; + } + } + + // DocumentEvents + DocumentEvents::DocumentEvents( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData ) + :m_pData( new DocumentEvents_Data( _rParent, _rMutex, _rEventsData ) ) + { + const DocumentEventData* pEventData = lcl_getDocumentEventData(); + while ( pEventData->pAsciiEventName ) + { + OUString sEventName = OUString::createFromAscii( pEventData->pAsciiEventName ); + DocumentEventsData::const_iterator existingPos = m_pData->rEventsData.find( sEventName ); + if ( existingPos == m_pData->rEventsData.end() ) + m_pData->rEventsData[ sEventName ] = Sequence< PropertyValue >(); + ++pEventData; + } + } + + DocumentEvents::~DocumentEvents() + { + } + + void SAL_CALL DocumentEvents::acquire() throw() + { + m_pData->rParent.acquire(); + } + + void SAL_CALL DocumentEvents::release() throw() + { + m_pData->rParent.release(); + } + + bool DocumentEvents::needsSynchronousNotification( const OUString& _rEventName ) + { + const DocumentEventData* pEventData = lcl_getDocumentEventData(); + while ( pEventData->pAsciiEventName ) + { + if ( _rEventName.equalsAscii( pEventData->pAsciiEventName ) ) + return pEventData->bNeedsSyncNotify; + ++pEventData; + } + + // this is an unknown event ... assume async notification + return false; + } + + void SAL_CALL DocumentEvents::replaceByName( const OUString& Name, const Any& Element ) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + + DocumentEventsData::iterator elementPos = m_pData->rEventsData.find( Name ); + if ( elementPos == m_pData->rEventsData.end() ) + throw NoSuchElementException( Name, *this ); + + Sequence< PropertyValue > aEventDescriptor; + if ( Element.hasValue() && !( Element >>= aEventDescriptor ) ) + throw IllegalArgumentException( Element.getValueTypeName(), *this, 2 ); + + // Weird enough, the event assignment UI has (well: had) the idea of using an empty "EventType"/"Script" + // to indicate the event descriptor should be reset, instead of just passing an empty event descriptor. + ::comphelper::NamedValueCollection aCheck( aEventDescriptor ); + if ( aCheck.has( "EventType" ) ) + { + OUString sEventType = aCheck.getOrDefault( "EventType", OUString() ); + OSL_ENSURE( !sEventType.isEmpty(), "DocumentEvents::replaceByName: doing a reset via an empty EventType is weird!" ); + if ( sEventType.isEmpty() ) + aEventDescriptor.realloc( 0 ); + } + if ( aCheck.has( "Script" ) ) + { + OUString sScript = aCheck.getOrDefault( "Script", OUString() ); + OSL_ENSURE( !sScript.isEmpty(), "DocumentEvents::replaceByName: doing a reset via an empty Script is weird!" ); + if ( sScript.isEmpty() ) + aEventDescriptor.realloc( 0 ); + } + + elementPos->second = aEventDescriptor; + } + + Any SAL_CALL DocumentEvents::getByName( const OUString& Name ) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + + DocumentEventsData::const_iterator elementPos = m_pData->rEventsData.find( Name ); + if ( elementPos == m_pData->rEventsData.end() ) + throw NoSuchElementException( Name, *this ); + + Any aReturn; + const Sequence< PropertyValue >& rEventDesc( elementPos->second ); + if ( rEventDesc.hasElements() ) + aReturn <<= rEventDesc; + return aReturn; + } + + Sequence< OUString > SAL_CALL DocumentEvents::getElementNames( ) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + + return comphelper::mapKeysToSequence( m_pData->rEventsData ); + } + + sal_Bool SAL_CALL DocumentEvents::hasByName( const OUString& Name ) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + + return m_pData->rEventsData.find( Name ) != m_pData->rEventsData.end(); + } + + Type SAL_CALL DocumentEvents::getElementType( ) + { + return ::cppu::UnoType< Sequence< PropertyValue > >::get(); + } + + sal_Bool SAL_CALL DocumentEvents::hasElements( ) + { + ::osl::MutexGuard aGuard( m_pData->rMutex ); + return !m_pData->rEventsData.empty(); + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/intercept.cxx b/dbaccess/source/core/dataaccess/intercept.cxx new file mode 100644 index 000000000..3b42df4ed --- /dev/null +++ b/dbaccess/source/core/dataaccess/intercept.cxx @@ -0,0 +1,365 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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(7) +{ + + OSL_ENSURE(DISPATCH_RELOAD < m_aInterceptedURL.getLength(),"Illegal size."); + + m_aInterceptedURL[DISPATCH_SAVEAS] = ".uno:SaveAs"; + m_aInterceptedURL[DISPATCH_SAVE] = ".uno:Save"; + m_aInterceptedURL[DISPATCH_CLOSEDOC] = ".uno:CloseDoc"; + m_aInterceptedURL[DISPATCH_CLOSEWIN] = ".uno:CloseWin"; + m_aInterceptedURL[DISPATCH_CLOSEFRAME] = ".uno:CloseFrame"; + m_aInterceptedURL[DISPATCH_RELOAD] = ".uno:Reload"; +} + + +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[nInd].Value <<= true; + break; + } + nInd++; + } + + if ( nInd == aNewArgs.getLength() ) + { + aNewArgs.realloc( nInd + 1 ); + aNewArgs[nInd].Name = "SaveTo"; + aNewArgs[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 PropertyChangeListenerContainer(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 PropertyChangeListenerContainer(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 PropertyChangeListenerContainer(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 ) +{ + Sequence< Reference< XDispatch > > aRet; + osl::MutexGuard aGuard(m_aMutex); + if(m_xSlaveDispatchProvider.is()) + aRet = m_xSlaveDispatchProvider->queryDispatches(Requests); + else + aRet.realloc(Requests.getLength()); + + 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 ) + { + aRet[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 000000000..c7ddd3d21 --- /dev/null +++ b/dbaccess/source/core/dataaccess/intercept.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_INTERCEPT_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_INTERCEPT_HXX + +#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; + + std::unique_ptr m_pStatCL; +}; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_INTERCEPT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx b/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx new file mode 100644 index 000000000..52d6bd6a2 --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx @@ -0,0 +1,330 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#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; + +// @@@ Adjust namespace name. +using namespace dbaccess; + +// @@@ Adjust namespace name. +namespace dbaccess +{ + +namespace { + +// struct ResultListEntry. +struct ResultListEntry +{ + OUString aId; + Reference< XContentIdentifier > xId; + ::rtl::Reference< OContentHelper > xContent; + Reference< XRow > xRow; + const ContentProperties& rData; + + explicit ResultListEntry(const ContentProperties& rEntry) : rData( rEntry ) {} +}; + +} + +// struct DataSupplier_Impl. +struct DataSupplier_Impl +{ + osl::Mutex m_aMutex; + std::vector< std::unique_ptr > m_aResults; + rtl::Reference< ODocumentContainer > m_xContent; + bool m_bCountFinal; + + explicit DataSupplier_Impl(const rtl::Reference< ODocumentContainer >& rContent) + : m_xContent(rContent) + , m_bCountFinal(false) + { + } +}; + +} + +// DataSupplier Implementation. + +DataSupplier::DataSupplier( const rtl::Reference< ODocumentContainer >& rContent ) +: m_pImpl( new DataSupplier_Impl( rContent ) ) +{ + +} + +DataSupplier::~DataSupplier() +{ + +} + +OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( static_cast(nIndex) < m_pImpl->m_aResults.size() ) + { + OUString aId = m_pImpl->m_aResults[ nIndex ]->aId; + if ( !aId.isEmpty() ) + { + // Already cached. + return aId; + } + } + + if ( getResult( nIndex ) ) + { + OUString aId = m_pImpl->m_xContent->getIdentifier()->getContentIdentifier(); + + if ( !aId.isEmpty() ) + aId += "/"; + + aId += m_pImpl->m_aResults[ nIndex ]->rData.aTitle; + + m_pImpl->m_aResults[ nIndex ]->aId = aId; + return aId; + } + return OUString(); +} + +Reference< XContentIdentifier > +DataSupplier::queryContentIdentifier( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( static_cast(nIndex) < m_pImpl->m_aResults.size() ) + { + Reference< XContentIdentifier > xId = m_pImpl->m_aResults[ nIndex ]->xId; + if ( xId.is() ) + { + // Already cached. + return xId; + } + } + + OUString aId = queryContentIdentifierString( nIndex ); + if ( !aId.isEmpty() ) + { + Reference< XContentIdentifier > xId = new ::ucbhelper::ContentIdentifier( aId ); + m_pImpl->m_aResults[ nIndex ]->xId = xId; + return xId; + } + return Reference< XContentIdentifier >(); +} + +Reference< XContent > +DataSupplier::queryContent( sal_uInt32 _nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( static_cast(_nIndex) < m_pImpl->m_aResults.size() ) + { + Reference< XContent > xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get(); + if ( xContent.is() ) + { + // Already cached. + return xContent; + } + } + + Reference< XContentIdentifier > xId = queryContentIdentifier( _nIndex ); + if ( xId.is() ) + { + try + { + Reference< XContent > xContent; + OUString sName = xId->getContentIdentifier(); + sName = sName.copy(sName.lastIndexOf('/')+1); + + m_pImpl->m_aResults[ _nIndex ]->xContent = m_pImpl->m_xContent->getContent(sName); + + xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get(); + return xContent; + + } + catch ( IllegalIdentifierException& ) + { + } + } + return Reference< XContent >(); +} + +bool DataSupplier::getResult( sal_uInt32 nIndex ) +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( static_cast(nIndex) < m_pImpl->m_aResults.size() ) + { + // Result already present. + return true; + } + + // Result not (yet) present. + + if ( m_pImpl->m_bCountFinal ) + return false; + + // Try to obtain result... + + sal_uInt32 nOldCount = m_pImpl->m_aResults.size(); + bool bFound = false; + sal_uInt32 nPos = nOldCount; + + // @@@ Obtain data and put it into result list... + Sequence< OUString> aSeq = m_pImpl->m_xContent->getElementNames(); + if ( nIndex < sal::static_int_cast< sal_uInt32 >( aSeq.getLength() ) ) + { + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for(pIter = pIter + nPos;pIter != pEnd;++pIter,++nPos) + { + m_pImpl->m_aResults.emplace_back( + new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) ); + + if ( nPos == nIndex ) + { + // Result obtained. + bFound = true; + break; + } + } + } + + if ( !bFound ) + m_pImpl->m_bCountFinal = true; + + rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet().get(); + if ( xResultSet.is() ) + { + // Callbacks follow! + aGuard.clear(); + + if ( static_cast(nOldCount) < m_pImpl->m_aResults.size() ) + xResultSet->rowCountChanged( + nOldCount, m_pImpl->m_aResults.size() ); + + if ( m_pImpl->m_bCountFinal ) + xResultSet->rowCountFinal(); + } + + return bFound; +} + +sal_uInt32 DataSupplier::totalCount() +{ + osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( m_pImpl->m_bCountFinal ) + return m_pImpl->m_aResults.size(); + + sal_uInt32 nOldCount = m_pImpl->m_aResults.size(); + + // @@@ Obtain data and put it into result list... + Sequence< OUString> aSeq = m_pImpl->m_xContent->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + m_pImpl->m_aResults.emplace_back( + new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) ); + + m_pImpl->m_bCountFinal = true; + + rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet().get(); + if ( xResultSet.is() ) + { + // Callbacks follow! + aGuard.clear(); + + if ( static_cast(nOldCount) < m_pImpl->m_aResults.size() ) + xResultSet->rowCountChanged( + nOldCount, m_pImpl->m_aResults.size() ); + + xResultSet->rowCountFinal(); + } + + return m_pImpl->m_aResults.size(); +} + +sal_uInt32 DataSupplier::currentCount() +{ + return m_pImpl->m_aResults.size(); +} + +bool DataSupplier::isCountFinal() +{ + return m_pImpl->m_bCountFinal; +} + +Reference< XRow > +DataSupplier::queryPropertyValues( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( static_cast(nIndex) < m_pImpl->m_aResults.size() ) + { + Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow; + if ( xRow.is() ) + { + // Already cached. + return xRow; + } + } + + if ( getResult( nIndex ) ) + { + if ( !m_pImpl->m_aResults[ nIndex ]->xContent.is() ) + queryContent(nIndex); + + Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xContent->getPropertyValues(getResultSet()->getProperties()); + m_pImpl->m_aResults[ nIndex ]->xRow = xRow; + return xRow; + } + + return Reference< XRow >(); +} + +void DataSupplier::releasePropertyValues( sal_uInt32 nIndex ) +{ + osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex ); + + if ( static_cast(nIndex) < m_pImpl->m_aResults.size() ) + m_pImpl->m_aResults[ nIndex ]->xRow.clear(); +} + +void DataSupplier::close() +{ +} + +void DataSupplier::validate() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx b/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx new file mode 100644 index 000000000..8806371d1 --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_MYUCP_DATASUPPLIER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_MYUCP_DATASUPPLIER_HXX + +#include +#include +#include "documentcontainer.hxx" +#include + +namespace dbaccess { + +struct DataSupplier_Impl; + +class DataSupplier : public ucbhelper::ResultSetDataSupplier +{ + std::unique_ptr m_pImpl; + +public: + explicit DataSupplier( const rtl::Reference< ODocumentContainer >& rxContent ); + virtual ~DataSupplier() override; + + virtual OUString queryContentIdentifierString( sal_uInt32 nIndex ) override; + virtual css::uno::Reference< css::ucb::XContentIdentifier > + queryContentIdentifier( sal_uInt32 nIndex ) override; + virtual css::uno::Reference< css::ucb::XContent > + queryContent( sal_uInt32 nIndex ) override; + + virtual bool getResult( sal_uInt32 nIndex ) override; + + virtual sal_uInt32 totalCount() override; + virtual sal_uInt32 currentCount() override; + virtual bool isCountFinal() override; + + virtual css::uno::Reference< css::sdbc::XRow > + queryPropertyValues( sal_uInt32 nIndex ) override; + virtual void releasePropertyValues( sal_uInt32 nIndex ) override; + + virtual void close() override; + + virtual void validate() override; +}; + +} + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_MYUCP_DATASUPPLIER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/myucp_resultset.cxx b/dbaccess/source/core/dataaccess/myucp_resultset.cxx new file mode 100644 index 000000000..67c1ad7c8 --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_resultset.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/************************************************************************** + TODO + ************************************************************************** + + - This implementation is not a dynamic result set!!! It only implements + the necessary interfaces, but never recognizes/notifies changes!!! + + *************************************************************************/ + +#include "myucp_datasupplier.hxx" +#include "myucp_resultset.hxx" + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::container; + +using namespace dbaccess; + +// DynamicResultSet Implementation. +DynamicResultSet::DynamicResultSet( + const Reference< XComponentContext >& rxContext, + const rtl::Reference< ODocumentContainer >& rxContent, + const OpenCommandArgument2& rCommand, + const Reference< XCommandEnvironment >& rxEnv ) + :ResultSetImplHelper( rxContext, rCommand ) + ,m_xContent(rxContent) + ,m_xEnv( rxEnv ) +{ +} + +// Non-interface methods. +void DynamicResultSet::initStatic() +{ + m_xResultSet1 + = new ::ucbhelper::ResultSet( m_xContext, + m_aCommand.Properties, + new DataSupplier( m_xContent ), + m_xEnv ); +} + +void DynamicResultSet::initDynamic() +{ + m_xResultSet1 + = new ::ucbhelper::ResultSet( m_xContext, + m_aCommand.Properties, + new DataSupplier( m_xContent ), + m_xEnv ); + m_xResultSet2 = m_xResultSet1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/dataaccess/myucp_resultset.hxx b/dbaccess/source/core/dataaccess/myucp_resultset.hxx new file mode 100644 index 000000000..6556ff76f --- /dev/null +++ b/dbaccess/source/core/dataaccess/myucp_resultset.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_MYUCP_RESULTSET_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_MYUCP_RESULTSET_HXX + +#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, + const rtl::Reference< ODocumentContainer >& rxContent, + const css::ucb::OpenCommandArgument2& rCommand, + const css::uno::Reference< css::ucb::XCommandEnvironment >& rxEnv ); +}; + +} + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_DATAACCESS_MYUCP_RESULTSET_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/ContainerMediator.hxx b/dbaccess/source/core/inc/ContainerMediator.hxx new file mode 100644 index 000000000..8d1bf9d8d --- /dev/null +++ b/dbaccess/source/core/inc/ContainerMediator.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_CONTAINERMEDIATOR_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_CONTAINERMEDIATOR_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_CONTAINERMEDIATOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/ContentHelper.hxx b/dbaccess/source/core/inc/ContentHelper.hxx new file mode 100644 index 000000000..87686496a --- /dev/null +++ b/dbaccess/source/core/inc/ContentHelper.hxx @@ -0,0 +1,185 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_INC_CONTENTHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_CONTENTHELPER_HXX + +#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 cppu::OMultiTypeInterfaceContainerHelperVar + PropertyChangeListenerContainer; + typedef ::cppu::WeakComponentImplHelper< css::ucb::XContent + , css::ucb::XCommandProcessor + , css::lang::XServiceInfo + , css::beans::XPropertiesChangeNotifier + , css::beans::XPropertyContainer + , css::lang::XInitialization + , css::lang::XUnoTunnel + , css::container::XChild + , css::sdbcx::XRename + > OContentHelper_COMPBASE; + + class OContentHelper : public ::cppu::BaseMutex + ,public OContentHelper_COMPBASE + { + css::uno::Sequence< css::uno::Any > + setPropertyValues( const css::uno::Sequence< css::beans::PropertyValue >& rValues ); + + void impl_rename_throw(const OUString& _sNewName,bool _bNotify = true); + + protected: + ::comphelper::OInterfaceContainerHelper2 m_aContentListeners; + PropertyChangeListenerContainer m_aPropertyChangeListeners; + css::uno::Reference< css::uno::XInterface > + m_xParentContainer; + const css::uno::Reference< css::uno::XComponentContext > + m_aContext; + const ::connectivity::SQLError m_aErrorHelper; + TContentPtr m_pImpl; + sal_uInt32 m_nCommandId; + + // helper + virtual void SAL_CALL disposing() override; + + void notifyDataSourceModified(); + + /** + * This method can be used to propagate changes of property values. + * + * @param evt is a sequence of property change events. + */ + void notifyPropertiesChange( const css::uno::Sequence< css::beans::PropertyChangeEvent >& evt ) const; + + OUString impl_getHierarchicalName( bool _includingRootContainer ) const; + + public: + + OContentHelper( const css::uno::Reference< css::uno::XComponentContext >& _xORB + ,const css::uno::Reference< css::uno::XInterface >& _xParentContainer + ,const TContentPtr& _pImpl + ); + + // css::lang::XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // css::lang::XServiceInfo + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + virtual OUString SAL_CALL getImplementationName( ) override; + + // XContent + virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL getIdentifier( ) override ; + virtual OUString SAL_CALL getContentType( ) override ; + virtual void SAL_CALL addContentEventListener( const css::uno::Reference< css::ucb::XContentEventListener >& Listener ) override ; + virtual void SAL_CALL removeContentEventListener( const css::uno::Reference< css::ucb::XContentEventListener >& Listener ) override ; + + // XCommandProcessor + virtual sal_Int32 SAL_CALL createCommandIdentifier( ) override ; + virtual css::uno::Any SAL_CALL execute( const css::ucb::Command& aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override ; + virtual void SAL_CALL abort( sal_Int32 CommandId ) override ; + + // XPropertiesChangeNotifier + virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& PropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener ) override ; + virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Sequence< OUString >& PropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener ) override ; + + // XPropertyContainer + virtual void SAL_CALL addProperty( const OUString& Name, sal_Int16 Attributes, const css::uno::Any& DefaultValue ) override ; + virtual void SAL_CALL removeProperty( const OUString& Name ) override ; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + // css::container::XChild + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override; + virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override; + + // XRename + virtual void SAL_CALL rename( const OUString& newName ) override; + + const ContentProperties& getContentProperties() const { return m_pImpl->m_aProps; } + css::uno::Reference< css::sdbc::XRow > + getPropertyValues( const css::uno::Sequence< css::beans::Property >& rProperties ); + + const css::uno::Reference< css::uno::XComponentContext >& getContext() const { return m_aContext; } + + const TContentPtr& getImpl() const { return m_pImpl; } + + protected: + virtual OUString determineContentType() const = 0; + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_CONTENTHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/DatabaseDataProvider.hxx b/dbaccess/source/core/inc/DatabaseDataProvider.hxx new file mode 100644 index 000000000..68c066412 --- /dev/null +++ b/dbaccess/source/core/inc/DatabaseDataProvider.hxx @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_INC_DATABASEDATAPROVIDER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_DATABASEDATAPROVIDER_HXX + +#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); + + // css::lang::XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(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() throw () override + { TDatabaseDataProvider::acquire(); } + virtual void SAL_CALL release() throw () 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) 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::makeAny(_member), css::uno::makeAny(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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_DATABASEDATAPROVIDER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/FilteredContainer.hxx b/dbaccess/source/core/inc/FilteredContainer.hxx new file mode 100644 index 000000000..b07892731 --- /dev/null +++ b/dbaccess/source/core/inc/FilteredContainer.hxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_FILTEREDCONTAINER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_FILTEREDCONTAINER_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_FILTEREDCONTAINER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/ModelImpl.hxx b/dbaccess/source/core/inc/ModelImpl.hxx new file mode 100644 index 000000000..c67e67d57 --- /dev/null +++ b/dbaccess/source/core/inc/ModelImpl.hxx @@ -0,0 +1,545 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_INC_MODELIMPL_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_MODELIMPL_HXX + +#include "ContentHelper.hxx" +#include "documentevents.hxx" + +#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!" ); + } +}; + +class ODatabaseContext; +class OSharedConnectionManager; + +// ODatabaseModelImpl +typedef ::utl::SharedUNOComponent< css::embed::XStorage > SharedStorage; + +class ODatabaseContext; +class DocumentStorageAccess; +class OSharedConnectionManager; +class ODatabaseModelImpl :public ::sfx2::IMacroDocumentAccess + ,public ::sfx2::IModifiableDocument +{ +public: + enum ObjectType + { + E_FORM = 0, + E_REPORT = 1, + E_QUERY = 2, + E_TABLE = 3 + }; + + enum EmbeddedMacros + { + // the database document (storage) itself contains macros + eDocumentWideMacros, + // there are sub document( storage)s containing macros + eSubDocumentMacros, + // there are no known macro( storage)s + eNoMacros + }; + +private: + css::uno::WeakReference< css::frame::XModel > m_xModel; + css::uno::WeakReference< css::sdbc::XDataSource > m_xDataSource; + + rtl::Reference m_pStorageAccess; + std::vector< TContentPtr > m_aContainer; // one for each ObjectType + ::sfx2::DocumentMacroMode m_aMacroMode; + sal_Int16 m_nImposedMacroExecMode; + + css::uno::Reference< css::script::XStorageBasedLibraryContainer > m_xBasicLibraries; + css::uno::Reference< css::script::XStorageBasedLibraryContainer > m_xDialogLibraries; + + SharedStorage m_xDocumentStorage; + ::rtl::Reference< ::sfx2::DocumentStorageModifyListener > m_pStorageModifyListener; + ODatabaseContext& m_rDBContext; + DocumentEventsData m_aDocumentEvents; + + ::comphelper::NamedValueCollection m_aMediaDescriptor; + /// the URL the document was loaded from + OUString m_sDocFileLocation; + + oslInterlockedCount m_refCount; + + /// do we have any object (forms/reports) which contains macros? + ::std::optional< EmbeddedMacros > m_aEmbeddedMacros; + + /// true if setting the Modified flag of the document is currently locked + bool m_bModificationLock; + + /// true if and only if a database document existed previously (though meanwhile disposed), and was already initialized + bool m_bDocumentInitialized; + + /** the URL which the document should report as its URL + + This might differ from ->m_sDocFileLocation in case the document was loaded + as part of a crash recovery process. In this case, ->m_sDocFileLocation points to + the temporary file where the DB had been saved to, after a crash. + ->m_sDocumentURL then is the URL of the document which actually had + been recovered. + */ + OUString m_sDocumentURL; + + SignatureState m_nScriptingSignatureState; + +public: + OWeakConnectionArray m_aConnections; + const css::uno::Reference< css::uno::XComponentContext > m_aContext; + +public: + css::uno::WeakReference< css::container::XNameAccess > m_xCommandDefinitions; + css::uno::WeakReference< css::container::XNameAccess > m_xTableDefinitions; + + css::uno::Reference< css::util::XNumberFormatsSupplier > + m_xNumberFormatsSupplier; + OUString m_sConnectURL; + OUString m_sName; // transient, our creator has to tell us the title + OUString m_sUser; + OUString m_aPassword; // transient ! + OUString m_sFailedPassword; + css::uno::Sequence< css::beans::PropertyValue> + m_aLayoutInformation; + sal_Int32 m_nLoginTimeout; + bool m_bReadOnly : 1; + bool m_bPasswordRequired : 1; + bool m_bSuppressVersionColumns : 1; + bool m_bModified : 1; + bool m_bDocumentReadOnly : 1; + bool m_bMacroCallsSeenWhileLoading : 1; + css::uno::Reference< css::beans::XPropertyBag > + m_xSettings; + css::uno::Sequence< OUString > m_aTableFilter; + css::uno::Sequence< OUString > m_aTableTypeFilter; + OSharedConnectionManager* m_pSharedConnectionManager; + css::uno::Reference< css::lang::XEventListener > + m_xSharedConnectionManager; + css::uno::Reference + 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( + const OUString& _rRegistrationName, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + ODatabaseContext& _rDBContext + ); + + // XEventListener + /// @throws css::uno::RuntimeException + void disposing( const css::lang::EventObject& Source ); + + void setModified( bool bModified ); + + void dispose(); + + const OUString& getURL() const { return m_sDocumentURL; } + const OUString& getDocFileLocation() const { return m_sDocFileLocation; } + + css::uno::Reference< css::embed::XStorage > + getStorage( const ObjectType _eType ); + +// helper + const css::uno::Reference< css::util::XNumberFormatsSupplier >& + getNumberFormatsSupplier(); + + DocumentEventsData& + getDocumentEvents() { return m_aDocumentEvents; } + + const ::comphelper::NamedValueCollection& + getMediaDescriptor() const { return m_aMediaDescriptor; } + + void setResource( + const OUString& _rURL, + const css::uno::Sequence< css::beans::PropertyValue >& _rArgs + ); + void setDocFileLocation( + const OUString& i_rLoadedFrom + ); + + static ::comphelper::NamedValueCollection + stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments ); + +// other stuff + + // disposes all elements in m_aStorages, and clears it + void disposeStorages(); + + /// creates a ->css::embed::StorageFactory + css::uno::Reference< css::lang::XSingleServiceFactory > + createStorageFactory() const; + + /// commits our storage + void commitRootStorage(); + + /// commits a given storage if it's not readonly, ignoring (but asserting) all errors + bool commitStorageIfWriteable_ignoreErrors( + const css::uno::Reference< css::embed::XStorage >& _rxStorage + ); + + void clearConnections(); + + css::uno::Reference< css::embed::XStorage > const & getOrCreateRootStorage(); + css::uno::Reference< css::embed::XStorage > const & getRootStorage() const { return m_xDocumentStorage.getTyped(); } + void resetRootStorage() { impl_switchToStorage_throw( nullptr ); } + + /** returns the data source. If it doesn't exist it will be created + */ + css::uno::Reference< css::sdbc::XDataSource> getOrCreateDataSource(); + + /** returns the model, if there already exists one + */ + css::uno::Reference< css::frame::XModel > getModel_noCreate() const; + + /** returns a new ->ODatabaseDocument + + @precond + No ->ODatabaseDocument exists so far + + @seealso + getModel_noCreate + */ + css::uno::Reference< css::frame::XModel > createNewModel_deliverOwnership(); + + struct ResetModelAccess { friend class ODatabaseDocument; private: ResetModelAccess() { } }; + + /** resets the model to NULL + + Only to be called when the model is being disposed + */ + void modelIsDisposing( const bool _wasInitialized, ResetModelAccess ); + + bool hadInitializedDocument() const { return m_bDocumentInitialized; } + + DocumentStorageAccess* + getDocumentStorageAccess(); + + css::uno::Reference< css::document::XDocumentSubStorageSupplier > + getDocumentSubStorageSupplier(); + + void acquire(); + + void release(); + + /// returns all known data source settings, including their default values + static const AsciiPropertyValue* getDefaultDataSourceSettings(); + + /** retrieves the requested container of objects (forms/reports/tables/queries) + */ + TContentPtr& getObjectContainer( const ObjectType _eType ); + + /** returns the name of the storage which is used to stored objects of the given type, if applicable + */ + static OUString + getObjectContainerStorageName( const ObjectType _eType ); + + /** determines whether a given object storage contains macros + */ + static bool objectHasMacros( + const css::uno::Reference< css::embed::XStorage >& _rxContainerStorage, + const OUString& _rPersistentName + ); + + /** determines which kind of embedded macros are present in the document + */ + EmbeddedMacros determineEmbeddedMacros(); + + /** checks our document's macro execution mode, using the interaction handler as supplied with our + load arguments + */ + bool checkMacrosOnLoading(); + + /** adjusts our document's macro execution mode, without using any UI, assuming the user + would reject execution of macros, if she would have been asked. + + If checkMacrosOnLoading has been called before (and thus the macro execution mode + is already adjusted), then the current execution mode is simply returned. + + @return + whether or not macro execution is allowed + */ + bool adjustMacroMode_AutoReject(); + + /** resets our macro execute mode, so next time the checkMacrosOnLoading is called, it will + behave as if it has never been called before + */ + void resetMacroExecutionMode(); + + /** ensures that ->m_xBasicLibraries resp. m_xDialogLibraries exists + + @return + the requested library container. Is never . + + @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( bool bAllowUIToAddAuthor ) override; + + // IModifiableDocument + virtual void storageIsModified() override; + + // don't use directly, use the ModifyLock class instead + void lockModify() { m_bModificationLock = true; } + void unlockModify() { m_bModificationLock = false; } + bool isModifyLocked() const { return m_bModificationLock; } + + weld::Window* GetFrameWeld(); + +private: + void impl_construct_nothrow(); + css::uno::Reference< css::embed::XStorage > const & + impl_switchToStorage_throw( const css::uno::Reference< css::embed::XStorage >& _rxNewRootStorage ); + + /** switches to the given document URL, which denotes the logical URL of the document, not necessarily the + URL where the doc was loaded/recovered from + */ + void impl_switchToLogicalURL( + const OUString& i_rDocumentURL + ); + +}; + +/** a small base class for UNO components whose functionality depends on an ODatabaseModelImpl +*/ +class ModelDependentComponent +{ +protected: + ::rtl::Reference< ODatabaseModelImpl > m_pImpl; + ::osl::Mutex m_aMutex; // only use this to init WeakComponentImplHelper + +protected: + explicit ModelDependentComponent( const ::rtl::Reference< ODatabaseModelImpl >& _model ); + virtual ~ModelDependentComponent(); + + /** returns the component itself + */ + virtual css::uno::Reference< css::uno::XInterface > getThis() const = 0; + + ::osl::Mutex& getMutex() + { + return m_aMutex; + } + +public: + /// checks whether the component is already disposed, throws a DisposedException if so + void checkDisposed() const + { + if ( !m_pImpl.is() ) + throw css::lang::DisposedException( "Component is already disposed.", getThis() ); + } + + void lockModify() + { + m_pImpl->lockModify(); + } + + void unlockModify() + { + m_pImpl->unlockModify(); + } +}; + +class ModifyLock +{ +public: + explicit ModifyLock( ModelDependentComponent& _component ) + :m_rComponent( _component ) + { + m_rComponent.lockModify(); + } + + ~ModifyLock() + { + m_rComponent.unlockModify(); + } + +private: + ModelDependentComponent& m_rComponent; +}; + +/** a guard for public methods of objects dependent on an ODatabaseModelImpl instance + + Just put this guard onto the stack at the beginning of your method. Don't bother yourself + with a MutexGuard, checks for being disposed, and the like. +*/ +class ModelMethodGuard +{ +private: + // to avoid deadlocks, lock SolarMutex + SolarMutexResettableGuard m_SolarGuard; + +public: + /** constructs the guard + + @param _component + the component whose functionality depends on an ODatabaseModelImpl instance + + @throws css::lang::DisposedException + If the given component is already disposed + */ + explicit ModelMethodGuard( const ModelDependentComponent& _component ) + { + _component.checkDisposed(); + } + + void clear() + { + // note: this only releases *once* so may still be locked + m_SolarGuard.clear(); + } + + void reset() + { + m_SolarGuard.reset(); + } +}; + +} // namespace dbaccess + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/PropertyForward.hxx b/dbaccess/source/core/inc/PropertyForward.hxx new file mode 100644 index 000000000..1b20e76e9 --- /dev/null +++ b/dbaccess/source/core/inc/PropertyForward.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_PROPERTYFORWARD_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_PROPERTYFORWARD_HXX + +#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, + const OUString& _sName, + const std::vector< OUString >& _aPropertyList + ); + + // css::beans::XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + // css::lang::XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& _rSource ) override; + + void setName( const OUString& _sName ) { m_sName = _sName; } + void setDefinition( const css::uno::Reference< css::beans::XPropertySet >& _xDest); + const css::uno::Reference< css::beans::XPropertySet >& getDefinition() const { return m_xDest; } + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_PROPERTYFORWARD_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/RefreshListener.hxx b/dbaccess/source/core/inc/RefreshListener.hxx new file mode 100644 index 000000000..37c6ea511 --- /dev/null +++ b/dbaccess/source/core/inc/RefreshListener.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_REFRESHLISTENER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_REFRESHLISTENER_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_REFRESHLISTENER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/SingleSelectQueryComposer.hxx b/dbaccess/source/core/inc/SingleSelectQueryComposer.hxx new file mode 100644 index 000000000..be2f48fdb --- /dev/null +++ b/dbaccess/source/core/inc/SingleSelectQueryComposer.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_SINGLESELECTQUERYCOMPOSER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_SINGLESELECTQUERYCOMPOSER_HXX + +#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; + ::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(); + + DECLARE_PROPERTYCONTAINER_DEFAULTS(); + + // 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_SINGLESELECTQUERYCOMPOSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/TableDeco.hxx b/dbaccess/source/core/inc/TableDeco.hxx new file mode 100644 index 000000000..f7bec41b9 --- /dev/null +++ b/dbaccess/source/core/inc/TableDeco.hxx @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_INC_TABLEDECO_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_TABLEDECO_HXX + +#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; + protected: + css::uno::Reference< css::container::XContainerListener > m_xColumnMediator; + css::uno::Reference< css::sdbcx::XColumnsSupplier > m_xTable; + css::uno::Reference< css::container::XNameAccess > m_xColumnDefinitions; + css::uno::Reference< css::sdbc::XConnection > m_xConnection; + css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData; + css::uno::Reference< css::util::XNumberFormatsSupplier > m_xNumberFormats; + + // + 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; + + // IColumnFactory + virtual OColumn* createColumn(const OUString& _rName) const override; + virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override; + virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override; + virtual void columnDropped(const OUString& _sName) override; + + virtual void refreshColumns() override; + + virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 _nId) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // OPropertySetHelper + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle) const override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + + virtual ~ODBTableDecorator() override; + public: + /** constructs a wrapper supporting the com.sun.star.sdb.Table service. + + @param _rxConn + the connection the table belongs to. Must not be + @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() throw() override; + virtual void SAL_CALL release() throw() 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 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_TABLEDECO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/View.hxx b/dbaccess/source/core/inc/View.hxx new file mode 100644 index 000000000..93985e068 --- /dev/null +++ b/dbaccess/source/core/inc/View.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_VIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_VIEW_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_VIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/bookmarkcontainer.hxx b/dbaccess/source/core/inc/bookmarkcontainer.hxx new file mode 100644 index 000000000..10da82a6c --- /dev/null +++ b/dbaccess/source/core/inc/bookmarkcontainer.hxx @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_BOOKMARKCONTAINER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_BOOKMARKCONTAINER_HXX + +#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::OInterfaceContainerHelper2 + 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( ) throw() override; + virtual void SAL_CALL release( ) throw() 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 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/callablestatement.hxx b/dbaccess/source/core/inc/callablestatement.hxx new file mode 100644 index 000000000..9ca89317c --- /dev/null +++ b/dbaccess/source/core/inc/callablestatement.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_CALLABLESTATEMENT_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_CALLABLESTATEMENT_HXX + +#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() throw() override; + virtual void SAL_CALL release() throw() 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_CALLABLESTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/column.hxx b/dbaccess/source/core/inc/column.hxx new file mode 100644 index 000000000..3744715c7 --- /dev/null +++ b/dbaccess/source/core/inc/column.hxx @@ -0,0 +1,219 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_INC_COLUMN_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_COLUMN_HXX + +#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() throw() override; + virtual void SAL_CALL release() throw() 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 OColumn* + createColumn( const OUString& _rName ) const = 0; + + /** creates a column descriptor object. + + A column descriptor object is used to append new columns to the collection. If such an append + actually happened, columnAppended is called afterwards. + */ + virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() = 0; + + /** notifies that a column, created from a column descriptor, has been appended + */ + virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) = 0; + + /** notifies that a column with a given name has been dropped + */ + virtual void columnDropped( const OUString& _sName ) = 0; + + protected: + ~IColumnFactory() {} + }; + + class OContainerMediator; + typedef ::cppu::ImplHelper1< css::container::XChild > TXChild; + typedef connectivity::OColumnsHelper OColumns_BASE; + + class OColumns : public OColumns_BASE + ,public TXChild + { + OContainerMediator* m_pMediator; + + protected: + // comes from the driver can be null + css::uno::Reference< css::container::XNameAccess > m_xDrvColumns; + css::uno::WeakReference< css::uno::XInterface > m_xParent; + IColumnFactory* m_pColFactoryImpl; + ::connectivity::sdbcx::IRefreshableColumns* m_pRefreshColumns; + + bool m_bInitialized : 1; + bool m_bAddColumn : 1; + bool m_bDropColumn : 1; + + virtual void impl_refresh() override; + virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override; + virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override; + virtual connectivity::sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override; + virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override; + + public: + connectivity::sdbcx::ObjectType createBaseObject(const OUString& _rName) + { + return OColumns_BASE::createObject(_rName); + } + /** flag which determines whether the container is filled or not + */ + bool isInitialized() const { return m_bInitialized; } + void setInitialized() {m_bInitialized = true;} + void setMediator(OContainerMediator* _pMediator) { m_pMediator = _pMediator; } + + public: + /** constructs an empty container without configuration location. + @param rParent the parent object. This instance will be used for refcounting, so the parent + cannot die before the container does. + @param _rMutex the mutex of the parent. + @param _bCaseSensitive the initial case sensitivity flag + @see setCaseSensitive + */ + OColumns( + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + bool _bCaseSensitive, + const std::vector< OUString>& _rVector, + IColumnFactory* _pColFactory, + ::connectivity::sdbcx::IRefreshableColumns* _pRefresh, + bool _bAddColumn = false, + bool _bDropColumn = false, + bool _bUseHardRef = true); + + OColumns( + ::cppu::OWeakObject& _rParent, + ::osl::Mutex& _rMutex, + const css::uno::Reference< css::container::XNameAccess >& _rxDrvColumns, + bool _bCaseSensitive, + const std::vector< OUString> &_rVector, + IColumnFactory* _pColFactory, + ::connectivity::sdbcx::IRefreshableColumns* _pRefresh, + bool _bAddColumn = false, + bool _bDropColumn = false, + bool _bUseHardRef = true); + virtual ~OColumns() override; + + //XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() throw() override { OColumns_BASE::acquire(); } + virtual void SAL_CALL release() throw() 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_COLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/columnsettings.hxx b/dbaccess/source/core/inc/columnsettings.hxx new file mode 100644 index 000000000..29a93effa --- /dev/null +++ b/dbaccess/source/core/inc/columnsettings.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_COLUMNSETTINGS_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_COLUMNSETTINGS_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_COLUMNSETTINGS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/commandbase.hxx b/dbaccess/source/core/inc/commandbase.hxx new file mode 100644 index 000000000..725e34876 --- /dev/null +++ b/dbaccess/source/core/inc/commandbase.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_COMMANDBASE_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_COMMANDBASE_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_COMMANDBASE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/composertools.hxx b/dbaccess/source/core/inc/composertools.hxx new file mode 100644 index 000000000..d0bfdc3ff --- /dev/null +++ b/dbaccess/source/core/inc/composertools.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_COMPOSERTOOLS_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_COMPOSERTOOLS_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_COMPOSERTOOLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/containerapprove.hxx b/dbaccess/source/core/inc/containerapprove.hxx new file mode 100644 index 000000000..d350470ad --- /dev/null +++ b/dbaccess/source/core/inc/containerapprove.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_CONTAINERAPPROVE_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_CONTAINERAPPROVE_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_CONTAINERAPPROVE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/databasecontext.hxx b/dbaccess/source/core/inc/databasecontext.hxx new file mode 100644 index 000000000..0c1848042 --- /dev/null +++ b/dbaccess/source/core/inc/databasecontext.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_DATABASECONTEXT_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_DATABASECONTEXT_HXX + +#include + +#include + +#include + +#include "ModelImpl.hxx" + +#include +#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 + , css::lang::XUnoTunnel + > DatabaseAccessContext_Base; + +class ODatabaseContext :public DatabaseAccessContext_Base + ,public ::basic::BasicManagerCreationListener +{ +private: + /** loads the given object from the given URL + @throws WrappedTargetException + if an error occurs accessing the URL via the UCB + */ + css::uno::Reference< css::uno::XInterface > loadObjectFromURL(const OUString& _rName,const OUString& _sURL); + css::uno::Reference< css::uno::XInterface > getObject( const OUString& _rURL ); + + /** sets all properties which were transient at the data source. e.g. password + @param _sURL The file URL of the data source + @param _xObject The data source itself. + */ + void setTransientProperties(const OUString& _sURL, ODatabaseModelImpl& _rDataSourceModel ); + + /** creates a new data source + */ + css::uno::Reference< css::uno::XInterface > + impl_createNewDataSource(); + +#if HAVE_FEATURE_SCRIPTING + BasicDLL m_aBasicDLL; +#endif + +protected: + ::osl::Mutex m_aMutex; + css::uno::Reference< css::uno::XComponentContext > + m_aContext; + + css::uno::Reference< css::uno::XAggregation > + m_xDBRegistrationAggregate; + css::uno::Reference< css::sdb::XDatabaseRegistrations > + m_xDatabaseRegistrations; + + typedef std::map 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::OInterfaceContainerHelper2 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; + + // XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_static(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::uno::XComponentContext >&); + + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + + // XEnumerationAccess + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override; + + // XNameAccess + virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override; + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override; + + // XNamingService + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getRegisteredObject( const OUString& Name ) override; + virtual void SAL_CALL registerObject( const OUString& Name, const css::uno::Reference< css::uno::XInterface >& Object ) override; + virtual void SAL_CALL revokeObject( const OUString& Name ) override; + + // XDatabaseRegistrations + virtual sal_Bool SAL_CALL hasRegisteredDatabase( const OUString& Name ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getRegistrationNames() override; + virtual OUString SAL_CALL getDatabaseLocation( const OUString& Name ) override; + virtual void SAL_CALL registerDatabaseLocation( const OUString& Name, const OUString& Location ) override; + virtual void SAL_CALL revokeDatabaseLocation( const OUString& Name ) override; + virtual void SAL_CALL changeDatabaseLocation( const OUString& Name, const OUString& NewLocation ) override; + virtual sal_Bool SAL_CALL isDatabaseRegistrationReadOnly( const OUString& Name ) override; + virtual void SAL_CALL addDatabaseRegistrationsListener( const css::uno::Reference< css::sdb::XDatabaseRegistrationsListener >& Listener ) override; + virtual void SAL_CALL removeDatabaseRegistrationsListener( const css::uno::Reference< css::sdb::XDatabaseRegistrationsListener >& Listener ) override; + + // XContainer + virtual void SAL_CALL addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override; + virtual void SAL_CALL removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override; + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + void registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl); + void revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl); + void databaseDocumentURLChange(const OUString& _sOldName, const OUString& _sNewName); + void storeTransientProperties( ODatabaseModelImpl& _rModelImpl); + void appendAtTerminateListener(const ODatabaseModelImpl& _rDataSourceModel); + void removeFromTerminateListener(const ODatabaseModelImpl& _rDataSourceModel); + +private: + // BasicManagerCreationListener + virtual void onBasicManagerCreated( + const css::uno::Reference< css::frame::XModel >& _rxForDocument, + BasicManager& _rBasicManager + ) override; +}; + +} // namespace dbaccess + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/datasettings.hxx b/dbaccess/source/core/inc/datasettings.hxx new file mode 100644 index 000000000..9b6a7f686 --- /dev/null +++ b/dbaccess/source/core/inc/datasettings.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_DATASETTINGS_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_DATASETTINGS_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_DATASETTINGS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/definitioncolumn.hxx b/dbaccess/source/core/inc/definitioncolumn.hxx new file mode 100644 index 000000000..69d2c3c84 --- /dev/null +++ b/dbaccess/source/core/inc/definitioncolumn.hxx @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_DEFINITIONCOLUMN_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_DEFINITIONCOLUMN_HXX + +#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, + const OUString &i_sLabel + ); + + // XTypeProvider + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + + // *Property* + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override; + virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override; + + private: + css::uno::Reference< css::beans::XPropertySet > + impl_determineOriginalTableColumn( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection + ); + + using ::cppu::OPropertySetHelper::getFastPropertyValue; + }; + + // OColumnWrapper + /** + * describes all properties for a columns of a table. Only the view parts are provided + * directly, all the other parts are derived from a driver implementation + */ + class OColumnWrapper :public OColumn + { + protected: + // definition which is provided by a driver! + css::uno::Reference< css::beans::XPropertySet > + m_xAggregate; + + sal_Int32 m_nColTypeID; + + protected: + OColumnWrapper( const css::uno::Reference< css::beans::XPropertySet >& _rCol, const bool _bNameIsReadOnly ); + virtual ~OColumnWrapper() override; + + public: + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + + protected: + OUString impl_getPropertyNameFromHandle( const sal_Int32 _nHandle ) const; + + protected: + using OColumn::getFastPropertyValue; + }; + + // OTableColumnDescriptorWrapper + /** + * provides the properties for description. A descriptor could be used to create a new table column. + */ + class OTableColumnDescriptorWrapper :public OColumnWrapper + ,public OColumnSettings + ,public ::comphelper::OIdPropertyArrayUsageHelper < OTableColumnDescriptorWrapper > + { + const bool m_bPureWrap; + const bool m_bIsDescriptor; + + public: + OTableColumnDescriptorWrapper(const css::uno::Reference< css::beans::XPropertySet >& rCol, + const bool _bPureWrap, const bool _bIsDescriptor ); + + // css::lang::XTypeProvider + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + + // css::lang::XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // OIdPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override; + + // cppu::OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual void SAL_CALL getFastPropertyValue( + css::uno::Any& rValue, + sal_Int32 nHandle + ) const override; + virtual sal_Bool SAL_CALL convertFastPropertyValue( + css::uno::Any & rConvertedValue, + css::uno::Any & rOldValue, + sal_Int32 nHandle, + const css::uno::Any& rValue ) override; + virtual void SAL_CALL setFastPropertyValue_NoBroadcast( + sal_Int32 nHandle, + const css::uno::Any& rValue + ) override; + + protected: + using OColumnWrapper::getFastPropertyValue; + }; + + // OTableColumnWrapper + /** + * describes all properties for a columns of a table. Only the view parts are provided + * directly, all the other parts are derived from a driver implementation + */ + class OTableColumnWrapper :public OTableColumnDescriptorWrapper + ,public ::comphelper::OIdPropertyArrayUsageHelper < OTableColumnWrapper > + { + protected: + virtual ~OTableColumnWrapper() override; + + public: + OTableColumnWrapper( const css::uno::Reference< css::beans::XPropertySet >& rCol, + const css::uno::Reference< css::beans::XPropertySet >& rColDefintion, + 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_DEFINITIONCOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/definitioncontainer.hxx b/dbaccess/source/core/inc/definitioncontainer.hxx new file mode 100644 index 000000000..98a4c3f14 --- /dev/null +++ b/dbaccess/source/core/inc/definitioncontainer.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_DEFINITIONCONTAINER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_DEFINITIONCONTAINER_HXX + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ContentHelper.hxx" +#include "containerapprove.hxx" +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_DEFINITIONCONTAINER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/documentevents.hxx b/dbaccess/source/core/inc/documentevents.hxx new file mode 100644 index 000000000..9a04074a3 --- /dev/null +++ b/dbaccess/source/core/inc/documentevents.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_DOCUMENTEVENTS_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_DOCUMENTEVENTS_HXX + +#include +#include + +#include + +#include +#include + +namespace dbaccess +{ + + typedef std::map< OUString, css::uno::Sequence< css::beans::PropertyValue > > + DocumentEventsData; + + // DocumentEvents + struct DocumentEvents_Data; + + typedef ::cppu::WeakImplHelper< css::container::XNameReplace + > DocumentEvents_Base; + + class DocumentEvents :public DocumentEvents_Base + { + public: + DocumentEvents( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData ); + virtual ~DocumentEvents() override; + + DocumentEvents(const DocumentEvents&) = delete; + const DocumentEvents& operator=(const DocumentEvents&) = delete; + + static bool needsSynchronousNotification( const OUString& _rEventName ); + + // XInterface + virtual void SAL_CALL acquire() throw() override; + virtual void SAL_CALL release() throw() override; + + // XNameReplace + virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override; + + // XNameAccess + virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override; + virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override; + + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + + private: + std::unique_ptr< DocumentEvents_Data > m_pData; + }; + +} // namespace dbaccess + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/migrwarndlg.hxx b/dbaccess/source/core/inc/migrwarndlg.hxx new file mode 100644 index 000000000..e01c2b9f0 --- /dev/null +++ b/dbaccess/source/core/inc/migrwarndlg.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/. + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_WARNDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_WARNDLG_HXX + +#include + +namespace dbaccess +{ +class MigrationWarnDialog : public weld::MessageDialogController +{ + std::unique_ptr m_xLater; + +public: + MigrationWarnDialog(weld::Window* pParent); +}; +} + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_WARNDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/object.hxx b/dbaccess/source/core/inc/object.hxx new file mode 100644 index 000000000..a6f085609 --- /dev/null +++ b/dbaccess/source/core/inc/object.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_OBJECT_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_OBJECT_HXX + +enum ObjectType +{ + dbaTable, + dbaQuery, + dbaForm, + dbaReport +}; + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_OBJECT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/objectnameapproval.hxx b/dbaccess/source/core/inc/objectnameapproval.hxx new file mode 100644 index 000000000..6e0ce4577 --- /dev/null +++ b/dbaccess/source/core/inc/objectnameapproval.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_OBJECTNAMEAPPROVAL_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_OBJECTNAMEAPPROVAL_HXX + +#include +#include "containerapprove.hxx" + +#include + +namespace dbaccess +{ + + // ObjectNameApproval + struct ObjectNameApproval_Impl; + /** implementation of the IContainerApprove interface which approves + elements for insertion into a query or tables container. + + The only check done by this instance is whether the query name is + not already used, taking into account that in some databases, queries + and tables share the same namespace. + + The class is not thread-safe. + */ + class ObjectNameApproval : public IContainerApprove + { + std::unique_ptr< ObjectNameApproval_Impl > m_pImpl; + + public: + enum ObjectType + { + TypeQuery, + TypeTable + }; + + public: + /** constructs the instance + + @param _rxConnection + the connection relative to which the names should be checked. This connection + will be held weak. In case it is closed, subsequent calls to this instance's + methods throw a DisposedException. + @param _eType + specifies which type of objects is to be approved with this instance + */ + ObjectNameApproval( + const css::uno::Reference< css::sdbc::XConnection >& _rxConnection, + ObjectType _eType + ); + virtual ~ObjectNameApproval() override; + + // IContainerApprove + virtual void approveElement( const OUString& _rName ) override; + + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_OBJECTNAMEAPPROVAL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/preparedstatement.hxx b/dbaccess/source/core/inc/preparedstatement.hxx new file mode 100644 index 000000000..d8e0f5b6a --- /dev/null +++ b/dbaccess/source/core/inc/preparedstatement.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_PREPAREDSTATEMENT_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_PREPAREDSTATEMENT_HXX + +#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() throw() override; + virtual void SAL_CALL release() throw() 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_PREPAREDSTATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/querycomposer.hxx b/dbaccess/source/core/inc/querycomposer.hxx new file mode 100644 index 000000000..1e5ef2ab0 --- /dev/null +++ b/dbaccess/source/core/inc/querycomposer.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_QUERYCOMPOSER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_QUERYCOMPOSER_HXX + +#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() throw() override; + virtual void SAL_CALL release() throw() 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_QUERYCOMPOSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/querycontainer.hxx b/dbaccess/source/core/inc/querycontainer.hxx new file mode 100644 index 000000000..b6797aa91 --- /dev/null +++ b/dbaccess/source/core/inc/querycontainer.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_QUERYCONTAINER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_QUERYCONTAINER_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_QUERYCONTAINER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/recovery/dbdocrecovery.hxx b/dbaccess/source/core/inc/recovery/dbdocrecovery.hxx new file mode 100644 index 000000000..c5dadce45 --- /dev/null +++ b/dbaccess/source/core/inc/recovery/dbdocrecovery.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_RECOVERY_DBDOCRECOVERY_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_RECOVERY_DBDOCRECOVERY_HXX + +#include +#include +#include + +#include +#include + +namespace dbaccess +{ + + // DatabaseDocumentRecovery + struct DatabaseDocumentRecovery_Data; + class DatabaseDocumentRecovery + { + public: + DatabaseDocumentRecovery( + const css::uno::Reference< css::uno::XComponentContext >& i_rContext + ); + ~DatabaseDocumentRecovery(); + + /** saves the modified sub components of the given controller(s) to the "recovery" sub storage of the document + storage. + + @throws css::uno::Exception + in case of an error. + */ + void saveModifiedSubComponents( + const css::uno::Reference< css::embed::XStorage >& i_rTargetStorage, + const std::vector< css::uno::Reference< css::frame::XController > >& i_rControllers + ); + + /** recovery sub components from the given document storage, if applicable + + If the given document storage does not contain a recovery folder, the method silently returns. + + @throws css::uno::Exception + in case of an error. + */ + void recoverSubDocuments( + const css::uno::Reference< css::embed::XStorage >& i_rDocumentStorage, + const css::uno::Reference< css::frame::XController >& i_rTargetController + ); + + private: + const std::unique_ptr< DatabaseDocumentRecovery_Data > m_pData; + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_RECOVERY_DBDOCRECOVERY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/sdbcoretools.hxx b/dbaccess/source/core/inc/sdbcoretools.hxx new file mode 100644 index 000000000..41097c676 --- /dev/null +++ b/dbaccess/source/core/inc/sdbcoretools.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_SDBCORETOOLS_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_SDBCORETOOLS_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_SDBCORETOOLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/statement.hxx b/dbaccess/source/core/inc/statement.hxx new file mode 100644 index 000000000..2024bb0de --- /dev/null +++ b/dbaccess/source/core/inc/statement.hxx @@ -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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_STATEMENT_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_STATEMENT_HXX + +#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() throw() override; + virtual void SAL_CALL release() throw() 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; +}; + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_STATEMENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/table.hxx b/dbaccess/source/core/inc/table.hxx new file mode 100644 index 000000000..ec851f3b5 --- /dev/null +++ b/dbaccess/source/core/inc/table.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_TABLE_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_TABLE_HXX + +#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; + + protected: + css::uno::Reference< css::container::XNameAccess > m_xColumnDefinitions; + css::uno::Reference< css::container::XNameAccess > m_xDriverColumns; + + // + sal_Int32 m_nPrivileges; + // + + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override; + virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override; + + // IColumnFactory + virtual OColumn* createColumn(const OUString& _rName) const override; + virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override; + virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override; + virtual void columnDropped(const OUString& _sName) override; + + /** creates the column collection for the table + @param _rNames + The column names. + */ + virtual ::connectivity::sdbcx::OCollection* createColumns(const ::std::vector< OUString>& _rNames) override; + + /** creates the key collection for the table + @param _rNames + The key names. + */ + virtual ::connectivity::sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override; + + /** creates the index collection for the table + @param _rNames + The index names. + */ + virtual ::connectivity::sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + public: + /** constructs a wrapper supporting the com.sun.star.sdb.Table service.
+ @param _rxConn the connection the table belongs to + @param _rxTable the table from the driver can be null + @param _rCatalog the name of the catalog the table belongs to. May be empty. + @param _rSchema the name of the schema the table belongs to. May be empty. + @param _rName the name of the table + @param _rType the type of the table, as supplied by the driver + @param _rDesc the description of the table, as supplied by the driver + @throws css::sdbc::SQLException + */ + ODBTable(connectivity::sdbcx::OCollection* _pTables + ,const css::uno::Reference< css::sdbc::XConnection >& _rxConn + ,const OUString& _rCatalog + , const OUString& _rSchema + , const OUString& _rName + ,const OUString& _rType + , const OUString& _rDesc + ,const css::uno::Reference< css::container::XNameAccess >& _rxColumnDefinitions); + + /// @throws css::sdbc::SQLException + ODBTable(connectivity::sdbcx::OCollection* _pTables + ,const css::uno::Reference< css::sdbc::XConnection >& _rxConn); + virtual ~ODBTable() override; + + // ODescriptor + virtual void construct() override; + + //XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + + // css::lang::XServiceInfo + DECLARE_SERVICE_INFO(); + + // css::beans::XPropertySet + virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle) const override; + + // css::sdbcx::XRename, + virtual void SAL_CALL rename( const OUString& _rNewName ) override; + + // css::sdbcx::XAlterTable, + virtual void SAL_CALL alterColumnByName( const OUString& _rName, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor ) override; + + // css::lang::XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override; + + private: + using OTable_Base::createArrayHelper; + using OTable_Base::getFastPropertyValue; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_TABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/tablecontainer.hxx b/dbaccess/source/core/inc/tablecontainer.hxx new file mode 100644 index 000000000..d2a70af2b --- /dev/null +++ b/dbaccess/source/core/inc/tablecontainer.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_TABLECONTAINER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_TABLECONTAINER_HXX + +#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() throw() override { OFilteredContainer::acquire();} + virtual void SAL_CALL release() throw() 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_TABLECONTAINER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/veto.hxx b/dbaccess/source/core/inc/veto.hxx new file mode 100644 index 000000000..63a0748b2 --- /dev/null +++ b/dbaccess/source/core/inc/veto.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_VETO_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_VETO_HXX + +#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( const css::uno::Any& _rDetails ); + + virtual OUString SAL_CALL getReason() override; + virtual css::uno::Any SAL_CALL getDetails() override; + + protected: + virtual ~Veto() override; + + private: + Veto( const Veto& ) = delete; + Veto& operator=( const Veto& ) = delete; + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_VETO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/inc/viewcontainer.hxx b/dbaccess/source/core/inc/viewcontainer.hxx new file mode 100644 index 000000000..12d7f7480 --- /dev/null +++ b/dbaccess/source/core/inc/viewcontainer.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_INC_VIEWCONTAINER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_INC_VIEWCONTAINER_HXX + +#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() throw() override { OFilteredContainer::acquire();} + virtual void SAL_CALL release() throw() 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_CORE_INC_VIEWCONTAINER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/misc/ContainerMediator.cxx b/dbaccess/source/core/misc/ContainerMediator.cxx new file mode 100644 index 000000000..338858c87 --- /dev/null +++ b/dbaccess/source/core/misc/ContainerMediator.cxx @@ -0,0 +1,231 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 000000000..b5179e57b --- /dev/null +++ b/dbaccess/source/core/misc/DatabaseDataProvider.cxx @@ -0,0 +1,1080 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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_aFilterManager(), + 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::makeAny(m_CommandType)); + m_xAggregateSet->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,uno::makeAny(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(); // (dito) + + 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); +} + +OUString DatabaseDataProvider::getImplementationName_Static( ) +{ + return "com.sun.star.comp.dbaccess.DatabaseDataProvider"; +} + +// XServiceInfo +OUString SAL_CALL DatabaseDataProvider::getImplementationName( ) +{ + return getImplementationName_Static(); +} + +sal_Bool SAL_CALL DatabaseDataProvider::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +uno::Sequence< OUString > DatabaseDataProvider::getSupportedServiceNames_Static( ) +{ + return { "com.sun.star.chart2.data.DatabaseDataProvider" }; +} + +uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getSupportedServiceNames( ) +{ + return getSupportedServiceNames_Static(); +} + +uno::Reference< uno::XInterface > DatabaseDataProvider::Create(uno::Reference< uno::XComponentContext > const & context) +{ + return *(new DatabaseDataProvider(context)) ; +} + +// 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::makeAny( 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() ) + { + uno::Sequence< uno::Any > aInitArgs(1); + beans::NamedValue aParam("CreateDefaultData",uno::makeAny(true)); + aInitArgs[0] <<= 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::makeAny( chart::ChartDataRowSource_COLUMNS ) ); + // internal data always contains labels + aArguments.put( "FirstCellAsLabel", uno::makeAny( 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::makeAny( 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::makeAny(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 const char s_sNumberFormatKey[] = "NumberFormatKey"; + 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*/ ) +{ + 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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::makeAny( 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() + :sName() + ,nResultSetPosition( 0 ) + ,nDataType( sdbc::DataType::VARCHAR ) + { + } + explicit ColumnDescription( const OUString& i_rName ) + :sName( i_rName ) + ,nResultSetPosition( 0 ) + ,nDataType( sdbc::DataType::VARCHAR ) + { + } + }; + + struct CreateColumnDescription + { + ColumnDescription operator()( const OUString& i_rName ) + { + return ColumnDescription( i_rName ); + } + }; + + struct SelectColumnName + { + const OUString& operator()( const ColumnDescription& i_rColumn ) + { + return i_rColumn.sName; + } + }; +} + +void DatabaseDataProvider::impl_fillInternalDataProvider_throw(bool _bHasCategories,const uno::Sequence< OUString >& i_aColumnNames) +{ + // clear the data before fill the new one + uno::Reference< sdbcx::XColumnsSupplier > xColSup(m_xRowSet,uno::UNO_QUERY_THROW); + uno::Reference< container::XNameAccess > xColumns( xColSup->getColumns(), uno::UNO_SET_THROW ); + const uno::Sequence< OUString > aRowSetColumnNames( xColumns->getElementNames() ); + + typedef std::vector< ColumnDescription > ColumnDescriptions; + ColumnDescriptions aColumns; + bool bFirstColumnIsCategory = _bHasCategories; + if ( i_aColumnNames.hasElements() ) + { + // some normalizations ... + uno::Sequence< OUString > aImposedColumnNames( i_aColumnNames ); + + // strangely, there exist documents where the ColumnDescriptions end with a number of empty strings. /me + // thinks they're generated when you have a chart based on a result set with n columns, but remove some + // of those columns from the chart - it looks like a bug in the report XML export to me. + // So, get rid of the "trailing" empty columns + sal_Int32 nLastNonEmptyColName = aImposedColumnNames.getLength() - 1; + for ( ; nLastNonEmptyColName >= 0; --nLastNonEmptyColName ) + { + if ( !aImposedColumnNames[ nLastNonEmptyColName ].isEmpty() ) + break; + } + aImposedColumnNames.realloc( nLastNonEmptyColName + 1 ); + + // second, for X-Y-charts the ColumnDescriptions exported by chart miss the name of the first (non-category) + // column. This, this results in a ColumnDescriptions array like <"", "col2", "col3">, where you'd expect + // <"col1", "col2", "col3">. + // Fix this with some heuristics: + if ( aImposedColumnNames.hasElements() && ( !aImposedColumnNames[0].isEmpty() ) ) + { + const sal_Int32 nAssumedRowSetColumnIndex = _bHasCategories ? 1 : 0; + if ( nAssumedRowSetColumnIndex < aRowSetColumnNames.getLength() ) + aImposedColumnNames[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() ) + { + double nValue; + ::rtl::math::setNan( &nValue ); + aRow.push_back( nValue ); + } + else + aRow.push_back( aValue.getDouble() ); + } + + aDataValues.push_back( aRow ); + } + + // insert default data when no rows exist + if ( !nRowCount ) + { + nRowCount = 3; + static const double fDefaultData[ ] = + { 9.10, 3.20, 4.54, + 2.40, 8.80, 9.65, + 3.10, 1.50, 3.70, + 4.30, 9.02, 6.20 }; + for(sal_Int32 h = 0,k = 0; h < nRowCount; ++h,++k ) + { + aRowLabels.push_back(OUString::number(h+1)); + std::vector< double > aRow; + const sal_Int32 nSize = SAL_N_ELEMENTS(fDefaultData); + for (size_t j = 0; j < (aColumns.size()-1); ++j,++k) + { + if ( k >= nSize ) + k = 0; + aRow.push_back(fDefaultData[k]); + } + aDataValues.push_back(aRow); + } + } + + uno::Reference< chart::XChartDataArray> xData(m_xInternal,uno::UNO_QUERY); + xData->setRowDescriptions(comphelper::containerToSequence(aRowLabels)); + + const size_t nOffset = bFirstColumnIsCategory ? 1 : 0; + uno::Sequence< OUString > aColumnDescriptions( aColumns.size() - nOffset ); + std::transform( + aColumns.begin() + nOffset, + aColumns.end(), + aColumnDescriptions.getArray(), + SelectColumnName() + ); + xData->setColumnDescriptions( aColumnDescriptions ); + + uno::Sequence< uno::Sequence< double > > aData(aDataValues.size()); + uno::Sequence< double >* pDataIter = aData.getArray(); + uno::Sequence< double >* pDataEnd = pDataIter + aData.getLength(); + for(sal_Int32 i= 0;pDataIter != pDataEnd; ++pDataIter,++i ) + { + if ( !aDataValues[i].empty() ) + *pDataIter = comphelper::containerToSequence(aDataValues[i]); + } + xData->setData(aData); +} + +void DatabaseDataProvider::impl_fillRowSet_throw() +{ + m_xAggregateSet->setPropertyValue( PROPERTY_FILTER, uno::makeAny( 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/misc/PropertyForward.cxx b/dbaccess/source/core/misc/PropertyForward.cxx new file mode 100644 index 000000000..239bd422f --- /dev/null +++ b/dbaccess/source/core/misc/PropertyForward.cxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#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, + const OUString& _sName, const std::vector< OUString>& _aPropertyList ) + :m_xSource( _xSource, UNO_SET_THROW ) + ,m_xDestContainer( _xDestContainer, UNO_SET_THROW ) + ,m_sName( _sName ) + ,m_bInInsert( false ) + { + + osl_atomic_increment(&m_refCount); + try + { + if ( _aPropertyList.empty() ) + _xSource->addPropertyChangeListener( OUString(), this ); + else + { + for (auto const& property : _aPropertyList) + _xSource->addPropertyChangeListener(property, this); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + osl_atomic_decrement( &m_refCount ); + } + + OPropertyForward::~OPropertyForward() + { + } + + void SAL_CALL OPropertyForward::propertyChange( const PropertyChangeEvent& evt ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !m_xDestContainer.is() ) + throw DisposedException( OUString(), *this ); + + try + { + if ( !m_xDest.is() ) + { + if ( m_xDestContainer->hasByName( m_sName ) ) + { + m_xDest.set( m_xDestContainer->getByName( m_sName ), UNO_QUERY_THROW ); + } + else + { + Reference< XDataDescriptorFactory > xFactory( m_xDestContainer, UNO_QUERY_THROW ); + m_xDest.set( xFactory->createDataDescriptor(), UNO_SET_THROW ); + + ::comphelper::copyProperties( m_xSource, m_xDest ); + + m_bInInsert = true; + Reference< XAppend > xAppend( m_xDestContainer, UNO_QUERY_THROW ); + xAppend->appendByDescriptor( m_xDest ); + m_bInInsert = false; + } + + m_xDestInfo.set( m_xDest->getPropertySetInfo(), UNO_SET_THROW ); + } + + if ( m_xDestInfo->hasPropertyByName( evt.PropertyName ) ) + { + m_xDest->setPropertyValue( evt.PropertyName, evt.NewValue ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void SAL_CALL OPropertyForward::disposing( const css::lang::EventObject& /*_rSource*/ ) + { + ::osl::MutexGuard aGuard(m_aMutex); + + if ( !m_xSource.is() ) + throw DisposedException( OUString(), *this ); + + m_xSource->removePropertyChangeListener( OUString(), this ); + m_xSource = nullptr; + m_xDestContainer = nullptr; + m_xDestInfo = nullptr; + m_xDest = nullptr; + } + + void OPropertyForward::setDefinition( const css::uno::Reference< css::beans::XPropertySet>& _xDest ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_bInInsert ) + return; + + OSL_ENSURE( !m_xDest.is(), "OPropertyForward::setDefinition: definition object is already set!" ); + try + { + m_xDest.set( _xDest, UNO_SET_THROW ); + m_xDestInfo.set( m_xDest->getPropertySetInfo(), UNO_SET_THROW ); + ::comphelper::copyProperties( m_xDest, m_xSource ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/misc/apitools.cxx b/dbaccess/source/core/misc/apitools.cxx new file mode 100644 index 000000000..c080979ba --- /dev/null +++ b/dbaccess/source/core/misc/apitools.cxx @@ -0,0 +1,114 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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) + :OComponentHelper(_rMutex) + ,m_xParent(xParent) +{ + +} + +OSubComponent::~OSubComponent() +{ + m_xParent = nullptr; + +} + +// css::lang::XTypeProvider +Sequence< Type > OSubComponent::getTypes() +{ + OTypeCollection aTypes(cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get()); + + return aTypes.getTypes(); +} + +// XInterface + +void OSubComponent::release() throw ( ) +{ + Reference< XInterface > x( xDelegator ); + if (! x.is()) + { + if (osl_atomic_decrement( &m_refCount ) == 0 ) + { + if (! rBHelper.bDisposed) + { + // *before* again incrementing our ref count, ensure that our weak connection point + // will not create references to us anymore (via XAdapter::queryAdapted) + disposeWeakConnectionPoint(); + + Reference< XInterface > xHoldAlive( *this ); + // remember the parent + Reference< XInterface > xParent; + { + MutexGuard aGuard( rBHelper.rMutex ); + xParent = m_xParent; + m_xParent = nullptr; + } + + SAL_WARN_IF( m_refCount != 1, "dbaccess.core", "OSubComponent::release: invalid ref count (before dispose)!" ); + + // First dispose + dispose(); + + // only the alive ref holds the object + SAL_WARN_IF( m_refCount != 1, "dbaccess.core", "OSubComponent::release: invalid ref count (after dispose)!" ); + + // release the parent in the ~ + if (xParent.is()) + { + MutexGuard aGuard( rBHelper.rMutex ); + m_xParent = xParent; + } + + // destroy the object if xHoldAlive decrement the refcount to 0 + return; + } + } + // restore the reference count + osl_atomic_increment( &m_refCount ); + } + + // as we cover the job of the componenthelper we use the ... + OWeakAggObject::release(); +} + +Any OSubComponent::queryInterface( const Type & rType ) +{ + Any aReturn; + if (!rType.equals(cppu::UnoType::get())) + aReturn = OComponentHelper::queryInterface(rType); + + return aReturn; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/misc/dsntypes.cxx b/dbaccess/source/core/misc/dsntypes.cxx new file mode 100644 index 000000000..8256f370c --- /dev/null +++ b/dbaccess/source/core/misc/dsntypes.cxx @@ -0,0 +1,563 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + + namespace + { + void lcl_extractHostAndPort(const OUString& _sUrl,OUString& _sHostname,sal_Int32& _nPortNumber) + { + if ( comphelper::string::getTokenCount(_sUrl, ':') >= 2 ) + { + sal_Int32 nPos {0}; + _sHostname = _sUrl.getToken(0, ':', nPos); + _nPortNumber = _sUrl.getToken(0, ':', nPos).toInt32(); + } + } + } +// 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(const OUString& _sURL) const +{ + return m_aDriverConfig.getDriverTypeDisplayName(_sURL); +} + +OUString ODsnTypeCollection::cutPrefix(const OUString& _sURL) const +{ + OUString sRet; + OUString sOldPattern; + + // on Windows or with gen rendering, the urls may begin with an ~ + const OUString& 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(prefix.getLength() <= sCleanURL.getLength(), "How can A match B when A shorter than B?"); + sRet = sCleanURL.copy(prefix.getLength()); + sOldPattern = dsnPrefix; + } + } + + return sRet; +} + +OUString ODsnTypeCollection::getPrefix(const OUString& _sURL) const +{ + OUString sRet; + OUString sOldPattern; + for (auto const& dsnPrefix : m_aDsnPrefixes) + { + WildCard aWildCard(dsnPrefix); + if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) ) + { + // This relies on the fact that all patterns are of the form + // foo* + // that is, the very concept of "prefix" applies. + sRet = comphelper::string::stripEnd(dsnPrefix, '*'); + OSL_ENSURE(sRet.getLength() <= _sURL.getLength(), "How can A match B when A shorter than B?"); + sOldPattern = dsnPrefix; + } + } + + return sRet; +} + +bool ODsnTypeCollection::hasDriver( const char* _pAsciiPattern ) const +{ + OUString sPrefix( getPrefix( OUString::createFromAscii( _pAsciiPattern ) ) ); + return !sPrefix.isEmpty(); +} + +bool ODsnTypeCollection::isConnectionUrlRequired(const OUString& _sURL) const +{ + OUString sRet; + OUString sOldPattern; + for (auto const& dsnPrefix : m_aDsnPrefixes) + { + WildCard aWildCard(dsnPrefix); + if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) ) + { + sRet = dsnPrefix; + sOldPattern = dsnPrefix; + } + } + return !sRet.isEmpty() && sRet[sRet.getLength()-1] == '*'; +} + +OUString ODsnTypeCollection::getMediaType(const OUString& _sURL) const +{ + const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL); + return aFeatures.getOrDefault("MediaType",OUString()); +} + +OUString ODsnTypeCollection::getDatasourcePrefixFromMediaType(const OUString& _sMediaType,const OUString& _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.isEmpty() ) + 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(const OUString& _sURL) const +{ + const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getProperties(_sURL); + return aFeatures.getOrDefault("JavaDriverClass",OUString()); +} + +bool ODsnTypeCollection::isFileSystemBased(const OUString& _sURL) const +{ + const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL); + return aFeatures.getOrDefault("FileSystemBased",false); +} + +bool ODsnTypeCollection::supportsTableCreation(const OUString& _sURL) const +{ + const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL); + return aFeatures.getOrDefault("SupportsTableCreation",false); +} + +bool ODsnTypeCollection::supportsColumnDescription(const OUString& _sURL) const +{ + const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL); + return aFeatures.getOrDefault("SupportsColumnDescription",false); +} + +bool ODsnTypeCollection::supportsBrowsing(const OUString& _sURL) const +{ + const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL); + return aFeatures.getOrDefault("SupportsBrowsing",false); +} + +bool ODsnTypeCollection::supportsDBCreation(const OUString& _sURL) const +{ + const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL); + return aFeatures.getOrDefault("SupportsDBCreation",false); +} + +Sequence ODsnTypeCollection::getDefaultDBSettings( const OUString& _sURL ) const +{ + const ::comphelper::NamedValueCollection& aProperties = m_aDriverConfig.getProperties(_sURL); + return aProperties.getPropertyValues(); +} + +bool ODsnTypeCollection::isEmbeddedDatabase( const OUString& _sURL ) +{ + return _sURL.startsWith( "sdbc:embedded:" ); +} + +OUString ODsnTypeCollection::getEmbeddedDatabase() +{ + SvtMiscOptions aMiscOptions; + if (aMiscOptions.IsExperimentalMode()) + return "sdbc:embedded:firebird"; + else + return "sdbc:embedded:hsqldb"; +} + + +DATASOURCE_TYPE ODsnTypeCollection::determineType(const OUString& _rDsn) const +{ + OUString sDsn(comphelper::string::stripEnd(_rDsn, '*')); + sal_Int32 nSeparator = sDsn.indexOf(u':'); + if (-1 == nSeparator) + { + if (!sDsn.isEmpty()) + { + // there should be at least one such separator + OSL_FAIL("ODsnTypeCollection::implDetermineType : missing the colon !"); + } + + return DST_UNKNOWN; + } + + // find first : + if (sDsn.startsWithIgnoreAsciiCase("jdbc:oracle:thin:")) + return DST_ORACLE_JDBC; + + if (sDsn.startsWithIgnoreAsciiCase("jdbc:")) + return DST_JDBC; + + if (sDsn.equalsIgnoreAsciiCase("sdbc:embedded:hsqldb")) + return DST_EMBEDDED_HSQLDB; + + if (sDsn.equalsIgnoreAsciiCase("sdbc:embedded:firebird")) + return DST_EMBEDDED_FIREBIRD; + + // find second : + nSeparator = sDsn.indexOf(u':', nSeparator + 1); + if (-1 == nSeparator) + { + // at the moment only jdbc is allowed to have just one separator + OSL_FAIL("ODsnTypeCollection::implDetermineType : missing the second colon !"); + return DST_UNKNOWN; + } + + if (sDsn.startsWithIgnoreAsciiCase("sdbc:ado:")) + { + if (sDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:")) + { + if (sDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:Provider=Microsoft.ACE.OLEDB.12.0;")) + return DST_MSACCESS_2007; + else + return DST_MSACCESS; + } + return DST_ADO; + } + + struct KnownPrefix + { + const OUString sPrefix; + const DATASOURCE_TYPE eType; + const bool bMatchComplete; + + KnownPrefix( const OUString &_s, const DATASOURCE_TYPE _t, const bool _m ) + :sPrefix( _s ) + ,eType ( _t ) + ,bMatchComplete( _m ) + { + } + + bool match( const OUString &url) const + { + if(bMatchComplete) + { + return url.equalsIgnoreAsciiCase(sPrefix); + } + else + { + return url.startsWithIgnoreAsciiCase(sPrefix); + } + } + }; + const KnownPrefix aKnowPrefixes[] = + { + KnownPrefix( "sdbc:calc:", DST_CALC, false ), + KnownPrefix( "sdbc:writer:", DST_WRITER, false ), + KnownPrefix( "sdbc:flat:", DST_FLAT, false ), + KnownPrefix( "sdbc:odbc:", DST_ODBC, false ), + KnownPrefix( "sdbc:dbase:", DST_DBASE, false ), + KnownPrefix( "sdbc:firebird:", DST_FIREBIRD, false ), + KnownPrefix( "sdbc:mysql:odbc:", DST_MYSQL_ODBC, false ), + KnownPrefix( "sdbc:mysql:jdbc:", DST_MYSQL_JDBC, false ), + KnownPrefix( "sdbc:mysql:mysqlc:", DST_MYSQL_NATIVE, false ), + KnownPrefix( "sdbc:mysqlc:", DST_MYSQL_NATIVE_DIRECT,false ), + KnownPrefix( "sdbc:postgresql:", DST_POSTGRES ,false ), + + KnownPrefix( "sdbc:address:mozilla:", DST_MOZILLA, true ), + KnownPrefix( "sdbc:address:thunderbird:", DST_THUNDERBIRD, true ), + KnownPrefix( "sdbc:address:ldap:", DST_LDAP, true ), + KnownPrefix( "sdbc:address:outlook", DST_OUTLOOK, true ), + KnownPrefix( "sdbc:address:outlookexp", DST_OUTLOOKEXP, true ), + KnownPrefix( "sdbc:address:evolution:ldap", DST_EVOLUTION_LDAP, true ), + KnownPrefix( "sdbc:address:evolution:groupwise",DST_EVOLUTION_GROUPWISE,true ), + KnownPrefix( "sdbc:address:evolution:local", DST_EVOLUTION, true ), + KnownPrefix( "sdbc:address:kab", DST_KAB, true ), + KnownPrefix( "sdbc:address:macab", DST_MACAB, true ) + }; + + for (const auto & aKnowPrefixe : aKnowPrefixes) + { + if( aKnowPrefixe.match(sDsn) ) + { + return aKnowPrefixe.eType; + } + } + + return DST_UNKNOWN; +} + +void ODsnTypeCollection::fillPageIds(const OUString& _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_LDAP: + _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_LDAP); + break; + case DST_MSACCESS: + case DST_MSACCESS_2007: + _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MSACCESS); + break; + case DST_OUTLOOKEXP: + case DST_OUTLOOK: + case DST_MOZILLA: + case DST_THUNDERBIRD: + case DST_EVOLUTION: + case DST_EVOLUTION_GROUPWISE: + case DST_EVOLUTION_LDAP: + case DST_KAB: + case DST_MACAB: + case DST_EMBEDDED_HSQLDB: + case DST_EMBEDDED_FIREBIRD: + break; + default: + _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_USERDEFINED); + break; + } +} + +OUString ODsnTypeCollection::getType(const OUString& _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(const OUString& _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 000000000..d1712fba3 --- /dev/null +++ b/dbaccess/source/core/misc/migrwarndlg.cxx @@ -0,0 +1,22 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include + +namespace dbaccess +{ +MigrationWarnDialog::MigrationWarnDialog(weld::Window* pParent) + : MessageDialogController(pParent, "dbaccess/ui/migrwarndlg.ui", "MigrationWarnDialog") + , m_xLater(m_xBuilder->weld_button("no")) +{ + m_xLater->grab_focus(); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/misc/objectnameapproval.cxx b/dbaccess/source/core/misc/objectnameapproval.cxx new file mode 100644 index 000000000..3ec15caaa --- /dev/null +++ b/dbaccess/source/core/misc/objectnameapproval.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include + +#include + +namespace dbaccess +{ + + using ::com::sun::star::sdbc::XConnection; + using ::com::sun::star::uno::WeakReference; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::sdb::tools::XConnectionTools; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::sdb::tools::XObjectNames; + using ::com::sun::star::uno::XInterface; + + namespace CommandType = com::sun::star::sdb::CommandType; + + // ObjectNameApproval_Impl + struct ObjectNameApproval_Impl + { + WeakReference< XConnection > aConnection; + sal_Int32 nCommandType; + }; + + // ObjectNameApproval + ObjectNameApproval::ObjectNameApproval( const Reference< XConnection >& _rxConnection, ObjectType _eType ) + :m_pImpl( new ObjectNameApproval_Impl ) + { + m_pImpl->aConnection = _rxConnection; + m_pImpl->nCommandType = _eType == TypeQuery ? CommandType::QUERY : CommandType::TABLE; + } + + ObjectNameApproval::~ObjectNameApproval() + { + } + + void ObjectNameApproval::approveElement( const OUString& _rName ) + { + Reference< XConnection > xConnection( m_pImpl->aConnection ); + if ( !xConnection.is() ) + throw DisposedException(); + + Reference< XConnectionTools > xConnectionTools( xConnection, UNO_QUERY_THROW ); + Reference< XObjectNames > xObjectNames( xConnectionTools->getObjectNames(), css::uno::UNO_SET_THROW ); + xObjectNames->checkNameForCreate( m_pImpl->nCommandType, _rName ); + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/misc/sdbcoretools.cxx b/dbaccess/source/core/misc/sdbcoretools.cxx new file mode 100644 index 000000000..70de1d194 --- /dev/null +++ b/dbaccess/source/core/misc/sdbcoretools.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 + +#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.get() ); + Optional< OUString > aMessage = xStringResolver->getStringFromInformationalRequest( pRequest.get() ); + if ( aMessage.IsPresent ) + sDisplayMessage = aMessage.Value; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( sDisplayMessage.isEmpty() ) + { + Exception aExcept; + _rError >>= aExcept; + + OUStringBuffer aBuffer; + aBuffer.append( _rError.getValueTypeName() ); + aBuffer.append( ":\n" ); + aBuffer.append( aExcept.Message ); + + sDisplayMessage = aBuffer.makeStringAndClear(); + } + + 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/services.cxx b/dbaccess/source/core/misc/services.cxx new file mode 100644 index 000000000..c45c1673b --- /dev/null +++ b/dbaccess/source/core/misc/services.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 +#include +#include + +#include + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; + +namespace dba{ + ::cppu::ImplementationEntry const entries[] = { + { + &::dbaccess::DatabaseDataProvider::Create, + &::dbaccess::DatabaseDataProvider::getImplementationName_Static, + &::dbaccess::DatabaseDataProvider::getSupportedServiceNames_Static, + &cppu::createSingleComponentFactory, nullptr, 0 + }, + + { + &dbaccess::ODatabaseContext::Create, + &dbaccess::ODatabaseContext::getImplementationName_static, + &dbaccess::ODatabaseContext::getSupportedServiceNames_static, + &cppu::createOneInstanceComponentFactory, nullptr, 0 + }, + + { nullptr, nullptr, nullptr, nullptr, nullptr, 0 } + }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* dba_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* pRegistryKey) +{ + return cppu::component_getFactoryHelper( + pImplementationName, pServiceManager, pRegistryKey, dba::entries); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/misc/veto.cxx b/dbaccess/source/core/misc/veto.cxx new file mode 100644 index 000000000..d2596d4e1 --- /dev/null +++ b/dbaccess/source/core/misc/veto.cxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +namespace dbaccess +{ + + using ::com::sun::star::uno::Any; + + // Veto + Veto::Veto( const Any& _rDetails ) + :m_aDetails( _rDetails ) + { + } + + Veto::~Veto() + { + } + + OUString SAL_CALL Veto::getReason() + { + return OUString(); + } + + Any SAL_CALL Veto::getDetails() + { + return m_aDetails; + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/dbdocrecovery.cxx b/dbaccess/source/core/recovery/dbdocrecovery.cxx new file mode 100644 index 000000000..280789ff8 --- /dev/null +++ b/dbaccess/source/core/recovery/dbdocrecovery.cxx @@ -0,0 +1,347 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include "storagetextstream.hxx" +#include "subcomponentrecovery.hxx" +#include "subcomponents.hxx" + +#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( const OUString& i_rIniLine, OUString& o_rStorName, SubComponentDescriptor& o_rCompDesc ) + { + const sal_Int32 nEqualSignPos = i_rIniLine.indexOf( '=' ); + if ( nEqualSignPos < 1 ) + { + OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of '='" ); + return false; + } + o_rStorName = i_rIniLine.copy( 0, nEqualSignPos ); + + const sal_Int32 nCommaPos = i_rIniLine.lastIndexOf( ',' ); + if ( nCommaPos != i_rIniLine.getLength() - 2 ) + { + OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of ','" ); + return false; + } + o_rCompDesc.sName = i_rIniLine.copy( nEqualSignPos + 1, nCommaPos - nEqualSignPos - 1 ); + o_rCompDesc.bForEditing = ( i_rIniLine[ nCommaPos + 1 ] == '1' ); + return true; + } + + static const char sRecoveryDataSubStorageName[] = "recovery"; + + static const char sObjectMapStreamName[] = "storage-component-map.ini"; + + 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( const OUString& i_rIniLine, OUString& o_rSectionName ) + { + const sal_Int32 nLen = i_rIniLine.getLength(); + if ( i_rIniLine.startsWith("[") && i_rIniLine.endsWith("]") ) + { + o_rSectionName = i_rIniLine.copy( 1, nLen -2 ); + return true; + } + return false; + } + + void lcl_stripTrailingLineFeed( OUString& io_rLine ) + { + const sal_Int32 nLen = io_rLine.getLength(); + if ( io_rLine.endsWith("\n") ) + io_rLine = io_rLine.copy( 0, nLen - 1 ); + } + + void lcl_readObjectMap_throw( const Reference & i_rxContext, const Reference< XStorage >& i_rStorage, + MapStringToCompDesc& o_mapStorageToObjectName ) + { + ENSURE_OR_THROW( i_rStorage.is(), "invalid storage" ); + if ( !i_rStorage->hasByName( sObjectMapStreamName ) ) + { // nothing to do, though suspicious + OSL_FAIL( "lcl_readObjectMap_throw: if there's no map file, then there's expected to be no storage, too!" ); + return; + } + + Reference< XStream > xIniStream( i_rStorage->openStreamElement( + sObjectMapStreamName, ElementModes::READ ), UNO_SET_THROW ); + + Reference< XTextInputStream2 > xTextInput = TextInputStream::create( i_rxContext ); + xTextInput->setEncoding( "UTF-8" ); + xTextInput->setInputStream( xIniStream->getInputStream() ); + + OUString sCurrentSection; + bool bCurrentSectionIsKnownToBeUnsupported = true; + while ( !xTextInput->isEOF() ) + { + OUString sLine = xTextInput->readLine(); + lcl_stripTrailingLineFeed( sLine ); + + if ( sLine.isEmpty() ) + continue; + + if ( lcl_isSectionStart( sLine, sCurrentSection ) ) + { + bCurrentSectionIsKnownToBeUnsupported = false; + continue; + } + + if ( bCurrentSectionIsKnownToBeUnsupported ) + continue; + + // the only section we support so far is "storages" + if ( sCurrentSection != "storages" ) + { + bCurrentSectionIsKnownToBeUnsupported = true; + continue; + } + + OUString sStorageName; + SubComponentDescriptor aCompDesc; + if ( !lcl_extractCompDesc( sLine, sStorageName, aCompDesc ) ) + continue; + o_mapStorageToObjectName[ sStorageName ] = aCompDesc; + } + } + + void lcl_markModified( const Reference< XComponent >& i_rSubComponent ) + { + const Reference< XModifiable > xModify( i_rSubComponent, UNO_QUERY ); + if ( !xModify.is() ) + { + OSL_FAIL( "lcl_markModified: unhandled case!" ); + return; + } + + xModify->setModified( true ); + } + } + + // DatabaseDocumentRecovery_Data + struct DatabaseDocumentRecovery_Data + { + const Reference aContext; + + explicit DatabaseDocumentRecovery_Data( const Reference & i_rContext ) + :aContext( i_rContext ) + { + } + }; + + // DatabaseDocumentRecovery + DatabaseDocumentRecovery::DatabaseDocumentRecovery( const Reference & i_rContext ) + :m_pData( new DatabaseDocumentRecovery_Data( i_rContext ) ) + { + } + + DatabaseDocumentRecovery::~DatabaseDocumentRecovery() + { + } + + void DatabaseDocumentRecovery::saveModifiedSubComponents( const Reference< XStorage >& i_rTargetStorage, + const std::vector< Reference< XController > >& i_rControllers ) + { + ENSURE_OR_THROW( i_rTargetStorage.is(), "invalid document storage" ); + + // create a sub storage for recovery data + if ( i_rTargetStorage->hasByName( sRecoveryDataSubStorageName ) ) + i_rTargetStorage->removeElement( sRecoveryDataSubStorageName ); + Reference< XStorage > xRecoveryStorage = i_rTargetStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READWRITE ); + + // store recovery data for open sub components of the given controller(s) + if ( !i_rControllers.empty() ) + { + ENSURE_OR_THROW( i_rControllers.size() == 1, "can't handle more than one controller" ); + // At the moment, there can be only one view to a database document. If we ever allow for more than this, + // then we need a concept for sub documents opened from different controllers (i.e. two document views, + // and the user opens the very same form in both views). And depending on this, we need a concept for + // how those are saved to the recovery file. + + MapCompTypeToCompDescs aMapCompDescs; + + for (auto const& controller : i_rControllers) + { + Reference< XDatabaseDocumentUI > xDatabaseUI(controller, UNO_QUERY_THROW); + const Sequence< Reference< XComponent > > aComponents( xDatabaseUI->getSubComponents() ); + + for ( auto const & component : aComponents ) + { + SubComponentRecovery aComponentRecovery( m_pData->aContext, xDatabaseUI, component ); + aComponentRecovery.saveToRecoveryStorage( xRecoveryStorage, aMapCompDescs ); + } + } + + for (auto const& elem : aMapCompDescs) + { + Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement( + SubComponentRecovery::getComponentsStorageName( elem.first ), ElementModes::WRITE | ElementModes::NOCREATE ) ); + lcl_writeObjectMap_throw( m_pData->aContext, xComponentsStor, elem.second ); + tools::stor::commitStorageIfWriteable( xComponentsStor ); + } + } + + // commit the recovery storage + tools::stor::commitStorageIfWriteable( xRecoveryStorage ); + } + + void DatabaseDocumentRecovery::recoverSubDocuments( const Reference< XStorage >& i_rDocumentStorage, + const Reference< XController >& i_rTargetController ) + { + ENSURE_OR_THROW( i_rDocumentStorage.is(), "illegal document storage" ); + Reference< XDatabaseDocumentUI > xDocumentUI( i_rTargetController, UNO_QUERY_THROW ); + + if ( !i_rDocumentStorage->hasByName( sRecoveryDataSubStorageName ) ) + // that's allowed + return; + + // the "recovery" sub storage + Reference< XStorage > xRecoveryStorage = i_rDocumentStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READ ); + + // read the map from sub storages to object names + MapCompTypeToCompDescs aMapCompDescs; + const SubComponentType aKnownTypes[] = { TABLE, QUERY, FORM, REPORT, RELATION_DESIGN }; + for (SubComponentType aKnownType : aKnownTypes) + { + if ( !xRecoveryStorage->hasByName( SubComponentRecovery::getComponentsStorageName( aKnownType ) ) ) + continue; + + Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement( + SubComponentRecovery::getComponentsStorageName( aKnownType ), ElementModes::READ ) ); + lcl_readObjectMap_throw( m_pData->aContext, xComponentsStor, aMapCompDescs[ aKnownType ] ); + xComponentsStor->dispose(); + } + + // recover all sub components as indicated by the map + for (auto const& elemMapCompDescs : aMapCompDescs) + { + const SubComponentType eComponentType = elemMapCompDescs.first; + + // the storage for all components of the current type + Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement( + SubComponentRecovery::getComponentsStorageName( eComponentType ), ElementModes::READ ), UNO_SET_THROW ); + + // loop through all components of this type + for (auto const& elem : elemMapCompDescs.second) + { + const OUString sComponentName(elem.second.sName); + if ( !xComponentsStor->hasByName(elem.first) ) + { + SAL_WARN( "dbaccess", + "DatabaseDocumentRecovery::recoverSubDocuments: inconsistent recovery storage: storage '" << + elem.first << + "' not found in '" << + SubComponentRecovery::getComponentsStorageName( eComponentType ) << + "', but required per map file!" ); + continue; + } + + // the controller needs to have a connection to be able to open sub components + if ( !xDocumentUI->isConnected() ) + xDocumentUI->connect(); + + // recover the single component + Reference< XStorage > xCompStor( xComponentsStor->openStorageElement( elem.first, ElementModes::READ ) ); + SubComponentRecovery aComponentRecovery( m_pData->aContext, xDocumentUI, eComponentType ); + Reference< XComponent > xSubComponent( aComponentRecovery.recoverFromStorage( xCompStor, sComponentName, elem.second.bForEditing ) ); + + // at the moment, we only store, during session save, sub components which are modified. So, set this + // recovered sub component to "modified", too. + lcl_markModified( xSubComponent ); + } + + xComponentsStor->dispose(); + } + + xRecoveryStorage->dispose(); + + // now that we successfully recovered, removed the "recovery" sub storage + try + { + i_rDocumentStorage->removeElement( sRecoveryDataSubStorageName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/settingsimport.cxx b/dbaccess/source/core/recovery/settingsimport.cxx new file mode 100644 index 000000000..b64787aa8 --- /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( const OUString& 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 + const OUString sValue = getAccumulatedCharacters().toString(); + + 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 <<= sValue; + } + else + { + SAL_WARN( "dbaccess", "ConfigItemImport::getItemValue: unsupported item type '" + << rItemType << "', ignoring"); + } + } + + // ConfigItemSetImport + ConfigItemSetImport::ConfigItemSetImport( ::comphelper::NamedValueCollection& o_rSettings ) + :ConfigItemImport( o_rSettings ) + { + } + + ConfigItemSetImport::~ConfigItemSetImport() + { + } + + ::rtl::Reference< SettingsImport > ConfigItemSetImport::nextState( const OUString& i_rElementName ) + { + // separate the namespace part from the element name + OUString sNamespace; + OUString sLocalName; + split( i_rElementName, sNamespace, sLocalName ); + + if ( sLocalName == "config-item-set" ) + return new ConfigItemSetImport( m_aChildSettings ); + if ( sLocalName == "config-item" ) + return new ConfigItemImport( m_aChildSettings ); + + SAL_WARN( "dbaccess", "unknown element name '" + << i_rElementName << "', ignoring"); + return new IgnoringSettingsImport; + } + + void ConfigItemSetImport::getItemValue( Any& o_rValue ) const + { + o_rValue <<= m_aChildSettings.getPropertyValues(); + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/settingsimport.hxx b/dbaccess/source/core/recovery/settingsimport.hxx new file mode 100644 index 000000000..c698263ad --- /dev/null +++ b/dbaccess/source/core/recovery/settingsimport.hxx @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SETTINGSIMPORT_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SETTINGSIMPORT_HXX + +#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( const OUString& 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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SETTINGSIMPORT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/storagestream.cxx b/dbaccess/source/core/recovery/storagestream.cxx new file mode 100644 index 000000000..2831f406b --- /dev/null +++ b/dbaccess/source/core/recovery/storagestream.cxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "storagestream.hxx" + +#include + +#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::embed::XStorage; + using ::com::sun::star::io::XStream; + + namespace ElementModes = ::com::sun::star::embed::ElementModes; + + // StorageOutputStream + StorageOutputStream::StorageOutputStream( const Reference< XStorage >& i_rParentStorage, + const OUString& i_rStreamName + ) + { + ENSURE_OR_THROW( i_rParentStorage.is(), "illegal stream" ); + + const Reference< XStream > xStream( + i_rParentStorage->openStreamElement( i_rStreamName, ElementModes::READWRITE ), UNO_SET_THROW ); + m_xOutputStream.set( xStream->getOutputStream(), UNO_SET_THROW ); + } + + StorageOutputStream::~StorageOutputStream() + { + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/storagestream.hxx b/dbaccess/source/core/recovery/storagestream.hxx new file mode 100644 index 000000000..6dffdf7a1 --- /dev/null +++ b/dbaccess/source/core/recovery/storagestream.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_STORAGESTREAM_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_STORAGESTREAM_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_STORAGESTREAM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/storagetextstream.cxx b/dbaccess/source/core/recovery/storagetextstream.cxx new file mode 100644 index 000000000..142615f00 --- /dev/null +++ b/dbaccess/source/core/recovery/storagetextstream.cxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "storagetextstream.hxx" + +#include + +namespace dbaccess +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::embed::XStorage; + using ::com::sun::star::io::TextOutputStream; + using ::com::sun::star::io::XTextOutputStream2; + + // StorageTextOutputStream_Data + struct StorageTextOutputStream_Data + { + Reference< XTextOutputStream2 > xTextOutput; + }; + + static const char sLineFeed[] = "\n"; + + // StorageTextOutputStream + StorageTextOutputStream::StorageTextOutputStream( const Reference& i_rContext, + const Reference< XStorage >& i_rParentStorage, + const OUString& i_rStreamName + ) + :StorageOutputStream( i_rParentStorage, i_rStreamName ) + ,m_pData( new StorageTextOutputStream_Data ) + { + m_pData->xTextOutput = TextOutputStream::create( i_rContext ); + m_pData->xTextOutput->setEncoding( "UTF-8" ); + m_pData->xTextOutput->setOutputStream( getOutputStream() ); + } + + StorageTextOutputStream::~StorageTextOutputStream() + { + } + + void StorageTextOutputStream::writeLine( const OUString& i_rLine ) + { + m_pData->xTextOutput->writeString( i_rLine ); + m_pData->xTextOutput->writeString( sLineFeed ); + } + + void StorageTextOutputStream::writeLine() + { + m_pData->xTextOutput->writeString( sLineFeed ); + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/storagetextstream.hxx b/dbaccess/source/core/recovery/storagetextstream.hxx new file mode 100644 index 000000000..5d7c88986 --- /dev/null +++ b/dbaccess/source/core/recovery/storagetextstream.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_STORAGETEXTSTREAM_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_STORAGETEXTSTREAM_HXX + +#include "storagestream.hxx" + +#include + +#include + +namespace dbaccess +{ + + // StorageTextStream + struct StorageTextOutputStream_Data; + class StorageTextOutputStream : public StorageOutputStream + { + public: + StorageTextOutputStream( + const css::uno::Reference< css::uno::XComponentContext >& i_rContext, + const css::uno::Reference< css::embed::XStorage >& i_rParentStorage, + const OUString& i_rStreamName + ); + virtual ~StorageTextOutputStream() override; + + void writeLine( const OUString& i_rLine ); + void writeLine(); + + private: + std::unique_ptr< StorageTextOutputStream_Data > m_pData; + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_STORAGETEXTSTREAM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/storagexmlstream.cxx b/dbaccess/source/core/recovery/storagexmlstream.cxx new file mode 100644 index 000000000..c04eff6f8 --- /dev/null +++ b/dbaccess/source/core/recovery/storagexmlstream.cxx @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "storagexmlstream.hxx" + +#include +#include +#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_Data + struct StorageXMLOutputStream_Data + { + Reference< XDocumentHandler > xHandler; + std::stack< OUString > aElements; + ::rtl::Reference< SvXMLAttributeList > xAttributes; + }; + + // StorageXMLOutputStream + StorageXMLOutputStream::StorageXMLOutputStream( const Reference& i_rContext, + const Reference< XStorage >& i_rParentStorage, + const OUString& i_rStreamName ) + :StorageOutputStream( i_rParentStorage, i_rStreamName ) + ,m_pData( new StorageXMLOutputStream_Data ) + { + const Reference< XWriter > xSaxWriter = Writer::create( i_rContext ); + xSaxWriter->setOutputStream( getOutputStream() ); + + m_pData->xHandler.set( xSaxWriter, UNO_QUERY_THROW ); + m_pData->xHandler->startDocument(); + + m_pData->xAttributes = new SvXMLAttributeList; + } + + StorageXMLOutputStream::~StorageXMLOutputStream() + { + } + + void StorageXMLOutputStream::close() + { + ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "illegal document handler" ); + m_pData->xHandler->endDocument(); + // do not call the base class, it would call closeOutput on the output stream, which is already done by + // endDocument + } + + void StorageXMLOutputStream::addAttribute( const OUString& i_rName, const OUString& i_rValue ) const + { + m_pData->xAttributes->AddAttribute( i_rName, i_rValue ); + } + + void StorageXMLOutputStream::startElement( const OUString& i_rElementName ) const + { + ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" ); + + m_pData->xHandler->startElement( i_rElementName, m_pData->xAttributes.get() ); + m_pData->xAttributes = new SvXMLAttributeList; + m_pData->aElements.push( i_rElementName ); + } + + void StorageXMLOutputStream::endElement() const + { + ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" ); + ENSURE_OR_RETURN_VOID( !m_pData->aElements.empty(), "no element on the stack" ); + + const OUString sElementName( m_pData->aElements.top() ); + m_pData->xHandler->endElement( sElementName ); + m_pData->aElements.pop(); + } + + void StorageXMLOutputStream::ignorableWhitespace( const OUString& i_rWhitespace ) const + { + ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" ); + + m_pData->xHandler->ignorableWhitespace( i_rWhitespace ); + } + + void StorageXMLOutputStream::characters( const OUString& i_rCharacters ) const + { + ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" ); + + m_pData->xHandler->characters( i_rCharacters ); + } + + // StorageXMLInputStream + StorageXMLInputStream::StorageXMLInputStream( const Reference& i_rContext, + const Reference< XStorage >& i_rParentStorage, + const OUString& i_rStreamName ) + { + ENSURE_OR_THROW( i_rParentStorage.is(), "illegal stream" ); + + const Reference< css::io::XStream > xStream( + i_rParentStorage->openStreamElement( i_rStreamName, css::embed::ElementModes::READ ), css::uno::UNO_SET_THROW ); + m_xInputStream.set( xStream->getInputStream(), css::uno::UNO_SET_THROW ); + + m_xParser.set( Parser::create(i_rContext) ); + } + + void StorageXMLInputStream::import( const Reference< XDocumentHandler >& i_rHandler ) + { + ENSURE_OR_THROW( i_rHandler.is(), "illegal document handler (NULL)" ); + + InputSource aInputSource; + aInputSource.aInputStream = m_xInputStream; + + m_xParser->setDocumentHandler( i_rHandler ); + m_xParser->parseStream( aInputSource ); + } + + StorageXMLInputStream::~StorageXMLInputStream() + { + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/storagexmlstream.hxx b/dbaccess/source/core/recovery/storagexmlstream.hxx new file mode 100644 index 000000000..ca0f3d343 --- /dev/null +++ b/dbaccess/source/core/recovery/storagexmlstream.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_STORAGEXMLSTREAM_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_STORAGEXMLSTREAM_HXX + +#include "storagestream.hxx" + +#include +#include +#include +#include + +#include + +namespace dbaccess +{ + + // StorageXMLOutputStream + struct StorageXMLOutputStream_Data; + class StorageXMLOutputStream : public StorageOutputStream + { + public: + StorageXMLOutputStream( + const css::uno::Reference< css::uno::XComponentContext >& i_rContext, + const css::uno::Reference< css::embed::XStorage >& i_rParentStorage, + const OUString& i_rStreamName + ); + virtual ~StorageXMLOutputStream() override; + + void close(); + + void addAttribute( const OUString& i_rName, const OUString& i_rValue ) const; + + void startElement( const OUString& i_rElementName ) const; + void endElement() const; + + void ignorableWhitespace( const OUString& i_rWhitespace ) const; + void characters( const OUString& i_rCharacters ) const; + + private: + StorageXMLOutputStream( const StorageXMLOutputStream& ) = delete; + StorageXMLOutputStream& operator=( const StorageXMLOutputStream& ) = delete; + + private: + std::unique_ptr< StorageXMLOutputStream_Data > m_pData; + }; + + class StorageXMLInputStream + { + public: + StorageXMLInputStream( + const css::uno::Reference< css::uno::XComponentContext >& i_rContext, + const css::uno::Reference< css::embed::XStorage >& i_rParentStorage, + const OUString& i_rStreamName + ); + ~StorageXMLInputStream(); + + void import( + const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_rHandler + ); + + StorageXMLInputStream( const StorageXMLInputStream& ) = delete; + StorageXMLInputStream& operator=( const StorageXMLInputStream& ) = delete; + + private: + css::uno::Reference< css::xml::sax::XParser > m_xParser; + css::uno::Reference< css::io::XInputStream > m_xInputStream; + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_STORAGEXMLSTREAM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/subcomponentloader.cxx b/dbaccess/source/core/recovery/subcomponentloader.cxx new file mode 100644 index 000000000..3393c3d13 --- /dev/null +++ b/dbaccess/source/core/recovery/subcomponentloader.cxx @@ -0,0 +1,124 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "subcomponentloader.hxx" + +#include +#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 000000000..a8f12071f --- /dev/null +++ b/dbaccess/source/core/recovery/subcomponentloader.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SUBCOMPONENTLOADER_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SUBCOMPONENTLOADER_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SUBCOMPONENTLOADER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/subcomponentrecovery.cxx b/dbaccess/source/core/recovery/subcomponentrecovery.cxx new file mode 100644 index 000000000..55f3f98a2 --- /dev/null +++ b/dbaccess/source/core/recovery/subcomponentrecovery.cxx @@ -0,0 +1,628 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "subcomponentrecovery.hxx" + +#include +#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::XInterface; + using css::uno::UNO_QUERY; + using css::uno::UNO_QUERY_THROW; + using css::uno::UNO_SET_THROW; + using css::uno::Exception; + using css::uno::RuntimeException; + using css::uno::Any; + using css::uno::Sequence; + using css::uno::XComponentContext; + using css::embed::XStorage; + using css::sdb::application::XDatabaseDocumentUI; + using css::beans::Pair; + using css::frame::ModuleManager; + using css::frame::XModuleManager2; + using css::lang::XComponent; + using css::frame::XModel; + using css::frame::XController; + using css::beans::XPropertySet; + using css::beans::PropertyValue; + using css::document::XStorageBasedDocument; + using css::ucb::XCommandProcessor; + using css::container::XHierarchicalNameAccess; + using css::sdb::XFormDocumentsSupplier; + using css::sdb::XReportDocumentsSupplier; + using css::xml::sax::XLocator; + using css::xml::sax::XDocumentHandler; + using css::xml::sax::XAttributeList; + + namespace ElementModes = css::embed::ElementModes; + namespace DatabaseObject = css::sdb::application::DatabaseObject; + + // helper + namespace + { + OUString lcl_getComponentStorageBaseName( const SubComponentType i_eType ) + { + switch ( i_eType ) + { + case FORM: + return "form"; + case REPORT: + return "report"; + case TABLE: + return "table"; + case QUERY: + return "query"; + default: + break; + } + + OSL_FAIL( "lcl_getComponentStorageBaseName: unimplemented case!" ); + return OUString(); + } + + SubComponentType lcl_databaseObjectToSubComponentType( const sal_Int32 i_nObjectType ) + { + switch ( i_nObjectType ) + { + case DatabaseObject::TABLE: return TABLE; + case DatabaseObject::QUERY: return QUERY; + case DatabaseObject::FORM: return FORM; + case DatabaseObject::REPORT:return REPORT; + default: + break; + } + return UNKNOWN; + } + + bool lcl_determineReadOnly( const Reference< XComponent >& i_rComponent ) + { + Reference< XModel > xDocument( i_rComponent, UNO_QUERY ); + if ( !xDocument.is() ) + { + Reference< XController > xController( i_rComponent, UNO_QUERY_THROW ); + xDocument = xController->getModel(); + } + + if ( !xDocument.is() ) + return false; + + ::comphelper::NamedValueCollection aDocArgs( xDocument->getArgs() ); + return aDocArgs.getOrDefault( "ReadOnly", false ); + } + + Reference< XCommandProcessor > lcl_getSubComponentDef_nothrow( const Reference< XDatabaseDocumentUI >& i_rAppUI, + const SubComponentType i_eType, const OUString& i_rName ) + { + Reference< XController > xController( i_rAppUI, UNO_QUERY_THROW ); + ENSURE_OR_RETURN( ( i_eType == FORM ) || ( i_eType == REPORT ), "lcl_getSubComponentDef_nothrow: illegal controller", nullptr ); + + Reference< XCommandProcessor > xCommandProcessor; + try + { + Reference< XHierarchicalNameAccess > xDefinitionContainer; + if ( i_eType == FORM ) + { + Reference< XFormDocumentsSupplier > xSuppForms( xController->getModel(), UNO_QUERY_THROW ); + xDefinitionContainer.set( xSuppForms->getFormDocuments(), UNO_QUERY_THROW ); + } + else + { + Reference< XReportDocumentsSupplier > xSuppReports( xController->getModel(), UNO_QUERY_THROW ); + xDefinitionContainer.set( xSuppReports->getReportDocuments(), UNO_QUERY_THROW ); + } + xCommandProcessor.set( xDefinitionContainer->getByHierarchicalName( i_rName ), UNO_QUERY_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xCommandProcessor; + } + + static const char sSettingsStreamName[] = "settings.xml"; + static const char sCurrentQueryDesignName[] = "ooo:current-query-design"; + } + + namespace { + + // SettingsExportContext + class SettingsExportContext : public ::xmloff::XMLSettingsExportContext + { + public: + SettingsExportContext( const Reference& i_rContext, const StorageXMLOutputStream& i_rDelegator ) + :m_rContext( i_rContext ) + ,m_rDelegator( i_rDelegator ) + ,m_aNamespace( ::xmloff::token::GetXMLToken( ::xmloff::token::XML_NP_CONFIG ) ) + { + } + + virtual ~SettingsExportContext() + { + } + + public: + virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, const OUString& i_rValue ) override; + virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, enum ::xmloff::token::XMLTokenEnum i_eValue ) override; + virtual void StartElement( enum ::xmloff::token::XMLTokenEnum i_eName ) override; + virtual void EndElement ( const bool i_bIgnoreWhitespace ) override; + virtual void Characters( const OUString& i_rCharacters ) override; + + virtual css::uno::Reference< css::uno::XComponentContext > + GetComponentContext() const override; + + private: + OUString impl_prefix( const ::xmloff::token::XMLTokenEnum i_eToken ) + { + return m_aNamespace + ":" + ::xmloff::token::GetXMLToken( i_eToken ); + } + + private: + const Reference& m_rContext; + const StorageXMLOutputStream& m_rDelegator; + const OUString m_aNamespace; + }; + + } + + void SettingsExportContext::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, const OUString& i_rValue ) + { + m_rDelegator.addAttribute( impl_prefix( i_eName ), i_rValue ); + } + + void SettingsExportContext::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, enum ::xmloff::token::XMLTokenEnum i_eValue ) + { + m_rDelegator.addAttribute( impl_prefix( i_eName ), ::xmloff::token::GetXMLToken( i_eValue ) ); + } + + void SettingsExportContext::StartElement( enum ::xmloff::token::XMLTokenEnum i_eName ) + { + m_rDelegator.ignorableWhitespace( " " ); + + m_rDelegator.startElement( impl_prefix( i_eName ) ); + } + + void SettingsExportContext::EndElement( const bool i_bIgnoreWhitespace ) + { + if ( i_bIgnoreWhitespace ) + m_rDelegator.ignorableWhitespace( " " ); + m_rDelegator.endElement(); + } + + void SettingsExportContext::Characters( const OUString& i_rCharacters ) + { + m_rDelegator.characters( i_rCharacters ); + } + + Reference< css::uno::XComponentContext > SettingsExportContext::GetComponentContext() const + { + return m_rContext; + } + + // SettingsDocumentHandler + typedef ::cppu::WeakImplHelper< XDocumentHandler + > SettingsDocumentHandler_Base; + + namespace { + + class SettingsDocumentHandler : public SettingsDocumentHandler_Base + { + public: + SettingsDocumentHandler() + { + } + + protected: + virtual ~SettingsDocumentHandler() override + { + } + + public: + // XDocumentHandler + virtual void SAL_CALL startDocument( ) override; + virtual void SAL_CALL endDocument( ) override; + virtual void SAL_CALL startElement( const OUString& aName, const Reference< XAttributeList >& xAttribs ) override; + virtual void SAL_CALL endElement( const OUString& aName ) override; + virtual void SAL_CALL characters( const OUString& aChars ) override; + virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) override; + virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) override; + virtual void SAL_CALL setDocumentLocator( const Reference< XLocator >& xLocator ) override; + + const ::comphelper::NamedValueCollection& getSettings() const { return m_aSettings; } + + private: + std::stack< ::rtl::Reference< SettingsImport > > m_aStates; + ::comphelper::NamedValueCollection m_aSettings; + }; + + } + + void SAL_CALL SettingsDocumentHandler::startDocument( ) + { + } + + void SAL_CALL SettingsDocumentHandler::endDocument( ) + { + } + + void SAL_CALL SettingsDocumentHandler::startElement( const OUString& i_Name, const Reference< XAttributeList >& i_Attribs ) + { + ::rtl::Reference< SettingsImport > pNewState; + + if ( m_aStates.empty() ) + { + if ( i_Name == "office:settings" ) + { + pNewState = new OfficeSettingsImport( m_aSettings ); + } + else + { + OSL_FAIL( "SettingsDocumentHandler::startElement: invalid settings file!" ); + // Yes, that's not correct. Somebody could, in theory, give us a document which starts with "foo:settings", + // where "foo" is mapped to the proper namespace URL. + // However, there's no need to bother with this. The "recovery" sub storage we're recovering from is + // not part of ODF, so we can impose any format restrictions on it ... + } + } + else + { + ::rtl::Reference< SettingsImport > pCurrentState( m_aStates.top() ); + pNewState = pCurrentState->nextState( i_Name ); + } + + ENSURE_OR_THROW( pNewState.is(), "no new state - aborting import" ); + pNewState->startElement( i_Attribs ); + + m_aStates.push( pNewState ); + } + + void SAL_CALL SettingsDocumentHandler::endElement( const OUString& ) + { + ENSURE_OR_THROW( !m_aStates.empty(), "no active element" ); + + ::rtl::Reference< SettingsImport > pCurrentState( m_aStates.top() ); + pCurrentState->endElement(); + m_aStates.pop(); + } + + void SAL_CALL SettingsDocumentHandler::characters( const OUString& i_Chars ) + { + ENSURE_OR_THROW( !m_aStates.empty(), "no active element" ); + + ::rtl::Reference< SettingsImport > pCurrentState( m_aStates.top() ); + pCurrentState->characters( i_Chars ); + } + + void SAL_CALL SettingsDocumentHandler::ignorableWhitespace( const OUString& ) + { + // ignore them - that's why they're called "ignorable" + } + + void SAL_CALL SettingsDocumentHandler::processingInstruction( const OUString&, const OUString& ) + { + OSL_FAIL( "SettingsDocumentHandler::processingInstruction: unexpected ..." ); + } + + void SAL_CALL SettingsDocumentHandler::setDocumentLocator( const Reference< XLocator >& ) {} + + // SubComponentRecovery + OUString SubComponentRecovery::getComponentsStorageName( const SubComponentType i_eType ) + { + switch ( i_eType ) + { + case FORM: + return "forms"; + case REPORT: + return "reports"; + case TABLE: + return "tables"; + case QUERY: + return "queries"; + case RELATION_DESIGN: + return "relations"; + default: + break; + } + + OSL_FAIL( "SubComponentRecovery::getComponentsStorageName: unimplemented case!" ); + return OUString(); + } + + void SubComponentRecovery::saveToRecoveryStorage( const Reference< XStorage >& i_rRecoveryStorage, + MapCompTypeToCompDescs& io_mapCompDescs ) + { + if ( m_eType == UNKNOWN ) + // quite fatal, but has already been reported (as assertion) before + return; + + // open the sub storage for the given kind of components + const OUString& rStorageName( getComponentsStorageName( m_eType ) ); + const Reference< XStorage > xComponentsStorage( i_rRecoveryStorage->openStorageElement( + rStorageName, ElementModes::READWRITE ), UNO_SET_THROW ); + + // find a free sub storage name, and create Yet Another Sub Storage + const OUString& rBaseName( lcl_getComponentStorageBaseName( m_eType ) ); + const OUString sStorName = ::dbtools::createUniqueName( xComponentsStorage.get(), 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 ); + + const OUString sWhitespace( " " ); + + 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.get() ); + + const ::comphelper::NamedValueCollection& rSettings( pDocHandler->getSettings() ); + const Any& aCurrentQueryDesign = rSettings.get( sCurrentQueryDesignName ); +#if OSL_DEBUG_LEVEL > 0 + Sequence< PropertyValue > aQueryDesignLayout; + OSL_VERIFY( aCurrentQueryDesign >>= aQueryDesignLayout ); +#endif + + // then load the query designer + ::comphelper::NamedValueCollection aLoadArgs; + aLoadArgs.put( "CurrentQueryDesign", aCurrentQueryDesign ); + aLoadArgs.put( "Hidden", true ); + + if ( !i_rComponentName.isEmpty() ) + { + xSubComponent.set( m_xDocumentUI->loadComponentWithArguments( + m_eType, + i_rComponentName, + i_bForEditing, + aLoadArgs.getPropertyValues() + ), + UNO_SET_THROW + ); + } + else + { + Reference< XComponent > xDummy; + xSubComponent.set( m_xDocumentUI->createComponentWithArguments( + m_eType, + aLoadArgs.getPropertyValues(), + xDummy + ), + UNO_SET_THROW + ); + } + + Reference< XController > xController( m_xDocumentUI, UNO_QUERY_THROW ); + rtl::Reference( new SubComponentLoader( xController, xSubComponent ) ); + + return xSubComponent; + } + + Reference< XComponent > SubComponentRecovery::recoverFromStorage( const Reference< XStorage >& i_rRecoveryStorage, + const OUString& i_rComponentName, const bool i_bForEditing ) + { + Reference< XComponent > xSubComponent; + switch ( m_eType ) + { + case FORM: + case REPORT: + xSubComponent = impl_recoverSubDocument_throw( i_rRecoveryStorage, i_rComponentName, i_bForEditing ); + break; + case QUERY: + xSubComponent = impl_recoverQueryDesign_throw( i_rRecoveryStorage, i_rComponentName, i_bForEditing ); + break; + default: + OSL_FAIL( "SubComponentRecovery::recoverFromStorage: unimplemented case!" ); + break; + } + return xSubComponent; + } + +} // namespace dbaccess + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/subcomponentrecovery.hxx b/dbaccess/source/core/recovery/subcomponentrecovery.hxx new file mode 100644 index 000000000..988177800 --- /dev/null +++ b/dbaccess/source/core/recovery/subcomponentrecovery.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SUBCOMPONENTRECOVERY_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SUBCOMPONENTRECOVERY_HXX + +#include "subcomponents.hxx" + +#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, + const css::uno::Reference< css::lang::XComponent >& i_rComponent ) + :m_rContext( i_rContext ) + ,m_xDocumentUI( i_rController, css::uno::UNO_SET_THROW ) + ,m_xComponent( i_rComponent ) + ,m_eType( UNKNOWN ) + ,m_aCompDesc() + { + impl_identifyComponent_throw(); + } + + SubComponentRecovery( + const css::uno::Reference< css::uno::XComponentContext >& i_rContext, + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& i_rController, + const SubComponentType i_eType ) + :m_rContext( i_rContext ) + ,m_xDocumentUI( i_rController, css::uno::UNO_SET_THROW ) + ,m_xComponent() + ,m_eType( i_eType ) + ,m_aCompDesc() + { + } + + // only to be used after being constructed with a component + void saveToRecoveryStorage( + const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage, + MapCompTypeToCompDescs& io_mapCompDescs + ); + + // only to be used after being constructed with a type + css::uno::Reference< css::lang::XComponent > + recoverFromStorage( + const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage, + const OUString& i_rComponentName, + const bool i_bForEditing + ); + + static OUString getComponentsStorageName( const SubComponentType i_eType ); + + private: + void impl_saveSubDocument_throw( + const css::uno::Reference< css::embed::XStorage >& i_rObjectStorage + ); + + void impl_saveQueryDesign_throw( + const css::uno::Reference< css::embed::XStorage >& i_rObjectStorage + ); + + css::uno::Reference< css::lang::XComponent > + impl_recoverSubDocument_throw( + const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage, + const OUString& i_rComponentName, + const bool i_bForEditing + ); + + css::uno::Reference< css::lang::XComponent > + impl_recoverQueryDesign_throw( + const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage, + const OUString& i_rComponentName, + const bool i_bForEditing + ); + + void impl_identifyComponent_throw(); + + private: + const css::uno::Reference< css::uno::XComponentContext >& + m_rContext; + css::uno::Reference< css::sdb::application::XDatabaseDocumentUI > + m_xDocumentUI; + const css::uno::Reference< css::lang::XComponent > + m_xComponent; + SubComponentType m_eType; + SubComponentDescriptor m_aCompDesc; + }; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SUBCOMPONENTRECOVERY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/recovery/subcomponents.hxx b/dbaccess/source/core/recovery/subcomponents.hxx new file mode 100644 index 000000000..029b31c95 --- /dev/null +++ b/dbaccess/source/core/recovery/subcomponents.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SUBCOMPONENTS_HXX +#define INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SUBCOMPONENTS_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_CORE_RECOVERY_SUBCOMPONENTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/core/resource/core_resource.cxx b/dbaccess/source/core/resource/core_resource.cxx new file mode 100644 index 000000000..34ab1b0ba --- /dev/null +++ b/dbaccess/source/core/resource/core_resource.cxx @@ -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 . + */ + +#include + +#include + +// ---- needed as long as we have no contexts for components --- +#include + +namespace dbaccess +{ + // ResourceManager + namespace + { + // access safety + struct theResourceManagerMutex : public rtl::Static< osl::Mutex, theResourceManagerMutex > {}; + } + + OUString ResourceManager::loadString(const char* pResId) + { + return Translate::get(pResId, Translate::Create("dba")); + } + + OUString ResourceManager::loadString(const char* pResId, const char* _pPlaceholderAscii, const OUString& _rReplace) + { + OUString sString(loadString(pResId)); + return sString.replaceFirst( OUString::createFromAscii(_pPlaceholderAscii), _rReplace ); + } + + OUString ResourceManager::loadString(const char* pResId, const char* _pPlaceholderAscii1, const OUString& _rReplace1, + const char* _pPlaceholderAscii2, const OUString& _rReplace2) + { + OUString sString(loadString(pResId)); + sString = sString.replaceFirst( OUString::createFromAscii(_pPlaceholderAscii1), _rReplace1 ); + sString = sString.replaceFirst( OUString::createFromAscii(_pPlaceholderAscii2), _rReplace2 ); + return sString; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/alterparser.cxx b/dbaccess/source/filter/hsqldb/alterparser.cxx new file mode 100644 index 000000000..1dd770b1f --- /dev/null +++ b/dbaccess/source/filter/hsqldb/alterparser.cxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 000000000..710cd3c79 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/alterparser.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_ALTERPARSER_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_ALTERPARSER_HXX + +#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; +}; +} + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_ALTERPARSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/columndef.cxx b/dbaccess/source/filter/hsqldb/columndef.cxx new file mode 100644 index 000000000..62bd7b541 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/columndef.cxx @@ -0,0 +1,44 @@ + +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "columndef.hxx" +#include + +namespace dbahsql +{ +using namespace css::sdbc; + +ColumnDefinition::ColumnDefinition(const OUString& sName, sal_Int32 eType, + const std::vector& aParams, bool bPrimary, + sal_Int32 nAutoIncr, bool bNullable, bool bCaseInsensitive, + const OUString& sDefault) + : m_sName(sName) + , m_eType(eType) + , m_aParams(aParams) + , m_bPrimaryKey(bPrimary) + , m_nAutoIncrement(nAutoIncr) + , m_bNullable(bNullable) + , m_bCaseInsensitive(bCaseInsensitive) + , m_sDefaultValue(sDefault) +{ +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/columndef.hxx b/dbaccess/source/filter/hsqldb/columndef.hxx new file mode 100644 index 000000000..849e7c757 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/columndef.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_COLUMNDEF_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_COLUMNDEF_HXX + +#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(const OUString& sName, sal_Int32 eType, const std::vector& aParams, + bool bPrimary = false, sal_Int32 nAutoIncr = -1, bool bNullable = true, + bool bCaseInsensitive = false, const OUString& sDefault = OUString{}); + + OUString const& getName() const { return m_sName; } + sal_Int32 getDataType() const { return m_eType; } + bool isPrimaryKey() const { return m_bPrimaryKey; } + bool isNullable() const { return m_bNullable; } + bool isAutoIncremental() const { return m_nAutoIncrement >= 0; } + bool isCaseInsensitive() const { return m_bCaseInsensitive; } + sal_Int32 getStartValue() const { return m_nAutoIncrement; } + const std::vector& getParams() const { return m_aParams; } + OUString const& getDefault() const { return m_sDefaultValue; } +}; +} + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_COLUMNDEF_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/createparser.cxx b/dbaccess/source/filter/hsqldb/createparser.cxx new file mode 100644 index 000000000..ad1c95f89 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/createparser.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 +#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) +OUString lcl_getColumnPart(const OUString& sSql) +{ + sal_Int32 nBeginIndex = sSql.indexOf("(") + 1; + if (nBeginIndex < 0) + { + SAL_WARN("dbaccess", "No column definitions found"); + return OUString(); + } + sal_Int32 nCount = sSql.lastIndexOf(")") - nBeginIndex; + return sSql.copy(nBeginIndex, nCount); +} + +/// 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(const OUString& 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(const OUString& sColumnDef) +{ + // TODO what if there are more spaces? + if (sColumnDef.indexOf("GENERATED BY DEFAULT AS IDENTITY") > 0) + { + // TODO parse starting sequence stated by "START WITH" + return 0; + } + return -1; +} + +OUString lcl_getDefaultValue(const OUString& sColumnDef) +{ + constexpr char DEFAULT_KW[] = "DEFAULT"; + auto nDefPos = sColumnDef.indexOf(DEFAULT_KW); + if (nDefPos > 0 && lcl_getAutoIncrementDefault(sColumnDef) < 0) + { + const OUString& fromDefault = sColumnDef.copy(nDefPos + sizeof(DEFAULT_KW)).trim(); + + // next word is the value + auto nNextSpace = fromDefault.indexOf(" "); + return nNextSpace > 0 ? fromDefault.copy(0, fromDefault.indexOf(" ")) : fromDefault; + } + return OUString{}; +} + +bool lcl_isNullable(const OUString& sColumnDef) { return sColumnDef.indexOf("NOT NULL") < 0; } + +bool lcl_isPrimaryKey(const OUString& sColumnDef) { return sColumnDef.indexOf("PRIMARY KEY") >= 0; } + +sal_Int32 lcl_getDataTypeFromHsql(const OUString& sTypeName) +{ + if (sTypeName == "CHAR") + return DataType::CHAR; + else if (sTypeName == "VARCHAR" || sTypeName == "VARCHAR_IGNORECASE") + return DataType::VARCHAR; + else if (sTypeName == "TINYINT") + return DataType::TINYINT; + else if (sTypeName == "SMALLINT") + return DataType::SMALLINT; + else if (sTypeName == "INTEGER") + return DataType::INTEGER; + else if (sTypeName == "BIGINT") + return DataType::BIGINT; + else if (sTypeName == "NUMERIC") + return DataType::NUMERIC; + else if (sTypeName == "DECIMAL") + return DataType::DECIMAL; + else if (sTypeName == "BOOLEAN") + return DataType::BOOLEAN; + else if (sTypeName == "LONGVARCHAR") + return DataType::LONGVARCHAR; + else if (sTypeName == "LONGVARBINARY") + return DataType::LONGVARBINARY; + else if (sTypeName == "CLOB") + return DataType::CLOB; + else if (sTypeName == "BLOB") + return DataType::BLOB; + else if (sTypeName == "BINARY") + return DataType::BINARY; + else if (sTypeName == "VARBINARY") + return DataType::VARBINARY; + else if (sTypeName == "DATE") + return DataType::DATE; + else if (sTypeName == "TIME") + return DataType::TIME; + else if (sTypeName == "TIMESTAMP") + return DataType::TIMESTAMP; + else if (sTypeName == "DOUBLE") + return DataType::DOUBLE; + else if (sTypeName == "REAL") + return DataType::REAL; + else if (sTypeName == "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(const OUString& sFullTypeName) +{ + ColumnTypeParts parts; + auto nParenPos = sFullTypeName.indexOf("("); + if (nParenPos > 0) + { + parts.typeName = sFullTypeName.copy(0, nParenPos).trim(); + OUString sParamStr + = sFullTypeName.copy(nParenPos + 1, sFullTypeName.indexOf(")") - nParenPos - 1); + auto sParams = string::split(sParamStr, sal_Unicode(u',')); + for (const auto& sParam : sParams) + { + parts.params.push_back(sParam.toInt32()); + } + } + else + { + parts.typeName = sFullTypeName.trim(); + lcl_addDefaultParameters(parts.params, lcl_getDataTypeFromHsql(parts.typeName)); + } + return parts; +} + +} // unnamed namespace + +namespace dbahsql +{ +CreateStmtParser::CreateStmtParser() {} + +void CreateStmtParser::parsePrimaryKeys(const OUString& sPrimaryPart) +{ + sal_Int32 nParenPos = sPrimaryPart.indexOf("("); + if (nParenPos > 0) + { + OUString sParamStr + = sPrimaryPart.copy(nParenPos + 1, sPrimaryPart.lastIndexOf(")") - nParenPos - 1); + auto sParams = string::split(sParamStr, sal_Unicode(u',')); + for (const auto& sParam : sParams) + { + m_PrimaryKeys.push_back(sParam); + } + } +} + +void CreateStmtParser::parseColumnPart(const OUString& 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 = sColumn.copy(nEndColumnName).trim(); + + // 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(" "); + OUString sFullTypeName; + if (nNextSpace > 0) + sFullTypeName = sFromTypeName.copy(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 OUString sColumnWithoutName = sColumn.copy(sColumn.indexOf(typeParts.typeName)); + + ColumnDefinition aColDef(rColumnName, lcl_getDataTypeFromHsql(typeParts.typeName), + typeParts.params, isPrimaryKey, + lcl_getAutoIncrementDefault(sColumnWithoutName), + lcl_isNullable(sColumnWithoutName), bCaseInsensitive, + lcl_getDefaultValue(sColumnWithoutName)); + + m_aColumns.push_back(aColDef); + } +} + +void CreateStmtParser::parse(const OUString& sSql) +{ + // TODO Foreign keys + if (!sSql.startsWith("CREATE")) + { + SAL_WARN("dbaccess", "Not a create statement"); + return; + } + + m_sTableName = utils::getTableNameFromStmt(sSql); + OUString sColumnPart = lcl_getColumnPart(sSql); + parseColumnPart(sColumnPart); +} + +} // namespace dbahsql + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/createparser.hxx b/dbaccess/source/filter/hsqldb/createparser.hxx new file mode 100644 index 000000000..327cab869 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/createparser.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_CREATEPARSER_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_CREATEPARSER_HXX + +#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(const OUString& sColumnPart); + void parsePrimaryKeys(const OUString& 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(const OUString& sSql); + + /** + * Recreate the sql statement. + */ + virtual OUString compose() const = 0; +}; +} + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_CREATEPARSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/fbalterparser.cxx b/dbaccess/source/filter/hsqldb/fbalterparser.cxx new file mode 100644 index 000000000..818673cbd --- /dev/null +++ b/dbaccess/source/filter/hsqldb/fbalterparser.cxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "fbalterparser.hxx" +#include +#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 "); + sSql.append(getTableName()); + + if (getActionType() == AlterAction::IDENTITY_RESTART) + { + sSql.append(" ALTER COLUMN "); + } + sSql.append(getColumnName()); + sSql.append(" RESTART WITH "); + + // Firebird: restart with 0 means the first number is 1, not 0. + sSql.append(OUString::number(getIdentityParam() - 1)); + + return sSql.makeStringAndClear(); +} + +} // dbahsql + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/fbalterparser.hxx b/dbaccess/source/filter/hsqldb/fbalterparser.hxx new file mode 100644 index 000000000..e1546996c --- /dev/null +++ b/dbaccess/source/filter/hsqldb/fbalterparser.hxx @@ -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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_FBALTERPARSER_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_FBALTERPARSER_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_FBALTERPARSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/fbcreateparser.cxx b/dbaccess/source/filter/hsqldb/fbcreateparser.cxx new file mode 100644 index 000000000..4f8fb8667 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/fbcreateparser.cxx @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "fbcreateparser.hxx" +#include "columndef.hxx" +#include "utils.hxx" + +#include + +#include + +using namespace css::sdbc; + +namespace +{ +void lcl_appendWithSpace(OUStringBuffer& sBuff, const OUString& sStr) +{ + sBuff.append(" "); + sBuff.append(sStr); +} + +OUString lcl_DataTypetoFbTypeName(sal_Int32 eType) +{ + switch (eType) + { + case DataType::CHAR: + case DataType::BINARY: + return "CHAR"; + case DataType::VARCHAR: + case DataType::VARBINARY: + return "VARCHAR"; + case DataType::TINYINT: // no such type in Firebird + case DataType::SMALLINT: + return "SMALLINT"; + case DataType::INTEGER: + return "INTEGER"; + case DataType::BIGINT: + return "BIGINT"; + case DataType::NUMERIC: + return "NUMERIC"; + case DataType::DECIMAL: + return "DECIMAL"; + case DataType::BOOLEAN: + return "BOOLEAN"; + case DataType::LONGVARCHAR: + case DataType::LONGVARBINARY: + case DataType::CLOB: + case DataType::BLOB: + case DataType::OTHER: + return "BLOB"; + case DataType::DATE: + return "DATE"; + case DataType::TIME: + return "TIME"; + case DataType::TIMESTAMP: + return "TIMESTAMP"; + case DataType::DOUBLE: + case DataType::REAL: + return "DOUBLE PRECISION"; + case DataType::FLOAT: + return "FLOAT"; + default: + assert(false); + return OUString(); + } +} + +OUString lcl_getTypeModifier(sal_Int32 eType) +{ + // TODO bind -9546 magic number to a common definition. It also appears + // in the connectivity module. + switch (eType) + { + case DataType::CLOB: + case DataType::LONGVARCHAR: + return "SUB_TYPE 1"; + case DataType::LONGVARBINARY: + return "SUB_TYPE -9546"; + case DataType::BINARY: + case DataType::VARBINARY: + return "CHARACTER SET OCTETS"; + default: + return OUString(); + } +} + +} // unnamed namespace + +namespace dbahsql +{ +void FbCreateStmtParser::appendPrimaryKeyPart(OUStringBuffer& rSql) const +{ + const std::vector& sPrimaryKeys = getPrimaryKeys(); + if (sPrimaryKeys.empty()) + return; // no primary key specified + + rSql.append(","); + rSql.append("PRIMARY KEY("); + auto it = sPrimaryKeys.cbegin(); + while (it != sPrimaryKeys.end()) + { + rSql.append(*it); + ++it; + if (it != sPrimaryKeys.end()) + rSql.append(","); + } + + rSql.append(")"); // end of primary key declaration +} + +void FbCreateStmtParser::ensureProperTableLengths() const +{ + const std::vector& rColumns = getColumnDef(); + for (const auto& col : rColumns) + utils::ensureFirebirdTableLength(col.getName()); +} + +OUString FbCreateStmtParser::compose() const +{ + ensureProperTableLengths(); + OUStringBuffer sSql(128); + sSql.append("CREATE TABLE "); + sSql.append(getTableName()); + + lcl_appendWithSpace(sSql, "("); // column declaration + auto& rColumns = getColumnDef(); + auto columnIter = rColumns.cbegin(); + while (columnIter != rColumns.end()) + { + lcl_appendWithSpace(sSql, columnIter->getName()); + lcl_appendWithSpace(sSql, lcl_DataTypetoFbTypeName(columnIter->getDataType())); + + std::vector 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(OUString::number(*it)); + ++it; + if (it != params.end()) + sSql.append(","); + } + sSql.append(")"); // end of param declaration + } + + // special modifiers here, based on type (e.g. charset, subtype) + OUString sModifier = lcl_getTypeModifier(columnIter->getDataType()); + if (!sModifier.isEmpty()) + lcl_appendWithSpace(sSql, sModifier); + + if (columnIter->isAutoIncremental()) + { + lcl_appendWithSpace(sSql, "GENERATED BY DEFAULT AS IDENTITY (START WITH "); + + // start with 0: + // HSQLDB: first value will be 0. + // Firebird: first value will be 1. + sSql.append(columnIter->getStartValue() - 1); + sSql.append(")"); + } + else if (!columnIter->isNullable()) + lcl_appendWithSpace(sSql, "NOT NULL"); + + if (columnIter->isCaseInsensitive()) + lcl_appendWithSpace(sSql, "COLLATE UNICODE_CI"); + + const OUString& sDefaultVal = columnIter->getDefault(); + if (!sDefaultVal.isEmpty()) + { + lcl_appendWithSpace(sSql, "DEFAULT"); + if (sDefaultVal.equalsIgnoreAsciiCase("NOW")) + lcl_appendWithSpace(sSql, "\'NOW\'"); // Fb likes it single quoted + else + lcl_appendWithSpace(sSql, sDefaultVal); + } + + ++columnIter; + if (columnIter != rColumns.end()) + sSql.append(","); + } + + appendPrimaryKeyPart(sSql); + + sSql.append(")"); // end of column declaration + return sSql.makeStringAndClear(); +} + +} // dbahsql + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/fbcreateparser.hxx b/dbaccess/source/filter/hsqldb/fbcreateparser.hxx new file mode 100644 index 000000000..c90e05c3b --- /dev/null +++ b/dbaccess/source/filter/hsqldb/fbcreateparser.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_FBCREATEPARSER_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_FBCREATEPARSER_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_FBCREATEPARSER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/hsqlbinarynode.cxx b/dbaccess/source/filter/hsqldb/hsqlbinarynode.cxx new file mode 100644 index 000000000..6211916fc --- /dev/null +++ b/dbaccess/source/filter/hsqldb/hsqlbinarynode.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 "hsqlbinarynode.hxx" +#include "rowinputbinary.hxx" + +namespace dbahsql +{ +using ColumnTypeVector = std::vector; + +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 000000000..7f57aae24 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/hsqlbinarynode.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_HSQLBINARYNODE_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_HSQLBINARYNODE_HXX + +#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); +}; +} + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_HSQLBINARYNODE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/hsqlimport.cxx b/dbaccess/source/filter/hsqldb/hsqlimport.cxx new file mode 100644 index 000000000..a017d8dfa --- /dev/null +++ b/dbaccess/source/filter/hsqldb/hsqlimport.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 +#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(const OUString& sTableName, + const std::vector& rColTypes) +{ + assert(rColTypes.size() > 0); + OUStringBuffer sql("INSERT INTO "); + sql.append(sTableName); + sql.append(" ("); + + // column names + for (size_t i = 0; i < rColTypes.size(); ++i) + { + sql.append(rColTypes.at(i).getName()); + if (i < rColTypes.size() - 1) + sql.append(", "); + } + sql.append(")"); + + sql.append(" VALUES ("); + for (size_t i = 0; i < rColTypes.size(); ++i) + { + sql.append("?"); + if (i < rColTypes.size() - 1) + sql.append(", "); + } + sql.append(")"); + return sql.makeStringAndClear(); +} + +} // unnamed namespace + +namespace dbahsql +{ +using namespace css::embed; + +HsqlImporter::HsqlImporter(Reference& rConnection, const Reference& rStorage) + : m_rConnection(rConnection) +{ + m_xStorage.set(rStorage); +} + +void HsqlImporter::insertRow(const std::vector& xRows, const OUString& 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) +{ + constexpr char BINARY_FILENAME[] = "data"; + + if (!m_xStorage->hasByName(BINARY_FILENAME)) + { + SAL_WARN("dbaccess", "data file does not exist in storage during hsqldb import"); + assert(false); // TODO throw error + } + + Reference 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 000000000..c4f4d1f24 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/hsqlimport.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_HSQLIMPORT_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_HSQLIMPORT_HXX + +#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, const OUString& 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); +}; +} + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_HSQLIMPORT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/parseschema.cxx b/dbaccess/source/filter/hsqldb/parseschema.cxx new file mode 100644 index 000000000..d2215e96e --- /dev/null +++ b/dbaccess/source/filter/hsqldb/parseschema.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 "parseschema.hxx" +#include "fbcreateparser.hxx" +#include "fbalterparser.hxx" +#include "utils.hxx" + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ +using namespace ::comphelper; + +using IndexVector = std::vector; + +class IndexStmtParser +{ +private: + OUString m_sql; + +public: + IndexStmtParser(const OUString& sSql) + : m_sql(sSql) + { + } + + bool isIndexStatement() const + { + return m_sql.startsWith("SET TABLE") && m_sql.indexOf("INDEX") >= 0; + } + + IndexVector getIndexes() const + { + assert(isIndexStatement()); + + OUString sIndexPart = m_sql.copy(m_sql.indexOf("INDEX") + 5); + sal_Int32 nQuotePos = sIndexPart.indexOf("'") + 1; + OUString sIndexNums = sIndexPart.copy(nQuotePos, sIndexPart.lastIndexOf("'") - 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 + OUStringBuffer sMultiName("\""); + sMultiName.append(string::split(m_sql, u'"')[1]); + sMultiName.append("\""); + sName = sMultiName.makeStringAndClear(); + } + return sName; + } +}; + +OUString lcl_createAlterForeign(const OUString& sForeignPart, const OUString& sTableName) +{ + return "ALTER TABLE " + sTableName + " ADD " + sForeignPart; +} + +} // anonymous namespace + +namespace dbahsql +{ +using namespace css::io; +using namespace css::uno; +using namespace css::embed; + +typedef std::vector ColumnTypeVector; + +SchemaParser::SchemaParser(Reference& rStorage) + : m_rStorage(rStorage) +{ +} + +void SchemaParser::parseSchema() +{ + assert(m_rStorage); + + constexpr char SCHEMA_FILENAME[] = "script"; + 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) + { + constexpr char NOT_EXIST[] = "Internal error while getting column information of table"; + SAL_WARN("dbaccess", NOT_EXIST << ". Table name is: " << sTableName); + dbtools::throwGenericSQLException(NOT_EXIST, ::comphelper::getProcessComponentContext()); + } + return m_ColumnTypes.at(sTableName); +} + +const std::map>& 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 000000000..6530eb263 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/parseschema.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_PARSECHEMA_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_PARSECHEMA_HXX + +#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; +}; +} + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_PARSESCHEMA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/rowinputbinary.cxx b/dbaccess/source/filter/hsqldb/rowinputbinary.cxx new file mode 100644 index 000000000..89c748fcb --- /dev/null +++ b/dbaccess/source/filter/hsqldb/rowinputbinary.cxx @@ -0,0 +1,402 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#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(OString(scratch.data(), scratch.size()), RTL_TEXTENCODING_UTF8); +} + +OUString lcl_makeStringFromBigint(const std::vector& bytes) +{ + std::vector aBytes{ bytes }; + OUStringBuffer sRet; + + // two's complement + if ((aBytes[0] & 0x80) != 0) + { + sRet.append("-"); + for (auto& byte : aBytes) + byte = ~byte; + // add 1 to byte array + // FIXME e.g. 10000 valid ? + for (size_t i = aBytes.size() - 1; i != 0; --i) + { + aBytes[i] += 1; + if (aBytes[i] != 0) + break; + } + } + // convert binary to BCD + OUString sNum = lcl_double_dabble(aBytes); + sRet.append(sNum); + return sRet.makeStringAndClear(); +} + +OUString lcl_putDot(const OUString& sNum, sal_Int32 nScale) +{ + // e.g. sNum = "0", nScale = 2 -> "0.00" + OUStringBuffer sBuf{ sNum }; + sal_Int32 nNullsToAppend = nScale - sNum.getLength() + 1; + for (sal_Int32 i = 0; i < nNullsToAppend; ++i) + sBuf.insert(0, "0"); + + if (nScale > 0) + sBuf.insert(sBuf.getLength() - 1 - nScale, "."); + return sBuf.makeStringAndClear(); +} +} + +namespace dbahsql +{ +using namespace css::uno; +using namespace css::sdbc; +using namespace css::io; +using namespace boost::posix_time; +using namespace boost::gregorian; + +HsqlRowInputStream::HsqlRowInputStream() {} + +void HsqlRowInputStream::setInputStream(Reference 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) + { + unsigned char cIn = 0; + m_pStream->ReadUChar(cIn); + sal_uInt8 c = reinterpret_cast(cIn); + 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(cIn); + char2 = reinterpret_cast(cIn); + 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(cIn); + char2 = reinterpret_cast(cIn); + m_pStream->ReadUChar(cIn); + char3 = reinterpret_cast(cIn); + + 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() +{ + unsigned char cIn = 0; + m_pStream->ReadUChar(cIn); + sal_uInt8 nNull = reinterpret_cast(cIn); + 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(makeAny(readString())); + break; + case DataType::TINYINT: + case DataType::SMALLINT: + { + sal_Int16 value = 0; + m_pStream->ReadInt16(value); + aData.push_back(makeAny(value)); + } + break; + case DataType::INTEGER: + { + sal_Int32 value = 0; + m_pStream->ReadInt32(value); + aData.push_back(makeAny(value)); + } + break; + case DataType::BIGINT: + { + sal_Int64 value = 0; + m_pStream->ReadInt64(value); + aData.push_back(makeAny(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(makeAny(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); + + Sequence result(2); + OUString sNum = lcl_makeStringFromBigint(aBytes); + result[0] <<= lcl_putDot(sNum, nScale); + result[1] <<= nScale; + aData.push_back(makeAny(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(makeAny(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(makeAny(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(makeAny(dateTime)); + } + break; + case DataType::BOOLEAN: + { + sal_uInt8 nBool = 0; + m_pStream->ReadUChar(nBool); + aData.push_back(makeAny(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(makeAny(aBytes)); + } + break; + + default: + throw WrongFormatException(); + } + } + return aData; +} + +} // namespace dbahsql + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/rowinputbinary.hxx b/dbaccess/source/filter/hsqldb/rowinputbinary.hxx new file mode 100644 index 000000000..b5c50a602 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/rowinputbinary.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_ROWINPUTBINARY_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_ROWINPUTBINARY_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_ROWINPUTBINARY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/utils.cxx b/dbaccess/source/filter/hsqldb/utils.cxx new file mode 100644 index 000000000..3dc8f2e55 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/utils.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 "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(const OString& 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, OUString(c)); + ++i; + } + } + } + return res; +} + +OUString utils::getTableNameFromStmt(const OUString& 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) + { + sal_Int32 nAposBegin = sSql.indexOf("\""); + sal_Int32 nAposEnd = nAposBegin; + bool bProperEndAposFound = false; + while (!bProperEndAposFound) + { + nAposEnd = sSql.indexOf("\"", nAposEnd + 1); + if (sSql[nAposEnd - 1] != u'\\') + bProperEndAposFound = true; + } + OUString result = sSql.copy(nAposBegin, nAposEnd - nAposBegin + 1); + return result; + } + + // next word is the table's name + // it might stuck together with the column definitions. + sal_Int32 nParenPos = wordIter->indexOf("("); + if (nParenPos > 0) + return wordIter->copy(0, nParenPos); + else + return *wordIter; +} + +void utils::ensureFirebirdTableLength(const OUString& sName) +{ + if (sName.getLength() > 30) // Firebird limitation + { + constexpr char NAME_TOO_LONG[] = "Firebird 3 doesn't support object (table, field) names " + "of more than 30 characters; please shorten your object " + "names in the original file and try again."; + dbtools::throwGenericSQLException(NAME_TOO_LONG, + ::comphelper::getProcessComponentContext()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/hsqldb/utils.hxx b/dbaccess/source/filter/hsqldb/utils.hxx new file mode 100644 index 000000000..b2d54fbc1 --- /dev/null +++ b/dbaccess/source/filter/hsqldb/utils.hxx @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_UTILS_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_UTILS_HXX + +#include + +namespace dbahsql +{ +namespace utils +{ +OUString convertToUTF8(const OString& original); + +OUString getTableNameFromStmt(const OUString& sSql); + +void ensureFirebirdTableLength(const OUString& sName); +} +} + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_HSQLDB_UTILS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/dbaxml.component b/dbaccess/source/filter/xml/dbaxml.component new file mode 100644 index 000000000..51a4182e4 --- /dev/null +++ b/dbaccess/source/filter/xml/dbaxml.component @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/source/filter/xml/dbloader2.cxx b/dbaccess/source/filter/xml/dbloader2.cxx new file mode 100644 index 000000000..8546c693a --- /dev/null +++ b/dbaccess/source/filter/xml/dbloader2.cxx @@ -0,0 +1,574 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "xmlservices.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 + +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::registry; +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; + + // static methods + static OUString getImplementationName_Static() throw( ) + { + return "org.openoffice.comp.dbflt.DBTypeDetection"; + } + static Sequence< OUString> getSupportedServiceNames_Static() throw( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + 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( OUString( "InputStream" ) ); + aMedia.remove( OUString( "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(); +} + +Reference< XInterface > DBTypeDetection::Create( const Reference< XMultiServiceFactory > & rSMgr ) +{ + return *(new DBTypeDetection( comphelper::getComponentContext(rSMgr) )); +} + +// XServiceInfo +OUString SAL_CALL DBTypeDetection::getImplementationName() +{ + return getImplementationName_Static(); +} + +// XServiceInfo +sal_Bool SAL_CALL DBTypeDetection::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > SAL_CALL DBTypeDetection::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +// ORegistryServiceManager_Static +Sequence< OUString > DBTypeDetection::getSupportedServiceNames_Static() throw( ) +{ + Sequence aSNS { "com.sun.star.document.ExtendedTypeDetection" }; + return aSNS; +} + +} // namespace dbaxml + +extern "C" void createRegistryInfo_DBTypeDetection() +{ + static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::DBTypeDetection > aAutoRegistration; +} + +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; + + // static methods + static OUString getImplementationName_Static() throw( ) + { + return "org.openoffice.comp.dbflt.DBContentLoader2"; + } + static Sequence< OUString > getSupportedServiceNames_Static() throw( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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) +{ + +} + +Reference< XInterface > DBContentLoader::Create( const Reference< XMultiServiceFactory > & rSMgr ) +{ + return *(new DBContentLoader( comphelper::getComponentContext(rSMgr) )); +} + +// XServiceInfo +OUString SAL_CALL DBContentLoader::getImplementationName() +{ + return getImplementationName_Static(); +} + +// XServiceInfo +sal_Bool SAL_CALL DBContentLoader::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > SAL_CALL DBContentLoader::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +// ORegistryServiceManager_Static +Sequence< OUString > DBContentLoader::getSupportedServiceNames_Static() throw( ) +{ + Sequence aSNS { "com.sun.star.frame.FrameLoader" }; + return aSNS; +} + +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& ) + { + OSL_FAIL( "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" ); + + sal_Int32 nInitialSelection = -1; + if ( !xModel.is() ) + { + Reference< XDatabaseContext > 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( OUString(INFO_POOLURL), sSalvagedURL ); + xDocumentDataSource.set( xDatabaseContext->createInstanceWithArguments( aCreationArgs.getWrappedNamedValues() ), UNO_QUERY_THROW ); + } + + xModel.set( xDocumentDataSource->getDatabaseDocument(), UNO_QUERY ); + + if ( bCreateNew && xModel.is() ) + { + if ( bNewAndInteractive ) + { + bSuccess = impl_executeNewDatabaseWizard( xModel, bStartTableWizard ); + } + else + { + try + { + Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW ); + xLoad->initNew(); + bSuccess = true; + } + catch( const Exception& ) + { + bSuccess = false; + } + } + + // initially select the "Tables" category (will be done below) + nInitialSelection = css::sdb::application::DatabaseObjectContainer::TABLES; + } + } + + if ( !xModel.is() ) + { + if ( rListener.is() ) + rListener->loadCancelled(this); + return; + } + + if ( !bCreateNew ) + { + // We need to XLoadable::load the document if it does not yet have a URL. + // If it already *does* have a URL, then it was either passed in the arguments, or a previous incarnation + // of that model existed before (which can happen if a model is closed, but an associated DataSource is kept + // alive 'til loading the document again). + bool bNeedLoad = xModel->getURL().isEmpty(); + try + { + aMediaDesc.put( "FileName", _rURL ); + Sequence< PropertyValue > aResource( aMediaDesc.getPropertyValues() ); + + if ( bNeedLoad ) + { + Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW ); + xLoad->load( aResource ); + } + + // always attach the resource, even if the document has not been freshly loaded + xModel->attachResource( _rURL, aResource ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + bSuccess = false; + } + } + + if ( bSuccess ) + { + try + { + Reference< XModel2 > xModel2( xModel, UNO_QUERY_THROW ); + Reference< XController2 > xController( xModel2->createViewController( sViewName, Sequence< PropertyValue >(), rFrame ), UNO_SET_THROW ); + + xController->attachModel( xModel ); + xModel->connectController( xController.get() ); + rFrame->setComponent( xController->getComponentWindow(), xController.get() ); + xController->attachFrame( rFrame ); + xModel->setCurrentController( xController.get() ); + + 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( makeAny( 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&) + { + OSL_FAIL("caught an exception while starting the table wizard!"); + } + m_xMySelf = nullptr; +} + +} + +extern "C" void createRegistryInfo_DBContentLoader2() +{ + static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::DBContentLoader > aAutoRegistration; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlAutoStyle.cxx b/dbaccess/source/filter/xml/xmlAutoStyle.cxx new file mode 100644 index 000000000..991015671 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlAutoStyle.cxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xmlAutoStyle.hxx" +#include "xmlHelper.hxx" +#include "xmlExport.hxx" +#include +namespace dbaxml +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::xml::sax; + +void OXMLAutoStylePoolP::exportStyleAttributes( + SvXMLAttributeList& rAttrList, + XmlStyleFamily nFamily, + const std::vector< XMLPropertyState >& rProperties, + const SvXMLExportPropertyMapper& rPropExp + , const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap + ) const +{ + SvXMLAutoStylePoolP::exportStyleAttributes( rAttrList, nFamily, rProperties, rPropExp, rUnitConverter, rNamespaceMap ); + if ( nFamily != XmlStyleFamily::TABLE_COLUMN ) + return; + + rtl::Reference< XMLPropertySetMapper > aPropMapper = rODBExport.GetColumnStylesPropertySetMapper(); + for (auto const& property : rProperties) + { + sal_Int16 nContextID = aPropMapper->GetEntryContextId(property.mnIndex); + switch (nContextID) + { + case CTF_DB_NUMBERFORMAT : + { + sal_Int32 nNumberFormat = 0; + if ( property.maValue >>= nNumberFormat ) + { + OUString sAttrValue = rODBExport.getDataStyleName(nNumberFormat); + if ( !sAttrValue.isEmpty() ) + { + GetExport().AddAttribute( + aPropMapper->GetEntryNameSpace(property.mnIndex), + aPropMapper->GetEntryXMLName(property.mnIndex), + sAttrValue ); + } + } + break; + } + } + } +} + +OXMLAutoStylePoolP::OXMLAutoStylePoolP(ODBExport& rTempODBExport): + SvXMLAutoStylePoolP(rTempODBExport), + rODBExport(rTempODBExport) +{ + +} + +OXMLAutoStylePoolP::~OXMLAutoStylePoolP() +{ + +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlAutoStyle.hxx b/dbaccess/source/filter/xml/xmlAutoStyle.hxx new file mode 100644 index 000000000..3d81a9327 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlAutoStyle.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLAUTOSTYLE_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLAUTOSTYLE_HXX +#include +#include + +namespace dbaxml +{ + class ODBExport; + class OXMLAutoStylePoolP : public SvXMLAutoStylePoolP + { + ODBExport& rODBExport; + + virtual void exportStyleAttributes( + SvXMLAttributeList& rAttrList, + XmlStyleFamily nFamily, + const std::vector< XMLPropertyState >& rProperties, + const SvXMLExportPropertyMapper& rPropExp, + const SvXMLUnitConverter& rUnitConverter, + const SvXMLNamespaceMap& rNamespaceMap + ) const override; + + public: + explicit OXMLAutoStylePoolP(ODBExport& rXMLExport); + virtual ~OXMLAutoStylePoolP() override; + }; +} // dbaxml +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLAUTOSTYLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlColumn.cxx b/dbaccess/source/filter/xml/xmlColumn.cxx new file mode 100644 index 000000000..334c4fbfc --- /dev/null +++ b/dbaccess/source/filter/xml/xmlColumn.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 "xmlColumn.hxx" +#include "xmlfilter.hxx" +#include +#include +#include +#include +#include "xmlStyleImport.hxx" +#include +#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 )) + { + OUString sValue = aIter.toString(); + + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_NAME: + m_sName = sValue; + break; + case XML_STYLE_NAME: + m_sStyleName = sValue; + break; + case XML_HELP_MESSAGE: + m_sHelpMessage = sValue; + break; + case XML_VISIBILITY: + m_bHidden = sValue != "visible"; + break; + case XML_TYPE_NAME: + sType = sValue; + OSL_ENSURE(!sType.isEmpty(),"No type name set"); + break; + case XML_DEFAULT_VALUE: + if ( !(sValue.isEmpty() || sType.isEmpty()) ) + m_aDefaultValue <<= sValue; + break; + case XML_VISIBLE: + m_bHidden = sValue == "false"; + break; + case XML_DEFAULT_CELL_STYLE_NAME: + m_sCellStyleName = sValue; + break; + default: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << " value=" << aIter.toString()); + } + } +} + +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,makeAny(m_sName)); + xProp->setPropertyValue(PROPERTY_HIDDEN,makeAny(m_bHidden)); + if ( !m_sHelpMessage.isEmpty() ) + xProp->setPropertyValue(PROPERTY_HELPTEXT,makeAny(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 000000000..cc242a905 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlColumn.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCOLUMN_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCOLUMN_HXX + +#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 startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCOLUMN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlComponent.cxx b/dbaccess/source/filter/xml/xmlComponent.cxx new file mode 100644 index 000000000..863a98f16 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlComponent.cxx @@ -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 . + */ + +#include "xmlComponent.hxx" +#include "xmlfilter.hxx" +#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); + static const OUString s_sTRUE = ::xmloff::token::GetXMLToken(XML_TRUE); + for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList )) + { + OUString sValue = aIter.toString(); + + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + sHREF = sValue; + break; + case XML_ELEMENT(DB, XML_NAME): + case XML_ELEMENT(DB_OASIS, XML_NAME): + sName = sValue; + // 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 = sValue == s_sTRUE; + break; + default: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + } + 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, makeAny( xComponent ) ); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +OXMLComponent::~OXMLComponent() +{ + +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlComponent.hxx b/dbaccess/source/filter/xml/xmlComponent.hxx new file mode 100644 index 000000000..43eae3261 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlComponent.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCOMPONENT_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCOMPONENT_HXX + +#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 void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual ~OXMLComponent() override; + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCOMPONENT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlConnectionData.cxx b/dbaccess/source/filter/xml/xmlConnectionData.cxx new file mode 100644 index 000000000..221358537 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlConnectionData.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xmlConnectionData.hxx" +#include "xmlLogin.hxx" +#include "xmlfilter.hxx" +#include +#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 000000000..88ef09315 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlConnectionData.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCONNECTIONDATA_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCONNECTIONDATA_HXX + +#include + +namespace dbaxml +{ + class ODBFilter; + class OXMLConnectionData : public SvXMLImportContext + { + bool m_bFoundOne; + + ODBFilter& GetOwnImport(); + public: + + OXMLConnectionData( ODBFilter& rImport ); + virtual ~OXMLConnectionData() override; + + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCONNECTIONDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlConnectionResource.cxx b/dbaccess/source/filter/xml/xmlConnectionResource.cxx new file mode 100644 index 000000000..b2c37fc35 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlConnectionResource.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 "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 )) + { + OUString sValue = aIter.toString(); + aProperty.Name.clear(); + aProperty.Value = Any(); + + switch( aIter.getToken() ) + { + case XML_ELEMENT(XLINK, XML_HREF): + try + { + xDataSource->setPropertyValue(PROPERTY_URL,makeAny(sValue)); + } + 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: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + if ( !aProperty.Name.isEmpty() ) + { + if ( !aProperty.Value.hasValue() ) + aProperty.Value <<= sValue; + rImport.addInfo(aProperty); + } + } +} + +OXMLConnectionResource::~OXMLConnectionResource() +{ + +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlConnectionResource.hxx b/dbaccess/source/filter/xml/xmlConnectionResource.hxx new file mode 100644 index 000000000..c73651e98 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlConnectionResource.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCONNECTIONRESOURCE_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCONNECTIONRESOURCE_HXX + +#include + +namespace dbaxml +{ + class ODBFilter; + class OXMLConnectionResource : public SvXMLImportContext + { + public: + + OXMLConnectionResource( ODBFilter& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ); + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual ~OXMLConnectionResource() override; + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLCONNECTIONRESOURCE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlDataSource.cxx b/dbaccess/source/filter/xml/xmlDataSource.cxx new file mode 100644 index 000000000..53095dfe0 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDataSource.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 "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; + + static const OUString s_sTRUE = ::xmloff::token::GetXMLToken(XML_TRUE); + if (xDataSource.is()) + { + for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList )) + { + OUString sValue = aIter.toString(); + + aProperty.Name.clear(); + aProperty.Value = Any(); + + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_CONNECTION_RESOURCE: + try + { + xDataSource->setPropertyValue(PROPERTY_URL,makeAny(sValue)); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + break; + case XML_SUPPRESS_VERSION_COLUMNS: + try + { + xDataSource->setPropertyValue(PROPERTY_SUPPRESSVERSIONCL,makeAny(sValue == s_sTRUE)); + 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 <<= (sValue == s_sTRUE); + break; + case XML_SHOW_DELETED: + aProperty.Name = INFO_SHOWDELETEDROWS; + aProperty.Value <<= (sValue == s_sTRUE); + break; + case XML_IS_TABLE_NAME_LENGTH_LIMITED: + aProperty.Name = INFO_ALLOWLONGTABLENAMES; + aProperty.Value <<= (sValue == s_sTRUE); + bFoundTableNameLengthLimited = true; + break; + case XML_SYSTEM_DRIVER_SETTINGS: + aProperty.Name = INFO_ADDITIONALOPTIONS; + break; + case XML_ENABLE_SQL92_CHECK: + aProperty.Name = PROPERTY_ENABLESQL92CHECK; + aProperty.Value <<= (sValue == s_sTRUE); + break; + case XML_APPEND_TABLE_ALIAS_NAME: + aProperty.Name = INFO_APPEND_TABLE_ALIAS; + aProperty.Value <<= (sValue == s_sTRUE); + bFoundAppendTableAliasName = true; + break; + case XML_PARAMETER_NAME_SUBSTITUTION: + aProperty.Name = INFO_PARAMETERNAMESUBST; + aProperty.Value <<= (sValue == s_sTRUE); + bFoundParamNameSubstitution = true; + break; + case XML_IGNORE_DRIVER_PRIVILEGES: + aProperty.Name = INFO_IGNOREDRIVER_PRIV; + aProperty.Value <<= (sValue == s_sTRUE); + break; + case XML_BOOLEAN_COMPARISON_MODE: + aProperty.Name = PROPERTY_BOOLEANCOMPARISONMODE; + if ( sValue == "equal-integer" ) + aProperty.Value <<= sal_Int32(0); + else if ( sValue == "is-boolean" ) + aProperty.Value <<= sal_Int32(1); + else if ( sValue == "equal-boolean" ) + aProperty.Value <<= sal_Int32(2); + else if ( sValue == "equal-use-only-zero" ) + aProperty.Value <<= sal_Int32(3); + break; + case XML_USE_CATALOG: + aProperty.Name = INFO_USECATALOG; + aProperty.Value <<= (sValue == s_sTRUE); + 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 <<= sValue.toInt32(); + break; + case XML_JAVA_CLASSPATH: + aProperty.Name = "JavaDriverClassPath"; + break; + default: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + if ( !aProperty.Name.isEmpty() ) + { + if ( !aProperty.Value.hasValue() ) + aProperty.Value <<= sValue; + 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,makeAny(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 000000000..22bb90f76 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDataSource.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCE_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCE_HXX + +#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 void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlDataSourceInfo.cxx b/dbaccess/source/filter/xml/xmlDataSourceInfo.cxx new file mode 100644 index 000000000..82ab36eb2 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDataSourceInfo.cxx @@ -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 . + */ + +#include "xmlDataSourceInfo.hxx" +#include "xmlfilter.hxx" +#include +#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 )) + { + OUString sValue = aIter.toString(); + + 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: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + if ( !aProperty.Name.isEmpty() ) + { + aProperty.Value <<= sValue; + rImport.addInfo(aProperty); + } + } + if ( bAutoEnabled ) + { + aProperty.Name = INFO_AUTORETRIEVEENABLED; + aProperty.Value <<= true; + rImport.addInfo(aProperty); + } + if ( !rImport.isNewFormat() ) + return; + + if ( (nElement & TOKEN_MASK) == XML_DELIMITER ) + { + if ( !bFoundField ) + { + aProperty.Name = INFO_FIELDDELIMITER; + aProperty.Value <<= OUString(";"); + rImport.addInfo(aProperty); + } + if ( !bFoundThousand ) + { + aProperty.Name = INFO_THOUSANDSDELIMITER; + aProperty.Value <<= OUString(","); + rImport.addInfo(aProperty); + } + } + if ( (nElement & TOKEN_MASK) == XML_FONT_CHARSET && !bFoundCharset ) + { + aProperty.Name = INFO_CHARSET; + aProperty.Value <<= OUString("utf8"); + rImport.addInfo(aProperty); + } +} + +OXMLDataSourceInfo::~OXMLDataSourceInfo() +{ + +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlDataSourceInfo.hxx b/dbaccess/source/filter/xml/xmlDataSourceInfo.hxx new file mode 100644 index 000000000..b0f617a53 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDataSourceInfo.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCEINFO_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCEINFO_HXX + +#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 void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual ~OXMLDataSourceInfo() override; + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCEINFO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlDataSourceSetting.cxx b/dbaccess/source/filter/xml/xmlDataSourceSetting.cxx new file mode 100644 index 000000000..3b7e6d512 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDataSourceSetting.cxx @@ -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 . + */ + +#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 )) + { + OUString sValue = aIter.toString(); + + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_DATA_SOURCE_SETTING_IS_LIST: + m_bIsList = sValue == "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(sValue); + 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 = sValue; + break; + default: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + } + +} + +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[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 000000000..9f28d3343 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDataSourceSetting.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCESETTING_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCESETTING_HXX + +#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 startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCESETTING_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlDataSourceSettings.cxx b/dbaccess/source/filter/xml/xmlDataSourceSettings.cxx new file mode 100644 index 000000000..49847ef54 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDataSourceSettings.cxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xmlDataSourceSettings.hxx" +#include "xmlDataSourceSetting.hxx" +#include "xmlfilter.hxx" +#include +#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 000000000..27bd20435 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDataSourceSettings.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCESETTINGS_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCESETTINGS_HXX + +#include + +namespace dbaxml +{ + class ODBFilter; + class OXMLDataSourceSettings : public SvXMLImportContext + { + ODBFilter& GetOwnImport(); + public: + + OXMLDataSourceSettings( ODBFilter& rImport ); + virtual ~OXMLDataSourceSettings() override; + + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATASOURCESETTINGS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlDatabase.cxx b/dbaccess/source/filter/xml/xmlDatabase.cxx new file mode 100644 index 000000000..9de9bf349 --- /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_DATASOURCE: + 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 000000000..d1f87c263 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDatabase.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATABASE_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATABASE_HXX + +#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 startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATABASE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlDatabaseDescription.cxx b/dbaccess/source/filter/xml/xmlDatabaseDescription.cxx new file mode 100644 index 000000000..a8168e129 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDatabaseDescription.cxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xmlDatabaseDescription.hxx" +#include "xmlfilter.hxx" +#include +#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 000000000..0da571da0 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDatabaseDescription.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATABASEDESCRIPTION_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATABASEDESCRIPTION_HXX + +#include + +namespace dbaxml +{ + class ODBFilter; + class OXMLDatabaseDescription : public SvXMLImportContext + { + bool m_bFoundOne; + + ODBFilter& GetOwnImport(); + public: + + OXMLDatabaseDescription( ODBFilter& rImport); + virtual ~OXMLDatabaseDescription() override; + + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDATABASEDESCRIPTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlDocuments.cxx b/dbaccess/source/filter/xml/xmlDocuments.cxx new file mode 100644 index 000000000..71d5b4589 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDocuments.cxx @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xmlDocuments.hxx" +#include "xmlfilter.hxx" +#include +#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 + ,const OUString& _sCollectionServiceName + ,const OUString& _sComponentServiceName) : + SvXMLImportContext( rImport ) + ,m_xContainer(_xContainer) + ,m_sCollectionServiceName(_sCollectionServiceName) + ,m_sComponentServiceName(_sComponentServiceName) +{ + +} + +OXMLDocuments::OXMLDocuments( ODBFilter& rImport + ,const Reference< XNameAccess >& _xContainer + ,const OUString& _sCollectionServiceName + ) : + SvXMLImportContext( rImport ) + ,m_xContainer(_xContainer) + ,m_sCollectionServiceName(_sCollectionServiceName) +{ +} + +OXMLDocuments::~OXMLDocuments() +{ + +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > OXMLDocuments::createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContext *pContext = nullptr; + + switch( nElement & TOKEN_MASK ) + { + case XML_TABLE: + case XML_TABLE_REPRESENTATION: + GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP ); + pContext = new OXMLTable( GetOwnImport(), xAttrList, m_xContainer, "com.sun.star.sdb.TableDefinition"); + break; + case XML_QUERY: + GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP ); + pContext = new OXMLQuery( GetOwnImport(), xAttrList, m_xContainer ); + break; + case XML_COMPONENT: + GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP ); + pContext = new OXMLComponent( GetOwnImport(), xAttrList, m_xContainer,m_sComponentServiceName ); + break; + case XML_COMPONENT_COLLECTION: + GetOwnImport().GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP ); + pContext = new OXMLHierarchyCollection( GetOwnImport(), xAttrList, m_xContainer,m_sCollectionServiceName,m_sComponentServiceName ); + break; + } + + return pContext; +} + +ODBFilter& OXMLDocuments::GetOwnImport() +{ + return static_cast(GetImport()); +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlDocuments.hxx b/dbaccess/source/filter/xml/xmlDocuments.hxx new file mode 100644 index 000000000..35f642cf3 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlDocuments.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDOCUMENTS_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDOCUMENTS_HXX + +#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 + ,const OUString& _sCollectionServiceName + ,const OUString& _sComponentServiceName); + + // for queries + OXMLDocuments( ODBFilter& rImport + ,const css::uno::Reference< css::container::XNameAccess >& _xContainer + ,const OUString& _sCollectionServiceName = OUString() + ); + + virtual ~OXMLDocuments() override; + + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLDOCUMENTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlEnums.hxx b/dbaccess/source/filter/xml/xmlEnums.hxx new file mode 100644 index 000000000..0f4be1aaa --- /dev/null +++ b/dbaccess/source/filter/xml/xmlEnums.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLENUMS_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLENUMS_HXX + +#define PROGRESS_BAR_STEP 20 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLENUMS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlExport.cxx b/dbaccess/source/filter/xml/xmlExport.cxx new file mode 100644 index 000000000..64d84729c --- /dev/null +++ b/dbaccess/source/filter/xml/xmlExport.cxx @@ -0,0 +1,1409 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "xmlservices.hxx" +#include +#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 +#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; + +namespace dbaxml +{ + namespace { + + class ODBExportHelper + { + public: + /// @throws RuntimeException + static OUString getImplementationName_Static( ); + /// @throws RuntimeException + static Sequence< OUString > getSupportedServiceNames_Static( ); + static Reference< XInterface > Create(const Reference< css::lang::XMultiServiceFactory >&); + }; + class ODBFullExportHelper + { + public: + /// @throws RuntimeException + static OUString getImplementationName_Static( ); + /// @throws RuntimeException + static Sequence< OUString > getSupportedServiceNames_Static( ); + static Reference< XInterface > Create(const Reference< css::lang::XMultiServiceFactory >&); + }; + + } +} + +extern "C" void createRegistryInfo_ODBFilterExport( ) +{ + static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::ODBExport > aAutoRegistration; +} + +extern "C" void createRegistryInfo_OSettingsExport( ) + +{ + static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::ODBExportHelper > aAutoRegistration; +} + +extern "C" void createRegistryInfo_OFullExport( ) +{ + static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::ODBFullExportHelper > aAutoRegistration; +} + +namespace dbaxml +{ + Reference< XInterface > ODBExportHelper::Create(const Reference< XMultiServiceFactory >& _rxORB) + { + return static_cast< XServiceInfo* >(new ODBExport(comphelper::getComponentContext(_rxORB), getImplementationName_Static(), SvXMLExportFlags::SETTINGS | SvXMLExportFlags::PRETTY )); + } + + OUString ODBExportHelper::getImplementationName_Static( ) + { + return "com.sun.star.comp.sdb.XMLSettingsExporter"; + } + + Sequence< OUString > ODBExportHelper::getSupportedServiceNames_Static( ) + { + Sequence< OUString > aSupported { "com.sun.star.document.ExportFilter" }; + return aSupported; + } + + Reference< XInterface > ODBFullExportHelper::Create(const Reference< XMultiServiceFactory >& _rxORB) + { + return static_cast< XServiceInfo* >(new ODBExport(comphelper::getComponentContext(_rxORB), getImplementationName_Static(), SvXMLExportFlags::ALL)); + } + OUString ODBFullExportHelper::getImplementationName_Static( ) + { + return "com.sun.star.comp.sdb.XMLFullExporter"; + } + Sequence< OUString > ODBFullExportHelper::getSupportedServiceNames_Static( ) + { + Sequence< OUString > aSupported { "com.sun.star.document.ExportFilter" }; + return aSupported; + } + + static OUString lcl_implGetPropertyXMLType(const Type& _rType) + { + // possible types we can write (either because we recognize them directly or because we convert _rValue + // into one of these types) + + // handle the type description + switch (_rType.getTypeClass()) + { + case TypeClass_STRING: + return "string"; + case TypeClass_DOUBLE: + return "double"; + case TypeClass_BOOLEAN: + return "boolean"; + case TypeClass_BYTE: + case TypeClass_SHORT: + return "short"; + case TypeClass_LONG: + return "int"; + case TypeClass_HYPER: + return "long"; + case TypeClass_ENUM: + return "int"; + + default: + OSL_FAIL( "lcl_implGetPropertyXMLType: unsupported value type!" ); + return "double"; + } + } + + namespace { + + class OSpecialHandleXMLExportPropertyMapper : public SvXMLExportPropertyMapper + { + public: + explicit OSpecialHandleXMLExportPropertyMapper(const rtl::Reference< XMLPropertySetMapper >& rMapper) : SvXMLExportPropertyMapper(rMapper ) + { + } + /** this method is called for every item that has the + MID_FLAG_SPECIAL_ITEM_EXPORT flag set */ + virtual void handleSpecialItem( + SvXMLAttributeList& /*rAttrList*/, + const XMLPropertyState& /*rProperty*/, + const SvXMLUnitConverter& /*rUnitConverter*/, + const SvXMLNamespaceMap& /*rNamespaceMap*/, + const std::vector< XMLPropertyState > * /*pProperties*/ , + sal_uInt32 /*nIdx*/ ) const override + { + // nothing to do here + } + }; + + } + +ODBExport::ODBExport(const Reference< XComponentContext >& _rxContext, OUString const & implementationName, SvXMLExportFlags nExportFlag) +: SvXMLExport( util::MeasureUnit::MM_10TH, _rxContext, implementationName, XML_DATABASE, + SvXMLExportFlags::OASIS | nExportFlag) +,m_aTypeCollection(_rxContext) +,m_bAllreadyFilled(false) +{ + GetMM100UnitConverter().SetCoreMeasureUnit(util::MeasureUnit::MM_10TH); + GetMM100UnitConverter().SetXMLMeasureUnit(util::MeasureUnit::CM); + + GetNamespaceMap_().Add( GetXMLToken(XML_NP_OFFICE), GetXMLToken(XML_N_OFFICE), XML_NAMESPACE_OFFICE ); + GetNamespaceMap_().Add( GetXMLToken(XML_NP_OOO), GetXMLToken(XML_N_OOO), XML_NAMESPACE_OOO ); + GetNamespaceMap_().Add( GetXMLToken(XML_NP_SVG), GetXMLToken(XML_N_SVG), XML_NAMESPACE_SVG ); + + GetNamespaceMap_().Add( GetXMLToken(XML_NP_DB), GetXMLToken(XML_N_DB_OASIS), XML_NAMESPACE_DB ); + + if( nExportFlag & (SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::FONTDECLS) ) + GetNamespaceMap_().Add( GetXMLToken(XML_NP_FO), GetXMLToken(XML_N_FO_COMPAT), XML_NAMESPACE_FO ); + + if( nExportFlag & (SvXMLExportFlags::META|SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::SCRIPTS|SvXMLExportFlags::SETTINGS) ) + { + GetNamespaceMap_().Add( GetXMLToken(XML_NP_XLINK), GetXMLToken(XML_N_XLINK), XML_NAMESPACE_XLINK ); + } + if( nExportFlag & SvXMLExportFlags::SETTINGS ) + { + GetNamespaceMap_().Add( GetXMLToken(XML_NP_CONFIG), GetXMLToken(XML_N_CONFIG), XML_NAMESPACE_CONFIG ); + } + + if( nExportFlag & (SvXMLExportFlags::STYLES|SvXMLExportFlags::MASTERSTYLES|SvXMLExportFlags::AUTOSTYLES|SvXMLExportFlags::CONTENT|SvXMLExportFlags::FONTDECLS) ) + { + GetNamespaceMap_().Add( GetXMLToken(XML_NP_STYLE), GetXMLToken(XML_N_STYLE), XML_NAMESPACE_STYLE ); + } + + GetNamespaceMap_().Add( GetXMLToken(XML_NP_TABLE), GetXMLToken(XML_N_TABLE), XML_NAMESPACE_TABLE ); + GetNamespaceMap_().Add( GetXMLToken(XML_NP_NUMBER), GetXMLToken(XML_N_NUMBER), XML_NAMESPACE_NUMBER ); + + m_xExportHelper = new SvXMLExportPropertyMapper(GetTableStylesPropertySetMapper()); + m_xColumnExportHelper = new OSpecialHandleXMLExportPropertyMapper(GetColumnStylesPropertySetMapper()); + + m_xCellExportHelper = new OSpecialHandleXMLExportPropertyMapper(GetCellStylesPropertySetMapper()); + m_xRowExportHelper = new OSpecialHandleXMLExportPropertyMapper(OXMLHelper::GetRowStylesPropertySetMapper()); + + GetAutoStylePool()->AddFamily( + XmlStyleFamily::TABLE_TABLE, + OUString(XML_STYLE_FAMILY_TABLE_TABLE_STYLES_NAME ), + m_xExportHelper.get(), + OUString(XML_STYLE_FAMILY_TABLE_TABLE_STYLES_PREFIX )); + + GetAutoStylePool()->AddFamily( + XmlStyleFamily::TABLE_COLUMN, + OUString(XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_NAME ), + m_xColumnExportHelper.get(), + OUString(XML_STYLE_FAMILY_TABLE_COLUMN_STYLES_PREFIX )); + + GetAutoStylePool()->AddFamily( + XmlStyleFamily::TABLE_CELL, + OUString(XML_STYLE_FAMILY_TABLE_CELL_STYLES_NAME ), + m_xCellExportHelper.get(), + OUString(XML_STYLE_FAMILY_TABLE_CELL_STYLES_PREFIX )); + + GetAutoStylePool()->AddFamily( + XmlStyleFamily::TABLE_ROW, + OUString(XML_STYLE_FAMILY_TABLE_ROW_STYLES_NAME ), + m_xRowExportHelper.get(), + OUString(XML_STYLE_FAMILY_TABLE_ROW_STYLES_PREFIX )); +} + +OUString ODBExport::getImplementationName_Static() +{ + return "com.sun.star.comp.sdb.DBExportFilter"; +} + +css::uno::Sequence ODBExport::getSupportedServiceNames_Static() +{ + css::uno::Sequence s { "com.sun.star.document.ExportFilter" }; + return s; +} + +css::uno::Reference< css::uno::XInterface > + ODBExport::Create(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB) +{ + return static_cast< XServiceInfo* >(new ODBExport( comphelper::getComponentContext(_rxORB), getImplementationName_Static())); +} + +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( const OUString& _rPropertyName, const XMLTokenEnum _eToken ) + :sPropertyName( _rPropertyName ) + ,eAttributeToken( _eToken ) + ,aXMLDefault() + { + } + + PropertyMap( const OUString& _rPropertyName, const XMLTokenEnum _eToken, const OUString& _rDefault ) + :sPropertyName( _rPropertyName ) + ,eAttributeToken( _eToken ) + ,aXMLDefault( _rDefault ) + { + } + }; + + const PropertyMap aTokens[] = + { + PropertyMap( INFO_TEXTFILEHEADER, XML_IS_FIRST_ROW_HEADER_LINE, s_sTrue ), + PropertyMap( INFO_SHOWDELETEDROWS, XML_SHOW_DELETED, s_sFalse ), + PropertyMap( INFO_ALLOWLONGTABLENAMES, XML_IS_TABLE_NAME_LENGTH_LIMITED, s_sTrue ), + PropertyMap( INFO_ADDITIONALOPTIONS, XML_SYSTEM_DRIVER_SETTINGS ), + PropertyMap( PROPERTY_ENABLESQL92CHECK, XML_ENABLE_SQL92_CHECK, s_sFalse ), + PropertyMap( INFO_APPEND_TABLE_ALIAS, XML_APPEND_TABLE_ALIAS_NAME, s_sTrue ), + PropertyMap( INFO_PARAMETERNAMESUBST, XML_PARAMETER_NAME_SUBSTITUTION, s_sTrue ), + PropertyMap( INFO_IGNOREDRIVER_PRIV, XML_IGNORE_DRIVER_PRIVILEGES, s_sTrue ), + PropertyMap( INFO_USECATALOG, XML_USE_CATALOG, s_sFalse ), + PropertyMap( INFO_CONN_LDAP_BASEDN, XML_BASE_DN ), + PropertyMap( INFO_CONN_LDAP_ROWCOUNT, XML_MAX_ROW_COUNT ) + }; + + bool bIsXMLDefault = false; + for (const auto & aToken : aTokens) + { + if ( pProperties->Name == aToken.sPropertyName ) + { + eToken = aToken.eAttributeToken; + + if ( !!aToken.aXMLDefault + && ( sValue == *aToken.aXMLDefault ) + ) + { + bIsXMLDefault = true; + } + break; + } + } + + if ( bIsXMLDefault ) + // the property has the value which is specified as default in the XML schema -> no need to write it + continue; + + if ( eToken == XML_TOKEN_INVALID ) + { + // for properties which are not REMOVABLE, we care for their state, and + // only export them if they're not DEFAULTed + if ( ( pProperties->Attributes & PropertyAttribute::REMOVABLE ) == 0 ) + { + PropertyState ePropertyState = xSettingsState->getPropertyState( pProperties->Name ); + if ( PropertyState_DEFAULT_VALUE == ePropertyState ) + continue; + } + + // special handlings + if ( pProperties->Name == PROPERTY_BOOLEANCOMPARISONMODE ) + { + if ( sValue == "0" ) + sValue = "equal-integer"; + else if ( sValue == "1" ) + sValue = "is-boolean"; + else if ( sValue == "2" ) + sValue = "equal-boolean"; + else if ( sValue == "3" ) + sValue = "equal-use-only-zero"; + if ( sValue == "equal-integer" ) + continue; + eToken = XML_BOOLEAN_COMPARISON_MODE; + } + else if ( pProperties->Name == INFO_AUTORETRIEVEENABLED ) + { + aValue >>= bAutoIncrementEnabled; + continue; + } + else if ( pProperties->Name == INFO_AUTORETRIEVEVALUE ) + { + aAutoIncrement.first = sValue; + continue; + } + else if ( pProperties->Name == PROPERTY_AUTOINCREMENTCREATION ) + { + aAutoIncrement.second = sValue; + continue; + } + else if ( pProperties->Name == INFO_TEXTDELIMITER ) + { + aDelimiter.sText = sValue; + aDelimiter.bUsed = true; + continue; + } + else if ( pProperties->Name == INFO_FIELDDELIMITER ) + { + aDelimiter.sField = sValue; + aDelimiter.bUsed = true; + continue; + } + else if ( pProperties->Name == INFO_DECIMALDELIMITER ) + { + aDelimiter.sDecimal = sValue; + aDelimiter.bUsed = true; + continue; + } + else if ( pProperties->Name == INFO_THOUSANDSDELIMITER ) + { + aDelimiter.sThousand = sValue; + aDelimiter.bUsed = true; + continue; + } + else if ( pProperties->Name == INFO_CHARSET ) + { + m_sCharSet = sValue; + continue; + } + else + { + if ( !aDriverSupportedProperties.has(pProperties->Name) || aDriverSupportedProperties.get(pProperties->Name) != aValue ) + { + m_aDataSourceSettings.emplace_back( + pProperties->Name, pProperties->Type, aValue ); + } + continue; + } + } + + aSettingsMap.emplace(eToken,sValue); + } + if ( bAutoIncrementEnabled && !(aAutoIncrement.first.isEmpty() && aAutoIncrement.second.isEmpty()) ) + m_aAutoIncrement.reset( new TStringPair(aAutoIncrement)); + if ( aDelimiter.bUsed ) + m_aDelimiter.reset( new TDelimiter( aDelimiter ) ); + + SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_DATASOURCE, 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 ); + + + const OUString sPropertyName = "LocalSocket"; + if ( xSettingsInfo->hasPropertyByName( sPropertyName ) ) + { + OUString sPropertyValue; + if ( ( xDataSourceSettings->getPropertyValue( sPropertyName ) >>= sPropertyValue ) && !sPropertyValue.isEmpty() ) + AddAttribute( XML_NAMESPACE_DB, XML_LOCAL_SOCKET, sPropertyValue ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + SvXMLElementExport aServerDB(*this,XML_NAMESPACE_DB, XML_SERVER_DATABASE, true, true); + } + } + else + { + AddAttribute(XML_NAMESPACE_XLINK, XML_HREF,sValue); + AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE); + SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_CONNECTION_RESOURCE, true, true); + } + } + + } + + exportLogin(); +} + +template< typename T > void ODBExport::exportDataSourceSettingsSequence( + std::vector< TypedPropertyValue >::iterator const & in) +{ + css::uno::Sequence anySeq; + bool bSuccess = in->Value >>= anySeq; + assert(bSuccess); (void)bSuccess; + for (T const & i : 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_aAutoIncrement) + { + AddAttribute(XML_NAMESPACE_DB, XML_ADDITIONAL_COLUMN_STATEMENT,m_aAutoIncrement->second); + AddAttribute(XML_NAMESPACE_DB, XML_ROW_RETRIEVING_STATEMENT,m_aAutoIncrement->first); + SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, XML_AUTO_INCREMENT, true, true); + } +} + +void ODBExport::exportSequence(const Sequence< OUString>& _aValue + ,::xmloff::token::XMLTokenEnum _eTokenFilter + ,::xmloff::token::XMLTokenEnum _eTokenType) +{ + if ( _aValue.hasElements() ) + { + SvXMLElementExport aElem(*this,XML_NAMESPACE_DB, _eTokenFilter, true, true); + + const OUString* pIter = _aValue.getConstArray(); + const OUString* pEnd = pIter + _aValue.getLength(); + for(;pIter != pEnd;++pIter) + { + SvXMLElementExport aDataSource(*this,XML_NAMESPACE_DB, _eTokenType, true, false); + Characters(*pIter); + } + } +} + +void ODBExport::exportLogin() +{ + Reference 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,SvXMLAttributeList& _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,SvXMLAttributeList& _rAtt,TPropertyStyleMap& _rMap) +{ + TPropertyStyleMap::const_iterator aFind = _rMap.find(_xProp); + if ( aFind != _rMap.end() ) + { + _rAtt.AddAttribute( GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_DB, GetXMLToken(_eToken) ), + aFind->second ); + _rMap.erase(aFind); + } +} + +void ODBExport::exportTableName(XPropertySet* _xProp,bool _bUpdate) +{ + OUString sValue; + _xProp->getPropertyValue(_bUpdate ? OUString(PROPERTY_UPDATE_TABLENAME) : OUString(PROPERTY_NAME)) >>= sValue; + if ( sValue.isEmpty() ) + return; + + AddAttribute(XML_NAMESPACE_DB, XML_NAME,sValue); + _xProp->getPropertyValue(_bUpdate ? OUString(PROPERTY_UPDATE_SCHEMANAME) : OUString(PROPERTY_SCHEMANAME)) >>= sValue; + if ( !sValue.isEmpty() ) + AddAttribute(XML_NAMESPACE_DB, XML_SCHEMA_NAME,sValue); + _xProp->getPropertyValue(_bUpdate ? OUString(PROPERTY_UPDATE_CATALOGNAME) : OUString(PROPERTY_CATALOGNAME)) >>= sValue; + if ( !sValue.isEmpty() ) + AddAttribute(XML_NAMESPACE_DB, XML_CATALOG_NAME,sValue); + + if ( _bUpdate ) + { + SvXMLElementExport aComponents(*this,XML_NAMESPACE_DB, XML_UPDATE_TABLE, true, true); + } +} + +void ODBExport::exportFilter(XPropertySet* _xProp + ,const OUString& _sProp + ,enum ::xmloff::token::XMLTokenEnum _eStatementType) +{ + OSL_PRECOND(!GetAttrList().getLength(),"Invalid attribute length!"); + OUString sCommand; + _xProp->getPropertyValue(_sProp) >>= sCommand; + if ( !sCommand.isEmpty() ) + { + AddAttribute(XML_NAMESPACE_DB, XML_COMMAND,sCommand); + SvXMLElementExport aComponents(*this,XML_NAMESPACE_DB, _eStatementType, true, true); + } + SAL_WARN_IF(GetAttrList().getLength(), "dbaccess", "Invalid attribute length!"); +} + +void ODBExport::exportColumns(const Reference& _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); + SvXMLAttributeList* pAtt = new SvXMLAttributeList; + Reference xAtt = pAtt; + exportStyleName(aFind->second.get(),*pAtt); + AddAttributeList(xAtt); + 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() ) + { + SvXMLAttributeList* pAtt = new SvXMLAttributeList; + Reference xAtt = pAtt; + 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(xAtt); + } + + 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)) + }; + + std::vector< XMLPropertyState > aPropertyStates; + for (const auto & i : pExportHelper) + { + aPropertyStates = i.first->Filter(_xProp); + if ( !aPropertyStates.empty() ) + i.second.first->emplace( _xProp,GetAutoStylePool()->Add( i.second.second, 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(_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( _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 ) + std::copy( m_aCurrentPropertyStates.begin(), m_aCurrentPropertyStates.end(), std::back_inserter( aPropStates )); + if ( !aPropStates.empty() ) + i.second.first->emplace( _xProp,GetAutoStylePool()->Add( i.second.second, 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); + aProps[nLength].Name = "Queries"; + Sequence< OUString> aSeq = xCollection->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + + Sequence aQueries(aSeq.getLength()); + for(sal_Int32 i = 0;pIter != pEnd;++pIter,++i) + { + Reference xProp(xCollection->getByName(*pIter),UNO_QUERY); + if ( xProp.is() ) + { + aQueries[i].Name = *pIter; + aQueries[i].Value = xProp->getPropertyValue(PROPERTY_LAYOUTINFORMATION); + } + } + aProps[nLength].Value <<= aQueries; + } + catch(const Exception&) + { + OSL_FAIL("ODBExport::GetViewSettings: Exception caught!"); + } + +} + +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); + aProps[nLength].Name = "layout-settings"; + aProps[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 000000000..337163f64 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlExport.hxx @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLEXPORT_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLEXPORT_HXX + +#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( const OUString& _name, const css::uno::Type& _type, const css::uno::Any& _value ) + :Name( _name ) + ,Type( _type ) + ,Value( _value ) + { + } + }; + + std::unique_ptr< TStringPair > m_aAutoIncrement; + std::unique_ptr< TDelimiter > m_aDelimiter; + std::vector< TypedPropertyValue > m_aDataSourceSettings; + std::vector< XMLPropertyState > m_aCurrentPropertyStates; + TPropertyStyleMap m_aAutoStyleNames; + TPropertyStyleMap m_aCellAutoStyleNames; + TPropertyStyleMap m_aRowAutoStyleNames; + TTableColumnMap m_aTableDummyColumns; + OUString m_sCharSet; + rtl::Reference < SvXMLExportPropertyMapper> m_xExportHelper; + rtl::Reference < SvXMLExportPropertyMapper> m_xColumnExportHelper; + rtl::Reference < SvXMLExportPropertyMapper> m_xCellExportHelper; + rtl::Reference < SvXMLExportPropertyMapper> m_xRowExportHelper; + + mutable rtl::Reference < XMLPropertySetMapper > m_xTableStylesPropertySetMapper; + mutable rtl::Reference < XMLPropertySetMapper > m_xColumnStylesPropertySetMapper; + mutable rtl::Reference < XMLPropertySetMapper > m_xCellStylesPropertySetMapper; + + Reference m_xDataSource; + ::dbaccess::ODsnTypeCollection m_aTypeCollection; + bool m_bAllreadyFilled; + + void exportDataSource(); + void exportConnectionData(); + void exportDriverSettings(const TSettingsMap& _aSettings); + void exportApplicationConnectionSettings(const TSettingsMap& _aSettings); + void exportLogin(); + void exportSequence(const Sequence< OUString>& _aValue + ,::xmloff::token::XMLTokenEnum _eTokenFilter + ,::xmloff::token::XMLTokenEnum _eTokenType); + void exportDelimiter(); + void exportAutoIncrement(); + void exportCharSet(); + template< typename T > void exportDataSourceSettingsSequence( + std::vector< TypedPropertyValue >::iterator const & in); + void exportDataSourceSettings(); + void exportForms(); + void exportReports(); + void exportQueries(bool _bExportContext); + void exportTables(bool _bExportContext); + void exportStyleName(XPropertySet* _xProp,SvXMLAttributeList& _rAtt); + void exportStyleName(const ::xmloff::token::XMLTokenEnum _eToken,const Reference& _xProp,SvXMLAttributeList& _rAtt,TPropertyStyleMap& _rMap); + void exportCollection(const Reference< XNameAccess >& _xCollection + ,enum ::xmloff::token::XMLTokenEnum _eComponents + ,enum ::xmloff::token::XMLTokenEnum _eSubComponents + ,bool _bExportContext + ,const ::comphelper::mem_fun1_t& _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 ); + + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + + /// @throws css::uno::RuntimeException + static css::uno::Sequence + getSupportedServiceNames_Static(); + + static css::uno::Reference Create( + css::uno::Reference const & _rxORB); + + 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 +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLEXPORT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlFileBasedDatabase.cxx b/dbaccess/source/filter/xml/xmlFileBasedDatabase.cxx new file mode 100644 index 000000000..8070790e4 --- /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: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + 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,makeAny(sURL)); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +OXMLFileBasedDatabase::~OXMLFileBasedDatabase() +{ + +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlFileBasedDatabase.hxx b/dbaccess/source/filter/xml/xmlFileBasedDatabase.hxx new file mode 100644 index 000000000..e82bf1876 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlFileBasedDatabase.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLFILEBASEDDATABASE_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLFILEBASEDDATABASE_HXX + +#include + +namespace dbaxml +{ + class ODBFilter; + class OXMLFileBasedDatabase : public SvXMLImportContext + { + public: + + OXMLFileBasedDatabase( ODBFilter& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList ); + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual ~OXMLFileBasedDatabase() override; + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLFILEBASEDDATABASE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlHelper.cxx b/dbaccess/source/filter/xml/xmlHelper.cxx new file mode 100644 index 000000000..a9f156fc5 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlHelper.cxx @@ -0,0 +1,151 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "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; +} + +#define MAP_END() { nullptr, 0, 0, XML_TOKEN_INVALID, 0 , 0, SvtSaveOptions::ODFSVER_010, false} +rtl::Reference < XMLPropertySetMapper > OXMLHelper::GetTableStylesPropertySetMapper( bool bForExport ) +{ + static const XMLPropertyMapEntry s_aTableStylesProperties[] = + { + MAP_END() + }; + rtl::Reference < XMLPropertyHandlerFactory> xFac = new ::xmloff::OControlPropertyHandlerFactory(); + return new XMLPropertySetMapper(s_aTableStylesProperties, xFac, bForExport); +} + +rtl::Reference < XMLPropertySetMapper > OXMLHelper::GetColumnStylesPropertySetMapper( bool bForExport ) +{ +#define MAP_CONST_COLUMN( name, prefix, token, type, context ) { name, sizeof(name)-1, prefix, token, type|XML_TYPE_PROP_TABLE_COLUMN, context, SvtSaveOptions::ODFSVER_010, false } + static const XMLPropertyMapEntry s_aColumnStylesProperties[] = + { + MAP_CONST_COLUMN( PROPERTY_WIDTH, XML_NAMESPACE_STYLE, XML_COLUMN_WIDTH, XML_TYPE_MEASURE, 0), + MAP_CONST_COLUMN( PROPERTY_HIDDEN, XML_NAMESPACE_TABLE, XML_DISPLAY, XML_DB_TYPE_EQUAL|MID_FLAG_SPECIAL_ITEM, CTF_DB_ISVISIBLE ), + MAP_CONST_COLUMN( PROPERTY_NUMBERFORMAT, XML_NAMESPACE_STYLE, XML_DATA_STYLE_NAME, XML_TYPE_NUMBER|MID_FLAG_SPECIAL_ITEM, CTF_DB_NUMBERFORMAT), + MAP_END() + }; + rtl::Reference < XMLPropertyHandlerFactory> xFac = new OPropertyHandlerFactory(); + return new XMLPropertySetMapper(s_aColumnStylesProperties, xFac, bForExport); +} + +rtl::Reference < XMLPropertySetMapper > OXMLHelper::GetCellStylesPropertySetMapper( bool bForExport ) +{ +#define MAP_CONST_CELL( name, prefix, token, type, context ) { name, sizeof(name)-1, prefix, token, type|XML_TYPE_PROP_PARAGRAPH, context, SvtSaveOptions::ODFSVER_010, false } +#define MAP_CONST_TEXT( name, prefix, token, type, context ) { name, sizeof(name)-1, prefix, token, type|XML_TYPE_PROP_TEXT, context, SvtSaveOptions::ODFSVER_010, false } + static const XMLPropertyMapEntry s_aCellStylesProperties[] = + { + MAP_CONST_CELL( PROPERTY_ALIGN, XML_NAMESPACE_FO, XML_TEXT_ALIGN, XML_TYPE_TEXT_ALIGN, CTF_DB_COLUMN_TEXT_ALIGN), + MAP_CONST_TEXT( PROPERTY_FONTNAME, XML_NAMESPACE_STYLE, XML_FONT_NAME, XML_TYPE_STRING, 0 ), + MAP_CONST_TEXT( PROPERTY_TEXTCOLOR, XML_NAMESPACE_FO, XML_COLOR, XML_TYPE_COLOR, 0 ), + MAP_CONST_TEXT( PROPERTY_TEXTLINECOLOR, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + + MAP_CONST_TEXT( PROPERTY_TEXTRELIEF, XML_NAMESPACE_STYLE, XML_FONT_RELIEF, XML_TYPE_TEXT_FONT_RELIEF|MID_FLAG_MULTI_PROPERTY, 0 ), + MAP_CONST_TEXT( PROPERTY_TEXTEMPHASIS, XML_NAMESPACE_STYLE, XML_TEXT_EMPHASIZE, XML_TYPE_CONTROL_TEXT_EMPHASIZE, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTCHARWIDTH, XML_NAMESPACE_STYLE, XML_FONT_CHAR_WIDTH, XML_TYPE_NUMBER16, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTCHARSET, XML_NAMESPACE_STYLE, XML_FONT_CHARSET, XML_TYPE_TEXT_FONTENCODING, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTFAMILY, XML_NAMESPACE_STYLE, XML_FONT_FAMILY_GENERIC, XML_TYPE_TEXT_FONTFAMILY, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTHEIGHT, XML_NAMESPACE_FO, XML_FONT_SIZE, XML_TYPE_MEASURE16, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTKERNING, XML_NAMESPACE_STYLE, XML_LETTER_KERNING, XML_TYPE_BOOL, 0 ), + + MAP_CONST_TEXT( PROPERTY_FONTORIENTATION, XML_NAMESPACE_STYLE, XML_ROTATION_ANGLE, XML_TYPE_ROTATION_ANGLE, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTPITCH, XML_NAMESPACE_STYLE, XML_FONT_PITCH, XML_TYPE_TEXT_FONTPITCH, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTSLANT, XML_NAMESPACE_FO, XML_FONT_STYLE, XML_TYPE_TEXT_POSTURE, 0 ), + MAP_CONST_TEXT( "CharStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_STYLE, XML_TYPE_TEXT_CROSSEDOUT_STYLE|MID_FLAG_MERGE_PROPERTY, 0), + MAP_CONST_TEXT( "CharStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TYPE, XML_TYPE_TEXT_CROSSEDOUT_TYPE|MID_FLAG_MERGE_PROPERTY, 0), + MAP_CONST_TEXT( "CharStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_WIDTH, XML_TYPE_TEXT_CROSSEDOUT_WIDTH|MID_FLAG_MERGE_PROPERTY, 0), + MAP_CONST_TEXT( "CharStrikeout", XML_NAMESPACE_STYLE, XML_TEXT_LINE_THROUGH_TEXT, XML_TYPE_TEXT_CROSSEDOUT_TEXT|MID_FLAG_MERGE_PROPERTY, 0), + MAP_CONST_TEXT( PROPERTY_FONTSTYLENAME, XML_NAMESPACE_STYLE, XML_FONT_STYLE_NAME, XML_TYPE_STRING, 0 ), + MAP_CONST_TEXT( "CharUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_STYLE, XML_TYPE_TEXT_UNDERLINE_STYLE|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_CONST_TEXT( "CharUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_TYPE, XML_TYPE_TEXT_UNDERLINE_TYPE|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_CONST_TEXT( "CharUnderline", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_WIDTH, XML_TYPE_TEXT_UNDERLINE_WIDTH|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_CONST_TEXT( "CharUnderlineColor", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_COLOR|MID_FLAG_MULTI_PROPERTY, 0 ), + MAP_CONST_TEXT( "CharUnderlineHasColor", XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_COLOR, XML_TYPE_TEXT_UNDERLINE_HASCOLOR|MID_FLAG_MERGE_ATTRIBUTE, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTWEIGHT, XML_NAMESPACE_FO, XML_FONT_WEIGHT, XML_TYPE_TEXT_WEIGHT, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTWIDTH, XML_NAMESPACE_STYLE, XML_FONT_WIDTH, XML_TYPE_FONT_WIDTH, 0 ), + MAP_CONST_TEXT( PROPERTY_FONTWORDLINEMODE, XML_NAMESPACE_STYLE, XML_TEXT_UNDERLINE_MODE, XML_TYPE_TEXT_LINE_MODE|MID_FLAG_MERGE_PROPERTY, 0 ), + MAP_END() + }; + rtl::Reference < XMLPropertyHandlerFactory> xFac = new /*OPropertyHandlerFactory*/::xmloff::OControlPropertyHandlerFactory(); + return new XMLPropertySetMapper(s_aCellStylesProperties, xFac, bForExport); +} + +rtl::Reference < XMLPropertySetMapper > OXMLHelper::GetRowStylesPropertySetMapper() +{ +#define MAP_CONST_ROW( name, prefix, token, type, context ) { name, sizeof(name)-1, prefix, token, type|XML_TYPE_PROP_TABLE_ROW, context, SvtSaveOptions::ODFSVER_010, false } + static const XMLPropertyMapEntry s_aStylesProperties[] = + { + MAP_CONST_ROW( PROPERTY_ROW_HEIGHT, XML_NAMESPACE_STYLE, XML_ROW_HEIGHT, XML_TYPE_MEASURE, 0), + MAP_END() + }; + rtl::Reference < XMLPropertyHandlerFactory> xFac = new OPropertyHandlerFactory(); + return new XMLPropertySetMapper(s_aStylesProperties, xFac, true/*bForExport*/); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlHelper.hxx b/dbaccess/source/filter/xml/xmlHelper.hxx new file mode 100644 index 000000000..fc1c20d3f --- /dev/null +++ b/dbaccess/source/filter/xml/xmlHelper.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLHELPER_HXX + +#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 +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlHierarchyCollection.cxx b/dbaccess/source/filter/xml/xmlHierarchyCollection.cxx new file mode 100644 index 000000000..d542a1ad7 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlHierarchyCollection.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 "xmlHierarchyCollection.hxx" +#include "xmlComponent.hxx" +#include "xmlColumn.hxx" +#include "xmlfilter.hxx" +#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 + ,const OUString& _sComponentServiceName) : + SvXMLImportContext( rImport ) + ,m_sCollectionServiceName(_sCollectionServiceName) + ,m_sComponentServiceName(_sComponentServiceName) +{ + OUString sName; + for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList )) + { + OUString sValue = aIter.toString(); + + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_NAME: + sName = sValue; + break; + default: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + } + 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,makeAny(m_xContainer)); + } + } + catch(Exception&) + { + OSL_FAIL("OXMLHierarchyCollection::OXMLHierarchyCollection -> exception caught"); + } +} + +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 000000000..ad7e7d39e --- /dev/null +++ b/dbaccess/source/filter/xml/xmlHierarchyCollection.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLHIERARCHYCOLLECTION_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLHIERARCHYCOLLECTION_HXX + +#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 + ,const OUString& _sComponentServiceName + ); + OXMLHierarchyCollection( ODBFilter& rImport + ,const css::uno::Reference< css::container::XNameAccess >& _xContainer + ,const css::uno::Reference< css::beans::XPropertySet >& _xTable + ); + virtual ~OXMLHierarchyCollection() override; + + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLHIERARCHYCOLLECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlLogin.cxx b/dbaccess/source/filter/xml/xmlLogin.cxx new file mode 100644 index 000000000..c74d98be7 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlLogin.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 "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()); + + static const OUString s_sTRUE = ::xmloff::token::GetXMLToken(XML_TRUE); + bool bUserFound = false; + if (!xDataSource.is()) + return; + + for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList )) + { + OUString sValue = aIter.toString(); + + try + { + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_USER_NAME: + if ( !bUserFound ) + { + bUserFound = true; + try + { + xDataSource->setPropertyValue(PROPERTY_USER,makeAny(sValue)); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + break; + case XML_IS_PASSWORD_REQUIRED: + try + { + xDataSource->setPropertyValue(PROPERTY_ISPASSWORDREQUIRED,makeAny(sValue == s_sTRUE)); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + break; + case XML_USE_SYSTEM_USER: + if ( !bUserFound ) + { + bUserFound = true; + PropertyValue aProperty; + aProperty.Name = "UseSystemUser"; + aProperty.Value <<= (sValue == s_sTRUE); + rImport.addInfo(aProperty); + } + break; + case XML_LOGIN_TIMEOUT: + try + { + Reference< XDataSource>(xDataSource,UNO_QUERY_THROW)->setLoginTimeout(sValue.toInt32()); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + break; + default: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +OXMLLogin::~OXMLLogin() +{ + +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlLogin.hxx b/dbaccess/source/filter/xml/xmlLogin.hxx new file mode 100644 index 000000000..50297416d --- /dev/null +++ b/dbaccess/source/filter/xml/xmlLogin.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLLOGIN_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLLOGIN_HXX + +#include + +namespace dbaxml +{ + class ODBFilter; + class OXMLLogin : public SvXMLImportContext + { + public: + + OXMLLogin( ODBFilter& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList ); + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual ~OXMLLogin() override; + + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLLOGIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlQuery.cxx b/dbaccess/source/filter/xml/xmlQuery.cxx new file mode 100644 index 000000000..7ab4940da --- /dev/null +++ b/dbaccess/source/filter/xml/xmlQuery.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 "xmlQuery.hxx" +#include "xmlfilter.hxx" +#include +#include +#include "xmlEnums.hxx" +#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; + + +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 )) + { + OUString sValue = aIter.toString(); + + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_COMMAND: + m_sCommand = sValue; + break; + case XML_ESCAPE_PROCESSING: + m_bEscapeProcessing = sValue == "true"; + break; + default: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + } +} + +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,makeAny(m_sCommand)); + _xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,makeAny(m_bEscapeProcessing)); + + if ( !m_sTable.isEmpty() ) + _xProp->setPropertyValue(PROPERTY_UPDATE_TABLENAME,makeAny(m_sTable)); + if ( !m_sCatalog.isEmpty() ) + _xProp->setPropertyValue(PROPERTY_UPDATE_CATALOGNAME,makeAny(m_sCatalog)); + if ( !m_sSchema.isEmpty() ) + _xProp->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,makeAny(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,makeAny(aFind->second)); + } + } + catch(Exception&) + { + OSL_FAIL("OXMLTable::EndElement -> exception caught"); + } +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlQuery.hxx b/dbaccess/source/filter/xml/xmlQuery.hxx new file mode 100644 index 000000000..bd13072e0 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlQuery.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLQUERY_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLQUERY_HXX + +#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 void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLQUERY_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlServerDatabase.cxx b/dbaccess/source/filter/xml/xmlServerDatabase.cxx new file mode 100644 index 000000000..87ff119b5 --- /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: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + } + } + if ( sType.isEmpty() ) + return; + + OUStringBuffer sURL; + if ( sType == "sdbc:mysql:jdbc" || sType == "sdbc:mysqlc" || sType == "sdbc:mysql:mysqlc" ) + { + sURL.append( sType ).append( ":" ).append(sHostName); + if ( !sPortNumber.isEmpty() ) + { + sURL.append(":").append(sPortNumber); + } + if ( !sDatabaseName.isEmpty() ) + { + sURL.append("/").append(sDatabaseName); + } + } + else if ( sType == "jdbc:oracle:thin" ) + { + sURL.append("jdbc:oracle:thin:@").append(sHostName); + if ( !sPortNumber.isEmpty() ) + { + sURL.append(":").append(sPortNumber); + } + if ( !sDatabaseName.isEmpty() ) + { + sURL.append(":").append(sDatabaseName); + } + } + else if ( sType == "sdbc:address:ldap" ) + { + sURL.append("sdbc:address:ldap:").append(sHostName); + if ( !sPortNumber.isEmpty() ) + { + sURL.append(":").append(sPortNumber); + } + } + else + { + sURL.append(sType).append(":").append(sHostName); + if ( !sPortNumber.isEmpty() ) + { + sURL.append(":").append(sPortNumber); + } + if ( !sDatabaseName.isEmpty() ) + { + sURL.append(":").append(sDatabaseName); + } + } + try + { + xDataSource->setPropertyValue(PROPERTY_URL,makeAny(sURL.makeStringAndClear())); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +OXMLServerDatabase::~OXMLServerDatabase() +{ + +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlServerDatabase.hxx b/dbaccess/source/filter/xml/xmlServerDatabase.hxx new file mode 100644 index 000000000..4f0378de4 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlServerDatabase.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLSERVERDATABASE_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLSERVERDATABASE_HXX + +#include + +namespace dbaxml +{ + class ODBFilter; + class OXMLServerDatabase : public SvXMLImportContext + { + public: + + OXMLServerDatabase( ODBFilter& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList > & _xAttrList ); + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual ~OXMLServerDatabase() override; + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLSERVERDATABASE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlStyleImport.cxx b/dbaccess/source/filter/xml/xmlStyleImport.cxx new file mode 100644 index 000000000..9e7b1f8cc --- /dev/null +++ b/dbaccess/source/filter/xml/xmlStyleImport.cxx @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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, + sal_uInt16 nPrfx, const OUString& rLName, + const Reference< XAttributeList > & xAttrList, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily ) + :XMLPropStyleContext( rImport, nPrfx, rLName, xAttrList, 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(static_cast(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_uInt16 nPrefixKey, + const OUString& rLocalName, + const OUString& rValue ) +{ + // TODO: use a map here + if( IsXMLToken(rLocalName, XML_DATA_STYLE_NAME ) ) + m_sDataStyleName = rValue; + else if ( IsXMLToken(rLocalName, XML_MASTER_PAGE_NAME ) ) + sPageStyle = rValue; + else + XMLPropStyleContext::SetAttribute( nPrefixKey, rLocalName, 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 nElement) +{ + SvXMLStylesContext::endFastElement(nElement); + 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_uInt16 nPrefix, const OUString& rLocalName, + const Reference< xml::sax::XAttributeList > & xAttrList ) +{ + SvXMLStyleContext *pStyle = SvXMLStylesContext::CreateStyleStyleChildContext( nFamily, nPrefix, + rLocalName, + xAttrList ); + if (!pStyle) + { + switch( nFamily ) + { + case XmlStyleFamily::TABLE_TABLE: + case XmlStyleFamily::TABLE_COLUMN: + case XmlStyleFamily::TABLE_CELL: + pStyle = new OTableStyleContext( GetOwnImport(), nPrefix, rLocalName, + xAttrList, *this, nFamily ); + break; + default: break; + } + } + + return pStyle; +} + +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 000000000..8eeb7ac7d --- /dev/null +++ b/dbaccess/source/filter/xml/xmlStyleImport.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLSTYLEIMPORT_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLSTYLEIMPORT_HXX + +#include +#include +#include +#include + +namespace dbaxml +{ + class ODBFilter; + + class OTableStyleContext : public XMLPropStyleContext + { + OUString m_sDataStyleName; + OUString sPageStyle; + SvXMLStylesContext* pStyles; + sal_Int32 m_nNumberFormat; + + ODBFilter& GetOwnImport(); + + protected: + + virtual void SetAttribute( sal_uInt16 nPrefixKey, + const OUString& rLocalName, + const OUString& rValue ) override; + + public: + + + OTableStyleContext( ODBFilter& rImport, sal_uInt16 nPrfx, + const OUString& rLName, + const css::uno::Reference< css::xml::sax::XAttributeList > & xAttrList, + SvXMLStylesContext& rStyles, XmlStyleFamily nFamily ); + + virtual ~OTableStyleContext() override; + + virtual void FillPropertySet(const css::uno::Reference< + css::beans::XPropertySet > & rPropSet ) override; + + virtual void SetDefaults() override; + + void AddProperty(sal_Int16 nContextID, const css::uno::Any& aValue); + }; + + class OTableStylesContext : public SvXMLStylesContext + { + sal_Int32 m_nNumberFormatIndex; + sal_Int32 m_nMasterPageNameIndex; + bool bAutoStyles : 1; + + mutable rtl::Reference < SvXMLImportPropertyMapper > m_xTableImpPropMapper; + mutable rtl::Reference < SvXMLImportPropertyMapper > m_xColumnImpPropMapper; + mutable rtl::Reference < SvXMLImportPropertyMapper > m_xCellImpPropMapper; + + ODBFilter& GetOwnImport(); + + protected: + + // Create a style context. + virtual SvXMLStyleContext *CreateStyleStyleChildContext( + XmlStyleFamily nFamily, + sal_uInt16 nPrefix, + const OUString& rLocalName, + const css::uno::Reference< css::xml::sax::XAttributeList > & 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 +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLSTYLEIMPORT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlTable.cxx b/dbaccess/source/filter/xml/xmlTable.cxx new file mode 100644 index 000000000..9477f13fa --- /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 "xmlEnums.hxx" +#include "xmlStyleImport.hxx" +#include "xmlHierarchyCollection.hxx" +#include +#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 + ,const uno::Reference< css::container::XNameAccess >& _xParentContainer + ,const OUString& _sServiceName + ) + :SvXMLImportContext( _rImport ) + ,m_xParentContainer(_xParentContainer) + ,m_bApplyFilter(false) + ,m_bApplyOrder(false) +{ + for (auto &aIter : sax_fastparser::castToFastAttributeList( _xAttrList )) + { + OUString sValue = aIter.toString(); + + switch( aIter.getToken() & TOKEN_MASK ) + { + case XML_NAME: + m_sName = sValue; + break; + case XML_CATALOG_NAME: + m_sCatalog = sValue; + break; + case XML_SCHEMA_NAME: + m_sSchema = sValue; + break; + case XML_STYLE_NAME: + m_sStyleName = sValue; + break; + case XML_APPLY_FILTER: + m_bApplyFilter = sValue == "true"; + break; + case XML_APPLY_ORDER: + m_bApplyOrder = sValue == "true"; + break; + default: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + } + 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,makeAny(m_bApplyFilter)); + _xProp->setPropertyValue(PROPERTY_FILTER,makeAny(m_sFilterStatement)); + + if ( _xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_APPLYORDER) ) + _xProp->setPropertyValue(PROPERTY_APPLYORDER,makeAny(m_bApplyOrder)); + _xProp->setPropertyValue(PROPERTY_ORDER,makeAny(m_sOrderStatement)); + } + } + catch(Exception&) + { + OSL_FAIL("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,makeAny(m_xTable)); + } + } + catch(Exception&) + { + OSL_FAIL("OXMLQuery::EndElement -> exception caught"); + } + +} + +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: + SAL_WARN("dbaccess", "unknown attribute " << SvXMLImport::getPrefixAndNameFromToken(aIter.getToken()) << "=" << aIter.toString()); + } + } +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlTable.hxx b/dbaccess/source/filter/xml/xmlTable.hxx new file mode 100644 index 000000000..2ba1f557f --- /dev/null +++ b/dbaccess/source/filter/xml/xmlTable.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLTABLE_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLTABLE_HXX + +#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 + ,const css::uno::Reference< css::container::XNameAccess >& _xParentContainer + ,const OUString& _sServiceName + ); + virtual ~OXMLTable() override; + + virtual css::uno::Reference< css::xml::sax::XFastContextHandler > SAL_CALL createFastChildContext( + sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& AttrList ) override; + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual void SAL_CALL endFastElement(sal_Int32 nElement) override; + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlTableFilterList.cxx b/dbaccess/source/filter/xml/xmlTableFilterList.cxx new file mode 100644 index 000000000..ddd799087 --- /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,makeAny(comphelper::containerToSequence(m_aPatterns))); + if ( !m_aTypes.empty() ) + xDataSource->setPropertyValue(PROPERTY_TABLETYPEFILTER,makeAny(comphelper::containerToSequence(m_aTypes))); + } +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlTableFilterList.hxx b/dbaccess/source/filter/xml/xmlTableFilterList.hxx new file mode 100644 index 000000000..755bb8e9f --- /dev/null +++ b/dbaccess/source/filter/xml/xmlTableFilterList.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLTABLEFILTERLIST_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLTABLEFILTERLIST_HXX + +#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 startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLTABLEFILTERLIST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlTableFilterPattern.cxx b/dbaccess/source/filter/xml/xmlTableFilterPattern.cxx new file mode 100644 index 000000000..0c4b2892d --- /dev/null +++ b/dbaccess/source/filter/xml/xmlTableFilterPattern.cxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xmlTableFilterPattern.hxx" +#include "xmlTableFilterList.hxx" + +namespace dbaxml +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::xml::sax; + +OXMLTableFilterPattern::OXMLTableFilterPattern( SvXMLImport& rImport + ,bool _bNameFilter + ,OXMLTableFilterList& _rParent) + :SvXMLImportContext( rImport ) + ,m_rParent(_rParent) + ,m_bNameFilter(_bNameFilter) +{ + +} + +OXMLTableFilterPattern::~OXMLTableFilterPattern() +{ + +} + +void OXMLTableFilterPattern::characters( const OUString& rChars ) +{ + maBuffer.append(rChars); +} + +void OXMLTableFilterPattern::endFastElement( sal_Int32 ) +{ + OUString sChars = maBuffer.makeStringAndClear(); + if ( m_bNameFilter ) + m_rParent.pushTableFilterPattern(sChars); + else + m_rParent.pushTableTypeFilter(sChars); +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlTableFilterPattern.hxx b/dbaccess/source/filter/xml/xmlTableFilterPattern.hxx new file mode 100644 index 000000000..2c6fbb2c7 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlTableFilterPattern.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLTABLEFILTERPATTERN_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLTABLEFILTERPATTERN_HXX + +#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 startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + virtual void SAL_CALL endFastElement( sal_Int32 nElement ) override; + virtual void SAL_CALL characters( const OUString& rChars ) override; + }; +} // namespace dbaxml + +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLTABLEFILTERPATTERN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlfilter.cxx b/dbaccess/source/filter/xml/xmlfilter.cxx new file mode 100644 index 000000000..50acc7bcf --- /dev/null +++ b/dbaccess/source/filter/xml/xmlfilter.cxx @@ -0,0 +1,650 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "xmlservices.hxx" +#include +#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 +#include + +using namespace ::com::sun::star; + +extern "C" void createRegistryInfo_ODBFilter( ) +{ + static ::dbaxml::OMultiInstanceAutoRegistration< ::dbaxml::ODBFilter > aAutoRegistration; +} + + +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 ParserInputSrouce + 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.is() ) + { + 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 ); + } + + // TODO/LATER: better error handling + return ErrCode(1); +} + + +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() throw() +{ + +} + + +OUString ODBFilter::getImplementationName_Static() +{ + return "com.sun.star.comp.sdb.DBFilter"; +} + + +css::uno::Sequence ODBFilter::getSupportedServiceNames_Static() +{ + return { "com.sun.star.document.ImportFilter" }; +} + + +css::uno::Reference< css::uno::XInterface > + ODBFilter::Create(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB) +{ + return static_cast< XServiceInfo* >(new ODBFilter( comphelper::getComponentContext(_rxORB))); +} + +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 void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + + 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 void SAL_CALL startFastElement( + sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/ ) override {} + + 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); + break; + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES): + case XML_ELEMENT(OOO, XML_AUTOMATIC_STYLES): + rImport.GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP ); + return rImport.CreateStylesContext(true); + break; + } + return nullptr; + } +}; + +class DBXMLDocumentBodyContext : public SvXMLImportContext +{ +public: + DBXMLDocumentBodyContext(SvXMLImport & rImport) + : SvXMLImportContext(rImport) + { + } + + virtual void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + + 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 void SAL_CALL startFastElement( sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& ) override {} + + 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); + break; + case XML_ELEMENT(OFFICE, XML_SCRIPTS): + return new XMLScriptContext(GetImport(), rImport.GetModel()); + break; + case XML_ELEMENT(OFFICE, XML_AUTOMATIC_STYLES): + case XML_ELEMENT(OOO, XML_AUTOMATIC_STYLES): + rImport.GetProgressBarHelper()->Increment( PROGRESS_BAR_STEP ); + return rImport.CreateStylesContext(true); + break; + 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,makeAny(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,makeAny(aInfo)); + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +} // namespace dbaxml + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlfilter.hxx b/dbaccess/source/filter/xml/xmlfilter.hxx new file mode 100644 index 000000000..983b7da5f --- /dev/null +++ b/dbaccess/source/filter/xml/xmlfilter.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLFILTER_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLFILTER_HXX + +#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::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() throw() 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(); + + /// @throws css::uno::RuntimeException + static css::uno::Sequence + getSupportedServiceNames_Static(); + + static css::uno::Reference Create( + css::uno::Reference const & _rxORB); + + // 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 +#endif // INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLFILTER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlservices.cxx b/dbaccess/source/filter/xml/xmlservices.cxx new file mode 100644 index 000000000..c4b7987a2 --- /dev/null +++ b/dbaccess/source/filter/xml/xmlservices.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 "xmlservices.hxx" +#include + +using namespace ::dbaxml; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; + +extern "C" { + +static void createRegistryInfo_dbaxml() +{ + static std::once_flag aInit; + std::call_once(aInit, [&]() + { + createRegistryInfo_DBTypeDetection(); + createRegistryInfo_ODBFilter(); + createRegistryInfo_ODBFilterExport(); + createRegistryInfo_OSettingsExport(); + createRegistryInfo_OFullExport(); + createRegistryInfo_DBContentLoader2(); + return true; + }); +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* dbaxml_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + createRegistryInfo_dbaxml(); + + Reference< XInterface > xRet; + if (pServiceManager && pImplementationName) + { + xRet = ::dbaxml::OModuleRegistration::getComponentFactory( + OUString::createFromAscii(pImplementationName), + static_cast< XMultiServiceFactory* >(pServiceManager)); + } + + if (xRet.is()) + xRet->acquire(); + return xRet.get(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/filter/xml/xmlservices.hxx b/dbaccess/source/filter/xml/xmlservices.hxx new file mode 100644 index 000000000..3691c472c --- /dev/null +++ b/dbaccess/source/filter/xml/xmlservices.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLSERVICES_HXX +#define INCLUDED_DBACCESS_SOURCE_FILTER_XML_XMLSERVICES_HXX + +#include + +extern "C" { + +void createRegistryInfo_DBContentLoader2(); +void createRegistryInfo_DBTypeDetection(); +void createRegistryInfo_ODBFilter(); +void createRegistryInfo_ODBFilterExport(); +void createRegistryInfo_OFullExport(); +void createRegistryInfo_OSettingsExport(); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/inc/OAuthenticationContinuation.hxx b/dbaccess/source/inc/OAuthenticationContinuation.hxx new file mode 100644 index 000000000..ce933b31b --- /dev/null +++ b/dbaccess/source/inc/OAuthenticationContinuation.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_INC_OAUTHENTICATIONCONTINUATION_HXX +#define INCLUDED_DBACCESS_SOURCE_INC_OAUTHENTICATIONCONTINUATION_HXX + +#include + +#include +#include +#include + +#include +#include + +namespace dbaccess +{ + +class OOO_DLLPUBLIC_DBA OAuthenticationContinuation : + public comphelper::OInteraction< css::ucb::XInteractionSupplyAuthentication > +{ + bool m_bRemberPassword : 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_bRemberPassword; } +}; + +} // namespace dbaccess + +#endif // INCLUDED_DBACCESS_SOURCE_INC_OAUTHENTICATIONCONTINUATION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/inc/apitools.hxx b/dbaccess/source/inc/apitools.hxx new file mode 100644 index 000000000..725cebd0b --- /dev/null +++ b/dbaccess/source/inc/apitools.hxx @@ -0,0 +1,234 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_INC_APITOOLS_HXX +#define INCLUDED_DBACCESS_SOURCE_INC_APITOOLS_HXX + +#include + +#include +#include +#include +#include +#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::OComponentHelper +{ +protected: + // the parent must support the tunnel implementation + css::uno::Reference< css::uno::XInterface > m_xParent; + virtual ~OSubComponent() override; + +public: + OSubComponent(::osl::Mutex& _rMutex, + const css::uno::Reference< css::uno::XInterface >& _xParent); + +// css::lang::XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + +// css::uno::XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL release() throw() override; + + operator css::uno::Reference< css::uno::XInterface > () const + { return static_cast(const_cast(this)); } + +}; + +// helper for implementing the XServiceInfo interface + +// (internal - not to be used outside - usually) +#define IMPLEMENT_SERVICE_INFO_IMPLNAME(classname, implasciiname) \ + OUString SAL_CALL classname::getImplementationName( ) \ + { \ + return implasciiname; \ + } \ + +#define IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(classname, implasciiname) \ + OUString SAL_CALL classname::getImplementationName( ) \ + { \ + return getImplementationName_Static(); \ + } \ + OUString classname::getImplementationName_Static( ) \ + { \ + return implasciiname; \ + } \ + +#define IMPLEMENT_SERVICE_INFO_SUPPORTS(classname) \ + sal_Bool SAL_CALL classname::supportsService( const OUString& _rServiceName ) \ + { \ + const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames()); \ + for (const OUString& s : aSupported) \ + if (s == _rServiceName) \ + return true; \ + \ + return false; \ + } \ + +#define IMPLEMENT_SERVICE_INFO_GETSUPPORTED1_STATIC(classname, serviceasciiname) \ + css::uno::Sequence< OUString > SAL_CALL classname::getSupportedServiceNames( ) \ + { \ + return getSupportedServiceNames_Static(); \ + } \ + css::uno::Sequence< OUString > classname::getSupportedServiceNames_Static( ) \ + { \ + return { serviceasciiname }; \ + } \ + +#define IMPLEMENT_SERVICE_INFO_GETSUPPORTED2_STATIC(classname, serviceasciiname1, serviceasciiname2) \ + css::uno::Sequence< OUString > SAL_CALL classname::getSupportedServiceNames( ) \ + { \ + return getSupportedServiceNames_Static(); \ + } \ + css::uno::Sequence< OUString > classname::getSupportedServiceNames_Static( ) \ + { \ + return { serviceasciiname1, serviceasciiname2 }; \ + } \ + +#define IMPLEMENT_SERVICE_INFO1(classname, implasciiname, serviceasciiname) \ + IMPLEMENT_SERVICE_INFO_IMPLNAME(classname, implasciiname) \ + IMPLEMENT_SERVICE_INFO_SUPPORTS(classname) \ + css::uno::Sequence< OUString > SAL_CALL classname::getSupportedServiceNames( ) \ + { \ + return { serviceasciiname }; \ + } \ + + +#define IMPLEMENT_SERVICE_INFO2(classname, implasciiname, serviceasciiname1, serviceasciiname2) \ + IMPLEMENT_SERVICE_INFO_IMPLNAME(classname, implasciiname) \ + IMPLEMENT_SERVICE_INFO_SUPPORTS(classname) \ + css::uno::Sequence< OUString > SAL_CALL classname::getSupportedServiceNames( ) \ + { \ + return { serviceasciiname1, serviceasciiname2 }; \ + } + + +#define IMPLEMENT_SERVICE_INFO2_STATIC(classname, implasciiname, serviceasciiname1, serviceasciiname2) \ + IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(classname, implasciiname) \ + IMPLEMENT_SERVICE_INFO_SUPPORTS(classname) \ + IMPLEMENT_SERVICE_INFO_GETSUPPORTED2_STATIC(classname, serviceasciiname1,serviceasciiname2) \ + css::uno::Reference< css::uno::XInterface > \ + classname::Create(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB) \ + { \ + return static_cast< XServiceInfo* >(new classname(_rxORB)); \ + } + + +#define IMPLEMENT_SERVICE_INFO3(classname, implasciiname, serviceasciiname1, serviceasciiname2, serviceasciiname3) \ + IMPLEMENT_SERVICE_INFO_IMPLNAME(classname, implasciiname) \ + IMPLEMENT_SERVICE_INFO_SUPPORTS(classname) \ + css::uno::Sequence< OUString > SAL_CALL classname::getSupportedServiceNames( ) \ + { \ + return { serviceasciiname1, serviceasciiname2, serviceasciiname3 }; \ + } \ + + +// XTypeProvider helpers + +#define IMPLEMENT_GETTYPES2( classname, baseclass1, baseclass2 ) \ + css::uno::Sequence< css::uno::Type > classname::getTypes() \ + { \ + return ::comphelper::concatSequences( \ + baseclass1::getTypes( ), \ + baseclass2::getTypes( ) \ + ); \ + } + +#define IMPLEMENT_GETTYPES3( classname, baseclass1, baseclass2, baseclass3 ) \ + css::uno::Sequence< css::uno::Type > classname::getTypes() \ + { \ + return ::comphelper::concatSequences( \ + baseclass1::getTypes( ), \ + baseclass2::getTypes( ), \ + baseclass3::getTypes( ) \ + ); \ + } + +// helper for declaring/implementing classes based on the OPropertyContainer and an OPropertyArrayUsageHelper +#define DECLARE_PROPERTYCONTAINER_DEFAULTS( ) \ + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; \ + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; \ + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override + +#define IMPLEMENT_PROPERTYCONTAINER_DEFAULTS2( classname , baseclass1) \ + css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL classname::getPropertySetInfo() \ + { \ + Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); \ + return xInfo; \ + } \ + ::cppu::IPropertyArrayHelper& classname::getInfoHelper() \ + { \ + return *baseclass1::getArrayHelper(); \ + } \ + ::cppu::IPropertyArrayHelper* classname::createArrayHelper( ) const \ + { \ + css::uno::Sequence< css::beans::Property > aProps; \ + describeProperties(aProps); \ + return new ::cppu::OPropertyArrayHelper(aProps); \ + } +#define IMPLEMENT_PROPERTYCONTAINER_DEFAULTS( classname ) \ + IMPLEMENT_PROPERTYCONTAINER_DEFAULTS2( classname, classname ) + +// helper for implementing the createArrayHelper +#define BEGIN_PROPERTY_SEQUENCE(count) \ + css::uno::Sequence< css::beans::Property> aDescriptor(count); \ + css::beans::Property* pDesc = aDescriptor.getArray(); \ + sal_Int32 nPos = 0; \ + +#define BEGIN_PROPERTY_HELPER(count) \ + BEGIN_PROPERTY_SEQUENCE(count) + +#define DECL_PROP_IMPL(varname, cpputype) \ + pDesc[nPos++] = css::beans::Property(PROPERTY_##varname, PROPERTY_ID_##varname, cpputype, + +#define DECL_PROP0(varname, type) \ + DECL_PROP_IMPL(varname, cppu::UnoType::get()) 0) + +#define DECL_PROP0_BOOL(varname) \ + DECL_PROP_IMPL(varname, cppu::UnoType::get()) 0) + +#define DECL_PROP1(varname, type, attrib1) \ + DECL_PROP_IMPL(varname, cppu::UnoType::get()) css::beans::PropertyAttribute::attrib1) + +#define DECL_PROP1_BOOL(varname, attrib1) \ + DECL_PROP_IMPL(varname, cppu::UnoType::get()) css::beans::PropertyAttribute::attrib1) + +#define DECL_PROP2_IFACE(varname, iface, attrib1, attrib2) \ + DECL_PROP_IMPL(varname, cppu::UnoType::get()) css::beans::PropertyAttribute::attrib1 | css::beans::PropertyAttribute::attrib2) + +#define DECL_PROP2(varname, type, attrib1, attrib2) \ + DECL_PROP_IMPL(varname, cppu::UnoType::get()) css::beans::PropertyAttribute::attrib1 | css::beans::PropertyAttribute::attrib2) + +#define DECL_PROP3(varname, type, attrib1, attrib2, attrib3) \ + DECL_PROP_IMPL(varname, cppu::UnoType::get()) css::beans::PropertyAttribute::attrib1 | css::beans::PropertyAttribute::attrib2 | css::beans::PropertyAttribute::attrib3) + +#define END_PROPERTY_SEQUENCE() \ + OSL_ENSURE(nPos == aDescriptor.getLength(), "forgot to adjust the count ?"); \ + +#define END_PROPERTY_HELPER() \ + END_PROPERTY_SEQUENCE() \ + return new ::cppu::OPropertyArrayHelper(aDescriptor); + +#endif // INCLUDED_DBACCESS_SOURCE_INC_APITOOLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/inc/dbu_reghelper.hxx b/dbaccess/source/inc/dbu_reghelper.hxx new file mode 100644 index 000000000..1e105b25d --- /dev/null +++ b/dbaccess/source/inc/dbu_reghelper.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_INC_DBU_REGHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_INC_DBU_REGHELPER_HXX + +#include +#include +#include +#include + +namespace dbaui +{ + + #define REGISTRATIONHELPER_INCLUDED_INDIRECTLY_ + #include "registrationhelper.hxx" + #undef REGISTRATIONHELPER_INCLUDED_INDIRECTLY_ + +} + +#endif // INCLUDED_DBACCESS_SOURCE_INC_DBU_REGHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/inc/dsntypes.hxx b/dbaccess/source/inc/dsntypes.hxx new file mode 100644 index 000000000..334b297b0 --- /dev/null +++ b/dbaccess/source/inc/dsntypes.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_INC_DSNTYPES_HXX +#define INCLUDED_DBACCESS_SOURCE_INC_DSNTYPES_HXX + +#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_USERDEFINE1, /// first user defined driver + DST_USERDEFINE2, + DST_USERDEFINE3, + DST_USERDEFINE4, + DST_USERDEFINE5, + DST_USERDEFINE6, + DST_USERDEFINE7, + DST_USERDEFINE8, + DST_USERDEFINE9, + DST_USERDEFINE10, + + DST_UNKNOWN /// unrecognized type +}; + +#define PAGE_DBSETUPWIZARD_INTRO 0 +#define PAGE_DBSETUPWIZARD_DBASE 1 +#define PAGE_DBSETUPWIZARD_TEXT 2 +#define PAGE_DBSETUPWIZARD_MSACCESS 3 +#define PAGE_DBSETUPWIZARD_LDAP 4 +//5 was PAGE_DBSETUPWIZARD_ADABAS +#define PAGE_DBSETUPWIZARD_MYSQL_INTRO 6 +#define PAGE_DBSETUPWIZARD_MYSQL_JDBC 7 +#define PAGE_DBSETUPWIZARD_MYSQL_ODBC 8 +#define PAGE_DBSETUPWIZARD_ORACLE 9 +#define PAGE_DBSETUPWIZARD_JDBC 10 +#define PAGE_DBSETUPWIZARD_ADO 11 +#define PAGE_DBSETUPWIZARD_ODBC 12 +#define PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET 13 +#define PAGE_DBSETUPWIZARD_AUTHENTIFICATION 14 +#define PAGE_DBSETUPWIZARD_FINAL 16 +#define PAGE_DBSETUPWIZARD_USERDEFINED 17 +#define PAGE_DBSETUPWIZARD_MYSQL_NATIVE 18 + +// ODsnTypeCollection +class OOO_DLLPUBLIC_DBA ODsnTypeCollection final +{ + + std::vector 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(const OUString& _sURL) const; + + /// on a given string, cut the type prefix and return the result + OUString cutPrefix(const OUString& _sURL) const; + + /// on a given string, return the type prefix + OUString getPrefix(const OUString& _sURL) const; + + /// determines whether there is a driver for the given URL prefix/pattern + bool hasDriver( const char* _pAsciiPattern ) const; + + /// on a given string, return the Java Driver Class + OUString getJavaDriverClass(const OUString& _sURL) const; + + /// returns the media type of a file based database + OUString getMediaType(const OUString& _sURL) const; + + /// returns the dsn prefix for a given media type + OUString getDatasourcePrefixFromMediaType(const OUString& _sMediaType, const OUString& _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(const OUString& _sURL) const; + + /// check if the given data source allows to show column description. + bool supportsColumnDescription(const OUString& _sURL) const; + + // check if a Browse button may be shown to insert connection url + bool supportsBrowsing(const OUString& _sURL) const; + + // check if a Create New Database button may be shown to insert connection url + bool supportsDBCreation(const OUString& _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(const OUString& _sURL) const; + + bool isConnectionUrlRequired(const OUString& _sURL) const; + + /// checks if the given data source type embeds its data into the database document + static bool isEmbeddedDatabase( const OUString& _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( const OUString& _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(const OUString& _sURL,std::vector& _rOutPathIds) const; + + DATASOURCE_TYPE determineType(const OUString& _rDsn) const; + + sal_Int32 getIndexOf(const OUString& _sURL) const; + sal_Int32 size() const; + OUString getType(const OUString& _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 + +#endif // INCLUDED_DBACCESS_SOURCE_INC_DSNTYPES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/inc/flt_reghelper.hxx b/dbaccess/source/inc/flt_reghelper.hxx new file mode 100644 index 000000000..df43de320 --- /dev/null +++ b/dbaccess/source/inc/flt_reghelper.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_INC_FLT_REGHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_INC_FLT_REGHELPER_HXX + +#include +#include +#include +#include + +namespace dbaxml +{ + + #define REGISTRATIONHELPER_INCLUDED_INDIRECTLY_ + #include "registrationhelper.hxx" + #undef REGISTRATIONHELPER_INCLUDED_INDIRECTLY_ + +} + +#endif // INCLUDED_DBACCESS_SOURCE_INC_FLT_REGHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/inc/registrationhelper.hxx b/dbaccess/source/inc/registrationhelper.hxx new file mode 100644 index 000000000..a90781887 --- /dev/null +++ b/dbaccess/source/inc/registrationhelper.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 . + */ + +#ifndef REGISTRATIONHELPER_INCLUDED_INDIRECTLY_ +#error "don't include this file directly! use dbu_reghelper.hxx instead!" +#endif + +typedef css::uno::Reference< css::lang::XSingleServiceFactory > (*FactoryInstantiation) + ( + const css::uno::Reference< css::lang::XMultiServiceFactory >& _rServiceManager, + const OUString & _rComponentName, + ::cppu::ComponentInstantiation _pCreateFunction, + const css::uno::Sequence< OUString > & _rServiceNames, + rtl_ModuleCount* + ); + +class OModuleRegistration +{ + static css::uno::Sequence< OUString >* + s_pImplementationNames; + static css::uno::Sequence< css::uno::Sequence< OUString > >* + s_pSupportedServices; + static css::uno::Sequence< sal_Int64 >* + s_pCreationFunctionPointers; + static css::uno::Sequence< sal_Int64 >* + s_pFactoryFunctionPointers; + + // no direct instantiation, only static members/methods + OModuleRegistration() = delete; + +public: + /** register a component implementing a service with the given data. + @param _rImplementationName the implementation name of the component + @param _rServiceNames the services the component supports + @param _pCreateFunction a function for creating an instance of the component + @param _pFactoryFunction a function for creating a factory for that component + @see revokeComponent + */ + static void registerComponent( + const OUString& _rImplementationName, + const css::uno::Sequence< OUString >& _rServiceNames, + ::cppu::ComponentInstantiation _pCreateFunction, + FactoryInstantiation _pFactoryFunction); + + /** revoke the registration for the specified component + @param _rImplementationName the implementation name of the component + */ + static void revokeComponent( + const OUString& _rImplementationName); + + /** creates a Factory for the component with the given implementation name. Usually used from within component_getFactory. + @param _rxServiceManager a pointer to an XMultiServiceFactory interface as got in component_getFactory + @param _pImplementationName the implementation name of the component + @return the XInterface access to a factory for the component + */ + static css::uno::Reference< css::uno::XInterface > getComponentFactory( + const OUString& _rImplementationName, + const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxServiceManager + ); +}; + +template +class OMultiInstanceAutoRegistration +{ +public: + /** assumed that the template argument has the three methods
+ static OUString getImplementationName_Static()
+ static css::uno::Sequence< OUString > getSupportedServiceNames_Static()
+ and
+ static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&)
+ the instantiation of this object will automatically register the class via OModuleRegistration::registerComponent. + The factory creation function used is ::cppu::createSingleFactory.
+ */ + OMultiInstanceAutoRegistration(); + ~OMultiInstanceAutoRegistration(); +}; + +template +OMultiInstanceAutoRegistration::OMultiInstanceAutoRegistration() +{ + OModuleRegistration::registerComponent( + TYPE::getImplementationName_Static(), + TYPE::getSupportedServiceNames_Static(), + TYPE::Create, + ::cppu::createSingleFactory + ); +} + +template +OMultiInstanceAutoRegistration::~OMultiInstanceAutoRegistration() +{ + OModuleRegistration::revokeComponent(TYPE::getImplementationName_Static()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/inc/stringconstants.hxx b/dbaccess/source/inc/stringconstants.hxx new file mode 100644 index 000000000..9b7e732fe --- /dev/null +++ b/dbaccess/source/inc/stringconstants.hxx @@ -0,0 +1,174 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_INC_STRINGCONSTANTS_HRC +#define INCLUDED_DBACCESS_SOURCE_INC_STRINGCONSTANTS_HRC + +// 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 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/sdbtools/connection/connectiontools.cxx b/dbaccess/source/sdbtools/connection/connectiontools.cxx new file mode 100644 index 000000000..2bc8bfd33 --- /dev/null +++ b/dbaccess/source/sdbtools/connection/connectiontools.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 "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 getImplementationName_static(); + } + + sal_Bool SAL_CALL ConnectionTools::supportsService(const OUString & ServiceName) + { + return cppu::supportsService(this, ServiceName); + } + + Sequence< OUString > SAL_CALL ConnectionTools::getSupportedServiceNames() + { + return getSupportedServiceNames_static(); + } + + OUString ConnectionTools::getImplementationName_static() + { + return "com.sun.star.comp.dbaccess.ConnectionTools"; + } + + Sequence< OUString > ConnectionTools::getSupportedServiceNames_static() + { + Sequence aSupported { "com.sun.star.sdb.tools.ConnectionTools" }; + return aSupported; + } + + Reference< XInterface > ConnectionTools::Create(const Reference< XComponentContext >& _rxContext ) + { + return *( new ConnectionTools( _rxContext ) ); + } + + 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 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/sdbtools/connection/datasourcemetadata.cxx b/dbaccess/source/sdbtools/connection/datasourcemetadata.cxx new file mode 100644 index 000000000..a446885b8 --- /dev/null +++ b/dbaccess/source/sdbtools/connection/datasourcemetadata.cxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "datasourcemetadata.hxx" + +#include + +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 000000000..232f97f60 --- /dev/null +++ b/dbaccess/source/sdbtools/connection/datasourcemetadata.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#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 000000000..5ec2c22e8 --- /dev/null +++ b/dbaccess/source/sdbtools/connection/objectnames.cxx @@ -0,0 +1,420 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "objectnames.hxx" +#include + +#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( const OUString& _rName ) + { + if ( ( _rName.indexOf( u'"' ) >= 0 ) + || ( _rName.indexOf( u'\'' ) >= 0 ) + || ( _rName.indexOf( u'`' ) >= 0 ) + || ( _rName.indexOf( u'\x0091' ) >= 0 ) + || ( _rName.indexOf( u'\x0092' ) >= 0 ) + || ( _rName.indexOf( u'\x00B4' ) >= 0 ) // removed unparsable chars + ) + return ErrorCondition::DB_QUERY_NAME_WITH_QUOTES; + + if ( _rName.indexOf( '/') >= 0 ) + return ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES; + + return 0; + } + + virtual bool validateName( const OUString& _rName ) override + { + return validateName_getErrorCondition( _rName ) == 0; + } + + virtual void validateName_throw( const OUString& _rName ) override + { + ::connectivity::ErrorCondition nErrorCondition = validateName_getErrorCondition( _rName ); + if ( nErrorCondition != 0 ) + { + ::connectivity::SQLError aErrors; + aErrors.raiseException( nErrorCondition, m_xConnection ); + } + } + }; + + // CombinedNameCheck + class CombinedNameCheck : public INameValidation + { + private: + PNameValidation m_pPrimary; + PNameValidation m_pSecondary; + + public: + CombinedNameCheck(const PNameValidation& _pPrimary, const PNameValidation& _pSecondary) + :m_pPrimary( _pPrimary ) + ,m_pSecondary( _pSecondary ) + { + OSL_ENSURE( m_pPrimary && m_pSecondary, "CombinedNameCheck::CombinedNameCheck: this will crash!" ); + } + + // INameValidation + virtual bool validateName( const OUString& _rName ) override + { + return m_pPrimary->validateName( _rName ) && m_pSecondary->validateName( _rName ); + } + + virtual void validateName_throw( const OUString& _rName ) override + { + m_pPrimary->validateName_throw( _rName ); + m_pSecondary->validateName_throw( _rName ); + } + }; + + // NameCheckFactory + class NameCheckFactory + { + public: + NameCheckFactory(const NameCheckFactory&) = delete; + const NameCheckFactory& operator=(const NameCheckFactory&) = delete; + /** creates an INameValidation instance which can be used to check the existence of query or table names + + @param _nCommandType + the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be checked for existence + + @param _rxConnection + the connection relative to which the names are to be checked. Must be an SDB-level connection + + @throws IllegalArgumentException + if the given connection is no SDB-level connection + + @throws IllegalArgumentException + if the given command type is neither CommandType::TABLE or CommandType::QUERY + */ + static PNameValidation createExistenceCheck( + sal_Int32 _nCommandType, + const Reference< XConnection >& _rxConnection + ); + + /** creates an INameValidation instance which can be used to check the validity of a query or table name + + @param _nCommandType + the type of objects (CommandType::TABLE or CommandType::QUERY) of which names shall be validated + + @param _rxConnection + the connection relative to which the names are to be checked. Must be an SDB-level connection + + @throws IllegalArgumentException + if the given connection is no SDB-level connection + + @throws IllegalArgumentException + if the given command type is neither CommandType::TABLE or CommandType::QUERY + */ + static PNameValidation createValidityCheck( + const sal_Int32 _nCommandType, + const Reference< XConnection >& _rxConnection + ); + + private: + static void verifyCommandType( sal_Int32 _nCommandType ); + }; + + } + + void NameCheckFactory::verifyCommandType( sal_Int32 _nCommandType ) + { + if ( ( _nCommandType != CommandType::TABLE ) + && ( _nCommandType != CommandType::QUERY ) + ) + throw IllegalArgumentException( + DBA_RES( STR_INVALID_COMMAND_TYPE ), + nullptr, + 0 + ); + } + + PNameValidation NameCheckFactory::createExistenceCheck( sal_Int32 _nCommandType, const Reference< XConnection >& _rxConnection ) + { + verifyCommandType( _nCommandType ); + + ::dbtools::DatabaseMetaData aMeta( _rxConnection ); + + Reference< XNameAccess > xTables, xQueries; + try + { + Reference< XTablesSupplier > xSuppTables( _rxConnection, UNO_QUERY_THROW ); + Reference< XQueriesSupplier > xQueriesSupplier( _rxConnection, UNO_QUERY_THROW ); + xTables.set( xSuppTables->getTables(), css::uno::UNO_SET_THROW ); + xQueries.set( xQueriesSupplier->getQueries(), css::uno::UNO_SET_THROW ); + } + catch( const Exception& ) + { + throw IllegalArgumentException( + DBA_RES( STR_CONN_WITHOUT_QUERIES_OR_TABLES ), + nullptr, + 0 + ); + } + + PNameValidation pTableCheck = std::make_shared( _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 000000000..439db0967 --- /dev/null +++ b/dbaccess/source/sdbtools/connection/objectnames.hxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#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 000000000..132484a24 --- /dev/null +++ b/dbaccess/source/sdbtools/connection/tablename.cxx @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "tablename.hxx" +#include +#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 + struct TableName_Impl + { + OUString sCatalog; + OUString sSchema; + OUString sName; + }; + + // TableName + TableName::TableName( const Reference& _rContext, const Reference< XConnection >& _rxConnection ) + :ConnectionDependentComponent( _rContext ) + ,m_pImpl( new TableName_Impl ) + { + setWeakConnection( _rxConnection ); + } + + TableName::~TableName() + { + } + + OUString SAL_CALL TableName::getCatalogName() + { + EntryGuard aGuard( *this ); + return m_pImpl->sCatalog; + } + + void SAL_CALL TableName::setCatalogName( const OUString& _catalogName ) + { + EntryGuard aGuard( *this ); + m_pImpl->sCatalog = _catalogName; + } + + OUString SAL_CALL TableName::getSchemaName() + { + EntryGuard aGuard( *this ); + return m_pImpl->sSchema; + } + + void SAL_CALL TableName::setSchemaName( const OUString& _schemaName ) + { + EntryGuard aGuard( *this ); + m_pImpl->sSchema = _schemaName; + } + + OUString SAL_CALL TableName::getTableName() + { + EntryGuard aGuard( *this ); + return m_pImpl->sName; + } + + void SAL_CALL TableName::setTableName( const OUString& _tableName ) + { + EntryGuard aGuard( *this ); + m_pImpl->sName = _tableName; + } + + OUString SAL_CALL TableName::getNameForSelect() + { + EntryGuard aGuard( *this ); + return composeTableNameForSelect( getConnection(), m_pImpl->sCatalog, m_pImpl->sSchema, m_pImpl->sName ); + } + + Reference< XPropertySet > SAL_CALL TableName::getTable() + { + EntryGuard aGuard( *this ); + + Reference< XTablesSupplier > xSuppTables( getConnection(), UNO_QUERY_THROW ); + Reference< XNameAccess > xTables( xSuppTables->getTables(), css::uno::UNO_SET_THROW ); + + Reference< XPropertySet > xTable; + try + { + xTable.set( xTables->getByName( getComposedName( CompositionType::Complete, false ) ), UNO_QUERY_THROW ); + } + catch( const WrappedTargetException& ) + { + throw NoSuchElementException(); + } + catch( const RuntimeException& ) { throw; } + catch( const NoSuchElementException& ) { throw; } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + throw NoSuchElementException(); + } + + return xTable; + } + + void SAL_CALL TableName::setTable( const Reference< XPropertySet >& _table ) + { + EntryGuard aGuard( *this ); + + Reference< XPropertySetInfo > xPSI( _table, UNO_QUERY ); + if ( !xPSI.is() + || !xPSI->hasPropertyByName( PROPERTY_CATALOGNAME ) + || !xPSI->hasPropertyByName( PROPERTY_SCHEMANAME ) + || !xPSI->hasPropertyByName( PROPERTY_NAME ) + ) + throw IllegalArgumentException( + DBA_RES( STR_NO_TABLE_OBJECT ), + *this, + 0 + ); + + try + { + OSL_VERIFY( _table->getPropertyValue( PROPERTY_CATALOGNAME ) >>= m_pImpl->sCatalog ); + OSL_VERIFY( _table->getPropertyValue( PROPERTY_SCHEMANAME ) >>= m_pImpl->sSchema ); + OSL_VERIFY( _table->getPropertyValue( PROPERTY_NAME ) >>= m_pImpl->sName ); + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& e ) + { + throw IllegalArgumentException( e.Message, e.Context, 0 ); + } + } + + namespace + { + /** translates a CompositionType into an EComposeRule + @throws IllegalArgumentException + if the given value does not denote a valid CompositionType + */ + EComposeRule lcl_translateCompositionType_throw( sal_Int32 _nType ) + { + static const struct + { + sal_Int32 nCompositionType; + EComposeRule eComposeRule; + } TypeTable[] = + { + { CompositionType::ForTableDefinitions, EComposeRule::InTableDefinitions }, + { CompositionType::ForIndexDefinitions, EComposeRule::InIndexDefinitions }, + { CompositionType::ForDataManipulation, EComposeRule::InDataManipulation }, + { CompositionType::ForProcedureCalls, EComposeRule::InProcedureCalls }, + { CompositionType::ForPrivilegeDefinitions, EComposeRule::InPrivilegeDefinitions }, + { CompositionType::Complete, EComposeRule::Complete } + }; + + bool found = false; + size_t i = 0; + for ( ; i < SAL_N_ELEMENTS( TypeTable ) && !found; ++i ) + if ( TypeTable[i].nCompositionType == _nType ) + found = true; + if ( !found ) + throw IllegalArgumentException( + DBA_RES( STR_INVALID_COMPOSITION_TYPE ), + nullptr, + 0 + ); + + return TypeTable[i].eComposeRule; + } + } + + OUString SAL_CALL TableName::getComposedName( ::sal_Int32 Type, sal_Bool Quote ) + { + EntryGuard aGuard( *this ); + + return composeTableName( + getConnection()->getMetaData(), + m_pImpl->sCatalog, m_pImpl->sSchema, m_pImpl->sName, Quote, + lcl_translateCompositionType_throw( Type ) ); + } + + void SAL_CALL TableName::setComposedName( const OUString& ComposedName, ::sal_Int32 Type ) + { + EntryGuard aGuard( *this ); + + qualifiedNameComponents( + getConnection()->getMetaData(), + ComposedName, + m_pImpl->sCatalog, m_pImpl->sSchema, m_pImpl->sName, + lcl_translateCompositionType_throw( Type ) ); + } + +} // namespace sdbtools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/sdbtools/connection/tablename.hxx b/dbaccess/source/sdbtools/connection/tablename.hxx new file mode 100644 index 000000000..3a7ece21a --- /dev/null +++ b/dbaccess/source/sdbtools/connection/tablename.hxx @@ -0,0 +1,84 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include + +#include + +namespace sdbtools +{ + + // TableName + typedef ::cppu::WeakImplHelper< css::sdb::tools::XTableName + > TableName_Base; + struct TableName_Impl; + /** default implementation for XTableName + */ + class TableName :public TableName_Base + ,public ConnectionDependentComponent + { + private: + std::unique_ptr< TableName_Impl > m_pImpl; + + public: + /** constructs the instance + + @param _rContext + the component's context + @param _rxConnection + the connection to work with. Will be held weak. Must not be . + + @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; + }; + +} // namespace sdbtools + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/sdbtools/inc/connectiondependent.hxx b/dbaccess/source/sdbtools/inc/connectiondependent.hxx new file mode 100644 index 000000000..d315d7018 --- /dev/null +++ b/dbaccess/source/sdbtools/inc/connectiondependent.hxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#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( const css::uno::Reference< css::uno::XComponentContext > & _rContext ) + :m_aContext( _rContext ) + { + } + + /** sets the connection we depend on. + + To be called exactly once. + + @param _rxConnection + the connection to set + */ + void setWeakConnection( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection ) + { + m_aConnection = _rxConnection; + } + + const css::uno::Reference< css::sdbc::XConnection >& + getConnection() const { return m_xConnection; } + + public: + struct GuardAccess; + friend struct GuardAccess; + /** helper for granting exclusive access to various other methods + */ + struct GuardAccess { friend class EntryGuard; private: GuardAccess() { } }; + + ::osl::Mutex& getMutex( GuardAccess ) const { return m_aMutex; } + + bool acquireConnection( GuardAccess ) + { + m_xConnection.set(m_aConnection); + return m_xConnection.is(); + } + void releaseConnection( GuardAccess ) + { + m_xConnection.clear(); + } + }; + + // ConnectionDependentComponent::EntryGuard + /** a class for guarding methods of a connection-dependent component + + This class serves multiple purposes: +

  • 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 000000000..a3dd610f8 --- /dev/null +++ b/dbaccess/source/sdbtools/inc/connectiontools.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 "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; + + // XServiceInfo - static versions + static OUString getImplementationName_static(); + static css::uno::Sequence< OUString > getSupportedServiceNames_static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::uno::XComponentContext >&); + + // 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/sdbtools/misc/sdbt_services.cxx b/dbaccess/source/sdbtools/misc/sdbt_services.cxx new file mode 100644 index 000000000..5023e9fcc --- /dev/null +++ b/dbaccess/source/sdbtools/misc/sdbt_services.cxx @@ -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 . + */ + +#include + +#include +#include +#include + +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::XInterface; + +extern "C" SAL_DLLPUBLIC_EXPORT void* sdbt_component_getFactory( + const char* pImplementationName, SAL_UNUSED_PARAMETER void*, SAL_UNUSED_PARAMETER void*) +{ + Reference< XInterface > xRet; + + if (sdbtools::ConnectionTools::getImplementationName_static() == OUString::createFromAscii(pImplementationName)) + { + xRet = ::cppu::createSingleComponentFactory(sdbtools::ConnectionTools::Create, + sdbtools::ConnectionTools::getImplementationName_static(), + sdbtools::ConnectionTools::getSupportedServiceNames_static(), nullptr); + } + + if (xRet.is()) + xRet->acquire(); + return xRet.get(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/shared/dbu_reghelper.cxx b/dbaccess/source/shared/dbu_reghelper.cxx new file mode 100644 index 000000000..c70793936 --- /dev/null +++ b/dbaccess/source/shared/dbu_reghelper.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 +{ + + #define REGISTRATIONHELPER_CXX_INCLUDED_INDIRECTLY_ + #include "registrationhelper.cxx" + #undef REGISTRATIONHELPER_CXX_INCLUDED_INDIRECTLY_ + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/shared/flt_reghelper.cxx b/dbaccess/source/shared/flt_reghelper.cxx new file mode 100644 index 000000000..c41947f82 --- /dev/null +++ b/dbaccess/source/shared/flt_reghelper.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 dbaxml +{ + + #define REGISTRATIONHELPER_CXX_INCLUDED_INDIRECTLY_ + #include "registrationhelper.cxx" + #undef REGISTRATIONHELPER_CXX_INCLUDED_INDIRECTLY_ + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/shared/registrationhelper.cxx b/dbaccess/source/shared/registrationhelper.cxx new file mode 100644 index 000000000..2c9fbc1f1 --- /dev/null +++ b/dbaccess/source/shared/registrationhelper.cxx @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// be included in other cxx files + +#ifndef REGISTRATIONHELPER_CXX_INCLUDED_INDIRECTLY_ +#error "don't build this file directly! use dbu_reghelper.cxx instead!" +#endif + +using namespace ::com::sun::star; +using namespace ::comphelper; +using namespace ::cppu; + +uno::Sequence< OUString >* OModuleRegistration::s_pImplementationNames = nullptr; +uno::Sequence< uno::Sequence< OUString > >* OModuleRegistration::s_pSupportedServices = nullptr; +uno::Sequence< sal_Int64 >* OModuleRegistration::s_pCreationFunctionPointers = nullptr; +uno::Sequence< sal_Int64 >* OModuleRegistration::s_pFactoryFunctionPointers = nullptr; + +void OModuleRegistration::registerComponent( + const OUString& _rImplementationName, + const uno::Sequence< OUString >& _rServiceNames, + ComponentInstantiation _pCreateFunction, + FactoryInstantiation _pFactoryFunction) +{ + if (!s_pImplementationNames) + { + OSL_ENSURE(!s_pSupportedServices && !s_pCreationFunctionPointers && !s_pFactoryFunctionPointers, + "OModuleRegistration::registerComponent : inconsistent state (the pointers (1)) !"); + s_pImplementationNames = new uno::Sequence< OUString >; + s_pSupportedServices = new uno::Sequence< uno::Sequence< OUString > >; + s_pCreationFunctionPointers = new uno::Sequence< sal_Int64 >; + s_pFactoryFunctionPointers = new uno::Sequence< sal_Int64 >; + } + OSL_ENSURE(s_pImplementationNames && s_pSupportedServices && s_pCreationFunctionPointers && s_pFactoryFunctionPointers, + "OModuleRegistration::registerComponent : inconsistent state (the pointers (2)) !"); + + OSL_ENSURE( (s_pImplementationNames->getLength() == s_pSupportedServices->getLength()) + && (s_pImplementationNames->getLength() == s_pCreationFunctionPointers->getLength()) + && (s_pImplementationNames->getLength() == s_pFactoryFunctionPointers->getLength()), + "OModuleRegistration::registerComponent : inconsistent state !"); + + sal_Int32 nOldLen = s_pImplementationNames->getLength(); + s_pImplementationNames->realloc(nOldLen + 1); + s_pSupportedServices->realloc(nOldLen + 1); + s_pCreationFunctionPointers->realloc(nOldLen + 1); + s_pFactoryFunctionPointers->realloc(nOldLen + 1); + + s_pImplementationNames->getArray()[nOldLen] = _rImplementationName; + s_pSupportedServices->getArray()[nOldLen] = _rServiceNames; + s_pCreationFunctionPointers->getArray()[nOldLen] = reinterpret_cast(_pCreateFunction); + s_pFactoryFunctionPointers->getArray()[nOldLen] = reinterpret_cast(_pFactoryFunction); +} + +void OModuleRegistration::revokeComponent(const OUString& _rImplementationName) +{ + if (!s_pImplementationNames) + { + OSL_FAIL("OModuleRegistration::revokeComponent : have no class infos ! Are you sure called this method at the right time ?"); + return; + } + OSL_ENSURE(s_pImplementationNames && s_pSupportedServices && s_pCreationFunctionPointers && s_pFactoryFunctionPointers, + "OModuleRegistration::revokeComponent : inconsistent state (the pointers) !"); + OSL_ENSURE( (s_pImplementationNames->getLength() == s_pSupportedServices->getLength()) + && (s_pImplementationNames->getLength() == s_pCreationFunctionPointers->getLength()) + && (s_pImplementationNames->getLength() == s_pFactoryFunctionPointers->getLength()), + "OModuleRegistration::revokeComponent : inconsistent state !"); + + sal_Int32 nLen = s_pImplementationNames->getLength(); + const OUString* pImplNames = s_pImplementationNames->getConstArray(); + for (sal_Int32 i=0; igetLength() == 0) + { + delete s_pImplementationNames; s_pImplementationNames = nullptr; + delete s_pSupportedServices; s_pSupportedServices = nullptr; + delete s_pCreationFunctionPointers; s_pCreationFunctionPointers = nullptr; + delete s_pFactoryFunctionPointers; s_pFactoryFunctionPointers = nullptr; + } +} + +uno::Reference< uno::XInterface > OModuleRegistration::getComponentFactory( + const OUString& _rImplementationName, + const uno::Reference< lang::XMultiServiceFactory >& _rxServiceManager) +{ + OSL_ENSURE(_rxServiceManager.is(), "OModuleRegistration::getComponentFactory : invalid argument (service manager) !"); + OSL_ENSURE(!_rImplementationName.isEmpty(), "OModuleRegistration::getComponentFactory : invalid argument (implementation name) !"); + + if (!s_pImplementationNames) + { + OSL_FAIL("OModuleRegistration::getComponentFactory : have no class infos ! Are you sure called this method at the right time ?"); + return nullptr; + } + OSL_ENSURE(s_pImplementationNames && s_pSupportedServices && s_pCreationFunctionPointers && s_pFactoryFunctionPointers, + "OModuleRegistration::getComponentFactory : inconsistent state (the pointers) !"); + OSL_ENSURE( (s_pImplementationNames->getLength() == s_pSupportedServices->getLength()) + && (s_pImplementationNames->getLength() == s_pCreationFunctionPointers->getLength()) + && (s_pImplementationNames->getLength() == s_pFactoryFunctionPointers->getLength()), + "OModuleRegistration::getComponentFactory : inconsistent state !"); + + uno::Reference< uno::XInterface > xReturn; + + sal_Int32 nLen = s_pImplementationNames->getLength(); + const OUString* pImplName = s_pImplementationNames->getConstArray(); + const uno::Sequence< OUString >* pServices = s_pSupportedServices->getConstArray(); + const sal_Int64* pComponentFunction = s_pCreationFunctionPointers->getConstArray(); + const sal_Int64* pFactoryFunction = s_pFactoryFunctionPointers->getConstArray(); + + for (sal_Int32 i=0; i(*pFactoryFunction); + const ComponentInstantiation ComponentInstantiationFunction = reinterpret_cast(*pComponentFunction); + + xReturn = FactoryInstantiationFunction( _rxServiceManager, *pImplName, ComponentInstantiationFunction, *pServices, nullptr); + if (xReturn.is()) + { + return xReturn.get(); + } + } + } + + return nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppController.cxx b/dbaccess/source/ui/app/AppController.cxx new file mode 100644 index 000000000..402880eed --- /dev/null +++ b/dbaccess/source/ui/app/AppController.cxx @@ -0,0 +1,2809 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "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 + +#include +#include "AppView.hxx" +#include +#include +#include +#include +#include +#include "AppDetailView.hxx" +#include +#include +#include +#include +#include + +extern "C" void createRegistryInfo_ODBApplication() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OApplicationController > aAutoRegistration; +} + +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 getImplementationName_Static(); +} + +OUString OApplicationController::getImplementationName_Static() +{ + return SERVICE_SDB_APPLICATIONCONTROLLER; +} + +Sequence< OUString> OApplicationController::getSupportedServiceNames_Static() +{ + Sequence aSupported { "com.sun.star.sdb.application.DefaultViewController" }; + return aSupported; +} + +Sequence< OUString> SAL_CALL OApplicationController::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference< XInterface > OApplicationController::Create(const Reference& _rxFactory) +{ + return *(new OApplicationController( comphelper::getComponentContext(_rxFactory))); +} + +namespace { + +class SelectionGuard; + +} + +// OApplicationController +class SelectionNotifier +{ +private: + ::comphelper::OInterfaceContainerHelper2 m_aSelectionListeners; + ::cppu::OWeakObject& m_rContext; + sal_Int32 m_nSelectionNestingLevel; + +public: + SelectionNotifier( ::osl::Mutex& _rMutex, ::cppu::OWeakObject& _rContext ) + :m_aSelectionListeners( _rMutex ) + ,m_rContext( _rContext ) + ,m_nSelectionNestingLevel( 0 ) + { + } + + SelectionNotifier(const SelectionNotifier&) = delete; + const SelectionNotifier& operator=(const SelectionNotifier&) = delete; + + void addListener( const Reference< XSelectionChangeListener >& Listener ) + { + m_aSelectionListeners.addInterface( Listener ); + } + + void removeListener( const Reference< XSelectionChangeListener >& Listener ) + { + m_aSelectionListeners.removeInterface( Listener ); + } + + void disposing() + { + EventObject aEvent( m_rContext ); + m_aSelectionListeners.disposeAndClear( aEvent ); + } + + struct SelectionGuardAccess { friend SelectionGuard; private: SelectionGuardAccess() { } }; + + /** enters a block which modifies the selection of our owner. + + Can be called multiple times, the only important thing is to call leaveSelection + equally often. + */ + void enterSelection( SelectionGuardAccess ) + { + ++m_nSelectionNestingLevel; + } + + /** leaves a block which modifies the selection of our owner + + Must be paired with enterSelection calls. + + When the last block is left, i.e. the last leaveSelection call is made on the current stack, + then our SelectionChangeListeners are notified + */ + void leaveSelection( SelectionGuardAccess ) + { + if ( --m_nSelectionNestingLevel == 0 ) + { + EventObject aEvent( m_rContext ); + m_aSelectionListeners.notifyEach( &XSelectionChangeListener::selectionChanged, aEvent ); + } + } +}; + +namespace { + +class SelectionGuard +{ +public: + explicit SelectionGuard( SelectionNotifier& _rNotifier ) + :m_rNotifier( _rNotifier ) + { + m_rNotifier.enterSelection( SelectionNotifier::SelectionGuardAccess() ); + } + + ~SelectionGuard() + { + m_rNotifier.leaveSelection( SelectionNotifier::SelectionGuardAccess() ); + } + + SelectionGuard(const SelectionGuard&) = delete; + const SelectionGuard& operator=(const SelectionGuard&) = delete; + +private: + SelectionNotifier& m_rNotifier; +}; + +} + +// OApplicationController +OApplicationController::OApplicationController(const Reference< XComponentContext >& _rxORB) + :OGenericUnoController( _rxORB ) + ,m_aContextMenuInterceptors( getMutex() ) + ,m_pSubComponentManager( new SubComponentManager( *this, getSharedMutex() ) ) + ,m_aTypeCollection( _rxORB ) + ,m_aTableCopyHelper(this) + ,m_nAsyncDrop(nullptr) + ,m_aSelectContainerEvent( LINK( this, OApplicationController, OnSelectContainer ) ) + ,m_ePreviewMode(E_PREVIEWNONE) + ,m_eCurrentType(E_NONE) + ,m_bNeedToReconnect(false) + ,m_bSuspended( false ) + ,m_pSelectionNotifier( new SelectionNotifier( getMutex(), *this ) ) +{ +} + +OApplicationController::~OApplicationController() +{ + if ( !rBHelper.bDisposed && !rBHelper.bInDispose ) + { + OSL_FAIL("Please check who doesn't dispose this component!"); + // increment ref count to prevent double call of Dtor + osl_atomic_increment( &m_refCount ); + dispose(); + } + clearView(); +} + +IMPLEMENT_FORWARD_XTYPEPROVIDER2(OApplicationController,OGenericUnoController,OApplicationController_Base) +IMPLEMENT_FORWARD_XINTERFACE2(OApplicationController,OGenericUnoController,OApplicationController_Base) +void OApplicationController::disconnect() +{ + if ( m_xDataSourceConnection.is() ) + stopConnectionListening( m_xDataSourceConnection ); + + try + { + // temporary (hopefully!) hack for #i55274# + Reference< XFlushable > xFlush( m_xDataSourceConnection, UNO_QUERY ); + if ( xFlush.is() && m_xMetaData.is() && !m_xMetaData->isReadOnly() ) + xFlush->flush(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_xDataSourceConnection.clear(); + m_xMetaData.clear(); + + InvalidateAll(); +} + +void SAL_CALL OApplicationController::disposing() +{ + for( const auto& rContainerListener : m_aCurrentContainers ) + { + if( rContainerListener.is() ) + { + rContainerListener->removeContainerListener( this ); + } + } + + m_aCurrentContainers.clear(); + m_pSubComponentManager->disposing(); + m_pSelectionNotifier->disposing(); + + if ( getView() ) + { + getContainer()->showPreview(nullptr); + m_pClipboardNotifier->ClearCallbackLink(); + m_pClipboardNotifier->RemoveListener( getView() ); + m_pClipboardNotifier.clear(); + } + + disconnect(); + try + { + Reference < XFrame > xFrame; + attachFrame( xFrame ); + + if ( m_xDataSource.is() ) + { + m_xDataSource->removePropertyChangeListener(OUString(), this); + m_xDataSource->removePropertyChangeListener(PROPERTY_INFO, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_URL, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_ISPASSWORDREQUIRED, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_LAYOUTINFORMATION, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_SUPPRESSVERSIONCL, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_TABLEFILTER, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_TABLETYPEFILTER, this); + m_xDataSource->removePropertyChangeListener(PROPERTY_USER, this); + m_xDataSource = nullptr; + } + + Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY ); + if ( xBroadcaster.is() ) + xBroadcaster->removeModifyListener(static_cast(this)); + + if ( m_xModel.is() ) + { + OUString sUrl = m_xModel->getURL(); + if ( !sUrl.isEmpty() ) + { + ::comphelper::NamedValueCollection aArgs( m_xModel->getArgs() ); + if ( aArgs.getOrDefault( "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( ePICKLIST, + aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ), + aFilter, + getStrippedDatabaseName(), + 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_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 const char s_sReportDesign[] = "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() == E_PREVIEWNONE; + break; + case SID_DB_APP_VIEW_DOCINFO_PREVIEW: + { + ElementType eType = getContainer()->getElementType(); + aReturn.bEnabled = (E_REPORT == eType || E_FORM == eType); + aReturn.bChecked = getContainer()->getPreviewMode() == E_DOCUMENTINFO; + } + break; + case SID_DB_APP_VIEW_DOC_PREVIEW: + aReturn.bEnabled = true; + aReturn.bChecked = getContainer()->getPreviewMode() == E_DOCUMENT; + break; + case ID_BROWSER_UNDO: + aReturn.bEnabled = false; + break; + case SID_MAIL_SENDDOC: + aReturn.bEnabled = true; + break; + case SID_DB_APP_SENDREPORTASMAIL: + { + ElementType eType = getContainer()->getElementType(); + aReturn.bEnabled = E_REPORT == eType && getContainer()->getSelectionCount() > 0 && getContainer()->isALeafSelected(); + } + break; + case SID_DB_APP_SENDREPORTTOWRITER: + case SID_DB_APP_DBADMIN: + aReturn.bEnabled = false; + break; + case SID_DB_APP_STATUS_TYPE: + aReturn.bEnabled = m_xDataSource.is(); + if ( aReturn.bEnabled ) + { + OUString sURL; + m_xDataSource->getPropertyValue(PROPERTY_URL) >>= sURL; + OUString sDSTypeName; + if ( dbaccess::ODsnTypeCollection::isEmbeddedDatabase( sURL ) ) + { + sDSTypeName = DBA_RES(RID_STR_EMBEDDED_DATABASE); + } + else + { + sDSTypeName = m_aTypeCollection.getTypeDisplayName(sURL); + } + aReturn.sTitle = sDSTypeName; + } + break; + case SID_DB_APP_STATUS_DBNAME: + aReturn.bEnabled = m_xDataSource.is(); + if ( aReturn.bEnabled ) + { + OUString sURL; + m_xDataSource->getPropertyValue(PROPERTY_URL) >>= sURL; + OUString sDatabaseName; + OUString sHostName; + sal_Int32 nPortNumber( -1 ); + + m_aTypeCollection.extractHostNamePort( sURL, sDatabaseName, sHostName, nPortNumber ); + + if ( sDatabaseName.isEmpty() ) + sDatabaseName = m_aTypeCollection.cutPrefix( sURL ); + if ( m_aTypeCollection.isFileSystemBased(sURL) ) + { + sDatabaseName = SvtPathOptions().SubstituteVariable( sDatabaseName ); + if ( !sDatabaseName.isEmpty() ) + { + ::svt::OFileNotation aFileNotation(sDatabaseName); + // set this decoded URL as text + sDatabaseName = aFileNotation.get(::svt::OFileNotation::N_SYSTEM); + } + } + + if ( sDatabaseName.isEmpty() ) + sDatabaseName = m_aTypeCollection.getTypeDisplayName( sURL ); + + aReturn.sTitle = sDatabaseName; + } + break; + case SID_DB_APP_STATUS_USERNAME: + aReturn.bEnabled = m_xDataSource.is(); + if ( aReturn.bEnabled ) + m_xDataSource->getPropertyValue( PROPERTY_USER ) >>= aReturn.sTitle; + break; + case SID_DB_APP_STATUS_HOSTNAME: + aReturn.bEnabled = m_xDataSource.is(); + if ( aReturn.bEnabled ) + { + OUString sURL; + m_xDataSource->getPropertyValue( PROPERTY_URL ) >>= sURL; + + OUString sHostName, sDatabaseName; + sal_Int32 nPortNumber = -1; + m_aTypeCollection.extractHostNamePort( sURL, sDatabaseName, sHostName, nPortNumber ); + aReturn.sTitle = sHostName; + } + break; + default: + aReturn = OGenericUnoController::GetState(_nId); + } + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return aReturn; +} + +namespace +{ + bool lcl_handleException_nothrow( const Reference< XModel >& _rxDocument, const Any& _rException ) + { + bool bHandled = false; + + // try handling the error with an interaction handler + ::comphelper::NamedValueCollection aArgs( _rxDocument->getArgs() ); + Reference< XInteractionHandler > xHandler( aArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) ); + if ( xHandler.is() ) + { + rtl::Reference pRequest( new ::comphelper::OInteractionRequest( _rException ) ); + rtl::Reference pApprove( new ::comphelper::OInteractionApprove ); + pRequest->addContinuation( pApprove.get() ); + + try + { + xHandler->handle( pRequest.get() ); + } + 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_uLong nTmp; + if ( pIter->Value >>= nTmp ) + pasteFormat(static_cast(nTmp)); + break; + } + } + } + } + break; + case SID_OPENDOC: + { + Reference < XDispatchProvider > xProv( getFrame(), UNO_QUERY ); + if ( xProv.is() ) + { + URL aURL; + aURL.Complete = ".uno:Open"; + + if ( m_xUrlTransformer.is() ) + m_xUrlTransformer->parseStrict( aURL ); + Reference < XDispatch > xDisp = xProv->queryDispatch( aURL, OUString(), 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(); + if ( sUrl.isEmpty() ) + sUrl = SvtPathOptions().GetWorkPath(); + + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, getFrameWeld()); + 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( OUString(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 ); + insertHierachyElement(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( OUString(PROPERTY_GRAPHICAL_DESIGN), ID_NEW_VIEW_DESIGN == _nId ); + + const Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY ); + const Reference< XComponent > xComponent = aDesigner.createNew( xDataSource, aCreationArgs ); + onDocumentOpened( OUString(), E_QUERY, E_OPEN_DESIGN, xComponent, nullptr ); + } + } + break; + case SID_DB_APP_DELETE: + case SID_DB_APP_TABLE_DELETE: + case SID_DB_APP_QUERY_DELETE: + case SID_DB_APP_FORM_DELETE: + case SID_DB_APP_REPORT_DELETE: + deleteEntries(); + break; + case SID_DB_APP_RENAME: + case SID_DB_APP_TABLE_RENAME: + case SID_DB_APP_QUERY_RENAME: + case SID_DB_APP_FORM_RENAME: + case SID_DB_APP_REPORT_RENAME: + renameEntry(); + break; + case SID_DB_APP_EDIT: + case SID_DB_APP_EDIT_SQL_VIEW: + case SID_DB_APP_TABLE_EDIT: + case SID_DB_APP_QUERY_EDIT: + case SID_DB_APP_FORM_EDIT: + case SID_DB_APP_REPORT_EDIT: + doAction( _nId, E_OPEN_DESIGN ); + break; + case SID_DB_APP_OPEN: + case SID_DB_APP_TABLE_OPEN: + case SID_DB_APP_QUERY_OPEN: + case SID_DB_APP_FORM_OPEN: + case SID_DB_APP_REPORT_OPEN: + doAction( _nId, E_OPEN_NORMAL ); + break; + case SID_DB_APP_CONVERTTOVIEW: + doAction( _nId, E_OPEN_NORMAL ); + break; + case SID_SELECTALL: + getContainer()->selectAll(); + InvalidateAll(); + break; + case SID_DB_APP_DSRELDESIGN: + { + Reference< XComponent > xRelationDesigner; + if ( !m_pSubComponentManager->activateSubFrame( OUString(), SID_DB_APP_DSRELDESIGN, E_OPEN_DESIGN, xRelationDesigner ) ) + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + { + RelationDesigner aDesigner( getORB(), this, m_aCurrentFrame.getFrame() ); + + const Reference< XDataSource > xDataSource( m_xDataSource, UNO_QUERY ); + const Reference< XComponent > xComponent = aDesigner.createNew( xDataSource ); + onDocumentOpened( OUString(), SID_DB_APP_DSRELDESIGN, E_OPEN_DESIGN, xComponent, nullptr ); + } + } + } + break; + case SID_DB_APP_DSUSERADMIN: + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + openDialog("com.sun.star.sdb.UserAdministrationDialog"); + } + break; + case SID_DB_APP_TABLEFILTER: + // opens the table filter dialog for the selected data source + openDialog( "com.sun.star.sdb.TableFilterDialog" ); + askToReconnect(); + break; + case SID_DB_APP_REFRESH_TABLES: + refreshTables(); + break; + case SID_DB_APP_DSPROPS: + // opens the administration dialog for the selected data source + openDialog( "com.sun.star.sdb.DatasourceAdministrationDialog" ); + askToReconnect(); + break; + case SID_DB_APP_DSADVANCED_SETTINGS: + openDialog("com.sun.star.sdb.AdvancedDatabaseSettingsDialog"); + askToReconnect(); + break; + case SID_DB_APP_DSCONNECTION_TYPE: + openDialog("com.sun.star.sdb.DataSourceTypeChangeDialog"); + askToReconnect(); + break; + case ID_DIRECT_SQL: + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + // opens the DirectSQLDialog to execute hand made sql statements. + openDialog( SERVICE_SDB_DIRECTSQLDIALOG ); + } + break; + case SID_DB_APP_VIEW_TABLES: + m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_TABLE ) ); + break; + case SID_DB_APP_VIEW_QUERIES: + m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_QUERY ) ); + break; + case SID_DB_APP_VIEW_FORMS: + m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_FORM ) ); + break; + case SID_DB_APP_VIEW_REPORTS: + m_aSelectContainerEvent.Call( reinterpret_cast< void* >( E_REPORT ) ); + break; + case SID_DB_APP_DISABLE_PREVIEW: + m_ePreviewMode = E_PREVIEWNONE; + getContainer()->switchPreview(m_ePreviewMode); + break; + case SID_DB_APP_VIEW_DOCINFO_PREVIEW: + m_ePreviewMode = E_DOCUMENTINFO; + getContainer()->switchPreview(m_ePreviewMode); + break; + case SID_DB_APP_VIEW_DOC_PREVIEW: + m_ePreviewMode = E_DOCUMENT; + getContainer()->switchPreview(m_ePreviewMode); + break; + case SID_MAIL_SENDDOC: + { + SfxMailModel aSendMail; + if ( aSendMail.AttachDocument(getModel(), OUString()) == SfxMailModel::SEND_MAIL_OK ) + aSendMail.Send( getFrame() ); + } + break; + case SID_DB_APP_SENDREPORTASMAIL: + doAction( _nId, E_OPEN_FOR_MAIL ); + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + InvalidateFeature(_nId); +} + +void OApplicationController::describeSupportedFeatures() +{ + OGenericUnoController::describeSupportedFeatures(); + + implDescribeSupportedFeature( ".uno: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); + OUString sNewName; + + ElementType eType = getElementType(xContainer); + switch( eType ) + { + case E_TABLE: + { + ensureConnection(); + if ( xProp.is() && m_xMetaData.is() ) + sNewName = ::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( SvTreeListBox const & _rTree ) +{ + if ( getContainer() && getContainer()->isLeaf( _rTree.GetHdlEntry() ) ) + { + try + { + // opens a new frame with either the table or the query or report or form or view + openElementWithArguments( + getContainer()->getQualifiedName( _rTree.GetHdlEntry() ), + getContainer()->getElementType(), + E_OPEN_NORMAL, + 0, + ::comphelper::NamedValueCollection() ); + return true; // handled + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + return false; // not handled +} + +bool OApplicationController::impl_isAlterableView_nothrow( const OUString& _rTableOrViewName ) const +{ + OSL_PRECOND( m_xDataSourceConnection.is(), "OApplicationController::impl_isAlterableView_nothrow: no connection!" ); + + bool bIsAlterableView( false ); + try + { + Reference< XViewsSupplier > xViewsSupp( m_xDataSourceConnection, UNO_QUERY ); + Reference< XNameAccess > xViews; + if ( xViewsSupp.is() ) + xViews = xViewsSupp->getViews(); + + Reference< XAlterView > xAsAlterableView; + if ( xViews.is() && xViews->hasByName( _rTableOrViewName ) ) + xAsAlterableView.set( xViews->getByName( _rTableOrViewName ), UNO_QUERY ); + + bIsAlterableView = xAsAlterableView.is(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bIsAlterableView; +} + +Reference< XComponent > OApplicationController::openElementWithArguments( const OUString& _sName, ElementType _eType, + ElementOpenMode _eOpenMode, sal_uInt16 _nInstigatorCommand, const ::comphelper::NamedValueCollection& _rAdditionalArguments ) +{ + OSL_PRECOND( getContainer(), "OApplicationController::openElementWithArguments: no view!" ); + if ( !getContainer() ) + return nullptr; + + Reference< XComponent > xRet; + if ( _eOpenMode == E_OPEN_DESIGN ) + { + // https://bz.apache.org/ooo/show_bug.cgi?id=30382 + getContainer()->showPreview(nullptr); + } + + bool isStandaloneDocument = false; + switch ( _eType ) + { + case E_REPORT: + if ( _eOpenMode != E_OPEN_DESIGN ) + { + // reports which are opened in a mode other than design are no sub components of our application + // component, but standalone documents. + isStandaloneDocument = true; + } + [[fallthrough]]; + case E_FORM: + { + if ( isStandaloneDocument || !m_pSubComponentManager->activateSubFrame( _sName, _eType, _eOpenMode, xRet ) ) + { + std::unique_ptr< OLinkedDocumentsAccess > aHelper = getDocumentsAccess( _eType ); + if ( !aHelper->isConnected() ) + break; + + Reference< XComponent > xDefinition; + xRet = aHelper->open( _sName, xDefinition, _eOpenMode, _rAdditionalArguments ); + + if ( !isStandaloneDocument ) + onDocumentOpened( _sName, _eType, _eOpenMode, xRet, xDefinition ); + } + } + break; + + case E_QUERY: + case E_TABLE: + { + if ( !m_pSubComponentManager->activateSubFrame( _sName, _eType, _eOpenMode, xRet ) ) + { + SharedConnection xConnection( ensureConnection() ); + if ( !xConnection.is() ) + break; + + std::unique_ptr< DatabaseObjectView > pDesigner; + ::comphelper::NamedValueCollection aArguments( _rAdditionalArguments ); + + Any aDataSource; + if ( _eOpenMode == E_OPEN_DESIGN ) + { + bool bAddViewTypeArg = false; + + if ( _eType == E_TABLE ) + { + if ( impl_isAlterableView_nothrow( _sName ) ) + { + pDesigner.reset( new QueryDesigner( getORB(), this, m_aCurrentFrame.getFrame(), true ) ); + bAddViewTypeArg = true; + } + else + { + pDesigner.reset( new TableDesigner( getORB(), this, m_aCurrentFrame.getFrame() ) ); + } + } + else if ( _eType == E_QUERY ) + { + pDesigner.reset( new QueryDesigner( getORB(), this, m_aCurrentFrame.getFrame(), false ) ); + bAddViewTypeArg = true; + } + aDataSource <<= m_xDataSource; + + if ( bAddViewTypeArg ) + { + const bool bQueryGraphicalMode =( _nInstigatorCommand != SID_DB_APP_EDIT_SQL_VIEW ); + aArguments.put( OUString(PROPERTY_GRAPHICAL_DESIGN), bQueryGraphicalMode ); + } + + } + else + { + pDesigner.reset( new ResultSetBrowser( getORB(), this, m_aCurrentFrame.getFrame(), _eType == E_TABLE ) ); + + if ( !aArguments.has( OUString(PROPERTY_SHOWMENU) ) ) + aArguments.put( OUString(PROPERTY_SHOWMENU), makeAny( 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, E_OPEN_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.get(), 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 == E_PREVIEWNONE ) + return; + + OApplicationView* pView = getContainer(); + if ( !pView ) + return; + + try + { + switch( _eType ) + { + case E_FORM: + case E_REPORT: + { + Reference< XHierarchicalNameAccess > xContainer( getElements( _eType ), UNO_QUERY_THROW ); + Reference< XContent> xContent( xContainer->getByHierarchicalName( _sName ), UNO_QUERY_THROW ); + pView->showPreview( xContent ); + } + break; + + case E_TABLE: + case E_QUERY: + { + SharedConnection xConnection( ensureConnection() ); + if ( xConnection.is() ) + pView->showPreview( getDatabaseName(), xConnection, _sName, _eType == E_TABLE ); + } + return; + + default: + OSL_FAIL( "OApplicationController::showPreviewFor: unexpected element type!" ); + break; + } + } + catch( const SQLException& ) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +IMPL_LINK_NOARG(OApplicationController, OnClipboardChanged, TransferableDataHelper*, void) +{ + OnInvalidateClipboard(); +} + +void OApplicationController::OnInvalidateClipboard() +{ + InvalidateFeature(ID_BROWSER_CUT); + InvalidateFeature(ID_BROWSER_COPY); + InvalidateFeature(ID_BROWSER_PASTE); + InvalidateFeature(SID_DB_APP_PASTE_SPECIAL); +} + +void OApplicationController::onCopyEntry() +{ + Execute(ID_BROWSER_COPY,Sequence()); +} + +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( Control& /*_rControl*/ ) const +{ + return "edit"; +} + +IController& OApplicationController::getCommandController() +{ + return *this; +} + +::comphelper::OInterfaceContainerHelper2* OApplicationController::getContextMenuInterceptors() +{ + return &m_aContextMenuInterceptors; +} + +Any OApplicationController::getCurrentSelection( Control& _rControl ) const +{ + Sequence< NamedDatabaseObject > aSelection; + getContainer()->describeCurrentSelectionForControl( _rControl, aSelection ); + return makeAny( aSelection ); +} + +bool OApplicationController::requestQuickHelp( const SvTreeListEntry* /*_pEntry*/, OUString& /*_rText*/ ) const +{ + return false; +} + +bool OApplicationController::requestDrag( const Point& /*_rPosPixel*/ ) +{ + rtl::Reference pTransfer; + if ( getContainer() && getContainer()->getSelectionCount() ) + { + try + { + pTransfer = copyObject( ); + + if ( pTransfer && getContainer()->getDetailView() ) + { + ElementType eType = getContainer()->getElementType(); + pTransfer->StartDrag( getContainer()->getDetailView()->getTreeWindow(), ((eType == E_FORM || eType == E_REPORT) ? DND_ACTION_COPYMOVE : DND_ACTION_COPY) ); + } + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + return pTransfer.is(); +} + +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() ) + { + ElementType eType = pView->getElementType(); + if ( eType != E_NONE && (eType != E_TABLE || !isConnectionReadOnly()) ) + { + // 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 ) + { + sal_Int8 nAction = OComponentTransferable::canExtractComponentDescriptor(_rFlavors,eType == E_FORM) ? DND_ACTION_COPY : DND_ACTION_NONE; + if ( nAction != DND_ACTION_NONE ) + { + SvTreeListEntry* pHitEntry = pView->getEntry(_rEvt.maPosPixel); + OUString sName; + if ( pHitEntry ) + { + sName = pView->getQualifiedName( pHitEntry ); + 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; + } + } + } + + return DND_ACTION_NONE; +} + +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); + SvTreeListEntry* pHitEntry = pView->getEntry(_rEvt.maPosPixel); + if ( pHitEntry ) + m_aAsyncDrop.aUrl = pView->getQualifiedName( pHitEntry ); + + 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. + ::comphelper::NamedValueCollection aModelArgs( m_xModel->getArgs() ); + if ( aModelArgs.getOrDefault( "SuppressMigrationWarning", false ) ) + return; + + // also, if the document is read-only, then no migration is possible, and the + // respective menu entry is hidden. So, don't show the warning in this case, too. + if ( Reference< XStorable >( m_xModel, UNO_QUERY_THROW )->isReadonly() ) + return; + + SQLWarning aWarning; + aWarning.Message = DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS); + SQLException aDetail; + aDetail.Message = DBA_RES(STR_SUB_DOCS_WITH_SCRIPTS_DETAIL); + aWarning.NextException <<= aDetail; + + Reference< XExecutableDialog > xDialog = ErrorMessageDialog::create( getORB(), "", nullptr, makeAny( aWarning ) ); + xDialog->execute(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void SAL_CALL OApplicationController::attachFrame( const Reference< XFrame > & i_rxFrame ) +{ + SolarMutexGuard aSolarGuard; // avoid deadlock in XModel calls + ::osl::MutexGuard aGuard( getMutex() ); + + OGenericUnoController::attachFrame( i_rxFrame ); + if ( getFrame().is() ) + onAttachedFrame(); +} + +sal_Bool SAL_CALL OApplicationController::attachModel(const Reference< XModel > & _rxModel) +{ + ::osl::MutexGuard aGuard( getMutex() ); + const Reference< XOfficeDatabaseDocument > xOfficeDoc( _rxModel, UNO_QUERY ); + const Reference< XModifiable > xDocModify( _rxModel, UNO_QUERY ); + if ( ( !xOfficeDoc.is() || !xDocModify.is() ) && _rxModel.is() ) + { + OSL_FAIL( "OApplicationController::attachModel: invalid model!" ); + return false; + } + + if ( m_xModel.is() && ( m_xModel != _rxModel ) && ( _rxModel.is() ) ) + { + OSL_ENSURE( false, "OApplicationController::attachModel: missing implementation: setting a new model while we have another one!" ); + // we'd need to completely update our view here, close sub components, and the like + return false; + } + + const OUString aPropertyNames[] = + { + OUString(PROPERTY_URL), OUString(PROPERTY_USER) + }; + + // disconnect from old model + try + { + if ( m_xDataSource.is() ) + { + for (const auto & aPropertyName : aPropertyNames) + { + m_xDataSource->removePropertyChangeListener( aPropertyName, this ); + } + } + + Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY ); + if ( xBroadcaster.is() ) + xBroadcaster->removeModifyListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_xModel = _rxModel; + m_xDataSource.set( xOfficeDoc.is() ? xOfficeDoc->getDataSource() : Reference< XDataSource >(), UNO_QUERY ); + + // connect to new model + try + { + if ( m_xDataSource.is() ) + { + for (const auto & aPropertyName : aPropertyNames) + { + m_xDataSource->addPropertyChangeListener( aPropertyName, this ); + } + } + + Reference< XModifyBroadcaster > xBroadcaster( m_xModel, UNO_QUERY_THROW ); + xBroadcaster->addModifyListener( this ); + + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // initial preview mode + if ( m_xDataSource.is() ) + { + try + { + // to get the 'modified' for the data source + ::comphelper::NamedValueCollection aLayoutInfo( m_xDataSource->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) ); + if ( aLayoutInfo.has( OUString(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[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); + aCurrentSelection[0].Name = getDatabaseName(); + switch ( eType ) + { + case E_TABLE: aCurrentSelection[0].Type = DatabaseObjectContainer::TABLES; break; + case E_QUERY: aCurrentSelection[0].Type = DatabaseObjectContainer::QUERIES; break; + case E_FORM: aCurrentSelection[0].Type = DatabaseObjectContainer::FORMS; break; + case E_REPORT: aCurrentSelection[0].Type = DatabaseObjectContainer::REPORTS; break; + default: + OSL_FAIL( "OApplicationController::getSelection: unexpected current element type!" ); + break; + } + } + } + return makeAny( aCurrentSelection ); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppController.hxx b/dbaccess/source/ui/app/AppController.hxx new file mode 100644 index 000000000..2edda8efd --- /dev/null +++ b/dbaccess/source/ui/app/AppController.hxx @@ -0,0 +1,526 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_APP_APPCONTROLLER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPCONTROLLER_HXX + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +class SvTreeListEntry; +class SvTreeListBox; +class TransferableHelper; +class TransferableClipboardListener; + +namespace com::sun::star { + namespace container { + class XNameContainer; + class XContainer; + } + namespace ucb { + class XContent; + } +} + +namespace dbaui +{ + 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 + TransferableHelper* copyObject(); + + /// 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 insertHierachyElement( 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; + // need by registration + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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(SvTreeListBox const & _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 SvTreeListEntry* _pEntry, OUString& _rText ) const override; + virtual bool requestDrag( const Point& _rPosPixel ) override; + virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) override; + virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) override; + + // IContextMenuProvider + virtual OUString getContextMenuResourceName( Control& _rControl ) const override; + virtual IController& getCommandController() override; + virtual ::comphelper::OInterfaceContainerHelper2* + getContextMenuInterceptors() override; + virtual css::uno::Any + getCurrentSelection( Control& _rControl ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPCONTROLLER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppControllerDnD.cxx b/dbaccess/source/ui/app/AppControllerDnD.cxx new file mode 100644 index 000000000..98d622584 --- /dev/null +++ b/dbaccess/source/ui/app/AppControllerDnD.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 "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 +#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# + std::set< OUString > aDeleteNames; + // 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::copy( + _rList.begin(), _rList.end(), + std::insert_iterator< std::set< OUString > >( aDeleteNames, aDeleteNames.begin() ) + ); + + 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; +} + +TransferableHelper* OApplicationController::copyObject() +{ + try + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + ElementType eType = getContainer()->getElementType(); + TransferableHelper* pData = nullptr; + 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 ) + { + pData = new ODataClipboard(sDataSource, CommandType::TABLE, sName, xConnection, getNumberFormatter(xConnection, getORB()), getORB()); + } + else + { + pData = new ODataClipboard(sDataSource, CommandType::QUERY, sName, getNumberFormatter(xConnection, getORB()), getORB()); + } + } + } + break; + 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); + pData = new OComponentTransferable( getDatabaseName(), xContent ); + } + } + break; + default: + break; + } + + // the ownership goes to ODataClipboards + return pData; + } + 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,makeAny(sCommand)); + xNewQuery->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,makeAny(bEscapeProcessing)); + } + // insert + xDestQueries->insertByName( sTargetName, makeAny(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 insertHierachyElement(_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(); + OUString sErase = sName.getToken(0,'/',nIndex); // we don't want to have the "private:forms" part + if ( nIndex != -1 ) + { + aList.push_back(sName.copy(sErase.getLength() + 1)); + deleteObjects( m_aAsyncDrop.nType, aList, false ); + } + } + } + + m_aAsyncDrop.aDroppedData.clear(); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppControllerGen.cxx b/dbaccess/source/ui/app/AppControllerGen.cxx new file mode 100644 index 000000000..2466f22df --- /dev/null +++ b/dbaccess/source/ui/app/AppControllerGen.cxx @@ -0,0 +1,741 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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,makeAny(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); + 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 + aArgs[nArgPos++] <<= PropertyValue( "ParentWindow", + 0, + makeAny(xWindow), + PropertyState_DIRECT_VALUE); + + // the initial selection + OUString sInitialSelection; + if ( getContainer() ) + sInitialSelection = getDatabaseName(); + if ( !sInitialSelection.isEmpty() ) + { + aArgs[ nArgPos++ ] <<= PropertyValue( + "InitialSelection", 0, + makeAny( sInitialSelection ), PropertyState_DIRECT_VALUE ); + } + + SharedConnection xConnection( getConnection() ); + if ( xConnection.is() ) + { + aArgs[ 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 ? E_OPEN_DESIGN : E_OPEN_NORMAL, + ForEditing ? SID_DB_APP_EDIT : SID_DB_APP_OPEN, + ::comphelper::NamedValueCollection( Arguments ) + ) ); + + return xComponent; +} + +Reference< XComponent > SAL_CALL OApplicationController::createComponent( ::sal_Int32 i_nObjectType, Reference< XComponent >& o_DocumentDefinition ) +{ + return createComponentWithArguments( i_nObjectType, Sequence< PropertyValue >(), o_DocumentDefinition ); +} + +Reference< XComponent > SAL_CALL OApplicationController::createComponentWithArguments( ::sal_Int32 i_nObjectType, const Sequence< PropertyValue >& i_rArguments, Reference< XComponent >& o_DocumentDefinition ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + impl_validateObjectTypeAndName_throw( i_nObjectType, ::std::optional< OUString >() ); + + Reference< XComponent > xComponent( newElement( + lcl_objectType2ElementType( i_nObjectType ), + ::comphelper::NamedValueCollection( i_rArguments ), + o_DocumentDefinition + ) ); + + return xComponent; +} + +void SAL_CALL OApplicationController::registerContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor ) +{ + if ( Interceptor.is() ) + m_aContextMenuInterceptors.addInterface( Interceptor ); +} + +void SAL_CALL OApplicationController::releaseContextMenuInterceptor( const Reference< XContextMenuInterceptor >& Interceptor ) +{ + m_aContextMenuInterceptors.removeInterface( Interceptor ); +} + +void OApplicationController::previewChanged( sal_Int32 _nMode ) +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + if ( m_xDataSource.is() && !isDataSourceReadOnly() ) + { + try + { + ::comphelper::NamedValueCollection aLayoutInfo( m_xDataSource->getPropertyValue( PROPERTY_LAYOUTINFORMATION ) ); + sal_Int32 nOldMode = aLayoutInfo.getOrDefault( "Preview", _nMode ); + if ( nOldMode != _nMode ) + { + aLayoutInfo.put( "Preview", _nMode ); + m_xDataSource->setPropertyValue( PROPERTY_LAYOUTINFORMATION, makeAny( 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::insertHierachyElement(ElementType _eType, const OUString& _sParentFolder, bool _bCollection, const Reference& _xContent, bool _bMove) +{ + Reference xNames(getElements(_eType), UNO_QUERY); + return dbaui::insertHierachyElement(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 const char s_sStatusbar[] = "private:resource/statusbar/statusbar"; + _xLayoutManager->createElement( s_sStatusbar ); + _xLayoutManager->requestElement( s_sStatusbar ); + + if ( getContainer() ) + { + // we need to share the "mnemonic space": + MnemonicGenerator aMnemonicGenerator; + // - the menu already has mnemonics + SystemWindow* pSystemWindow = getContainer()->GetSystemWindow(); + MenuBar* pMenu = pSystemWindow ? pSystemWindow->GetMenuBar() : nullptr; + if ( pMenu ) + { + sal_uInt16 nMenuItems = pMenu->GetItemCount(); + for ( sal_uInt16 i = 0; i < nMenuItems; ++i ) + aMnemonicGenerator.RegisterMnemonic( pMenu->GetItemText( pMenu->GetItemId( i ) ) ); + } + // - the icons should use automatic ones + getContainer()->createIconAutoMnemonics( aMnemonicGenerator ); + // - as well as the entries in the task pane + getContainer()->setTaskExternalMnemonics( aMnemonicGenerator ); + } + + Execute( SID_DB_APP_VIEW_FORMS, Sequence< PropertyValue >() ); + InvalidateAll(); +} + +void OApplicationController::doAction(sal_uInt16 _nId, const ElementOpenMode _eOpenMode) +{ + std::vector< OUString> aList; + getSelectionElementNames(aList); + ElementType eType = getContainer()->getElementType(); + ::comphelper::NamedValueCollection aArguments; + ElementOpenMode eOpenMode = _eOpenMode; + if ( eType == E_REPORT && E_OPEN_FOR_MAIL == _eOpenMode ) + { + aArguments.put("Hidden",true); + eOpenMode = E_OPEN_NORMAL; + } + + std::vector< std::pair< OUString ,Reference< XModel > > > aComponents; + for (auto const& elem : aList) + { + if ( SID_DB_APP_CONVERTTOVIEW == _nId ) + convertToView(elem); + else + { + Reference< XModel > xModel( openElementWithArguments( elem, eType, eOpenMode, _nId,aArguments ), UNO_QUERY ); + aComponents.emplace_back( elem, xModel ); + } + } + + // special handling for mail, if more than one document is selected attach them all + if ( _eOpenMode != E_OPEN_FOR_MAIL ) + return; + + + SfxMailModel aSendMail; + SfxMailModel::SendMailResult eResult = SfxMailModel::SEND_MAIL_OK; + for (auto const& component : aComponents) + { + try + { + Reference< XModel > xModel = component.second; + + // Send document as e-Mail using stored/default type + eResult = aSendMail.AttachDocument(xModel,component.first); + ::comphelper::disposeComponent(xModel); + if (eResult != SfxMailModel::SEND_MAIL_OK) + break; + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + if ( !aSendMail.IsEmpty() ) + aSendMail.Send( getFrame() ); +} + +ElementType OApplicationController::getElementType(const Reference< XContainer >& _xContainer) +{ + ElementType eRet = E_NONE; + Reference xServiceInfo(_xContainer,UNO_QUERY); + if ( xServiceInfo.is() ) + { + if ( xServiceInfo->supportsService(SERVICE_SDBCX_TABLES) ) + eRet = E_TABLE; + else if ( xServiceInfo->supportsService(SERVICE_NAME_FORM_COLLECTION) ) + eRet = E_FORM; + else if ( xServiceInfo->supportsService(SERVICE_NAME_REPORT_COLLECTION) ) + eRet = E_REPORT; + else + eRet = E_QUERY; + } + return eRet; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppDetailPageHelper.cxx b/dbaccess/source/ui/app/AppDetailPageHelper.cxx new file mode 100644 index 000000000..502ad243c --- /dev/null +++ b/dbaccess/source/ui/app/AppDetailPageHelper.cxx @@ -0,0 +1,1305 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "AppView.hxx" +#include +#include +#include +#include +#include +#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 +{ + SvTreeListEntry* lcl_findEntry_impl(DBTreeListBox const & rTree, const OUString& _rName, SvTreeListEntry* _pFirst) + { + SvTreeListEntry* pReturn = nullptr; + sal_Int32 nIndex = 0; + OUString sName( _rName.getToken(0,'/',nIndex) ); + + SvTreeListEntry* pEntry = _pFirst; + while( pEntry ) + { + if ( rTree.GetEntryText(pEntry) == sName ) + { + if ( nIndex != -1 ) + { + sName = _rName.getToken(0,'/',nIndex); + pEntry = rTree.FirstChild(pEntry); + } + else + { + pReturn = pEntry; + break; + } + } + else + pEntry = pEntry->NextSibling(); + } + return pReturn; + } + SvTreeListEntry* lcl_findEntry(DBTreeListBox const & rTree, const OUString& _rName,SvTreeListEntry* _pFirst) + { + sal_Int32 nIndex = 0; + OUString sErase = _rName.getToken(0,'/',nIndex); // we don't want to have the "private:forms" part + return (nIndex != -1 ? lcl_findEntry_impl(rTree,_rName.copy(sErase.getLength() + 1),_pFirst) : nullptr); + } + class OTablePreviewWindow : public vcl::Window + { + DECL_LINK(OnDisableInput, void*, void); + void ImplInitSettings(); + protected: + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + public: + OTablePreviewWindow( vcl::Window* pParent, WinBits nStyle ); + virtual bool EventNotify( NotifyEvent& rNEvt ) override; + }; + OTablePreviewWindow::OTablePreviewWindow(vcl::Window* pParent, WinBits nStyle) : Window( pParent, nStyle) + { + ImplInitSettings(); + } + bool OTablePreviewWindow::EventNotify( NotifyEvent& rNEvt ) + { + bool bRet = Window::EventNotify(rNEvt); + if ( rNEvt.GetType() == MouseNotifyEvent::INPUTENABLE && IsInputEnabled() ) + PostUserEvent( LINK( this, OTablePreviewWindow, OnDisableInput), nullptr, true ); + return bRet; + } + IMPL_LINK_NOARG(OTablePreviewWindow, OnDisableInput, void*, void) + { + EnableInput(false); + } + void OTablePreviewWindow::DataChanged( const DataChangedEvent& rDCEvt ) + { + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } + } + void OTablePreviewWindow::ImplInitSettings() + { + //FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont(*this, aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + + SetBackground( rStyleSettings.GetFieldColor() ); + } + +} + +OAppDetailPageHelper::OAppDetailPageHelper(vcl::Window* _pParent,OAppBorderWindow& _rBorderWin,PreviewMode _ePreviewMode) : Window(_pParent,WB_DIALOGCONTROL) + ,m_rBorderWin(_rBorderWin) + ,m_aFL(VclPtr::Create(this,WB_VERT)) + ,m_aTBPreview(VclPtr::Create(this,WB_TABSTOP) ) + ,m_aBorder(VclPtr::Create(this,WB_BORDER | WB_READONLY)) + ,m_aPreview(VclPtr::Create(m_aBorder.get())) + ,m_aDocumentInfo(VclPtr< ::svtools::ODocumentInfoPreview>::Create(m_aBorder.get(), WB_LEFT | WB_VSCROLL | WB_READONLY) ) + ,m_ePreviewMode(_ePreviewMode) +{ + m_aBorder->SetBorderStyle(WindowBorderStyle::MONO); + + m_aTBPreview->SetOutStyle(TOOLBOX_STYLE_FLAT); + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:DBDisablePreview", + "com.sun.star.sdb.OfficeDatabaseDocument"); + m_aTBPreview->InsertItem(SID_DB_APP_DISABLE_PREVIEW, + vcl::CommandInfoProvider::GetLabelForCommand(aProperties), + ToolBoxItemBits::LEFT|ToolBoxItemBits::DROPDOWNONLY|ToolBoxItemBits::AUTOSIZE|ToolBoxItemBits::RADIOCHECK); + m_aTBPreview->SetHelpId(HID_APP_VIEW_PREVIEW_CB); + m_aTBPreview->SetDropdownClickHdl( LINK( this, OAppDetailPageHelper, OnDropdownClickHdl ) ); + m_aTBPreview->Enable(); + + m_aPreview->SetHelpId(HID_APP_VIEW_PREVIEW_1); + + m_pTablePreview.set( VclPtr::Create(m_aBorder.get(), WB_READONLY | WB_DIALOGCONTROL ) ); + m_pTablePreview->SetHelpId(HID_APP_VIEW_PREVIEW_2); + + m_aDocumentInfo->SetHelpId(HID_APP_VIEW_PREVIEW_3); + + m_xWindow = VCLUnoHelper::GetInterface( m_pTablePreview ); + + for (VclPtr & rpBox : m_pLists) + rpBox = nullptr; + ImplInitSettings(); +} + +OAppDetailPageHelper::~OAppDetailPageHelper() +{ + disposeOnce(); +} + +void OAppDetailPageHelper::dispose() +{ + try + { + Reference< ::util::XCloseable> xCloseable(m_xFrame,UNO_QUERY); + if ( xCloseable.is() ) + xCloseable->close(true); + m_xFrame.clear(); + } + catch(const Exception&) + { + OSL_FAIL("Exception thrown while disposing preview frame!"); + } + + for (VclPtr & rpBox : m_pLists) + { + if ( rpBox ) + { + rpBox->clearCurrentSelection(); + rpBox->Hide(); + rpBox->clearCurrentSelection(); // why a second time? + rpBox.disposeAndClear(); + } + } + m_pTablePreview.disposeAndClear(); + m_aDocumentInfo.disposeAndClear(); + m_aPreview.disposeAndClear(); + m_aBorder.disposeAndClear(); + m_aTBPreview.disposeAndClear(); + m_aFL.disposeAndClear(); + + vcl::Window::dispose(); +} + +int OAppDetailPageHelper::getVisibleControlIndex() const +{ + int i = 0; + for (; i < E_ELEMENT_TYPE_COUNT ; ++i) + { + if ( m_pLists[i] && m_pLists[i]->IsVisible() ) + break; + } + return i; +} + +void OAppDetailPageHelper::selectAll() +{ + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + { + m_pLists[nPos]->SelectAll(true); + } +} + +void OAppDetailPageHelper::sort(int _nPos,SvSortMode _eSortMode ) +{ + OSL_ENSURE(m_pLists[_nPos],"List can not be NULL! ->GPF"); + SvTreeList* pModel = m_pLists[_nPos]->GetModel(); + SvSortMode eOldSortMode = pModel->GetSortMode(); + pModel->SetSortMode(_eSortMode); + if ( eOldSortMode != _eSortMode ) + pModel->Resort(); +} + +bool OAppDetailPageHelper::isSortUp() const +{ + SvSortMode eSortMode = SortNone; + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + { + SvTreeList* pModel = m_pLists[nPos]->GetModel(); + eSortMode = pModel->GetSortMode(); + } + return eSortMode == SortAscending; +} + +void OAppDetailPageHelper::sortDown() +{ + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + sort(nPos,SortDescending); +} + +void OAppDetailPageHelper::sortUp() +{ + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + sort(nPos,SortAscending); +} + +void OAppDetailPageHelper::getSelectionElementNames( std::vector< OUString>& _rNames ) const +{ + int nPos = getVisibleControlIndex(); + if ( nPos >= E_ELEMENT_TYPE_COUNT ) + return; + + DBTreeListBox& rTree = *m_pLists[nPos]; + sal_Int32 nCount = rTree.GetEntryCount(); + _rNames.reserve(nCount); + SvTreeListEntry* pEntry = rTree.FirstSelected(); + ElementType eType = getElementType(); + while( pEntry ) + { + if ( eType == E_TABLE ) + { + if( rTree.GetChildCount(pEntry) == 0 ) + _rNames.push_back( getQualifiedName( pEntry ) ); + } + else + { + OUString sName = rTree.GetEntryText(pEntry); + SvTreeListEntry* pParent = rTree.GetParent(pEntry); + while(pParent) + { + sName = rTree.GetEntryText(pParent) + "/" + sName; + pParent = rTree.GetParent(pParent); + } + _rNames.push_back(sName); + } + pEntry = rTree.NextSelected(pEntry); + } +} + +void OAppDetailPageHelper::describeCurrentSelectionForControl( const Control& _rControl, Sequence< NamedDatabaseObject >& _out_rSelectedObjects ) +{ + for (size_t i=0; i < E_ELEMENT_TYPE_COUNT; ++i) + { + if ( m_pLists[i] == &_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!" ); + DBTreeListBox* pList = ( _eType < E_ELEMENT_TYPE_COUNT ) ? m_pLists[ _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; + + SvTreeListEntry* pEntry = pList->FirstSelected(); + while( pEntry ) + { + NamedDatabaseObject aObject; + switch ( _eType ) + { + case E_TABLE: + { + OTableTreeListBox& rTableTree = dynamic_cast< OTableTreeListBox& >( *pList ); + aObject = rTableTree.describeObject( pEntry ); + } + break; + case E_QUERY: + aObject.Type = DatabaseObject::QUERY; + aObject.Name = pList->GetEntryText( pEntry ); + break; + + case E_FORM: + case E_REPORT: + { + OUString sName = pList->GetEntryText(pEntry); + SvTreeListEntry* pParent = pList->GetParent(pEntry); + while ( pParent ) + { + OUStringBuffer buffer; + buffer.append( pList->GetEntryText( pParent ) ); + buffer.append( '/' ); + buffer.append( sName ); + sName = buffer.makeStringAndClear(); + + pParent = pList->GetParent( pParent ); + } + + if ( isLeaf( pEntry ) ) + 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 ); + } + + pEntry = pList->NextSelected(pEntry); + } + + _out_rSelectedObjects = comphelper::containerToSequence( aSelected ); +} + +void OAppDetailPageHelper::selectElements(const Sequence< OUString>& _aNames) +{ + int nPos = getVisibleControlIndex(); + if ( nPos >= E_ELEMENT_TYPE_COUNT ) + return; + + DBTreeListBox& rTree = *m_pLists[nPos]; + rTree.SelectAll(false); + const OUString* pIter = _aNames.getConstArray(); + const OUString* pEnd = pIter + _aNames.getLength(); + for(;pIter != pEnd;++pIter) + { + SvTreeListEntry* pEntry = rTree.GetEntryPosByName(*pIter); + if ( pEntry ) + rTree.Select(pEntry); + } +} + +OUString OAppDetailPageHelper::getQualifiedName( SvTreeListEntry* _pEntry ) const +{ + int nPos = getVisibleControlIndex(); + OUString sComposedName; + + if ( nPos >= E_ELEMENT_TYPE_COUNT ) + return sComposedName; + + OSL_ENSURE(m_pLists[nPos],"Tables tree view is NULL! -> GPF"); + DBTreeListBox& rTree = *m_pLists[nPos]; + + SvTreeListEntry* pEntry = _pEntry; + if ( !pEntry ) + pEntry = rTree.FirstSelected(); + + if ( !pEntry ) + return sComposedName; + + if ( getElementType() == E_TABLE ) + { + const OTableTreeListBox& rTreeView = dynamic_cast< const OTableTreeListBox& >( *m_pLists[nPos] ); + sComposedName = rTreeView.getQualifiedTableName( pEntry ); + } + else + { + sComposedName = rTree.GetEntryText(pEntry); + SvTreeListEntry* pParent = rTree.GetParent(pEntry); + while(pParent) + { + sComposedName = rTree.GetEntryText(pParent) + "/" + sComposedName; + pParent = rTree.GetParent(pParent); + } + } + + 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 ) + { + DBTreeListBox& rTree = *m_pLists[nPos]; + SvTreeListEntry* pEntry = rTree.FirstSelected(); + while( pEntry ) + { + ++nCount; + pEntry = rTree.NextSelected(pEntry); + } + } + return nCount; +} + +sal_Int32 OAppDetailPageHelper::getElementCount() const +{ + sal_Int32 nCount = 0; + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + { + nCount = m_pLists[nPos]->GetEntryCount(); + } + return nCount; +} + +bool OAppDetailPageHelper::isLeaf(SvTreeListEntry const * _pEntry) +{ + if ( !_pEntry ) + return false; + sal_Int32 nEntryType = reinterpret_cast< sal_IntPtr >( _pEntry->GetUserData() ); + 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 ) + { + DBTreeListBox& rTree = *m_pLists[nPos]; + SvTreeListEntry* pEntry = rTree.FirstSelected( ); + while( !bLeafSelected && pEntry ) + { + bLeafSelected = isLeaf( pEntry ); + pEntry = rTree.NextSelected(pEntry); + } + } + return bLeafSelected; +} + +SvTreeListEntry* OAppDetailPageHelper::getEntry( const Point& _aPosPixel) const +{ + SvTreeListEntry* pReturn = nullptr; + int nPos = getVisibleControlIndex(); + if ( nPos < E_ELEMENT_TYPE_COUNT ) + pReturn = m_pLists[nPos]->GetEntry( _aPosPixel, true ); + return pReturn; +} + +void OAppDetailPageHelper::createTablesPage(const Reference< XConnection>& _xConnection) +{ + OSL_ENSURE(_xConnection.is(),"Connection is NULL! -> GPF"); + + if ( !m_pLists[E_TABLE] ) + { + VclPtrInstance pTreeView(this, + WB_HASLINES | WB_SORT | WB_HASBUTTONS | WB_HSCROLL |WB_HASBUTTONSATROOT | WB_TABSTOP); + pTreeView->SetHelpId(HID_APP_TABLE_TREE); + m_pLists[E_TABLE] = pTreeView; + + createTree( pTreeView, + ImageProvider::getDefaultImage( DatabaseObject::TABLE ) + ); + + pTreeView->notifyHiContrastChanged(); + m_aBorder->SetZOrder(pTreeView, ZOrderFlags::Behind); + } + if ( !m_pLists[E_TABLE]->GetEntryCount() ) + { + static_cast(m_pLists[E_TABLE].get())->UpdateTableList(_xConnection); + + SvTreeListEntry* pEntry = m_pLists[E_TABLE]->First(); + if ( pEntry ) + m_pLists[E_TABLE]->Expand(pEntry); + m_pLists[E_TABLE]->SelectAll(false); + } + + setDetailPage(m_pLists[E_TABLE]); +} + +OUString OAppDetailPageHelper::getElementIcons(ElementType _eType) +{ + sal_Int32 nDatabaseObjectType( 0 ); + switch(_eType ) + { + case E_FORM: nDatabaseObjectType = DatabaseObject::FORM; break; + case E_REPORT: nDatabaseObjectType = DatabaseObject::REPORT; break; + case E_QUERY: nDatabaseObjectType = DatabaseObject::QUERY; break; + default: + OSL_FAIL( "OAppDetailPageHelper::GetElementIcons: invalid element type!" ); + return OUString(); + } + + return ImageProvider::getDefaultImageResourceID(nDatabaseObjectType); +} + +void OAppDetailPageHelper::createPage(ElementType _eType,const Reference< XNameAccess >& _xContainer) +{ + OSL_ENSURE(E_TABLE != _eType,"E_TABLE isn't allowed."); + + OString sHelpId; + Image aFolderImage; + switch( _eType ) + { + case E_FORM: + sHelpId = HID_APP_FORM_TREE; + aFolderImage = ImageProvider::getFolderImage( DatabaseObject::FORM ); + break; + case E_REPORT: + sHelpId = HID_APP_REPORT_TREE; + aFolderImage = ImageProvider::getFolderImage( DatabaseObject::REPORT ); + break; + case E_QUERY: + sHelpId = HID_APP_QUERY_TREE; + aFolderImage = ImageProvider::getFolderImage( DatabaseObject::QUERY ); + break; + default: + OSL_FAIL("Illegal call!"); + } + OUString sImageId = getElementIcons(_eType); + + if ( !m_pLists[_eType] ) + { + m_pLists[_eType] = createSimpleTree( sHelpId, aFolderImage ); + } + + if ( m_pLists[_eType] ) + { + if ( !m_pLists[_eType]->GetEntryCount() && _xContainer.is() ) + { + fillNames( _xContainer, _eType, sImageId, nullptr ); + + m_pLists[_eType]->SelectAll(false); + } + setDetailPage(m_pLists[_eType]); + } +} + +void OAppDetailPageHelper::setDetailPage(vcl::Window* _pWindow) +{ + OSL_ENSURE(_pWindow,"OAppDetailPageHelper::setDetailPage: Window is NULL!"); + vcl::Window* pCurrent = getCurrentView(); + if ( pCurrent ) + pCurrent->Hide(); + + showPreview(nullptr); + bool bHasFocus = false; + m_aFL->Show(); + { + bHasFocus = pCurrent != nullptr && pCurrent->HasChildPathFocus(); + _pWindow->Show(); + } + m_aTBPreview->Show(); + m_aBorder->Show(); + switchPreview(m_ePreviewMode,true); + + if ( bHasFocus ) + _pWindow->GrabFocus(); + Resize(); +} + +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, SvTreeListEntry* _pParent ) +{ + OSL_ENSURE(_xContainer.is(),"Data source is NULL! -> GPF"); + OSL_ENSURE( ( _eType >= E_TABLE ) && ( _eType < E_ELEMENT_TYPE_COUNT ), "OAppDetailPageHelper::fillNames: invalid type!" ); + + DBTreeListBox* pList = m_pLists[ _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; + + 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) + { + SvTreeListEntry* pEntry = nullptr; + Reference xSubElements(_xContainer->getByName(*pIter),UNO_QUERY); + if ( xSubElements.is() ) + { + pEntry = pList->InsertEntry( *pIter, _pParent, false, TREELIST_APPEND, reinterpret_cast< void* >( nFolderIndicator ) ); + getBorderWin().getView()->getAppController().containerFound( Reference< XContainer >( xSubElements, UNO_QUERY ) ); + fillNames( xSubElements, _eType, rImageId, pEntry ); + } + else + { + pEntry = pList->InsertEntry( *pIter, _pParent ); + + Image aImage(StockImage::Yes, rImageId); + pList->SetExpandedEntryBmp(pEntry, aImage); + pList->SetCollapsedEntryBmp(pEntry, aImage); + } + } +} + +DBTreeListBox* OAppDetailPageHelper::createSimpleTree( const OString& _sHelpId, const Image& _rImage) +{ + VclPtrInstance pTreeView(this, + WB_HASLINES | WB_SORT | WB_HASBUTTONS | WB_HSCROLL |WB_HASBUTTONSATROOT | WB_TABSTOP); + pTreeView->SetHelpId( _sHelpId ); + return createTree( pTreeView, _rImage ); +} + +DBTreeListBox* OAppDetailPageHelper::createTree( DBTreeListBox* _pTreeView, const Image& _rImage ) +{ + weld::WaitObject aWaitCursor(GetFrameWeld()); + + _pTreeView->SetStyle(_pTreeView->GetStyle() | WB_HASLINES | WB_SORT | WB_HASBUTTONS | WB_HSCROLL |WB_HASBUTTONSATROOT | WB_TABSTOP); + _pTreeView->GetModel()->SetSortMode(SortAscending); + _pTreeView->EnableCheckButton( nullptr ); // do not show any buttons + _pTreeView->SetSelectionMode(SelectionMode::Multiple); + + _pTreeView->SetDefaultCollapsedEntryBmp( _rImage ); + _pTreeView->SetDefaultExpandedEntryBmp( _rImage ); + + _pTreeView->SetDoubleClickHdl(LINK(this, OAppDetailPageHelper, OnEntryDoubleClick)); + _pTreeView->SetEnterKeyHdl(LINK(this, OAppDetailPageHelper, OnEntryEnterKey)); + _pTreeView->SetSelChangeHdl(LINK(this, OAppDetailPageHelper, OnEntrySelChange)); + + _pTreeView->setCopyHandler(LINK(this, OAppDetailPageHelper, OnCopyEntry)); + _pTreeView->setPasteHandler(LINK(this, OAppDetailPageHelper, OnPasteEntry)); + _pTreeView->setDeleteHandler(LINK(this, OAppDetailPageHelper, OnDeleteEntry)); + + _pTreeView->setControlActionListener( &getBorderWin().getView()->getAppController() ); + _pTreeView->setContextMenuProvider( &getBorderWin().getView()->getAppController() ); + + return _pTreeView; +} + +void OAppDetailPageHelper::clearPages() +{ + showPreview(nullptr); + for (VclPtr & rpBox : m_pLists) + { + if ( rpBox ) + rpBox->Clear(); + } +} + +bool OAppDetailPageHelper::isFilled() const +{ + size_t i = 0; + for (; i < E_ELEMENT_TYPE_COUNT && !m_pLists[i]; ++i) + ; + return i != E_ELEMENT_TYPE_COUNT; +} + +void OAppDetailPageHelper::elementReplaced(ElementType _eType + ,const OUString& _rOldName + ,const OUString& _rNewName ) +{ + DBTreeListBox* pTreeView = getCurrentView(); + if ( !pTreeView ) + return; + + SvTreeListEntry* pEntry = nullptr; + switch( _eType ) + { + case E_TABLE: + static_cast(pTreeView)->removedTable( _rOldName ); + static_cast(pTreeView)->addedTable( _rNewName ); + return; + + case E_QUERY: + pEntry = lcl_findEntry_impl(*pTreeView,_rOldName,pTreeView->First()); + break; + case E_FORM: + case E_REPORT: + pEntry = lcl_findEntry(*pTreeView,_rOldName,pTreeView->First()); + break; + default: + OSL_FAIL("Invalid element type"); + } + OSL_ENSURE(pEntry,"Do you know that the name isn't existence!"); + if ( pEntry ) + { + pTreeView->SetEntryText(pEntry,_rNewName); + } +} + +SvTreeListEntry* OAppDetailPageHelper::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject ) +{ + SvTreeListEntry* pRet = nullptr; + DBTreeListBox* pTreeView = m_pLists[_eType].get(); + if( _eType == E_TABLE && pTreeView ) + { + pRet = static_cast(pTreeView)->addedTable( _rName ); + } + else if ( pTreeView ) + { + + SvTreeListEntry* pEntry = nullptr; + 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(); + pEntry = lcl_findEntry(*pTreeView,sName,pTreeView->First()); + } + } + + OUString sImageId = getElementIcons(_eType); + Reference xContainer(_rObject,UNO_QUERY); + if ( xContainer.is() ) + { + const sal_Int32 nFolderIndicator = lcl_getFolderIndicatorForType( _eType ); + pRet = pTreeView->InsertEntry( _rName, pEntry, false, TREELIST_APPEND, reinterpret_cast< void* >( nFolderIndicator ) ); + fillNames( xContainer, _eType, sImageId, pRet ); + } + else + { + pRet = pTreeView->InsertEntry( _rName, pEntry ); + + Image aImage(StockImage::Yes, sImageId); + pTreeView->SetExpandedEntryBmp( pRet, aImage ); + pTreeView->SetCollapsedEntryBmp( pRet, aImage ); + } + } + return pRet; +} + +void OAppDetailPageHelper::elementRemoved( ElementType _eType,const OUString& _rName ) +{ + DBTreeListBox* pTreeView = getCurrentView(); + if ( !pTreeView ) + return; + + switch( _eType ) + { + case E_TABLE: + // we don't need to clear the table here, it is already done by the dispose listener + static_cast< OTableTreeListBox* >( pTreeView )->removedTable( _rName ); + break; + case E_QUERY: + if (auto pEntry = lcl_findEntry_impl(*pTreeView, _rName, pTreeView->First())) + pTreeView->GetModel()->Remove(pEntry); + break; + case E_FORM: + case E_REPORT: + if (auto pEntry = lcl_findEntry(*pTreeView, _rName, pTreeView->First())) + pTreeView->GetModel()->Remove(pEntry); + break; + default: + OSL_FAIL("Invalid element type"); + } + if ( !pTreeView->GetEntryCount() ) + showPreview(nullptr); +} + +IMPL_LINK(OAppDetailPageHelper, OnEntryEnterKey, DBTreeListBox*, _pTree, void ) +{ + OnEntryDoubleClick(_pTree); +} +IMPL_LINK(OAppDetailPageHelper, OnEntryDoubleClick, SvTreeListBox*, _pTree, bool) +{ + OSL_ENSURE( _pTree, "OAppDetailPageHelper, OnEntryDoubleClick: invalid callback!" ); + bool bHandled = ( _pTree != nullptr ) && getBorderWin().getView()->getAppController().onEntryDoubleClick( *_pTree ); + return bHandled; +} + +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(); +} + +void OAppDetailPageHelper::Resize() +{ + // parent window dimension + Size aOutputSize( GetOutputSize() ); + long nOutputWidth = aOutputSize.Width(); + long nOutputHeight = aOutputSize.Height(); + + vcl::Window* pWindow = getCurrentView(); + if ( !pWindow ) + return; + + Size aFLSize = LogicToPixel(Size(2, 6), MapMode(MapUnit::MapAppFont)); + sal_Int32 n6PPT = aFLSize.Height(); + long nHalfOutputWidth = static_cast(nOutputWidth * 0.5); + + pWindow->SetPosSizePixel( Point(0, 0), Size(nHalfOutputWidth - n6PPT, nOutputHeight) ); + + m_aFL->SetPosSizePixel( Point(nHalfOutputWidth , 0 ), Size(aFLSize.Width(), nOutputHeight ) ); + + Size aTBSize = m_aTBPreview->CalcWindowSizePixel(); + m_aTBPreview->SetPosSizePixel(Point(nOutputWidth - aTBSize.getWidth(), 0 ), + aTBSize ); + + m_aBorder->SetPosSizePixel(Point(nHalfOutputWidth + aFLSize.Width() + n6PPT, aTBSize.getHeight() + n6PPT ), + Size(nHalfOutputWidth - aFLSize.Width() - n6PPT, nOutputHeight - 2*n6PPT - aTBSize.getHeight()) ); + m_aPreview->SetPosSizePixel(Point(0,0),m_aBorder->GetSizePixel() ); + m_aDocumentInfo->SetPosSizePixel(Point(0,0),m_aBorder->GetSizePixel() ); + m_pTablePreview->SetPosSizePixel(Point(0,0),m_aBorder->GetSizePixel() ); +} + + +bool OAppDetailPageHelper::isPreviewEnabled() const +{ + return m_ePreviewMode != E_PREVIEWNONE; +} + +namespace +{ + OUString stripTrailingDots(const OUString& rStr) + { + return 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 E_PREVIEWNONE: + aCommand = ".uno:DBDisablePreview"; + break; + case E_DOCUMENT: + aCommand = ".uno:DBShowDocPreview"; + break; + case E_DOCUMENTINFO: + if ( getBorderWin().getView()->getAppController().isCommandEnabled(SID_DB_APP_VIEW_DOCINFO_PREVIEW) ) + aCommand = ".uno:DBShowDocInfoPreview"; + else + { + m_ePreviewMode = E_PREVIEWNONE; + aCommand = ".uno:DBDisablePreview"; + } + break; + } + + auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommand, "com.sun.star.sdb.OfficeDatabaseDocument"); + OUString aCommandLabel = vcl::CommandInfoProvider::GetLabelForCommand(aProperties); + m_aTBPreview->SetItemText(SID_DB_APP_DISABLE_PREVIEW, stripTrailingDots(aCommandLabel)); + Resize(); + + // simulate a selectionChanged event at the controller, to force the preview to be updated + if ( isPreviewEnabled() ) + { + if ( getCurrentView() && getCurrentView()->FirstSelected() ) + { + getBorderWin().getView()->getAppController().onSelectionChanged(); + } + } + else + { + m_pTablePreview->Hide(); + m_aPreview->Hide(); + m_aDocumentInfo->Hide(); + } +} + +void OAppDetailPageHelper::showPreview(const Reference< XContent >& _xContent) +{ + if ( !isPreviewEnabled() ) + return; + + m_pTablePreview->Hide(); + + weld::WaitObject aWaitCursor(GetFrameWeld()); + try + { + Reference xContent(_xContent,UNO_QUERY); + if ( xContent.is() ) + { + css::ucb::Command aCommand; + if ( m_ePreviewMode == E_DOCUMENT ) + aCommand.Name = "preview"; + else + aCommand.Name = "getDocumentInfo"; + + Any aPreview = xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >()); + if ( m_ePreviewMode == E_DOCUMENT ) + { + m_aDocumentInfo->Hide(); + m_aPreview->Show(); + + Graphic aGraphic; + Sequence < sal_Int8 > aBmpSequence; + if ( aPreview >>= aBmpSequence ) + { + SvMemoryStream aData( aBmpSequence.getArray(), + aBmpSequence.getLength(), + StreamMode::READ ); + + GraphicConverter::Import(aData,aGraphic); + } + m_aPreview->setGraphic( aGraphic ); + m_aPreview->Invalidate(); + } + else + { + m_aPreview->Hide(); + m_aDocumentInfo->clear(); + m_aDocumentInfo->Show(); + Reference xProp( + aPreview, UNO_QUERY); + if ( xProp.is() ) + m_aDocumentInfo->fill(xProp); + } + } + else + { + m_aPreview->Hide(); + m_aDocumentInfo->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(GetFrameWeld()); + m_aPreview->Hide(); + m_aDocumentInfo->Hide(); + m_pTablePreview->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( OUString(PROPERTY_SHOWMENU), false ); + + Reference< XController > xPreview( pDispatcher->openExisting( makeAny( _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); +} + +IMPL_LINK_NOARG(OAppDetailPageHelper, OnDropdownClickHdl, ToolBox*, void) +{ + m_aTBPreview->EndSelection(); + + // tell the toolbox that the item is pressed down + m_aTBPreview->SetItemDown( SID_DB_APP_DISABLE_PREVIEW, true ); + + // simulate a mouse move (so the "down" state is really painted) + Point aPoint = m_aTBPreview->GetItemRect( SID_DB_APP_DISABLE_PREVIEW ).TopLeft(); + MouseEvent aMove( aPoint, 0, MouseEventModifiers::SIMPLEMOVE | MouseEventModifiers::SYNTHETIC ); + m_aTBPreview->MouseMove( aMove ); + + m_aTBPreview->PaintImmediately(); + + // execute the menu + css::uno::Reference xContext(getBorderWin().getView()->getORB()); + css::uno::Reference xPopupMenuFactory(css::frame::thePopupMenuControllerFactory::get(xContext)); + if (!xPopupMenuFactory.is()) + return; + + css::uno::Sequence aArgs { + css::uno::makeAny(comphelper::makePropertyValue("InToolbar", true)), + css::uno::makeAny(comphelper::makePropertyValue("ModuleIdentifier", OUString("com.sun.star.sdb.OfficeDatabaseDocument"))), + css::uno::makeAny(comphelper::makePropertyValue("Frame", getBorderWin().getView()->getAppController().getFrame())) }; + + css::uno::Reference xPopupController( + xPopupMenuFactory->createInstanceWithArgumentsAndContext(".uno:DBPreview", aArgs, xContext), css::uno::UNO_QUERY); + + if (!xPopupController.is()) + return; + + rtl::Reference xPopupMenu(new VCLXPopupMenu); + xPopupController->setPopupMenu(xPopupMenu.get()); + VclPtr aMenu(static_cast(xPopupMenu->GetMenu())); + + sal_uInt16 nSelectedAction = aMenu->Execute(m_aTBPreview.get(), m_aTBPreview->GetItemRect( SID_DB_APP_DISABLE_PREVIEW )); + // "cleanup" the toolbox state + MouseEvent aLeave( aPoint, 0, MouseEventModifiers::LEAVEWINDOW | MouseEventModifiers::SYNTHETIC ); + m_aTBPreview->MouseMove( aLeave ); + m_aTBPreview->SetItemDown( SID_DB_APP_DISABLE_PREVIEW, false); + if ( nSelectedAction ) + { + m_aTBPreview->SetItemText(SID_DB_APP_DISABLE_PREVIEW, stripTrailingDots(aMenu->GetItemText(nSelectedAction))); + Resize(); + } + + css::uno::Reference xComponent(xPopupController, css::uno::UNO_QUERY); + if (xComponent.is()) + xComponent->dispose(); +} + +void OAppDetailPageHelper::KeyInput( const KeyEvent& rKEvt ) +{ + SvTreeListBox* pCurrentView = getCurrentView(); + OSL_PRECOND( pCurrentView, "OAppDetailPageHelper::KeyInput: how this?" ); + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + + if ( ( KEY_RETURN == nCode ) && pCurrentView ) + { + getBorderWin().getView()->getAppController().onEntryDoubleClick( *pCurrentView ); + } + else + Window::KeyInput(rKEvt); +} + +void OAppDetailPageHelper::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) || + (rDCEvt.GetType() == DataChangedEventType::DISPLAY) || + (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) ) + + { + ImplInitSettings(); + if ( m_pLists[ E_TABLE ] ) + { + OTableTreeListBox* pTableTree = dynamic_cast< OTableTreeListBox* >( m_pLists[ E_TABLE ].get() ); + OSL_ENSURE( pTableTree != nullptr, "OAppDetailPageHelper::DataChanged: a tree list for tables which is no TableTreeList?" ); + if ( pTableTree ) + pTableTree->notifyHiContrastChanged(); + } + } +} + +void OAppDetailPageHelper::ImplInitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont(*this, aFont); + m_aTBPreview->SetPointFont(*m_aTBPreview, aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + m_aBorder->SetTextColor( rStyleSettings.GetFieldTextColor() ); + m_aBorder->SetTextFillColor(); + m_aTBPreview->SetTextColor( rStyleSettings.GetFieldTextColor() ); + m_aTBPreview->SetTextFillColor(); + SetBackground( rStyleSettings.GetFieldColor() ); + m_aBorder->SetBackground( rStyleSettings.GetFieldColor() ); + m_aFL->SetBackground( rStyleSettings.GetFieldColor() ); + m_aDocumentInfo->SetBackground( rStyleSettings.GetFieldColor() ); + m_aTBPreview->SetBackground( rStyleSettings.GetFieldColor() ); + m_pTablePreview->SetBackground( rStyleSettings.GetFieldColor() ); +} + +OPreviewWindow::OPreviewWindow(vcl::Window* _pParent) +: Window(_pParent) +{ + ImplInitSettings(); +} + +bool OPreviewWindow::ImplGetGraphicCenterRect( const Graphic& rGraphic, tools::Rectangle& rResultRect ) const +{ + const Size aWinSize( GetOutputSizePixel() ); + Size aNewSize( 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) +{ + Window::Paint(rRenderContext, rRect); + + if (ImplGetGraphicCenterRect(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); + } +} + +void OPreviewWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +void OPreviewWindow::ImplInitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont(*this, aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + + SetBackground( rStyleSettings.GetFieldColor() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppDetailPageHelper.hxx b/dbaccess/source/ui/app/AppDetailPageHelper.hxx new file mode 100644 index 000000000..1dd89d84a --- /dev/null +++ b/dbaccess/source/ui/app/AppDetailPageHelper.hxx @@ -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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILPAGEHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILPAGEHELPER_HXX + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::awt { class XWindow; } +namespace com::sun::star::frame { class XFrame2; } +namespace com::sun::star::io { class XPersist; } + +#define ELEMENT_COUNT size_t(E_ELEMENT_TYPE_COUNT) + +namespace dbaui +{ + class OAppBorderWindow; + class DBTreeListBox; + + class OPreviewWindow : public vcl::Window + { + GraphicObject m_aGraphicObj; + tools::Rectangle m_aPreviewRect; + + /** gets the graphic center rect + @param rGraphic + the graphic + @param rResultRect + the resulting rectangle + + @return + when successful + */ + bool ImplGetGraphicCenterRect( const Graphic& rGraphic, tools::Rectangle& rResultRect ) const; + void ImplInitSettings(); + protected: + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + public: + explicit OPreviewWindow(vcl::Window* _pParent); + + // Window overrides + 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 : public vcl::Window + { + VclPtr m_pLists[ELEMENT_COUNT]; + OAppBorderWindow& m_rBorderWin; + VclPtr m_aFL; + VclPtr m_aTBPreview; + VclPtr m_aBorder; + VclPtr m_aPreview; + VclPtr< ::svtools::ODocumentInfoPreview> + m_aDocumentInfo; + VclPtr m_pTablePreview; + 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 _eSortMode + How should be sorted. + */ + void sort(int _nPos,SvSortMode _eSortMode ); + + /** 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, + SvTreeListEntry* _pParent ); + + /** sets the detail page + @param _pWindow + The control which should be visible. + */ + void setDetailPage(vcl::Window* _pWindow); + + /** sets all HandleCallbacks + @param _pTreeView + The newly created DBTreeListBox + @param _rImage + the resource id of the default icon + @return + The new tree. + */ + DBTreeListBox* createTree( DBTreeListBox* _pTreeView, const Image& _rImage ); + + /** creates the tree and sets all HandleCallbacks + @param _nHelpId + The help id of the control + @param _nCollapsedBitmap + The image to use in high contrast mode. + @return + The new tree. + */ + DBTreeListBox* createSimpleTree( const OString& _sHelpId, const Image& _rImage); + + DECL_LINK( OnEntryDoubleClick, SvTreeListBox*, bool ); + DECL_LINK( OnEntryEnterKey, DBTreeListBox*, void ); + DECL_LINK( OnEntrySelChange, LinkParamNone*, void ); + + DECL_LINK( OnCopyEntry, LinkParamNone*, void ); + DECL_LINK( OnPasteEntry, LinkParamNone*, void ); + DECL_LINK( OnDeleteEntry, LinkParamNone*, void ); + + // click a TB slot + DECL_LINK(OnDropdownClickHdl, ToolBox*, void); + + OAppBorderWindow& getBorderWin() const { return m_rBorderWin; } + void ImplInitSettings(); + + public: + OAppDetailPageHelper(vcl::Window* _pParent,OAppBorderWindow& _rBorderWin,PreviewMode _ePreviewMode); + virtual ~OAppDetailPageHelper() override; + virtual void dispose() override; + + // Window overrides + virtual void Resize() override; + virtual void KeyInput( const KeyEvent& rKEvt ) 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 + */ + DBTreeListBox* getCurrentView() const + { + ElementType eType = getElementType(); + return (eType != E_NONE ) ? m_pLists[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 Control& _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 + ); + + /** 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( SvTreeListEntry* _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 _pEntry + The entry to check + @return + if the entry is a leaf, otherwise + */ + static bool isLeaf(SvTreeListEntry const * _pEntry); + + /** returns if one of the selected entries is a leaf + @return + if the entry is a leaf, otherwise + */ + bool isALeafSelected() const; + + SvTreeListEntry* getEntry( const Point& _aPosPixel ) 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. + */ + SvTreeListEntry* 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); + + protected: + void DataChanged( const DataChangedEvent& rDCEvt ) override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILPAGEHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppDetailView.cxx b/dbaccess/source/ui/app/AppDetailView.cxx new file mode 100644 index 000000000..39da2cd49 --- /dev/null +++ b/dbaccess/source/ui/app/AppDetailView.cxx @@ -0,0 +1,877 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include "AppDetailPageHelper.hxx" +#include +#include +#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::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; + +#define SPACEBETWEENENTRIES 4 + +TaskEntry::TaskEntry( const char* _pAsciiUNOCommand, const char* _pHelpID, const char* pTitleResourceID, bool _bHideWhenDisabled ) + :sUNOCommand( OUString::createFromAscii( _pAsciiUNOCommand ) ) + ,pHelpID( _pHelpID ) + ,sTitle( DBA_RES(pTitleResourceID) ) + ,bHideWhenDisabled( _bHideWhenDisabled ) +{ +} + +OCreationList::OCreationList( OTasksWindow& _rParent ) + :SvTreeListBox( &_rParent, WB_TABSTOP | WB_HASBUTTONSATROOT | WB_HASBUTTONS ) + ,m_rTaskWindow( _rParent ) + ,m_pMouseDownEntry( nullptr ) + ,m_pLastActiveEntry( nullptr ) +{ + SetSpaceBetweenEntries(SPACEBETWEENENTRIES); + SetSelectionMode( SelectionMode::NONE ); + SetNoAutoCurEntry( true ); + SetNodeDefaultImages( ); + EnableEntryMnemonics(); +} + +void OCreationList::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rRect ) +{ + SetBackground(); + + if (m_pMouseDownEntry) + m_aOriginalFont = rRenderContext.GetFont(); + + m_aOriginalBackgroundColor = rRenderContext.GetBackground().GetColor(); + SvTreeListBox::Paint(rRenderContext, _rRect); + rRenderContext.SetBackground(m_aOriginalBackgroundColor); + + if (m_pMouseDownEntry) + rRenderContext.SetFont(m_aOriginalFont); +} + +void OCreationList::PreparePaint(vcl::RenderContext& rRenderContext, SvTreeListEntry& rEntry) +{ + Wallpaper aEntryBackground(m_aOriginalBackgroundColor); + + if (&rEntry == GetCurEntry()) + { + // draw a selection background + bool bIsMouseDownEntry = ( &rEntry == m_pMouseDownEntry ); + vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, GetBoundingRect(&rEntry), + bIsMouseDownEntry ? 1 : 2, false, true, false ); + + if (bIsMouseDownEntry) + { + vcl::Font aFont(rRenderContext.GetFont()); + aFont.SetColor(rRenderContext.GetSettings().GetStyleSettings().GetHighlightTextColor()); + rRenderContext.SetFont(aFont); + } + + // and temporary set a transparent background, for all the other + // paint operations the SvTreeListBox is going to do + aEntryBackground = Wallpaper(); + } + + rRenderContext.SetBackground(aEntryBackground); + rEntry.SetBackColor(aEntryBackground.GetColor()); +} + +void OCreationList::SelectSearchEntry( const void* _pEntry ) +{ + SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) ); + OSL_ENSURE( pEntry, "OCreationList::SelectSearchEntry: invalid entry!" ); + + if ( pEntry ) + setCurrentEntryInvalidate( pEntry ); + + if ( !HasChildPathFocus() ) + GrabFocus(); +} + +void OCreationList::ExecuteSearchEntry( const void* _pEntry ) const +{ + SvTreeListEntry* pEntry = const_cast< SvTreeListEntry* >( static_cast< const SvTreeListEntry* >( _pEntry ) ); + OSL_ENSURE( pEntry, "OCreationList::ExecuteSearchEntry: invalid entry!" ); + OSL_ENSURE( pEntry == GetCurEntry(), "OCreationList::ExecuteSearchEntry: SelectSearchEntry should have been called before!" ); + + if ( pEntry ) + onSelected( pEntry ); +} + +tools::Rectangle OCreationList::GetFocusRect(const SvTreeListEntry* _pEntry, long _nLine) +{ + tools::Rectangle aRect = SvTreeListBox::GetFocusRect( _pEntry, _nLine ); + aRect.SetLeft( 0 ); + + // try to let the focus rect start before the bitmap item - this looks better + const SvLBoxItem* pBitmapItem = _pEntry->GetFirstItem(SvLBoxItemType::ContextBmp); + SvLBoxTab* pTab = pBitmapItem ? GetTab( _pEntry, pBitmapItem ) : nullptr; + SvViewDataItem* pItemData = pBitmapItem ? GetViewDataItem( _pEntry, pBitmapItem ) : nullptr; + OSL_ENSURE( pTab && pItemData, "OCreationList::GetFocusRect: could not find the first bitmap item!" ); + if ( pTab && pItemData ) + aRect.SetLeft( pTab->GetPos() - pItemData->mnWidth / 2 ); + + // inflate the rectangle a little bit - looks better, too + aRect.SetLeft( std::max< long >( 0, aRect.Left() - 2 ) ); + aRect.SetRight( std::min< long >( GetOutputSizePixel().Width() - 1, aRect.Right() + 2 ) ); + + return aRect; +} + +void OCreationList::StartDrag( sal_Int8 /*_nAction*/, const Point& /*_rPosPixel*/ ) +{ + // don't give this to the base class, it does a ReleaseMouse as very first action + // Though I think this is a bug (it should ReleaseMouse only if it is going to do + // something with the drag-event), I hesitate to fix it in the current state, + // since I don't overlook the consequences, and we're close to 2.0...) +} + +void OCreationList::ModelHasCleared() +{ + SvTreeListBox::ModelHasCleared(); + m_pLastActiveEntry = nullptr; + m_pMouseDownEntry = nullptr; +} + +void OCreationList::GetFocus() +{ + SvTreeListBox::GetFocus(); + if ( !GetCurEntry() ) + setCurrentEntryInvalidate( m_pLastActiveEntry ? m_pLastActiveEntry : GetFirstEntryInView() ); +} + +void OCreationList::LoseFocus() +{ + SvTreeListBox::LoseFocus(); + m_pLastActiveEntry = GetCurEntry(); + setCurrentEntryInvalidate( nullptr ); +} + +void OCreationList::MouseButtonDown( const MouseEvent& rMEvt ) +{ + SvTreeListBox::MouseButtonDown( rMEvt ); + + OSL_ENSURE( !m_pMouseDownEntry, "OCreationList::MouseButtonDown: I missed some mouse event!" ); + m_pMouseDownEntry = GetCurEntry(); + if ( m_pMouseDownEntry ) + { + InvalidateEntry( m_pMouseDownEntry ); + CaptureMouse(); + } +} + +void OCreationList::MouseMove( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeaveWindow() ) + { + setCurrentEntryInvalidate( nullptr ); + } + else if ( !rMEvt.IsSynthetic() ) + { + SvTreeListEntry* pEntry = GetEntry( rMEvt.GetPosPixel() ); + + if ( m_pMouseDownEntry ) + { + // we're currently in a "mouse down" phase + OSL_ENSURE( IsMouseCaptured(), "OCreationList::MouseMove: inconsistence (1)!" ); + if ( pEntry == m_pMouseDownEntry ) + { + setCurrentEntryInvalidate( m_pMouseDownEntry ); + } + else + { + OSL_ENSURE( ( GetCurEntry() == m_pMouseDownEntry ) || !GetCurEntry(), + "OCreationList::MouseMove: inconsistence (2)!" ); + setCurrentEntryInvalidate( nullptr ); + } + } + else + { + // the user is simply hovering with the mouse + if ( setCurrentEntryInvalidate( pEntry ) ) + { + if ( !m_pMouseDownEntry ) + updateHelpText(); + } + } + } + + SvTreeListBox::MouseMove(rMEvt); +} + +void OCreationList::MouseButtonUp( const MouseEvent& rMEvt ) +{ + SvTreeListEntry* pEntry = GetEntry( rMEvt.GetPosPixel() ); + bool bExecute = false; + // Was the mouse released over the active entry? + // (i.e. the entry which was under the mouse when the button went down) + if ( pEntry && ( m_pMouseDownEntry == pEntry ) ) + { + if ( !rMEvt.IsShift() && !rMEvt.IsMod1() && !rMEvt.IsMod2() && rMEvt.IsLeft() && rMEvt.GetClicks() == 1 ) + bExecute = true; + } + + if ( m_pMouseDownEntry ) + { + OSL_ENSURE( IsMouseCaptured(), "OCreationList::MouseButtonUp: hmmm... no mouse captured, but an active entry?" ); + ReleaseMouse(); + + InvalidateEntry( m_pMouseDownEntry ); + m_pMouseDownEntry = nullptr; + } + + SvTreeListBox::MouseButtonUp( rMEvt ); + + if ( bExecute ) + onSelected( pEntry ); +} + +bool OCreationList::setCurrentEntryInvalidate( SvTreeListEntry* _pEntry ) +{ + if ( GetCurEntry() != _pEntry ) + { + if ( GetCurEntry() ) + InvalidateEntry( GetCurEntry() ); + SetCurEntry( _pEntry ); + if ( GetCurEntry() ) + { + InvalidateEntry( GetCurEntry() ); + CallEventListeners( VclEventId::ListboxTreeSelect, GetCurEntry() ); + } + updateHelpText(); + return true; + } + return false; +} + +void OCreationList::updateHelpText() +{ + const char* pHelpTextId = nullptr; + if ( GetCurEntry() ) + pHelpTextId = static_cast< TaskEntry* >( GetCurEntry()->GetUserData() )->pHelpID; + m_rTaskWindow.setHelpText(pHelpTextId); +} + +void OCreationList::onSelected( SvTreeListEntry const * _pEntry ) const +{ + OSL_ENSURE( _pEntry, "OCreationList::onSelected: invalid entry!" ); + URL aCommand; + aCommand.Complete = static_cast< TaskEntry* >( _pEntry->GetUserData() )->sUNOCommand; + m_rTaskWindow.getDetailView()->getBorderWin().getView()->getAppController().executeChecked( aCommand, Sequence< PropertyValue >() ); +} + +void OCreationList::KeyInput( const KeyEvent& rKEvt ) +{ + const vcl::KeyCode& rCode = rKEvt.GetKeyCode(); + if ( !rCode.IsMod1() && !rCode.IsMod2() && !rCode.IsShift() ) + { + if ( rCode.GetCode() == KEY_RETURN ) + { + SvTreeListEntry* pEntry = GetCurEntry() ? GetCurEntry() : FirstSelected(); + if ( pEntry ) + onSelected( pEntry ); + return; + } + } + SvTreeListEntry* pOldCurrent = GetCurEntry(); + SvTreeListBox::KeyInput(rKEvt); + SvTreeListEntry* pNewCurrent = GetCurEntry(); + + if ( pOldCurrent != pNewCurrent ) + { + if ( pOldCurrent ) + InvalidateEntry( pOldCurrent ); + if ( pNewCurrent ) + { + InvalidateEntry( pNewCurrent ); + CallEventListeners( VclEventId::ListboxSelect, pNewCurrent ); + } + updateHelpText(); + } +} + +OTasksWindow::OTasksWindow(vcl::Window* _pParent,OApplicationDetailView* _pDetailView) + : Window(_pParent,WB_DIALOGCONTROL ) + ,m_aCreation(VclPtr::Create(*this)) + ,m_aDescription(VclPtr::Create(this)) + ,m_aHelpText(VclPtr::Create(this,WB_WORDBREAK)) + ,m_aFL(VclPtr::Create(this,WB_VERT)) + ,m_pDetailView(_pDetailView) +{ + m_aCreation->SetHelpId(HID_APP_CREATION_LIST); + m_aCreation->SetSelectHdl(LINK(this, OTasksWindow, OnEntrySelectHdl)); + m_aHelpText->SetHelpId(HID_APP_HELP_TEXT); + m_aDescription->SetHelpId(HID_APP_DESCRIPTION_TEXT); + m_aDescription->SetText(DBA_RES(STR_DESCRIPTION)); + + Image aFolderImage = ImageProvider::getFolderImage( css::sdb::application::DatabaseObject::FORM ); + m_aCreation->SetDefaultCollapsedEntryBmp( aFolderImage ); + m_aCreation->SetDefaultExpandedEntryBmp( aFolderImage ); + + ImplInitSettings(); +} + +OTasksWindow::~OTasksWindow() +{ + disposeOnce(); +} + +void OTasksWindow::dispose() +{ + Clear(); + m_aCreation.disposeAndClear(); + m_aDescription.disposeAndClear(); + m_aHelpText.disposeAndClear(); + m_aFL.disposeAndClear(); + m_pDetailView.clear(); + vcl::Window::dispose(); +} + +void OTasksWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +void OTasksWindow::ImplInitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont(*this, aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + m_aHelpText->SetTextColor( rStyleSettings.GetFieldTextColor() ); + m_aHelpText->SetTextFillColor(); + m_aDescription->SetTextColor( rStyleSettings.GetFieldTextColor() ); + m_aDescription->SetTextFillColor(); + + SetBackground( rStyleSettings.GetFieldColor() ); + m_aHelpText->SetBackground( rStyleSettings.GetFieldColor() ); + m_aDescription->SetBackground( rStyleSettings.GetFieldColor() ); + m_aFL->SetBackground( rStyleSettings.GetFieldColor() ); + + aFont = m_aDescription->GetControlFont(); + aFont.SetWeight(WEIGHT_BOLD); + m_aDescription->SetControlFont(aFont); +} + +void OTasksWindow::setHelpText(const char* pId) +{ + if (pId) + { + OUString sText = DBA_RES(pId); + m_aHelpText->SetText(sText); + } + else + { + m_aHelpText->SetText(OUString()); +} + +} + +IMPL_LINK_NOARG(OTasksWindow, OnEntrySelectHdl, SvTreeListBox*, void) +{ + SvTreeListEntry* pEntry = m_aCreation->GetHdlEntry(); + if ( pEntry ) + m_aHelpText->SetText(DBA_RES(static_cast(pEntry->GetUserData())->pHelpID)); +} + +void OTasksWindow::Resize() +{ + // parent window dimension + Size aOutputSize( GetOutputSize() ); + long nOutputWidth = aOutputSize.Width(); + long nOutputHeight = aOutputSize.Height(); + + Size aFLSize = LogicToPixel(Size(2, 6), MapMode(MapUnit::MapAppFont)); + sal_Int32 n6PPT = aFLSize.Height(); + long nHalfOutputWidth = static_cast(nOutputWidth * 0.5); + + m_aCreation->SetPosSizePixel( Point(0, 0), Size(nHalfOutputWidth - n6PPT, nOutputHeight) ); + // i77897 make the m_aHelpText a little bit smaller. (-5) + sal_Int32 nNewWidth = nOutputWidth - nHalfOutputWidth - aFLSize.Width() - 5; + m_aDescription->SetPosSizePixel( Point(nHalfOutputWidth + n6PPT, 0), Size(nNewWidth, nOutputHeight) ); + Size aDesc = m_aDescription->CalcMinimumSize(); + m_aHelpText->SetPosSizePixel( Point(nHalfOutputWidth + n6PPT, aDesc.Height() ), Size(nNewWidth, nOutputHeight - aDesc.Height() - n6PPT) ); + + m_aFL->SetPosSizePixel( Point(nHalfOutputWidth , 0), Size(aFLSize.Width(), nOutputHeight ) ); +} + +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() ); + + for (auto const& task : _rList) + { + SvTreeListEntry* pEntry = m_aCreation->InsertEntry(task.sTitle); + pEntry->SetUserData( new TaskEntry(task) ); + + Image aImage( *pImages ); + m_aCreation->SetExpandedEntryBmp( pEntry, aImage ); + m_aCreation->SetCollapsedEntryBmp( pEntry, aImage ); + ++pImages; + } + } + catch(Exception&) + { + } + + m_aCreation->Show(); + m_aCreation->SelectAll(false); + m_aHelpText->Show(); + m_aDescription->Show(); + m_aFL->Show(); + m_aCreation->updateHelpText(); + Enable(!_rList.empty()); +} + +void OTasksWindow::Clear() +{ + m_aCreation->resetLastActive(); + SvTreeListEntry* pEntry = m_aCreation->First(); + while ( pEntry ) + { + delete static_cast< TaskEntry* >( pEntry->GetUserData() ); + pEntry = m_aCreation->Next(pEntry); + } + m_aCreation->Clear(); +} + + +OApplicationDetailView::OApplicationDetailView(OAppBorderWindow& _rParent,PreviewMode _ePreviewMode) : OSplitterView(&_rParent ) + ,m_aHorzSplitter(VclPtr::Create(this)) + ,m_aTasks(VclPtr::Create(this, STR_TASKS, WB_BORDER | WB_DIALOGCONTROL)) + ,m_aContainer(VclPtr::Create(this, nullptr, WB_BORDER | WB_DIALOGCONTROL)) + ,m_rBorderWin(_rParent) +{ + ImplInitSettings(); + + m_pControlHelper = VclPtr::Create(m_aContainer.get(),m_rBorderWin,_ePreviewMode); + m_pControlHelper->Show(); + m_aContainer->setChildWindow(m_pControlHelper); + + VclPtrInstance pTasks(m_aTasks.get(),this); + pTasks->Show(); + pTasks->Disable(m_rBorderWin.getView()->getCommandController().isDataSourceReadOnly()); + m_aTasks->setChildWindow(pTasks); + m_aTasks->Show(); + + m_aContainer->Show(); + + const long nFrameWidth = LogicToPixel(Size(3, 0), MapMode(MapUnit::MapAppFont)).Width(); + m_aHorzSplitter->SetPosSizePixel( Point(0,50), Size(0,nFrameWidth) ); + // now set the components at the base class + set(m_aContainer.get(),m_aTasks.get()); + + m_aHorzSplitter->Show(); + setSplitter(m_aHorzSplitter.get()); +} + +OApplicationDetailView::~OApplicationDetailView() +{ + disposeOnce(); +} + +void OApplicationDetailView::dispose() +{ + set(nullptr); + setSplitter(nullptr); + m_aHorzSplitter.disposeAndClear(); + m_aTasks.disposeAndClear(); + m_aContainer.disposeAndClear(); + m_pControlHelper.clear(); + OSplitterView::dispose(); +} + +void OApplicationDetailView::ImplInitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont(*this, aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + + SetBackground( rStyleSettings.GetFieldColor() ); + + m_aHorzSplitter->SetBackground( rStyleSettings.GetDialogColor() ); + m_aHorzSplitter->SetFillColor( rStyleSettings.GetDialogColor() ); + m_aHorzSplitter->SetTextFillColor(rStyleSettings.GetDialogColor() ); +} + +void OApplicationDetailView::DataChanged( const DataChangedEvent& rDCEvt ) +{ + OSplitterView::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 OApplicationDetailView::setTaskExternalMnemonics( MnemonicGenerator const & _rMnemonics ) +{ + m_aExternalMnemonics = _rMnemonics; +} + +bool OApplicationDetailView::interceptKeyInput( const KeyEvent& _rEvent ) +{ + const vcl::KeyCode& rKeyCode = _rEvent.GetKeyCode(); + if ( rKeyCode.GetModifier() == KEY_MOD2 ) + return getTasksWindow().HandleKeyInput( _rEvent ); + + // not handled + return false; +} + +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_aContainer->setTitle(rData.pTitleId); + + // let our helper create the object list + if ( _eType == E_TABLE ) + m_pControlHelper->createTablesPage( _rxConnection ); + else + m_pControlHelper->createPage( _eType, _rxNonTableElements ); + + // resize for proper window arrangements + Resize(); +} + +const TaskPaneData& OApplicationDetailView::impl_getTaskPaneData( ElementType _eType ) +{ + if ( m_aTaskPaneData.empty() ) + m_aTaskPaneData.resize( ELEMENT_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; +} + +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!" ); + } + + MnemonicGenerator aAllMnemonics( m_aExternalMnemonics ); + + // 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 + { + aAllMnemonics.RegisterMnemonic( pTask->sTitle ); + ++pTask; + } + } + + // for the remaining entries, assign mnemonics + for (auto const& task : rList) + { + aAllMnemonics.CreateMnemonic(task.sTitle); + // don't do this for now, until our task window really supports mnemonics + } +} + +OUString OApplicationDetailView::getQualifiedName( SvTreeListEntry* _pEntry ) const +{ + return m_pControlHelper->getQualifiedName( _pEntry ); +} + +bool OApplicationDetailView::isLeaf(SvTreeListEntry const * _pEntry) +{ + return OAppDetailPageHelper::isLeaf(_pEntry); +} + +bool OApplicationDetailView::isALeafSelected() const +{ + return m_pControlHelper->isALeafSelected(); +} + +void OApplicationDetailView::selectAll() +{ + m_pControlHelper->selectAll(); +} + +void OApplicationDetailView::sortDown() +{ + m_pControlHelper->sortDown(); +} + +void OApplicationDetailView::sortUp() +{ + m_pControlHelper->sortUp(); +} + +bool OApplicationDetailView::isFilled() const +{ + return m_pControlHelper->isFilled(); +} + +ElementType OApplicationDetailView::getElementType() const +{ + return m_pControlHelper->getElementType(); +} + +void OApplicationDetailView::clearPages(bool _bTaskAlso) +{ + if ( _bTaskAlso ) + getTasksWindow().Clear(); + m_pControlHelper->clearPages(); +} + +sal_Int32 OApplicationDetailView::getSelectionCount() +{ + return m_pControlHelper->getSelectionCount(); +} + +sal_Int32 OApplicationDetailView::getElementCount() const +{ + return m_pControlHelper->getElementCount(); +} + +void OApplicationDetailView::getSelectionElementNames( std::vector< OUString>& _rNames ) const +{ + m_pControlHelper->getSelectionElementNames( _rNames ); +} + +void OApplicationDetailView::describeCurrentSelectionForControl( const Control& _rControl, Sequence< NamedDatabaseObject >& _out_rSelectedObjects ) +{ + m_pControlHelper->describeCurrentSelectionForControl( _rControl, _out_rSelectedObjects ); +} + +void OApplicationDetailView::describeCurrentSelectionForType( const ElementType _eType, Sequence< NamedDatabaseObject >& _out_rSelectedObjects ) +{ + m_pControlHelper->describeCurrentSelectionForType( _eType, _out_rSelectedObjects ); +} + +void OApplicationDetailView::selectElements(const Sequence< OUString>& _aNames) +{ + m_pControlHelper->selectElements( _aNames ); +} + +SvTreeListEntry* OApplicationDetailView::getEntry( const Point& _aPoint ) const +{ + return m_pControlHelper->getEntry(_aPoint); +} + +bool OApplicationDetailView::isCutAllowed() +{ + return false; +} + +bool OApplicationDetailView::isCopyAllowed() +{ + return true; +} + +bool OApplicationDetailView::isPasteAllowed() { return true; } + +void OApplicationDetailView::copy() { } + +void OApplicationDetailView::cut() { } + +void OApplicationDetailView::paste() { } + +SvTreeListEntry* OApplicationDetailView::elementAdded(ElementType _eType,const OUString& _rName, const Any& _rObject ) +{ + return m_pControlHelper->elementAdded(_eType,_rName, _rObject ); +} + +void OApplicationDetailView::elementRemoved(ElementType _eType,const OUString& _rName ) +{ + m_pControlHelper->elementRemoved(_eType,_rName ); +} + +void OApplicationDetailView::elementReplaced(ElementType _eType + ,const OUString& _rOldName + ,const OUString& _rNewName ) +{ + m_pControlHelper->elementReplaced( _eType, _rOldName, _rNewName ); +} + +PreviewMode OApplicationDetailView::getPreviewMode() const +{ + return m_pControlHelper->getPreviewMode(); +} + +bool OApplicationDetailView::isPreviewEnabled() const +{ + return m_pControlHelper->isPreviewEnabled(); +} + +void OApplicationDetailView::switchPreview(PreviewMode _eMode) +{ + m_pControlHelper->switchPreview(_eMode); +} + +void OApplicationDetailView::showPreview(const Reference< XContent >& _xContent) +{ + m_pControlHelper->showPreview(_xContent); +} + +void OApplicationDetailView::showPreview( const OUString& _sDataSourceName, + const OUString& _sName, + bool _bTable) +{ + m_pControlHelper->showPreview(_sDataSourceName,_sName,_bTable); +} + +bool OApplicationDetailView::isSortUp() const +{ + return m_pControlHelper->isSortUp(); +} + +vcl::Window* OApplicationDetailView::getTreeWindow() const +{ + return m_pControlHelper->getCurrentView(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppDetailView.hxx b/dbaccess/source/ui/app/AppDetailView.hxx new file mode 100644 index 000000000..38bc41ab1 --- /dev/null +++ b/dbaccess/source/ui/app/AppDetailView.hxx @@ -0,0 +1,368 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILVIEW_HXX + +#include +#include +#include +#include +#include +#include +#include +#include +#include "AppTitleWindow.hxx" +#include +#include +#include + +#include + +class SvTreeListEntry; + +namespace dbaui +{ + class OAppBorderWindow; + class OApplicationDetailView; + class OAppDetailPageHelper; + class OTasksWindow; + + class OCreationList : public SvTreeListBox + { + OTasksWindow& m_rTaskWindow; + + // members related to drawing the currently hovered/selected entry + SvTreeListEntry* m_pMouseDownEntry; + SvTreeListEntry* m_pLastActiveEntry; + Color m_aOriginalBackgroundColor; + vcl::Font m_aOriginalFont; + + public: + explicit OCreationList( OTasksWindow& _rParent ); + // Window overrides + virtual void MouseMove( const MouseEvent& rMEvt ) override; + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void MouseButtonUp( const MouseEvent& rMEvt ) override; + virtual void KeyInput( const KeyEvent& rKEvt ) override; + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + virtual void StartDrag( sal_Int8 _nAction, const Point& _rPosPixel ) override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + + void resetLastActive() { m_pLastActiveEntry = nullptr;} + + void updateHelpText(); + + protected: + virtual void PreparePaint(vcl::RenderContext& rRenderContext, SvTreeListEntry& rEntry) override; + virtual tools::Rectangle GetFocusRect(const SvTreeListEntry* _pEntry, long _nLine) override; + virtual void ModelHasCleared() override; + + // IMnemonicEntryList + virtual void SelectSearchEntry( const void* _pEntry ) override; + virtual void ExecuteSearchEntry( const void* _pEntry ) const override; + + private: + void onSelected( SvTreeListEntry const * _pEntry ) const; + /** sets a new current entry, and invalidates the old and the new one, if necessary + @return if and only if the "current entry" changed + */ + bool setCurrentEntryInvalidate( SvTreeListEntry* _pEntry ); + }; + + struct TaskEntry + { + OUString sUNOCommand; + const char* 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, const char* pHelpID, const char* 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 + const char* pTitleId; + }; + + class OTasksWindow : public vcl::Window + { + VclPtr m_aCreation; + VclPtr m_aDescription; + VclPtr m_aHelpText; + VclPtr m_aFL; + VclPtr m_pDetailView; + + DECL_LINK( OnEntrySelectHdl, SvTreeListBox*, void ); + void ImplInitSettings(); + protected: + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + public: + OTasksWindow(vcl::Window* _pParent,OApplicationDetailView* _pDetailView); + virtual ~OTasksWindow() override; + virtual void dispose() override; + + // Window overrides + virtual void Resize() override; + + OApplicationDetailView* getDetailView() const { return m_pDetailView; } + + /// fills the Creation listbox with the necessary strings and images + void fillTaskEntryList( const TaskEntryList& _rList ); + + bool HandleKeyInput( const KeyEvent& _rKEvt ) + { + return m_aCreation->HandleKeyInput( _rKEvt ); + } + + void Clear(); + void setHelpText(const char* pId); + }; + class OApplicationDetailView : public OSplitterView + , public IClipboardTest + { + VclPtr m_aHorzSplitter; + VclPtr m_aTasks; + VclPtr m_aContainer; + OAppBorderWindow& m_rBorderWin; // my parent + VclPtr m_pControlHelper; + std::vector< TaskPaneData > m_aTaskPaneData; + MnemonicGenerator m_aExternalMnemonics; + + void ImplInitSettings(); + + protected: + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + + public: + OApplicationDetailView(OAppBorderWindow& _rParent,PreviewMode _ePreviewMode); + virtual ~OApplicationDetailView() override; + // Window overrides + virtual void dispose() 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); + + void setTaskExternalMnemonics( MnemonicGenerator const & _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 ); + + OAppBorderWindow& getBorderWin() const { return m_rBorderWin; } + OTasksWindow& getTasksWindow() const { return *static_cast< OTasksWindow* >( m_aTasks->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( SvTreeListEntry* _pEntry ) const; + + /** returns if an entry is a leaf + @param _pEntry + The entry to check + @return + if the entry is a leaf, otherwise + */ + static bool isLeaf(SvTreeListEntry const * _pEntry); + + /** 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 Control& _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 + ); + + /** 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. + */ + SvTreeListEntry* 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); + + SvTreeListEntry* getEntry( const Point& _aPoint ) const; + + vcl::Window* getTreeWindow() 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPDETAILVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppIconControl.cxx b/dbaccess/source/ui/app/AppIconControl.cxx new file mode 100644 index 000000000..514580014 --- /dev/null +++ b/dbaccess/source/ui/app/AppIconControl.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 "AppIconControl.hxx" +#include +#include +#include +#include +#include +#include + +using namespace ::dbaui; +OApplicationIconControl::OApplicationIconControl(vcl::Window* _pParent) + : SvtIconChoiceCtrl(_pParent,WB_ICON | WB_NOCOLUMNHEADER | WB_HIGHLIGHTFRAME | /*!WB_NOSELECTION |*/ + WB_TABSTOP | WB_CLIPCHILDREN | WB_NOVSCROLL | WB_SMART_ARRANGE | WB_NOHSCROLL | WB_CENTER) + ,DropTargetHelper(this) + ,m_pActionListener(nullptr) +{ + + static const struct CategoryDescriptor + { + const char* pLabelResId; + ElementType eType; + const char* 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) + { + SvxIconChoiceCtrlEntry* pEntry = InsertEntry( + DBA_RES(aCategorie.pLabelResId) , + Image(StockImage::Yes, OUString::createFromAscii(aCategorie.aImageResId))); + if ( pEntry ) + pEntry->SetUserData( new ElementType( aCategorie.eType ) ); + } + + SetChoiceWithCursor(); + SetSelectionMode(SelectionMode::Single); +} + +OApplicationIconControl::~OApplicationIconControl() +{ + disposeOnce(); +} + +void OApplicationIconControl::dispose() +{ + sal_Int32 nCount = GetEntryCount(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + SvxIconChoiceCtrlEntry* pEntry = GetEntry( i ); + if ( pEntry ) + { + delete static_cast(pEntry->GetUserData()); + pEntry->SetUserData(nullptr); + } + } + DropTargetHelper::dispose(); + SvtIconChoiceCtrl::dispose(); +} + +sal_Int8 OApplicationIconControl::AcceptDrop( const AcceptDropEvent& _rEvt ) +{ + sal_Int8 nDropOption = DND_ACTION_NONE; + if ( m_pActionListener ) + { + + SvxIconChoiceCtrlEntry* pEntry = GetEntry(_rEvt.maPosPixel); + if ( pEntry ) + { + SetCursor(pEntry); + nDropOption = m_pActionListener->queryDrop( _rEvt, GetDataFlavorExVector() ); + } + } + + return nDropOption; +} + +sal_Int8 OApplicationIconControl::ExecuteDrop( const ExecuteDropEvent& _rEvt ) +{ + if ( m_pActionListener ) + return m_pActionListener->executeDrop( _rEvt ); + + return DND_ACTION_NONE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppIconControl.hxx b/dbaccess/source/ui/app/AppIconControl.hxx new file mode 100644 index 000000000..38408af60 --- /dev/null +++ b/dbaccess/source/ui/app/AppIconControl.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPICONCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPICONCONTROL_HXX + +#include +#include + +namespace dbaui +{ + class IControlActionListener; + class OApplicationIconControl :public SvtIconChoiceCtrl + ,public DropTargetHelper + { + IControlActionListener* m_pActionListener; + + public: + explicit OApplicationIconControl(vcl::Window* _pParent); + virtual ~OApplicationIconControl() override; + virtual void dispose() override; + + void setControlActionListener( IControlActionListener* _pListener ) { m_pActionListener = _pListener; } + + protected: + // DropTargetHelper overridables + virtual sal_Int8 AcceptDrop( const AcceptDropEvent& _rEvt ) override; + virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& _rEvt ) override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPICONCONTROL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppSwapWindow.cxx b/dbaccess/source/ui/app/AppSwapWindow.cxx new file mode 100644 index 000000000..e291bdb8a --- /dev/null +++ b/dbaccess/source/ui/app/AppSwapWindow.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 "AppSwapWindow.hxx" +#include +#include "AppView.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::lang; +using namespace ::com::sun::star::container; + +OApplicationSwapWindow::OApplicationSwapWindow( vcl::Window* _pParent, OAppBorderWindow& _rBorderWindow ) + :Window(_pParent,WB_DIALOGCONTROL ) + ,m_aIconControl(VclPtr::Create(this)) + ,m_eLastType(E_NONE) + ,m_rBorderWin( _rBorderWindow ) +{ + ImplInitSettings(); + + m_aIconControl->SetClickHdl(LINK(this, OApplicationSwapWindow, OnContainerSelectHdl)); + m_aIconControl->setControlActionListener( &m_rBorderWin.getView()->getAppController() ); + m_aIconControl->SetHelpId(HID_APP_SWAP_ICONCONTROL); + m_aIconControl->Show(); +} + +OApplicationSwapWindow::~OApplicationSwapWindow() +{ + disposeOnce(); +} + +void OApplicationSwapWindow::dispose() +{ + m_aIconControl.disposeAndClear(); + vcl::Window::dispose(); +} + +void OApplicationSwapWindow::Resize() +{ + Size aFLSize = LogicToPixel(Size(8, 0), MapMode(MapUnit::MapAppFont)); + long nX = 0; + if ( m_aIconControl->GetEntryCount() != 0 ) + nX = m_aIconControl->GetBoundingBox( m_aIconControl->GetEntry(0) ).GetWidth() + aFLSize.Width(); + + Size aOutputSize = GetOutputSize(); + + m_aIconControl->SetPosSizePixel( Point(static_cast((aOutputSize.Width() - nX)*0.5), 0) ,Size(nX,aOutputSize.Height())); + m_aIconControl->ArrangeIcons(); +} + +void OApplicationSwapWindow::ImplInitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont(*this, aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + + SetBackground( rStyleSettings.GetFieldColor() ); +} + +void OApplicationSwapWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::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 OApplicationSwapWindow::clearSelection() +{ + m_aIconControl->SetNoSelection(); + SvxIconChoiceCtrlEntry* pEntry = m_aIconControl->GetSelectedEntry(); + if ( pEntry ) + m_aIconControl->InvalidateEntry(pEntry); + m_aIconControl->GetClickHdl().Call(m_aIconControl.get()); +} + +void OApplicationSwapWindow::createIconAutoMnemonics( MnemonicGenerator& _rMnemonics ) +{ + m_aIconControl->CreateAutoMnemonics( _rMnemonics ); +} + +bool OApplicationSwapWindow::interceptKeyInput( const KeyEvent& _rEvent ) +{ + const vcl::KeyCode& rKeyCode = _rEvent.GetKeyCode(); + if ( rKeyCode.GetModifier() == KEY_MOD2 ) + return m_aIconControl->DoKeyInput( _rEvent ); + + // not handled + return false; +} + +ElementType OApplicationSwapWindow::getElementType() const +{ + SvxIconChoiceCtrlEntry* pEntry = m_aIconControl->GetSelectedEntry(); + return pEntry ? *static_cast(pEntry->GetUserData()) : E_NONE; +} + +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; + } + + PostUserEvent( LINK( this, OApplicationSwapWindow, ChangeToLastSelected ), nullptr, true ); + return false; +} + +IMPL_LINK(OApplicationSwapWindow, OnContainerSelectHdl, SvtIconChoiceCtrl*, _pControl, void) +{ + SvxIconChoiceCtrlEntry* pEntry = _pControl->GetSelectedEntry(); + ElementType eType = E_NONE; + if ( pEntry ) + { + eType = *static_cast(pEntry->GetUserData()); + onContainerSelected( eType ); // i87582 + } +} + +IMPL_LINK_NOARG(OApplicationSwapWindow, ChangeToLastSelected, void*, void) +{ + selectContainer(m_eLastType); +} + +void OApplicationSwapWindow::selectContainer(ElementType _eType) +{ + sal_Int32 nCount = m_aIconControl->GetEntryCount(); + SvxIconChoiceCtrlEntry* pEntry = nullptr; + for (sal_Int32 i=0; i < nCount; ++i) + { + pEntry = m_aIconControl->GetEntry(i); + if ( pEntry && *static_cast(pEntry->GetUserData()) == _eType ) + break; + pEntry = nullptr; + } + + if ( pEntry ) + m_aIconControl->SetCursor(pEntry); // this call also initiates a onContainerSelected call + else + onContainerSelected( _eType ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppSwapWindow.hxx b/dbaccess/source/ui/app/AppSwapWindow.hxx new file mode 100644 index 000000000..62f58c152 --- /dev/null +++ b/dbaccess/source/ui/app/AppSwapWindow.hxx @@ -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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX + +#include +#include +#include "AppIconControl.hxx" +#include + +namespace dbaui +{ + class OAppBorderWindow; + class OApplicationSwapWindow : public vcl::Window, + public IClipboardTest + { + VclPtr m_aIconControl; + ElementType m_eLastType; + OAppBorderWindow& m_rBorderWin; + + void ImplInitSettings(); + + DECL_LINK( OnContainerSelectHdl, SvtIconChoiceCtrl*, void ); + DECL_LINK( ChangeToLastSelected, void*, void ); + protected: + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + public: + OApplicationSwapWindow( vcl::Window* _pParent, OAppBorderWindow& _rBorderWindow ); + virtual ~OApplicationSwapWindow() override; + // Window overrides + virtual void dispose() override; + virtual void Resize() 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 { } + + sal_Int32 GetEntryCount() const { return m_aIconControl->GetEntryCount(); } + SvxIconChoiceCtrlEntry* GetEntry( sal_uLong nPos ) const { return m_aIconControl->GetEntry(nPos); } + tools::Rectangle GetBoundingBox( SvxIconChoiceCtrlEntry* pEntry ) const { return m_aIconControl->GetBoundingBox(pEntry); } + + /** 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 +#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPSWAPWINDOW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppTitleWindow.cxx b/dbaccess/source/ui/app/AppTitleWindow.cxx new file mode 100644 index 000000000..d6d121ba4 --- /dev/null +++ b/dbaccess/source/ui/app/AppTitleWindow.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 "AppTitleWindow.hxx" +#include +#include +#include +#include + +namespace dbaui +{ + +OTitleWindow::OTitleWindow(vcl::Window* _pParent, const char* pTitleId, WinBits _nBits, bool _bShift) +: Window(_pParent,_nBits | WB_DIALOGCONTROL) +, m_aSpace1(VclPtr::Create(this)) +, m_aSpace2(VclPtr::Create(this)) +, m_aTitle(VclPtr::Create(this)) +, m_pChild(nullptr) +, m_bShift(_bShift) +{ + setTitle(pTitleId); + SetBorderStyle(WindowBorderStyle::MONO); + ImplInitSettings(); + + const StyleSettings& rStyle = Application::GetSettings().GetStyleSettings(); + vcl::Window* pWindows[] = { m_aSpace1.get(), m_aSpace2.get(), m_aTitle.get() }; + for (vcl::Window* pWindow : pWindows) + { + vcl::Font aFont = pWindow->GetControlFont(); + aFont.SetWeight(WEIGHT_BOLD); + pWindow->SetControlFont(aFont); + pWindow->SetControlForeground(rStyle.GetLightColor()); + pWindow->SetControlBackground(rStyle.GetShadowColor()); + pWindow->Show(); + } +} + +OTitleWindow::~OTitleWindow() +{ + disposeOnce(); +} + +void OTitleWindow::dispose() +{ + if ( m_pChild ) + { + m_pChild->Hide(); + } + m_pChild.disposeAndClear(); + m_aSpace1.disposeAndClear(); + m_aSpace2.disposeAndClear(); + m_aTitle.disposeAndClear(); + vcl::Window::dispose(); +} + +void OTitleWindow::setChildWindow(vcl::Window* _pChild) +{ + m_pChild = _pChild; +} + +#define SPACE_BORDER 1 +void OTitleWindow::Resize() +{ + // parent window dimension + Size aOutputSize( GetOutputSize() ); + long nOutputWidth = aOutputSize.Width(); + long nOutputHeight = aOutputSize.Height(); + + Size aTextSize = LogicToPixel(Size(6, 3), MapMode(MapUnit::MapAppFont)); + sal_Int32 nXOffset = aTextSize.Width(); + sal_Int32 nYOffset = aTextSize.Height(); + sal_Int32 nHeight = GetTextHeight() + 2*nYOffset; + + m_aSpace1->SetPosSizePixel( Point(SPACE_BORDER, SPACE_BORDER ), + Size(nXOffset , nHeight - SPACE_BORDER) ); + m_aSpace2->SetPosSizePixel( Point(nXOffset + SPACE_BORDER, SPACE_BORDER ), + Size(nOutputWidth - nXOffset - 2*SPACE_BORDER, nYOffset) ); + m_aTitle->SetPosSizePixel( Point(nXOffset + SPACE_BORDER, nYOffset + SPACE_BORDER), + Size(nOutputWidth - nXOffset - 2*SPACE_BORDER, nHeight - nYOffset - SPACE_BORDER) ); + if ( m_pChild ) + { + m_pChild->SetPosSizePixel( Point(m_bShift ? (nXOffset+SPACE_BORDER) : sal_Int32(SPACE_BORDER), nHeight + nXOffset + SPACE_BORDER), + Size(nOutputWidth - ( m_bShift ? (2*nXOffset - 2*SPACE_BORDER) : sal_Int32(SPACE_BORDER) ), nOutputHeight - nHeight - 2*nXOffset - 2*SPACE_BORDER) ); + } +} + +void OTitleWindow::setTitle(const char* pTitleId) +{ + if (pTitleId) + { + m_aTitle->SetText(DBA_RES(pTitleId)); + } +} + +void OTitleWindow::GetFocus() +{ + Window::GetFocus(); + if ( m_pChild ) + m_pChild->GrabFocus(); +} + +long OTitleWindow::GetWidthPixel() const +{ + Size aTextSize = LogicToPixel(Size(12, 0), MapMode(MapUnit::MapAppFont)); + sal_Int32 nWidth = GetTextWidth(m_aTitle->GetText()) + 2*aTextSize.Width(); + + return nWidth; +} + +void OTitleWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::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 OTitleWindow::ImplInitSettings() +{ + // FIXME RenderContext + AllSettings aAllSettings = GetSettings(); + StyleSettings aStyle = aAllSettings.GetStyleSettings(); + aStyle.SetMonoColor(aStyle.GetActiveBorderColor());//GetMenuBorderColor()); + aAllSettings.SetStyleSettings(aStyle); + SetSettings(aAllSettings); + + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont(*this, aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + + SetBackground( rStyleSettings.GetFieldColor() ); +} + +void OTitleWindow::ApplySettings(vcl::RenderContext& rRenderContext) +{ + // FIXME RenderContext + AllSettings aAllSettings = rRenderContext.GetSettings(); + StyleSettings aStyle = aAllSettings.GetStyleSettings(); + aStyle.SetMonoColor(aStyle.GetActiveBorderColor());//GetMenuBorderColor()); + aAllSettings.SetStyleSettings(aStyle); + rRenderContext.SetSettings(aAllSettings); + + const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor(rStyleSettings.GetWindowTextColor()); + SetPointFont(*this, aFont); + + rRenderContext.SetTextColor(rStyleSettings.GetFieldTextColor()); + rRenderContext.SetTextFillColor(); + + rRenderContext.SetBackground(rStyleSettings.GetFieldColor()); +} + +} // namespace dbaui +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppTitleWindow.hxx b/dbaccess/source/ui/app/AppTitleWindow.hxx new file mode 100644 index 000000000..c6a8d417d --- /dev/null +++ b/dbaccess/source/ui/app/AppTitleWindow.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_APPTITLEWINDOW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPTITLEWINDOW_HXX + +#include + +namespace dbaui +{ + class OTitleWindow : public vcl::Window + { + VclPtr m_aSpace1; + VclPtr m_aSpace2; + VclPtr m_aTitle; + VclPtr m_pChild; + bool m_bShift; + void ImplInitSettings(); + protected: + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + public: + OTitleWindow(vcl::Window* _pParent, const char* pTitleId, WinBits _nBits, bool _bShift = true); + virtual ~OTitleWindow() override; + virtual void dispose() override; + + // Window overrides + virtual void Resize() override; + virtual void GetFocus() override; + + virtual void ApplySettings(vcl::RenderContext& rRenderContext) override; + + /** 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(vcl::Window* _pChild); + + /** gets the child window. + + @return + The child window. + */ + vcl::Window* getChildWindow() const { return m_pChild; } + + /** sets the title text out of the resource + @param pTitleId + The resource id of the title text. + */ + void setTitle(const char* pTitleId); + + /** Gets the min Width in Pixel which is needed to display the whole + + @return + the min width + */ + long GetWidthPixel() const; + }; +} // namespace dbaui +#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPTITLEWINDOW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppView.cxx b/dbaccess/source/ui/app/AppView.cxx new file mode 100644 index 000000000..fb61be909 --- /dev/null +++ b/dbaccess/source/ui/app/AppView.cxx @@ -0,0 +1,524 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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) : Window(_pParent,WB_DIALOGCONTROL) + ,m_pPanel(nullptr) + ,m_pDetailView(nullptr) + ,m_pView(_pParent) +{ + + SetBorderStyle(WindowBorderStyle::MONO); + + m_pPanel = VclPtr::Create(this,STR_DATABASE,WB_BORDER | WB_DIALOGCONTROL, false); + m_pPanel->SetBorderStyle(WindowBorderStyle::MONO); + VclPtrInstance pSwap( m_pPanel, *this ); + pSwap->Show(); + + m_pPanel->setChildWindow(pSwap); + m_pPanel->Show(); + + m_pDetailView = VclPtr::Create(*this,_ePreviewMode); + m_pDetailView->Show(); + + ImplInitSettings(); +} + +OAppBorderWindow::~OAppBorderWindow() +{ + disposeOnce(); +} + +void OAppBorderWindow::dispose() +{ + // destroy children + if ( m_pPanel ) + m_pPanel->Hide(); + m_pPanel.disposeAndClear(); + if ( m_pDetailView ) + m_pDetailView->Hide(); + m_pDetailView.disposeAndClear(); + m_pView.clear(); + vcl::Window::dispose(); +} + +void OAppBorderWindow::GetFocus() +{ + if ( m_pPanel ) + m_pPanel->GrabFocus(); +} + +void OAppBorderWindow::Resize() +{ + // parent window dimension + Size aOutputSize( GetOutputSize() ); + long nOutputWidth = aOutputSize.Width(); + long nOutputHeight = aOutputSize.Height(); + long nX = 0; + + Size aFLSize = LogicToPixel(Size(3, 8), MapMode(MapUnit::MapAppFont)); + if ( m_pPanel ) + { + OApplicationSwapWindow* pSwap = getPanel(); + if ( pSwap && pSwap->GetEntryCount() != 0 ) + nX = pSwap->GetBoundingBox( pSwap->GetEntry(0) ).GetWidth() + aFLSize.Height(); + nX = std::max(m_pPanel->GetWidthPixel() ,nX); + m_pPanel->SetPosSizePixel(Point(0,0),Size(nX,nOutputHeight)); + } + + if ( m_pDetailView ) + m_pDetailView->SetPosSizePixel(Point(nX + aFLSize.Width(),0),Size(nOutputWidth - nX - aFLSize.Width(),nOutputHeight)); +} + +void OAppBorderWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::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 OAppBorderWindow::ImplInitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + vcl::Font aFont = rStyleSettings.GetFieldFont(); + aFont.SetColor( rStyleSettings.GetWindowTextColor() ); + SetPointFont(*this, aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + + SetBackground( rStyleSettings.GetDialogColor() ); +} + + +OApplicationSwapWindow* OAppBorderWindow::getPanel() const +{ + return static_cast< OApplicationSwapWindow* >( m_pPanel->getChildWindow() ); +} + + +OApplicationView::OApplicationView( vcl::Window* pParent + ,const Reference< XComponentContext >& _rxOrb + ,OApplicationController& _rAppController + ,PreviewMode _ePreviewMode + ) : + ODataView( pParent, _rAppController, _rxOrb, WB_DIALOGCONTROL ) + ,m_rAppController( _rAppController ) + ,m_eChildFocus(NONE) +{ + 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 ) ); +} + +bool OApplicationView::PreNotify( NotifyEvent& rNEvt ) +{ + switch(rNEvt.GetType()) + { + case MouseNotifyEvent::GETFOCUS: + if( m_pWin && getPanel() && getPanel()->HasChildPathFocus() ) + m_eChildFocus = PANELSWAP; + else if ( m_pWin && getDetailView() && getDetailView()->HasChildPathFocus() ) + m_eChildFocus = DETAIL; + else + m_eChildFocus = NONE; + break; + case MouseNotifyEvent::KEYINPUT: + { + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + // give the pane the chance to intercept mnemonic accelerators + // #i34790# + if ( getPanel() && getPanel()->interceptKeyInput( *pKeyEvent ) ) + return true; + // and ditto the detail view + // #i72799# + if ( getDetailView() && getDetailView()->interceptKeyInput( *pKeyEvent ) ) + return true; + } + break; + default: + break; + } + + return ODataView::PreNotify(rNEvt); +} + +IClipboardTest* OApplicationView::getActiveChild() const +{ + IClipboardTest* pTest = nullptr; + if ( DETAIL == m_eChildFocus ) + 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( SvTreeListEntry* _pEntry ) const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->getQualifiedName( _pEntry ); +} + +bool OApplicationView::isLeaf(SvTreeListEntry const * _pEntry) const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return OApplicationDetailView::isLeaf(_pEntry); +} + +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 Control& _rControl, Sequence< NamedDatabaseObject >& _out_rSelectedObjects ) +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + getDetailView()->describeCurrentSelectionForControl( _rControl, _out_rSelectedObjects ); +} + +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 ); +} + +SvTreeListEntry* 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); +} + +SvTreeListEntry* OApplicationView::getEntry( const Point& _aPosPixel ) const +{ + OSL_ENSURE(m_pWin && getDetailView(),"Detail view is NULL! -> GPF"); + return getDetailView()->getEntry(_aPosPixel); +} + +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_eChildFocus == NONE && m_pWin ) + { + 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(*this, aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + + SetBackground( rStyleSettings.GetFieldColor() ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/AppView.hxx b/dbaccess/source/ui/app/AppView.hxx new file mode 100644 index 000000000..0d492953a --- /dev/null +++ b/dbaccess/source/ui/app/AppView.hxx @@ -0,0 +1,297 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_APP_APPVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_APP_APPVIEW_HXX + +#include +#include +#include +#include +#include +#include +#include + +namespace com::sun::star::beans { class XPropertySet; } + +class Control; +class SvTreeListEntry; +class MnemonicGenerator; + +namespace dbaui +{ + class OApplicationView; + class OApplicationDetailView; + class OApplicationSwapWindow; + class OTitleWindow; + class OApplicationController; + + class OAppBorderWindow : public vcl::Window + { + VclPtr m_pPanel; + VclPtr m_pDetailView; + VclPtr m_pView; + + void ImplInitSettings(); + protected: + // Window + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + public: + OAppBorderWindow(OApplicationView* _pParent,PreviewMode _ePreviewMode); + virtual ~OAppBorderWindow() override; + virtual void dispose() override; + + // Window overrides + virtual void GetFocus() override; + virtual void Resize() override; + + OApplicationView* getView() const { return m_pView;} + OApplicationSwapWindow* getPanel() const; + OApplicationDetailView* getDetailView() const { return m_pDetailView;} + }; + + 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 m_eChildFocus; + + 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( SvTreeListEntry* _pEntry ) const; + + /** returns if an entry is a leaf + @param _pEntry + The entry to check + @return + if the entry is a leaf, otherwise + */ + bool isLeaf(SvTreeListEntry const * _pEntry) 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 Control& _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 + ); + + /** 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. + */ + SvTreeListEntry* 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); + + SvTreeListEntry* getEntry( const Point& _aPosPixel ) const; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_APPVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/subcomponentmanager.cxx b/dbaccess/source/ui/app/subcomponentmanager.cxx new file mode 100644 index 000000000..08df1dff0 --- /dev/null +++ b/dbaccess/source/ui/app/subcomponentmanager.cxx @@ -0,0 +1,555 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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::makeAny; + 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() + :sName() + ,nComponentType( -1 ) + ,eOpenMode( E_OPEN_NORMAL ) + ,xFrame() + ,xController() + ,xModel() + { + } + + SubComponentDescriptor( const OUString& i_rName, const sal_Int32 i_nComponentType, + const ElementOpenMode i_eOpenMode, const Reference< XComponent >& i_rComponent ) + :sName( i_rName ) + ,nComponentType( i_nComponentType ) + ,eOpenMode( i_eOpenMode ) + { + if ( !impl_constructFrom( i_rComponent ) ) + { + // i_rComponent is neither a model, nor a controller, nor a frame + // => it must be a css.sdb.DocumentDefinition + Reference< XComponentSupplier > xCompSupp( i_rComponent, UNO_QUERY_THROW ); + Reference< XComponent > xComponent( xCompSupp->getComponent(), UNO_QUERY_THROW ); + if ( !impl_constructFrom( xComponent ) ) + throw RuntimeException("Illegal component type." ); + xComponentCommandProcessor.set( i_rComponent, UNO_QUERY_THROW ); + xDocumentDefinitionProperties.set( i_rComponent, UNO_QUERY_THROW ); + } + } + + bool is() const { return xFrame.is(); } + + private: + bool impl_constructFrom( const Reference< XComponent >& _rxComponent ) + { + // is it a model? + xModel.set( _rxComponent, UNO_QUERY ); + if ( xModel.is() ) + { + xController.set( xModel->getCurrentController() ); + if ( xController.is() ) + xFrame.set( xController->getFrame(), UNO_SET_THROW ); + } + else + { + // is it a controller? + xController.set( _rxComponent, UNO_QUERY ); + if ( xController.is() ) + { + xFrame.set( xController->getFrame(), UNO_SET_THROW ); + } + else + { + // is it a frame? + xFrame.set( _rxComponent, UNO_QUERY ); + if ( !xFrame.is() ) + return false; + + // ensure we have a controller + xController.set( xFrame->getController(), UNO_SET_THROW ); + } + + // check whether there is a model (not required) + xModel.set( xController->getModel() ); + } + + return true; + } + }; + + struct SelectSubComponent + { + Reference< XComponent > operator()( const SubComponentDescriptor &_desc ) const + { + if ( _desc.xModel.is() ) + return _desc.xModel.get(); + OSL_ENSURE( _desc.xController.is(), "SelectSubComponent::operator(): illegal component!" ); + return _desc.xController.get(); + } + }; + + typedef std::vector< SubComponentDescriptor > SubComponents; + + struct SubComponentMatch + { + public: + SubComponentMatch( const OUString& i_rName, const sal_Int32 i_nComponentType, + const ElementOpenMode i_eOpenMode ) + :m_sName( i_rName ) + ,m_nComponentType( i_nComponentType ) + ,m_eOpenMode( i_eOpenMode ) + { + } + + bool operator()( const SubComponentDescriptor& i_rCompareWith ) const + { + return ( m_sName == i_rCompareWith.sName ) + && ( m_nComponentType == i_rCompareWith.nComponentType ) + && ( m_eOpenMode == i_rCompareWith.eOpenMode ); + } + private: + const OUString m_sName; + const sal_Int32 m_nComponentType; + const ElementOpenMode m_eOpenMode; + }; + } + + // SubComponentManager_Data + struct SubComponentManager_Data + { + SubComponentManager_Data( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex ) + :m_rController( _rController ) + ,m_aMutex( _rMutex ) + { + } + + OApplicationController& m_rController; + mutable ::comphelper::SharedMutex m_aMutex; + SubComponents m_aComponents; + + ::osl::Mutex& getMutex() const { return m_aMutex; } + }; + + // SubComponentManager + SubComponentManager::SubComponentManager( OApplicationController& _rController, const ::comphelper::SharedMutex& _rMutex ) + :m_pData( new SubComponentManager_Data( _rController, _rMutex ) ) + { + } + + SubComponentManager::~SubComponentManager() + { + } + + void SubComponentManager::disposing() + { + ::osl::MutexGuard aGuard( m_pData->getMutex() ); + m_pData->m_aComponents.clear(); + } + + namespace + { + bool lcl_fallbackToAnotherController( SubComponentDescriptor& _rCompDesc ) + { + Reference< XController > xFallback; + OSL_PRECOND( _rCompDesc.xModel.is(), "lcl_fallbackToAnotherController: illegal call!" ); + if ( !_rCompDesc.xModel.is() ) + return false; + + xFallback.set( _rCompDesc.xModel->getCurrentController() ); + if ( xFallback == _rCompDesc.xController ) + // don't accept the very same controller as fallback + xFallback.clear(); + + if ( !xFallback.is() ) + { + // perhaps XModel2 can be of help here + Reference< XModel2 > xModel2( _rCompDesc.xModel, UNO_QUERY ); + Reference< XEnumeration > xControllerEnum; + if ( xModel2.is() ) + xControllerEnum = xModel2->getControllers(); + while ( xControllerEnum.is() && xControllerEnum->hasMoreElements() ) + { + xFallback.set( xControllerEnum->nextElement(), UNO_QUERY ); + if ( xFallback == _rCompDesc.xController ) + xFallback.clear(); + } + } + + if ( xFallback.is() ) + { + _rCompDesc.xController = xFallback; + _rCompDesc.xFrame.set( xFallback->getFrame(), UNO_SET_THROW ); + return true; + } + + return false; + } + + bool lcl_closeComponent( const Reference< XCommandProcessor >& _rxCommandProcessor ) + { + bool bSuccess = false; + try + { + sal_Int32 nCommandIdentifier = _rxCommandProcessor->createCommandIdentifier(); + + Command aCommand; + aCommand.Name = "close"; + _rxCommandProcessor->execute( aCommand, nCommandIdentifier, nullptr ); + bSuccess = true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bSuccess; + } + + bool lcl_closeComponent( const SubComponentDescriptor& _rComponent ) + { + if ( _rComponent.xComponentCommandProcessor.is() ) + return lcl_closeComponent( _rComponent.xComponentCommandProcessor ); + + Reference< XController > xController( _rComponent.xController ); + OSL_ENSURE( xController.is(), "lcl_closeComponent: invalid controller!" ); + + // suspend the controller in the document + if ( xController.is() ) + if ( !xController->suspend( true ) ) + return false; + + bool bSuccess = false; + try + { + Reference< XCloseable > xCloseable( _rComponent.xFrame, UNO_QUERY_THROW ); + xCloseable->close( true ); + bSuccess = true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bSuccess; + } + + void lcl_notifySubComponentEvent( const SubComponentManager_Data& _rData, const char* _pAsciiEventName, + const SubComponentDescriptor& _rComponent ) + { + try + { + Reference< XDocumentEventBroadcaster > xBroadcaster( _rData.m_rController.getModel(), UNO_QUERY_THROW ); + xBroadcaster->notifyDocumentEvent( + OUString::createFromAscii( _pAsciiEventName ), + &_rData.m_rController, + makeAny( _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( const OUString& i_rName, const sal_Int32 _nComponentType ) + { + ::osl::MutexGuard aGuard( m_pData->getMutex() ); + ENSURE_OR_RETURN_FALSE( !i_rName.isEmpty(), "SubComponentManager::closeSubFrames: illegal name!" ); + + SubComponents aWorkingCopy( m_pData->m_aComponents ); + for (auto const& elem : aWorkingCopy) + { + if ( ( elem.sName != i_rName ) || ( elem.nComponentType != _nComponentType ) ) + continue; + + if ( !lcl_closeComponent(elem) ) + return false; + } + + return true; + } + + bool SubComponentManager::lookupSubComponent( const Reference< XComponent >& i_rComponent, + OUString& o_rName, sal_Int32& o_rComponentType ) + { + for (auto const& component : m_pData->m_aComponents) + { + if ( ( component.xModel.is() + && ( component.xModel == i_rComponent ) + ) + || ( component.xController.is() + && ( component.xController == i_rComponent ) + ) + || ( component.xFrame.is() + && ( component.xFrame == i_rComponent ) + ) + ) + { + o_rName = component.sName; + o_rComponentType = component.nComponentType; + return true; + } + } + return false; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/subcomponentmanager.hxx b/dbaccess/source/ui/app/subcomponentmanager.hxx new file mode 100644 index 000000000..a2f56badc --- /dev/null +++ b/dbaccess/source/ui/app/subcomponentmanager.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_APP_SUBCOMPONENTMANAGER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_APP_SUBCOMPONENTMANAGER_HXX + +#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( + const OUString& _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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_APP_SUBCOMPONENTMANAGER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/app/window_layout.txt b/dbaccess/source/ui/app/window_layout.txt new file mode 100644 index 000000000..abb15f00b --- /dev/null +++ b/dbaccess/source/ui/app/window_layout.txt @@ -0,0 +1,49 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +(still unfinished) + +OApplicationView +| ++-OAppBorderWindow + | + +-OTitleWindow "Database" + | | + | +-OApplicationSwapWindow + | | + | +-OApplicationIconControl + | + +-OApplicationDetailView + | + +-OTitleWindow "Tasks" + | | + | +-OTasksWindow + | | + | +-OCreationList + | + +-OTitleWindow "Forms" "Tables" "Queries" "Reports" + | + +-OAppDetailPageHelper + | + +-SvTreeListBox* + | + +-FixedLine + | + +-Window (Border) + | + +-OPreviewWindow diff --git a/dbaccess/source/ui/browser/AsynchronousLink.cxx b/dbaccess/source/ui/browser/AsynchronousLink.cxx new file mode 100644 index 000000000..c8a7e500f --- /dev/null +++ b/dbaccess/source/ui/browser/AsynchronousLink.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 +#include + +// OAsynchronousLink +using namespace dbaui; +OAsynchronousLink::OAsynchronousLink( const Link& _rHandler ) + :m_aHandler(_rHandler) + ,m_aEventSafety() + ,m_aDestructionSafety() + ,m_nEventId(nullptr) +{ +} + +OAsynchronousLink::~OAsynchronousLink() +{ + { + ::osl::MutexGuard aEventGuard( m_aEventSafety ); + if ( m_nEventId ) + Application::RemoveUserEvent(m_nEventId); + m_nEventId = nullptr; + } + + { + ::osl::MutexGuard aDestructionGuard( m_aDestructionSafety ); + // this is just for the case we're deleted while another thread just handled the event : + // if this other thread called our link while we were deleting the event here, the + // link handler blocked. With leaving the above block it continued, but now we are prevented + // to leave this destructor 'til the link handler recognizes that nEvent == 0 and leaves. + } +} + +void OAsynchronousLink::Call( void* _pArgument ) +{ + ::osl::MutexGuard aEventGuard( m_aEventSafety ); + if (m_nEventId) + Application::RemoveUserEvent(m_nEventId); + m_nEventId = Application::PostUserEvent( LINK( this, OAsynchronousLink, OnAsyncCall ), _pArgument ); +} + +void OAsynchronousLink::CancelCall() +{ + ::osl::MutexGuard aEventGuard( m_aEventSafety ); + if ( m_nEventId ) + Application::RemoveUserEvent( m_nEventId ); + m_nEventId = nullptr; +} + +IMPL_LINK(OAsynchronousLink, OnAsyncCall, void*, _pArg, void) +{ + { + ::osl::MutexGuard aDestructionGuard( m_aDestructionSafety ); + { + ::osl::MutexGuard aEventGuard( m_aEventSafety ); + if (!m_nEventId) + // our destructor deleted the event just while we are waiting for m_aEventSafety + // -> get outta here + return; + m_nEventId = nullptr; + } + } + m_aHandler.Call(_pArg); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/brwctrlr.cxx b/dbaccess/source/ui/browser/brwctrlr.cxx new file mode 100644 index 000000000..4fb847750 --- /dev/null +++ b/dbaccess/source/ui/browser/brwctrlr.cxx @@ -0,0 +1,2596 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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; + +#define HANDLE_SQL_ERRORS( action, successflag, context, message ) \ + try \ + { \ + successflag = false; \ + action; \ + successflag = true; \ + } \ + catch(SQLException& e) \ + { \ + SQLException aError = ::dbtools::prependErrorInfo(e, *this, context); \ + css::sdb::SQLErrorEvent aEvent; \ + aEvent.Reason <<= aError; \ + errorOccured(aEvent); \ + } \ + catch(Exception&) \ + { \ + DBG_UNHANDLED_EXCEPTION("dbaccess"); \ + } \ + +#define DO_SAFE( action, message ) try { action; } catch(Exception&) { SAL_WARN("dbaccess.ui",message); } ; + +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::OInterfaceContainerHelper2 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_pFormControllerImpl->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_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_pFormControllerImpl(nullptr) + ,m_nFormActionNestingLevel(0) + ,m_bLoadCanceled( false ) + ,m_bCannotSelectUnfiltered( true ) +{ + // create the form controller aggregate + osl_atomic_increment(&m_refCount); + { + m_pFormControllerImpl = new FormControllerImpl(this); + m_xFormControllerImpl = m_pFormControllerImpl; + m_xFormControllerImpl->setDelegator(*this); + } + osl_atomic_decrement(&m_refCount); + + m_aInvalidateClipboard.SetDebugName("dbaui::SbaXDataBrowserController m_aInvalidateClipboard"); + 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, makeAny(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, makeAny(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); + ::comphelper::OInterfaceIteratorHelper2 aIter(m_pFormControllerImpl->m_aActivateListeners); + while (aIter.hasMoreElements()) + static_cast(aIter.next())->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); + ::comphelper::OInterfaceIteratorHelper2 aIter(m_pFormControllerImpl->m_aActivateListeners); + while (aIter.hasMoreElements()) + static_cast(aIter.next())->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 ( m_xFormControllerImpl != 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 + OParameterContinuation* pParamValues = new OParameterContinuation; + OInteractionAbort* pAbort = new OInteractionAbort; + // the request + ParametersRequest aRequest; + aRequest.Parameters = xParameters; + aRequest.Connection = getConnection(Reference< XRowSet >(aEvent.Source, UNO_QUERY)); + OInteractionRequest* pParamRequest = new OInteractionRequest(makeAny(aRequest)); + Reference< XInteractionRequest > xParamRequest(pParamRequest); + // 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(xParamRequest); + + 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 (xCurrentController.is() && nullptr != dynamic_cast< const EditCellController* >(xCurrentController.get())) + { + Edit& rEdit = static_cast(xCurrentController->GetWindow()); + bool bHasLen = (rEdit.GetSelection().Len() != 0); + bool bIsReadOnly = rEdit.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, makeAny(_xParser->getOrder())); + bSuccess = reloadForm(m_xLoadable); + } + catch(Exception&) + { + } + + if (!bSuccess) + { + xFormSet->setPropertyValue(PROPERTY_ORDER, makeAny(_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, makeAny(_xParser->getFilter())); + xFormSet->setPropertyValue(PROPERTY_HAVING_CLAUSE, makeAny(_xParser->getHavingClause())); + xFormSet->setPropertyValue(PROPERTY_APPLYFILTER, css::uno::Any(true)); + + bSuccess = reloadForm(m_xLoadable); + } + catch(Exception&) + { + } + + if (!bSuccess) + { + xFormSet->setPropertyValue(PROPERTY_FILTER, makeAny(_rOldFilter)); + xFormSet->setPropertyValue(PROPERTY_HAVING_CLAUSE, makeAny(_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", makeAny(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&) + { + SAL_WARN("dbaccess.ui", "Exception caught!"); + } + 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 (!xCurrentController.is()) + // should be intercepted by GetState. Normally. + // Unfortunately ID_BROWSER_PASTE is a 'fast call' slot, which means it may be executed without checking if it is + // enabled. This would be really deadly herein if the current cell has no controller ... + return; + + Edit& rEdit = static_cast(xCurrentController->GetWindow()); + switch (nId) + { + case ID_BROWSER_CUT : rEdit.Cut(); break; + case SID_COPY : rEdit.Copy(); break; + case ID_BROWSER_PASTE : rEdit.Paste(); break; + } + if (ID_BROWSER_CUT == nId || ID_BROWSER_PASTE == nId) + { + xCurrentController->SetModified(); + rEdit.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; + HANDLE_SQL_ERRORS( + xParser->setOrder(OUString()); xParser->appendOrderByColumn(xField, bSortUp), + bParserSuccess, + DBA_RES(SBA_BROWSER_SETTING_ORDER), + "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) + { + DO_SAFE( xParser->setFilter( OUString()), "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied filter !" ); + DO_SAFE( xParser->setHavingClause(OUString()), "SbaXDataBrowserController::Execute : caught an exception while resetting unapplied HAVING clause !" ); + } + + bool bParserSuccess = false; + + const sal_Int32 nOp = SQLFilterOperator::EQUAL; + + if ( bHaving ) + { + HANDLE_SQL_ERRORS( + xParser->appendHavingClauseByColumn(xField,true,nOp), + bParserSuccess, + DBA_RES(SBA_BROWSER_SETTING_FILTER), + "SbaXDataBrowserController::Execute : caught an exception while composing the new filter !" + ) + } + else + { + HANDLE_SQL_ERRORS( + xParser->appendFilterByColumn(xField,true,nOp), + bParserSuccess, + DBA_RES(SBA_BROWSER_SETTING_FILTER), + "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,makeAny(OUString())); + xSet->setPropertyValue(PROPERTY_HAVING_CLAUSE,makeAny(OUString())); + xSet->setPropertyValue(PROPERTY_ORDER,makeAny(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 000000000..01b17fd7c --- /dev/null +++ b/dbaccess/source/ui/browser/brwview.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 "dbtreeview.hxx" +#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) + ,m_pStatus(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); + + m_pStatus.disposeAndClear(); + + 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 ) +{ + 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(DBTreeView* _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_pStatus) + m_pStatus = VclPtr::Create(this); + m_pStatus->SetText(_rStatus); + m_pStatus->Show(); + Resize(); + PaintImmediately(); + } +} + +void UnoDataBrowserView::hideStatus() +{ + if (!m_pStatus || !m_pStatus->IsVisible()) + // nothing to do + return; + m_pStatus->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() ); + + // the status pos and size + if (m_pStatus && m_pStatus->IsVisible()) + { + Size aStatusSize(aPlaygroundPos.X(), GetTextHeight() + 2); + aStatusSize = LogicToPixel(aStatusSize, MapMode(MapUnit::MapAppFont)); + aStatusSize.setWidth( aTreeViewSize.Width() - 2 - 2 ); + + Point aStatusPos( aPlaygroundPos.X() + 2, aTreeViewPos.Y() + aTreeViewSize.Height() - aStatusSize.Height() ); + m_pStatus->SetPosSizePixel( aStatusPos, aStatusSize ); + aTreeViewSize.AdjustHeight( -(aStatusSize.Height()) ); + } + + // set the size of treelistbox + m_pTreeView->SetPosSizePixel( aTreeViewPos, aTreeViewSize ); + + //set the size of the splitter + m_pSplitter->SetPosSizePixel( aSplitPos, Size( aSplitSize.Width(), aPlaygroundSize.Height() ) ); + m_pSplitter->SetDragRectPixel( _rPlayground ); + } + + // set the size of grid control + Reference< css::awt::XWindow > xGridAsWindow(m_xGrid, UNO_QUERY); + if (xGridAsWindow.is()) + xGridAsWindow->setPosSize( aSplitPos.X() + aSplitSize.Width(), aPlaygroundPos.Y(), + aPlaygroundSize.Width() - aSplitSize.Width() - aSplitPos.X(), aPlaygroundSize.Height(), css::awt::PosSize::POSSIZE); + + // just for completeness: there is no space left, we occupied it all ... + _rPlayground.SetPos( _rPlayground.BottomRight() ); + _rPlayground.SetSize( Size( 0, 0 ) ); +} + +sal_uInt16 UnoDataBrowserView::View2ModelPos(sal_uInt16 nPos) const +{ + return m_pVclControl ? m_pVclControl->GetModelColumnPos(m_pVclControl->GetColumnIdFromViewPos(nPos)) : -1; +} + +SbaGridControl* UnoDataBrowserView::getVclControl() const +{ + if ( !m_pVclControl ) + { + OSL_ENSURE(m_xGrid.is(),"Grid not set!"); + if ( m_xGrid.is() ) + { + Reference< css::awt::XWindowPeer > xPeer = m_xGrid->getPeer(); + if ( xPeer.is() ) + { + SbaXGridPeer* pPeer = comphelper::getUnoTunnelImplementation(xPeer); + UnoDataBrowserView* pTHIS = const_cast(this); + if ( pPeer ) + { + m_pVclControl = static_cast(pPeer->GetWindow().get()); + pTHIS->startComponentListening(VCLUnoHelper::GetInterface(m_pVclControl)); + } + } + } + } + return m_pVclControl; +} + +void UnoDataBrowserView::GetFocus() +{ + ODataView::GetFocus(); + if( m_pTreeView && m_pTreeView->IsVisible() && !m_pTreeView->HasChildPathFocus()) + m_pTreeView->GrabFocus(); + else if (m_pVclControl && m_xGrid.is()) + { + bool bGrabFocus = false; + if(!m_pVclControl->HasChildPathFocus()) + { + bGrabFocus = isGrabVclControlFocusAllowed(this); + if( bGrabFocus ) + m_pVclControl->GrabFocus(); + } + if(!bGrabFocus && m_pTreeView && m_pTreeView->IsVisible() ) + m_pTreeView->GrabFocus(); + } +} + +void UnoDataBrowserView::_disposing( const css::lang::EventObject& /*_rSource*/ ) +{ + stopComponentListening(VCLUnoHelper::GetInterface(m_pVclControl)); + m_pVclControl = nullptr; +} + +bool UnoDataBrowserView::PreNotify( NotifyEvent& rNEvt ) +{ + bool bDone = false; + if(rNEvt.GetType() == MouseNotifyEvent::KEYINPUT) + { + bool bGrabAllowed = isGrabVclControlFocusAllowed(this); + if ( bGrabAllowed ) + { + const KeyEvent* pKeyEvt = rNEvt.GetKeyEvent(); + const vcl::KeyCode& rKeyCode = pKeyEvt->GetKeyCode(); + if ( ( rKeyCode == vcl::KeyCode( KEY_E, true, true, false, false ) ) + || ( rKeyCode == vcl::KeyCode( KEY_TAB, true, false, false, false ) ) + ) + { + if ( m_pTreeView && m_pVclControl && m_pTreeView->HasChildPathFocus() ) + m_pVclControl->GrabFocus(); + else if ( m_pTreeView && m_pVclControl && m_pVclControl->HasChildPathFocus() ) + m_pTreeView->GrabFocus(); + + bDone = true; + } + } + } + return bDone || ODataView::PreNotify(rNEvt); +} + +BrowserViewStatusDisplay::BrowserViewStatusDisplay( UnoDataBrowserView* _pView, const OUString& _rStatus ) + :m_pView(_pView) +{ + + if (m_pView) + m_pView->showStatus(_rStatus); +} + +BrowserViewStatusDisplay::~BrowserViewStatusDisplay( ) +{ + if (m_pView) + m_pView->showStatus(OUString()); + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dataview.cxx b/dbaccess/source/ui/browser/dataview.cxx new file mode 100644 index 000000000..099199bc2 --- /dev/null +++ b/dbaccess/source/ui/browser/dataview.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 +#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_aSeparator( VclPtr::Create(this) ) + { + m_pAccel = ::svt::AcceleratorExecute::createAcceleratorHelper(); + m_aSeparator->Show(); + } + + void ODataView::Construct() + { + } + + ODataView::~ODataView() + { + disposeOnce(); + } + + void ODataView::dispose() + { + m_xController.clear(); + m_aSeparator.disposeAndClear(); + 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(PushFlags::LINECOLOR | 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 ) + { + tools::Rectangle aPlayground( _rPlayground ); + + // position the separator + const Size aSeparatorSize( aPlayground.GetWidth(), 2 ); + m_aSeparator->SetPosSizePixel( aPlayground.TopLeft(), aSeparatorSize ); + aPlayground.AdjustTop(aSeparatorSize.Height() + 1 ); + + // position the controls of the document's view + resizeDocumentView( aPlayground ); + } + + void ODataView::Resize() + { + Window::Resize(); + resizeAll( tools::Rectangle( Point( 0, 0), GetSizePixel() ) ); + } + bool ODataView::PreNotify( NotifyEvent& _rNEvt ) + { + bool bHandled = false; + switch ( _rNEvt.GetType() ) + { + case MouseNotifyEvent::KEYINPUT: + { + const KeyEvent* pKeyEvent = _rNEvt.GetKeyEvent(); + const vcl::KeyCode& aKeyCode = pKeyEvent->GetKeyCode(); + if ( m_pAccel && m_pAccel->execute( aKeyCode ) ) + // the accelerator consumed the event + return true; + [[fallthrough]]; + } + case MouseNotifyEvent::KEYUP: + case MouseNotifyEvent::MOUSEBUTTONDOWN: + case MouseNotifyEvent::MOUSEBUTTONUP: + bHandled = m_xController->interceptUserInput( _rNEvt ); + break; + default: + break; + } + return bHandled || Window::PreNotify( _rNEvt ); + } + void ODataView::StateChanged( StateChangedType nType ) + { + Window::StateChanged( nType ); + + if ( nType == StateChangedType::ControlBackground ) + { + // Check if we need to get new images for normal/high contrast mode + m_xController->notifyHiContrastChanged(); + } + + 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::DataChanged( const DataChangedEvent& rDCEvt ) + { + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) || + (rDCEvt.GetType() == DataChangedEventType::DISPLAY) || + (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) || + ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) ) + { + // Check if we need to get new images for normal/high contrast mode + m_xController->notifyHiContrastChanged(); + } + } + void ODataView::attachFrame(const Reference< XFrame >& _xFrame) + { + m_pAccel->init(m_xContext, _xFrame); + } +} + +// namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dbexchange.cxx b/dbaccess/source/ui/browser/dbexchange.cxx new file mode 100644 index 000000000..2fe0a3b21 --- /dev/null +++ b/dbaccess/source/ui/browser/dbexchange.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 +#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( + const OUString& _rDatasource, + const sal_Int32 _nCommandType, + const OUString& _rCommand, + const Reference< XConnection >& _rxConnection, + const Reference< XNumberFormatter >& _rxFormatter, + const Reference< XComponentContext >& _rxORB) + :ODataAccessObjectTransferable( _rDatasource, _nCommandType, _rCommand, _rxConnection ) + { + osl_atomic_increment( &m_refCount ); + lcl_setListener( _rxConnection, this, true ); + + m_pHtml.set( new OHTMLImportExport( getDescriptor(), _rxORB, _rxFormatter ) ); + m_pRtf.set( new ORTFImportExport( getDescriptor(), _rxORB, _rxFormatter ) ); + + osl_atomic_decrement( &m_refCount ); + } + + ODataClipboard::ODataClipboard( + const OUString& _rDatasource, + const sal_Int32 _nCommandType, + const OUString& _rCommand, + const Reference< XNumberFormatter >& _rxFormatter, + const Reference< XComponentContext >& _rxORB) + :ODataAccessObjectTransferable( _rDatasource, _nCommandType, _rCommand) + { + m_pHtml.set( new OHTMLImportExport( getDescriptor(),_rxORB, _rxFormatter ) ); + m_pRtf.set( new ORTFImportExport( getDescriptor(),_rxORB, _rxFormatter ) ); + } + + 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 000000000..62a3c14b1 --- /dev/null +++ b/dbaccess/source/ui/browser/dbloader.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 + +#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 ::com::sun::star::registry; +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; + + // static methods + static OUString getImplementationName_Static() throw( ) + { + return "org.openoffice.comp.dbu.DBContentLoader"; + } + static Sequence< OUString> getSupportedServiceNames_Static() throw( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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" void createRegistryInfo_DBContentLoader() +{ + static ::dbaui::OMultiInstanceAutoRegistration< DBContentLoader > aAutoRegistration; +} + +Reference< XInterface > DBContentLoader::Create( const Reference< XMultiServiceFactory > & rSMgr ) +{ + return *(new DBContentLoader(comphelper::getComponentContext(rSMgr))); +} + +// XServiceInfo +OUString SAL_CALL DBContentLoader::getImplementationName() +{ + return getImplementationName_Static(); +} + +// XServiceInfo +sal_Bool SAL_CALL DBContentLoader::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > SAL_CALL DBContentLoader::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +// ORegistryServiceManager_Static +Sequence< OUString > DBContentLoader::getSupportedServiceNames_Static() throw( ) +{ + 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 const struct ServiceNameToImplName + { + const char* pAsciiServiceName; + const char* pAsciiImplementationName; + ServiceNameToImplName( const char* _pService, const char* _pImpl ) + :pAsciiServiceName( _pService ) + ,pAsciiImplementationName( _pImpl ) + { + } + } aImplementations[] = { + ServiceNameToImplName( URL_COMPONENT_FORMGRIDVIEW, "org.openoffice.comp.dbu.OFormGridView" ), + ServiceNameToImplName( URL_COMPONENT_DATASOURCEBROWSER, "org.openoffice.comp.dbu.ODatasourceBrowser" ), + ServiceNameToImplName( URL_COMPONENT_QUERYDESIGN, "org.openoffice.comp.dbu.OQueryDesign" ), + ServiceNameToImplName( URL_COMPONENT_TABLEDESIGN, "org.openoffice.comp.dbu.OTableDesign" ), + ServiceNameToImplName( URL_COMPONENT_RELATIONDESIGN, "org.openoffice.comp.dbu.ORelationDesign" ), + ServiceNameToImplName( 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.equalsAscii( aImplementation.pAsciiServiceName ) ) + { + xController.set( m_xContext->getServiceManager()-> + createInstanceWithContext( OUString::createFromAscii( aImplementation.pAsciiImplementationName ), m_xContext), UNO_QUERY_THROW ); + break; + } + } + + // if a data source browser is loaded without its tree pane, then we assume it to be a + // table data view, effectively. In this case, we need to adjust the module identifier. + // #i85879# + ::comphelper::NamedValueCollection aLoadArgs( rArgs ); + + if ( sComponentURL == URL_COMPONENT_DATASOURCEBROWSER ) + { + bool bDisableBrowser = !aLoadArgs.getOrDefault( "ShowTreeViewButton", true ) // compatibility name + || !aLoadArgs.getOrDefault( PROPERTY_ENABLE_BROWSER, true ); + + if ( bDisableBrowser ) + { + try + { + Reference< XModule > xModule( xController, UNO_QUERY_THROW ); + xModule->setIdentifier( "com.sun.star.sdb.TableDataView" ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + + if ( sComponentURL == URL_COMPONENT_REPORTDESIGN ) + { + bool bPreview = aLoadArgs.getOrDefault( "Preview", false ); + if ( bPreview ) + { // report designs cannot be previewed + if ( rListener.is() ) + rListener->loadCancelled( this ); + return; + } + Reference< XModel > xReportModel( aLoadArgs.getOrDefault( "Model", Reference< XModel >() ) ); + if ( xReportModel.is() ) + { + xController.set( ReportDesign::create( m_xContext ) ); + xController->attachModel( xReportModel ); + xReportModel->connectController( xController.get() ); + xReportModel->setCurrentController( xController.get() ); + } + } + + 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,makeAny(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.get() ); + xController->attachFrame(rFrame); + } + + if ( rListener.is() ) + rListener->loadFinished( this ); + } + else + if ( rListener.is() ) + rListener->loadCancelled( this ); +} + +void DBContentLoader::cancel() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dbtreemodel.cxx b/dbaccess/source/ui/browser/dbtreemodel.cxx new file mode 100644 index 000000000..88a9faeb0 --- /dev/null +++ b/dbaccess/source/ui/browser/dbtreemodel.cxx @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "dbtreemodel.hxx" + +namespace dbaui +{ + DBTreeListUserData::DBTreeListUserData() + :eType(SbaTableQueryBrowser::etQuery) + { + } + DBTreeListUserData::~DBTreeListUserData() + { + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dbtreemodel.hxx b/dbaccess/source/ui/browser/dbtreemodel.hxx new file mode 100644 index 000000000..42887fd00 --- /dev/null +++ b/dbaccess/source/ui/browser/dbtreemodel.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_BROWSER_DBTREEMODEL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_BROWSER_DBTREEMODEL_HXX + +#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 + +#define CONTAINER_QUERIES sal_uLong( 0 ) +#define CONTAINER_TABLES sal_uLong( 1 ) + +namespace com::sun::star::lang { class XMultiServiceFactory; } + +namespace dbaui +{ + struct DBTreeListUserData + { + /// if the entry denotes a table or query, this is the respective UNO object + css::uno::Reference< css::beans::XPropertySet > + xObjectProperties; + /// if the entry denotes an object container, this is the UNO interface for this container + css::uno::Reference< css::uno::XInterface > + xContainer; + /// if the entry denotes a data source, this is the connection for this data source (if already connection) + SharedConnection xConnection; + SbaTableQueryBrowser::EntryType eType; + OUString sAccessor; + + DBTreeListUserData(); + ~DBTreeListUserData(); + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_BROWSER_DBTREEMODEL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dbtreeview.cxx b/dbaccess/source/ui/browser/dbtreeview.cxx new file mode 100644 index 000000000..38464068b --- /dev/null +++ b/dbaccess/source/ui/browser/dbtreeview.cxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "dbtreeview.hxx" +#include +#include +#include + +namespace dbaui +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +DBTreeView::DBTreeView( vcl::Window* pParent, WinBits nBits) + : Window( pParent, nBits ) + , m_pTreeListBox(nullptr) +{ + + m_pTreeListBox = VclPtr::Create(this, WB_BORDER | WB_HASLINES | WB_HASLINESATROOT | WB_HASBUTTONS | WB_HSCROLL |WB_HASBUTTONSATROOT); + m_pTreeListBox->EnableCheckButton(nullptr); + m_pTreeListBox->SetDragDropMode( DragDropMode::NONE ); + m_pTreeListBox->EnableInplaceEditing( true ); + m_pTreeListBox->SetHelpId(HID_TLB_TREELISTBOX); + m_pTreeListBox->Show(); +} + +DBTreeView::~DBTreeView() +{ + disposeOnce(); +} + +void DBTreeView::dispose() +{ + m_pTreeListBox.disposeAndClear(); + vcl::Window::dispose(); +} + +SvTreeList* DBTreeView::GetTreeModel() +{ + return m_pTreeListBox->GetModel(); +} + +void DBTreeView::SetPreExpandHandler(const Link& _rHdl) +{ + m_pTreeListBox->SetPreExpandHandler(_rHdl); +} + +void DBTreeView::setCopyHandler(const Link& _rHdl) +{ + m_pTreeListBox->setCopyHandler(_rHdl); +} + +void DBTreeView::Resize() +{ + Window::Resize(); + m_pTreeListBox->SetPosSizePixel(Point(0,0),GetOutputSizePixel()); +} + +void DBTreeView::setSelChangeHdl( const Link& _rHdl ) +{ + m_pTreeListBox->SetSelChangeHdl( _rHdl ); +} + +void DBTreeView::GetFocus() +{ + Window::GetFocus(); + if ( m_pTreeListBox )//&& !m_pTreeListBox->HasChildPathFocus()) + m_pTreeListBox->GrabFocus(); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dbtreeview.hxx b/dbaccess/source/ui/browser/dbtreeview.hxx new file mode 100644 index 000000000..892a6beab --- /dev/null +++ b/dbaccess/source/ui/browser/dbtreeview.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_BROWSER_DBTREEVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_BROWSER_DBTREEVIEW_HXX + +#include + +class SvTreeList; +class SvTreeListEntry; + +namespace dbaui +{ + class DBTreeListBox; + // - DBTreeView - + + class DBTreeView : public vcl::Window + { + private: + VclPtr m_pTreeListBox; + protected: + // window overridables + virtual void Resize() override; + public: + + DBTreeView( vcl::Window* pParent, + WinBits nBits ); + virtual ~DBTreeView() override; + virtual void dispose() override; + + /** sets a handler which is called when a list box entry is to be expanded. +

When calling the link, the parameter is an SvTreeListEntry marking the entry to be expanded. +

+ */ + void SetPreExpandHandler(const Link& _rHdl); + + void setCopyHandler(const Link& _rHdl); + + SvTreeList* GetTreeModel(); + void setSelChangeHdl(const Link& _rHdl); + + DBTreeListBox& getListBox() const { return *m_pTreeListBox; } + + virtual void GetFocus() override; + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_BROWSER_DBTREEVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dsEntriesNoExp.cxx b/dbaccess/source/ui/browser/dsEntriesNoExp.cxx new file mode 100644 index 000000000..7e9bfc851 --- /dev/null +++ b/dbaccess/source/ui/browser/dsEntriesNoExp.cxx @@ -0,0 +1,256 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "dbtreeview.hxx" +#include +#include "dbtreemodel.hxx" +#include + +using namespace ::com::sun::star::frame; +using namespace ::dbtools; +using namespace ::svx; + +namespace dbaui +{ +SbaTableQueryBrowser::EntryType SbaTableQueryBrowser::getChildType( SvTreeListEntry const * _pEntry ) const +{ + OSL_ENSURE(isContainer(_pEntry), "SbaTableQueryBrowser::getChildType: invalid entry!"); + switch (getEntryType(_pEntry)) + { + case etTableContainer: + return etTableOrView; + case etQueryContainer: + return etQuery; + default: + break; + } + return etUnknown; +} + +OUString SbaTableQueryBrowser::GetEntryText( SvTreeListEntry* _pEntry ) const +{ + return m_pTreeView->getListBox().GetEntryText(_pEntry); +} + +SbaTableQueryBrowser::EntryType SbaTableQueryBrowser::getEntryType( const SvTreeListEntry* _pEntry ) const +{ + if (!_pEntry) + return etUnknown; + + SvTreeListEntry* pRootEntry = m_pTreeView->getListBox().GetRootLevelParent(const_cast(_pEntry)); + SvTreeListEntry* pEntryParent = m_pTreeView->getListBox().GetParent(const_cast(_pEntry)); + SvTreeListEntry* pTables = m_pTreeView->getListBox().GetEntry(pRootEntry, CONTAINER_TABLES); + SvTreeListEntry* pQueries = m_pTreeView->getListBox().GetEntry(pRootEntry, CONTAINER_QUERIES); + +#ifdef DBG_UTIL + OUString sTest; + if (pTables) sTest = m_pTreeView->getListBox().GetEntryText(pTables); + if (pQueries) sTest = m_pTreeView->getListBox().GetEntryText(pQueries); +#endif + + if (pRootEntry == _pEntry) + return etDatasource; + + if (pTables == _pEntry) + return etTableContainer; + + if (pQueries == _pEntry) + return etQueryContainer; + + if (pTables == pEntryParent) + return etTableOrView; + + if (pQueries == pEntryParent) + { + DBTreeListUserData* pEntryData = static_cast(_pEntry->GetUserData()); + if ( pEntryData ) + return pEntryData->eType; + + return etQuery; + } + while( pEntryParent != pQueries ) + { + pEntryParent = m_pTreeView->getListBox().GetParent(pEntryParent); + if ( !pEntryParent ) + return etUnknown; + } + + return etQueryContainer; +} + +void SbaTableQueryBrowser::select(SvTreeListEntry* _pEntry, bool _bSelect) +{ + SvLBoxItem* pTextItem = _pEntry ? _pEntry->GetFirstItem(SvLBoxItemType::String) : nullptr; + if (pTextItem) + { + static_cast(pTextItem)->emphasize(_bSelect); + m_pTreeView->GetTreeModel()->InvalidateEntry(_pEntry); + } + else { + OSL_FAIL("SbaTableQueryBrowser::select: invalid entry!"); + } +} + +void SbaTableQueryBrowser::selectPath(SvTreeListEntry* _pEntry, bool _bSelect) +{ + while (_pEntry) + { + select(_pEntry, _bSelect); + _pEntry = m_pTreeView->GetTreeModel()->GetParent(_pEntry); + } +} + +bool SbaTableQueryBrowser::isSelected(SvTreeListEntry* _pEntry) +{ + SvLBoxItem* pTextItem = _pEntry ? _pEntry->GetFirstItem(SvLBoxItemType::String) : nullptr; + if (pTextItem) + return static_cast(pTextItem)->isEmphasized(); + else { + OSL_FAIL("SbaTableQueryBrowser::isSelected: invalid entry!"); + } + return false; +} + +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; +} + +void SbaTableQueryBrowser::notifyHiContrastChanged() +{ + if ( !m_pTreeView ) + return; + + auto pTreeModel = m_pTreeView->GetTreeModel(); + // change all bitmap entries + SvTreeListEntry* pEntryLoop = pTreeModel->First(); + while ( pEntryLoop ) + { + DBTreeListUserData* pData = static_cast(pEntryLoop->GetUserData()); + if ( !pData ) + { + pEntryLoop = pTreeModel->Next(pEntryLoop); + continue; + } + + // the connection to which this entry belongs, if any + std::unique_ptr< ImageProvider > pImageProvider( getImageProviderFor( pEntryLoop ) ); + + // the images for this entry + Image aImage; + if ( pData->eType == etDatasource ) + aImage = ImageProvider::getDatabaseImage(); + else + { + bool bIsFolder = !isObject( pData->eType ); + if ( bIsFolder ) + { + sal_Int32 nObjectType( getDatabaseObjectType( pData->eType ) ); + aImage = ImageProvider::getFolderImage( nObjectType ); + } + else + { + sal_Int32 nObjectType( getDatabaseObjectType( pData->eType ) ); + pImageProvider->getImages( GetEntryText( pEntryLoop ), nObjectType, aImage ); + } + } + + // find the proper item, and set its icons + sal_uInt16 nCount = pEntryLoop->ItemCount(); + for (sal_uInt16 i=0;iGetItem(i); + if (rItem.GetType() != SvLBoxItemType::ContextBmp) + continue; + + SvLBoxContextBmp& rContextBitmapItem = static_cast< SvLBoxContextBmp& >( rItem ); + + rContextBitmapItem.SetBitmap1( aImage ); + rContextBitmapItem.SetBitmap2( aImage ); + break; + } + + pEntryLoop = pTreeModel->Next(pEntryLoop); + } +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/dsbrowserDnD.cxx b/dbaccess/source/ui/browser/dsbrowserDnD.cxx new file mode 100644 index 000000000..cd8c124f0 --- /dev/null +++ b/dbaccess/source/ui/browser/dsbrowserDnD.cxx @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "dbtreeview.hxx" +#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::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; + + TransferableHelper* SbaTableQueryBrowser::implCopyObject( SvTreeListEntry* _pApplyTo, sal_Int32 _nCommandType ) + { + try + { + OUString aName = GetEntryText( _pApplyTo ); + OUString aDSName = getDataSourceAccessor( m_pTreeView->getListBox().GetRootLevelParent( _pApplyTo ) ); + + ODataClipboard* pData = nullptr; + SharedConnection xConnection; + if ( CommandType::QUERY != _nCommandType ) + { + if ( !ensureConnection( _pApplyTo, xConnection) ) + return nullptr; + pData = new ODataClipboard(aDSName, _nCommandType, aName, xConnection, getNumberFormatter(), getORB()); + } + else + pData = new ODataClipboard(aDSName, _nCommandType, aName, getNumberFormatter(), getORB()); + + // the ownership goes to ODataClipboards + return pData; + } + catch(const SQLException& ) + { + showError( SQLExceptionInfo( ::cppu::getCaughtException() ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return nullptr; + } + sal_Int8 SbaTableQueryBrowser::queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) + { + // check if we're a table or query container + SvTreeListEntry* pHitEntry = m_pTreeView->getListBox().GetEntry( _rEvt.maPosPixel ); + + if ( pHitEntry ) // no drop if no entry was hit... + { + // it must be a container + EntryType eEntryType = getEntryType( pHitEntry ); + SharedConnection xConnection; + if ( eEntryType == etTableContainer && ensureConnection( pHitEntry, 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 ) + { + SvTreeListEntry* pHitEntry = m_pTreeView->getListBox().GetEntry( _rEvt.maPosPixel ); + EntryType eEntryType = getEntryType( pHitEntry ); + 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.pDroppedAt = nullptr; + 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.pDroppedAt = pHitEntry; + + // 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( pHitEntry, xDestConnection ) + && xDestConnection.is() + && m_aTableCopyHelper.copyTagTable( aDroppedData, m_aAsyncDrop, xDestConnection ) + ) + { + m_aAsyncDrop.pDroppedAt = pHitEntry; + + // 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 Point& _rPosPixel ) + { + // get the affected list entry + // ensure that the entry which the user clicked at is selected + SvTreeListEntry* pHitEntry = m_pTreeView->getListBox().GetEntry( _rPosPixel ); + if (!pHitEntry) + // no drag of no entry was hit... + return false; + + // it must be a query/table + EntryType eEntryType = getEntryType( pHitEntry ); + if (!isObject(eEntryType)) + return false; + + rtl::Reference pTransfer = implCopyObject( pHitEntry, ( etTableOrView == eEntryType ) ? CommandType::TABLE : CommandType::QUERY); + + if (pTransfer) + pTransfer->StartDrag( &m_pTreeView->getListBox(), DND_ACTION_COPY ); + + return pTransfer.is(); + } + IMPL_LINK_NOARG(SbaTableQueryBrowser, OnCopyEntry, LinkParamNone*, void) + { + SvTreeListEntry* pSelected = m_pTreeView->getListBox().FirstSelected(); + if( isEntryCopyAllowed( pSelected ) ) + copyEntry( pSelected ); + } + bool SbaTableQueryBrowser::isEntryCopyAllowed(SvTreeListEntry const * _pEntry) const + { + EntryType eType = getEntryType(_pEntry); + return ( eType == etTableOrView || eType == etQuery ); + } + void SbaTableQueryBrowser::copyEntry(SvTreeListEntry* _pEntry) + { + TransferableHelper* pTransfer = nullptr; + Reference< XTransferable> aEnsureDelete; + EntryType eType = getEntryType(_pEntry); + pTransfer = implCopyObject( _pEntry, eType == etQuery ? CommandType::QUERY : CommandType::TABLE); + aEnsureDelete = pTransfer; + if (pTransfer) + pTransfer->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.pDroppedAt, xDestConnection ) && xDestConnection.is() ) + { + SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().GetRootLevelParent(m_aAsyncDrop.pDroppedAt); + m_aTableCopyHelper.asyncCopyTagTable( m_aAsyncDrop, getDataSourceAccessor( pDataSourceEntry ), xDestConnection ); + } + } + + m_aAsyncDrop.aDroppedData.clear(); + } + void SbaTableQueryBrowser::clearTreeModel() + { + if (m_pTreeView) + { + auto pTreeModel = m_pTreeView->GetTreeModel(); + // clear the user data of the tree model + SvTreeListEntry* pEntryLoop = pTreeModel->First(); + while (pEntryLoop) + { + DBTreeListUserData* pData = static_cast(pEntryLoop->GetUserData()); + if(pData) + { + pEntryLoop->SetUserData(nullptr); + Reference< XContainer > xContainer(pData->xContainer, UNO_QUERY); + if (xContainer.is()) + xContainer->removeContainerListener(this); + + if ( pData->xConnection.is() ) + { + OSL_ENSURE( impl_isDataSourceEntry( pEntryLoop ), "SbaTableQueryBrowser::clearTreeModel: no data source entry, but a connection?" ); + // connections are to be stored *only* at the data source entries + impl_releaseConnection( pData->xConnection ); + } + + delete pData; + } + pEntryLoop = pTreeModel->Next(pEntryLoop); + } + } + m_pCurrentlyDisplayed = nullptr; + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/exsrcbrw.cxx b/dbaccess/source/ui/browser/exsrcbrw.cxx new file mode 100644 index 000000000..e468f9a5a --- /dev/null +++ b/dbaccess/source/ui/browser/exsrcbrw.cxx @@ -0,0 +1,434 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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::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" void createRegistryInfo_OFormGridView() +{ + static OMultiInstanceAutoRegistration< SbaExternalSourceBrowser > aAutoRegistration; +} + +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_pDataSourceImpl(nullptr) + ,m_bInQueryDispatch( false ) +{ + +} + +SbaExternalSourceBrowser::~SbaExternalSourceBrowser() +{ + +} + +css::uno::Sequence SAL_CALL SbaExternalSourceBrowser::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +OUString SbaExternalSourceBrowser::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.OFormGridView"; +} + +css::uno::Sequence SbaExternalSourceBrowser::getSupportedServiceNames_Static() +{ + css::uno::Sequence aSupported { "com.sun.star.sdb.FormGridView" }; + return aSupported; +} + +Reference< XInterface > SbaExternalSourceBrowser::Create(const Reference& _rxFactory) +{ + return *(new SbaExternalSourceBrowser( comphelper::getComponentContext(_rxFactory))); +} + +OUString SAL_CALL SbaExternalSourceBrowser::getImplementationName() +{ + return getImplementationName_Static(); +} + +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); + ::comphelper::OInterfaceIteratorHelper2 aIt(m_aModifyListeners); + while (aIt.hasMoreElements()) + static_cast< css::util::XModifyListener*>(aIt.next())->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, makeAny(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 000000000..9620d5840 --- /dev/null +++ b/dbaccess/source/ui/browser/formadapter.cxx @@ -0,0 +1,1651 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + STOP_MULTIPLEXER_LISTENING(LoadListener, m_aLoadListeners, css::form::XLoadable, m_xMainForm); + STOP_MULTIPLEXER_LISTENING(RowSetListener, m_aRowSetListeners, css::sdbc::XRowSet, m_xMainForm); + STOP_MULTIPLEXER_LISTENING(RowSetApproveListener, m_aRowSetApproveListeners, css::sdb::XRowSetApproveBroadcaster, m_xMainForm); + STOP_MULTIPLEXER_LISTENING(SQLErrorListener, m_aErrorListeners, css::sdb::XSQLErrorBroadcaster, m_xMainForm); + STOP_MULTIPLEXER_LISTENING(SubmitListener, m_aSubmitListeners, css::form::XSubmit, m_xMainForm); + STOP_MULTIPLEXER_LISTENING(ResetListener, m_aResetListeners, css::form::XReset, m_xMainForm); + + if (m_aParameterListeners.getLength()) + { + Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->removeParameterListener(&m_aParameterListeners); + } + + STOP_PROPERTY_MULTIPLEXER_LISTENING(PropertyChangeListener, m_aPropertyChangeListeners, css::beans::XPropertySet, m_xMainForm); + STOP_PROPERTY_MULTIPLEXER_LISTENING(VetoableChangeListener, m_aVetoablePropertyChangeListeners, css::beans::XPropertySet, m_xMainForm); + 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 + START_MULTIPLEXER_LISTENING(LoadListener, m_aLoadListeners, css::form::XLoadable, m_xMainForm); + START_MULTIPLEXER_LISTENING(RowSetListener, m_aRowSetListeners, css::sdbc::XRowSet, m_xMainForm); + START_MULTIPLEXER_LISTENING(RowSetApproveListener, m_aRowSetApproveListeners, css::sdb::XRowSetApproveBroadcaster, m_xMainForm); + START_MULTIPLEXER_LISTENING(SQLErrorListener, m_aErrorListeners, css::sdb::XSQLErrorBroadcaster, m_xMainForm); + START_MULTIPLEXER_LISTENING(SubmitListener, m_aSubmitListeners, css::form::XSubmit, m_xMainForm); + START_MULTIPLEXER_LISTENING(ResetListener, m_aResetListeners, css::form::XReset, m_xMainForm); + + if (m_aParameterListeners.getLength()) + { + Reference< css::form::XDatabaseParameterBroadcaster > xBroadcaster(m_xMainForm, UNO_QUERY); + if (xBroadcaster.is()) + xBroadcaster->addParameterListener(&m_aParameterListeners); + } + + START_PROPERTY_MULTIPLEXER_LISTENING(PropertyChangeListener, m_aPropertyChangeListeners, css::beans::XPropertySet, m_xMainForm); + START_PROPERTY_MULTIPLEXER_LISTENING(VetoableChangeListener, m_aVetoablePropertyChangeListeners, css::beans::XPropertySet, m_xMainForm); + 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); + ::comphelper::OInterfaceIteratorHelper2 aIt(m_aLoadListeners); + while (aIt.hasMoreElements()) + static_cast< css::form::XLoadListener*>(aIt.next())->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); + ::comphelper::OInterfaceIteratorHelper2 aIt(m_aLoadListeners); + while (aIt.hasMoreElements()) + static_cast< css::form::XLoadListener*>(aIt.next())->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(); +} + +IMPLEMENT_LISTENER_ADMINISTRATION(SbaXFormAdapter, sdbc, RowSetListener, m_aRowSetListeners, css::sdbc::XRowSet, m_xMainForm) + +// 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 +IMPLEMENT_LISTENER_ADMINISTRATION(SbaXFormAdapter, sdb, RowSetApproveListener, m_aRowSetApproveListeners, css::sdb::XRowSetApproveBroadcaster, m_xMainForm) + +// css::sdbc::XSQLErrorBroadcaster +IMPLEMENT_LISTENER_ADMINISTRATION(SbaXFormAdapter, sdb, SQLErrorListener, m_aErrorListeners, css::sdb::XSQLErrorBroadcaster, m_xMainForm) + +// 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; +} + +IMPLEMENT_LISTENER_ADMINISTRATION(SbaXFormAdapter, form, LoadListener, m_aLoadListeners, css::form::XLoadable, m_xMainForm) + +// 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); +} + +IMPLEMENT_LISTENER_ADMINISTRATION(SbaXFormAdapter, form, SubmitListener, m_aSubmitListeners, css::form::XSubmit, m_xMainForm) + +// 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(); +} + +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; + + ::cppu::OInterfaceIteratorHelper aIt(*m_aPropertyChangeListeners.getContainer(PROPERTY_NAME)); + while (aIt.hasMoreElements()) + static_cast< css::beans::XPropertyChangeListener*>(aIt.next())->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 makeAny(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, makeAny(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); + + // 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); +} + +IMPLEMENT_PROPERTY_LISTENER_ADMINISTRATION(SbaXFormAdapter, PropertyChangeListener, m_aPropertyChangeListeners, css::beans::XPropertySet, m_xMainForm); +IMPLEMENT_PROPERTY_LISTENER_ADMINISTRATION(SbaXFormAdapter, VetoableChangeListener, m_aVetoablePropertyChangeListeners, css::beans::XPropertySet, m_xMainForm); + +// 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 : 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(); +} + +IMPLEMENT_LISTENER_ADMINISTRATION(SbaXFormAdapter, form, ResetListener, m_aResetListeners, css::form::XReset, m_xMainForm) + +// 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, makeAny(*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; + ::comphelper::OInterfaceIteratorHelper2 aIt(m_aContainerListeners); + while (aIt.hasMoreElements()) + static_cast< css::container::XContainerListener*>(aIt.next())->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 makeAny(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; + ::comphelper::OInterfaceIteratorHelper2 aIt(m_aContainerListeners); + while (aIt.hasMoreElements()) + static_cast< css::container::XContainerListener*>(aIt.next())->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; + + ::comphelper::OInterfaceIteratorHelper2 aIt(m_aContainerListeners); + while (aIt.hasMoreElements()) + static_cast< css::container::XContainerListener*>(aIt.next())->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 makeAny(xElement); +} + +// css::container::XContainer +void SAL_CALL SbaXFormAdapter::addContainerListener(const Reference< css::container::XContainerListener >& xListener) +{ + m_aContainerListeners.addInterface(xListener); +} + +void SAL_CALL SbaXFormAdapter::removeContainerListener(const Reference< css::container::XContainerListener >& xListener) +{ + m_aContainerListeners.removeInterface(xListener); +} + +// css::container::XEnumerationAccess +Reference< css::container::XEnumeration > SAL_CALL SbaXFormAdapter::createEnumeration() +{ + return new ::comphelper::OEnumerationByName(this); +} + +// css::beans::XPropertyChangeListener +void SAL_CALL SbaXFormAdapter::propertyChange(const css::beans::PropertyChangeEvent& evt) +{ + if (evt.PropertyName != PROPERTY_NAME) + return; + + std::vector< css::uno::Reference< css::form::XFormComponent > >::const_iterator aIter = std::find_if( m_aChildren.begin(), + m_aChildren.end(), + [&evt](css::uno::Reference< css::uno::XInterface > const & x) { return x == evt.Source; }); + + if(aIter != m_aChildren.end()) + { + sal_Int32 nPos = aIter - m_aChildren.begin(); + OSL_ENSURE(*(m_aChildNames.begin() + nPos) == ::comphelper::getString(evt.OldValue), "SAL_CALL SbaXFormAdapter::propertyChange : object has a wrong name !"); + *(m_aChildNames.begin() + nPos) = ::comphelper::getString(evt.NewValue); + } +} + +// css::lang::XEventListener +void SAL_CALL SbaXFormAdapter::disposing(const css::lang::EventObject& Source) +{ + // was it our main form ? + if (Source.Source == m_xMainForm) + dispose(); + + std::vector< css::uno::Reference< css::form::XFormComponent > >::const_iterator aIter = std::find_if( m_aChildren.begin(), + m_aChildren.end(), + [&Source](css::uno::Reference< css::uno::XInterface > const & x) { return x == Source.Source; }); + if(aIter != m_aChildren.end()) + removeByIndex(aIter - m_aChildren.begin()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/genericcontroller.cxx b/dbaccess/source/ui/browser/genericcontroller.cxx new file mode 100644 index 000000000..58f5b55ea --- /dev/null +++ b/dbaccess/source/ui/browser/genericcontroller.cxx @@ -0,0 +1,1235 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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 +#define FIRST_USER_DEFINED_FEATURE ( std::numeric_limits< sal_uInt16 >::max() - 1000 ) +#define LAST_USER_DEFINED_FEATURE ( std::numeric_limits< sal_uInt16 >::max() ) + +typedef std::unordered_map< sal_Int16, sal_Int16 > CommandHashMap; + +namespace dbaui +{ + +namespace { + +// UserDefinedFeatures +class UserDefinedFeatures +{ +public: + explicit UserDefinedFeatures( const Reference< XController >& _rxController ); + + void execute( const URL& _rFeatureURL, const Sequence< PropertyValue>& _rArgs ); + +private: + css::uno::WeakReference< XController > m_aController; +}; + +} + +UserDefinedFeatures::UserDefinedFeatures( const Reference< XController >& _rxController ) + :m_aController( _rxController ) +{ +} + +void UserDefinedFeatures::execute( const URL& _rFeatureURL, const Sequence< PropertyValue>& _rArgs ) +{ + try + { + Reference< XController > xController( Reference< XController >(m_aController), UNO_SET_THROW ); + Reference< XDispatchProvider > xDispatchProvider( xController->getFrame(), UNO_QUERY_THROW ); + Reference< XDispatch > xDispatch( xDispatchProvider->queryDispatch( + _rFeatureURL, + "_self", + FrameSearchFlag::AUTO + ) ); + + if ( xDispatch == xController ) + { + SAL_WARN("dbaccess.ui", "UserDefinedFeatures::execute: the controller shouldn't be the dispatcher here!" ); + xDispatch.clear(); + } + + if ( xDispatch.is() ) + xDispatch->dispatch( _rFeatureURL, _rArgs ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +// OGenericUnoController_Data +struct OGenericUnoController_Data +{ + ::sfx2::UserInputInterception m_aUserInputInterception; + UserDefinedFeatures m_aUserDefinedFeatures; + + OGenericUnoController_Data( OGenericUnoController& _rController, ::osl::Mutex& _rMutex ) + :m_aUserInputInterception( _rController, _rMutex ) + ,m_aUserDefinedFeatures( _rController.getXController() ) + { + } +}; + +// OGenericUnoController +OGenericUnoController::OGenericUnoController(const Reference< XComponentContext >& _rM) + :OGenericUnoController_Base( getMutex() ) + ,m_pView(nullptr) +#ifdef DBG_UTIL + ,m_bDescribingSupportedFeatures( false ) +#endif + ,m_aAsyncInvalidateAll(LINK(this, OGenericUnoController, OnAsyncInvalidateAll)) + ,m_aAsyncCloseTask(LINK(this, OGenericUnoController, OnAsyncCloseTask)) + ,m_xContext(_rM) + ,m_aCurrentFrame( *this ) + ,m_bPreview(false) + ,m_bReadOnly(false) + ,m_bCurrentlyModified(false) + ,m_bExternalTitle(false) +{ + osl_atomic_increment( &m_refCount ); + { + m_pData.reset( new OGenericUnoController_Data( *this, getMutex() ) ); + } + osl_atomic_decrement( &m_refCount ); + + + try + { + m_xUrlTransformer = URLTransformer::create(_rM); + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +OGenericUnoController::~OGenericUnoController() +{ + +} + +bool OGenericUnoController::Construct(vcl::Window* /*pParent*/) +{ + OSL_ENSURE( getView(), "the view is NULL!" ); + + if ( getView() ) + { + getView()->Construct(); + getView()->Show(); + } + + m_aSupportedFeatures.clear(); + fillSupportedFeatures(); + + // create the database context + OSL_ENSURE(getORB().is(), "OGenericUnoController::Construct need a service factory!"); + try + { + m_xDatabaseContext = DatabaseContext::create(getORB()); + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui","OGenericUnoController::Construct: could not create (or start listening at) the database context!"); + // at least notify the user. Though the whole component does not make any sense without the database context ... + ShowServiceNotAvailableError(getFrameWeld(), "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< XWindow > xParent; + 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 ); + + xParent = xFrame->getContainerWindow(); + VCLXWindow* pParentComponent = comphelper::getUnoTunnelImplementation(xParent); + VclPtr< vcl::Window > pParentWin = pParentComponent ? pParentComponent->GetWindow() : VclPtr< vcl::Window >(); + 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( ) throw () +{ + OGenericUnoController_Base::acquire(); +} + +void SAL_CALL OGenericUnoController::release( ) throw () +{ + 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( makeAny( *_rFeatureState.sTitle ) ); + if ( !!_rFeatureState.bChecked ) + _out_rStates.push_back( makeAny( *_rFeatureState.bChecked ) ); + if ( !!_rFeatureState.bInvisible ) + _out_rStates.push_back( makeAny( 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() +{ +#ifdef DBG_UTIL + static sal_Int32 s_nRecursions = 0; + ++s_nRecursions; +#endif + + bool bEmpty = true; + FeatureListener aNextFeature; + { + ::osl::MutexGuard aGuard( m_aFeatureMutex); + bEmpty = m_aFeaturesToInvalidate.empty(); + if (!bEmpty) + aNextFeature = m_aFeaturesToInvalidate.front(); + } + while(!bEmpty) + { + if ( ALL_FEATURES == aNextFeature.nId ) + { + InvalidateAll_Impl(); + break; + } + else + { + SupportedFeatures::const_iterator aFeaturePos = std::find_if( + m_aSupportedFeatures.begin(), + m_aSupportedFeatures.end(), + CompareFeatureById( aNextFeature.nId ) + ); + +#if OSL_DEBUG_LEVEL > 0 + if ( m_aSupportedFeatures.end() == aFeaturePos ) + { + SAL_WARN( "dbaccess.ui", "OGenericUnoController::InvalidateFeature_Impl: feature id " + << aNextFeature.nId + << " has been invalidated, but is not supported!" ); + } +#endif + if ( m_aSupportedFeatures.end() != aFeaturePos ) + // we really know this feature + ImplBroadcastFeatureState( aFeaturePos->first, aNextFeature.xListener, aNextFeature.bForceBroadcast ); + } + + ::osl::MutexGuard aGuard( m_aFeatureMutex); + m_aFeaturesToInvalidate.pop_front(); + bEmpty = m_aFeaturesToInvalidate.empty(); + if (!bEmpty) + aNextFeature = m_aFeaturesToInvalidate.front(); + } + +#ifdef DBG_UTIL + --s_nRecursions; +#endif +} + +void OGenericUnoController::ImplInvalidateFeature( sal_Int32 _nId, const Reference< XStatusListener >& _xListener, bool _bForceBroadcast ) +{ +#if OSL_DEBUG_LEVEL > 0 + if ( _nId != -1 ) + { + auto isSupportedFeature = std::any_of( + m_aSupportedFeatures.begin(), + m_aSupportedFeatures.end(), + CompareFeatureById( _nId ) + ); + OSL_ENSURE( isSupportedFeature, "OGenericUnoController::ImplInvalidateFeature: invalidating an unsupported feature is suspicious, at least!" ); + } +#endif + + FeatureListener aListener; + aListener.nId = _nId; + aListener.xListener = _xListener; + aListener.bForceBroadcast = _bForceBroadcast; + + bool bWasEmpty; + { + ::osl::MutexGuard aGuard( m_aFeatureMutex ); + bWasEmpty = m_aFeaturesToInvalidate.empty(); + m_aFeaturesToInvalidate.push_back( aListener ); + } + + if ( bWasEmpty ) + m_aAsyncInvalidateAll.Call(); +} + +void OGenericUnoController::InvalidateFeature(sal_uInt16 _nId, const Reference< XStatusListener > & _xListener, bool _bForceBroadcast) +{ + ImplInvalidateFeature( _nId, _xListener, _bForceBroadcast ); +} + +void OGenericUnoController::InvalidateAll() +{ + ImplInvalidateFeature( ALL_FEATURES, nullptr, true ); +} + +void OGenericUnoController::InvalidateAll_Impl() +{ + // invalidate all supported features + for (auto const& supportedFeature : m_aSupportedFeatures) + ImplBroadcastFeatureState( supportedFeature.first, nullptr, true ); + + { + ::osl::MutexGuard aGuard( m_aFeatureMutex); + OSL_ENSURE(m_aFeaturesToInvalidate.size(), "OGenericUnoController::InvalidateAll_Impl: to be called from within InvalidateFeature_Impl only!"); + m_aFeaturesToInvalidate.pop_front(); + if(!m_aFeaturesToInvalidate.empty()) + m_aAsyncInvalidateAll.Call(); + } +} + +Reference< XDispatch > OGenericUnoController::queryDispatch(const URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) +{ + Reference< XDispatch > xReturn; + + OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::queryDispatch: shouldn't this be filled at construction time?" ); + if ( m_aSupportedFeatures.empty() ) + fillSupportedFeatures(); + + // URL's we can handle ourself? + if ( aURL.Complete == ".uno:FormSlots/ConfirmDeletion" + || ( ( m_aSupportedFeatures.find( aURL.Complete ) != m_aSupportedFeatures.end() ) + && !isUserDefinedFeature( aURL.Complete ) + ) + ) + { + xReturn = this; + } + // no? -> ask the slave dispatcher + else if ( m_xSlaveDispatcher.is() ) + { + xReturn = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags); + } + + // outta here + return xReturn; +} + +Sequence< Reference< XDispatch > > OGenericUnoController::queryDispatches(const Sequence< DispatchDescriptor >& aDescripts) +{ + Sequence< Reference< XDispatch > > aReturn; + sal_Int32 nLen = aDescripts.getLength(); + if ( nLen ) + { + aReturn.realloc( nLen ); + Reference< XDispatch >* pReturn = aReturn.getArray(); + const Reference< XDispatch >* pReturnEnd = aReturn.getArray() + nLen; + const DispatchDescriptor* pDescripts = aDescripts.getConstArray(); + + for ( ; pReturn != pReturnEnd; ++ pReturn, ++pDescripts ) + { + *pReturn = queryDispatch( pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags ); + } + } + + return aReturn; +} + +Reference< XDispatchProvider > OGenericUnoController::getSlaveDispatchProvider() +{ + return m_xSlaveDispatcher; +} + +void OGenericUnoController::setSlaveDispatchProvider(const Reference< XDispatchProvider > & _xNewProvider) +{ + m_xSlaveDispatcher = _xNewProvider; +} + +Reference< XDispatchProvider > OGenericUnoController::getMasterDispatchProvider() +{ + return m_xMasterDispatcher; +} + +void OGenericUnoController::setMasterDispatchProvider(const Reference< XDispatchProvider > & _xNewProvider) +{ + m_xMasterDispatcher = _xNewProvider; +} + +void OGenericUnoController::dispatch(const URL& _aURL, const Sequence< PropertyValue >& aArgs) +{ + SolarMutexGuard aSolarGuard; + // The SolarMutex is not locked anymore when the framework calls into + // here. So, lock it ourself. The real solution would be to lock it only in the places + // where it's needed, but a) this might turn out difficult, since we then also need to care + // for locking in the proper order (SolarMutex and m_aMutex), and b) this would be too many places + // for the time frame of the fix. + // #i52602# + executeChecked(_aURL,aArgs); +} + +void OGenericUnoController::addStatusListener(const Reference< XStatusListener > & aListener, const URL& _rURL) +{ + // parse the URL now and here, this saves later parsing in each notification round + URL aParsedURL( _rURL ); + if ( m_xUrlTransformer.is() ) + m_xUrlTransformer->parseStrict( aParsedURL ); + + // remember the listener together with the URL + m_arrStatusListener.insert( m_arrStatusListener.end(), DispatchTarget( aParsedURL, aListener ) ); + + // initially broadcast the state + ImplBroadcastFeatureState( aParsedURL.Complete, aListener, true ); + // force the new state to be broadcast to the new listener +} + +void OGenericUnoController::removeStatusListener(const Reference< XStatusListener > & aListener, const URL& _rURL) +{ + if (_rURL.Complete.isEmpty()) + { + m_arrStatusListener.erase(std::remove_if(m_arrStatusListener.begin(), m_arrStatusListener.end(), + [&aListener](const DispatchTarget& rCurrent) { return rCurrent.xListener == aListener; }), + m_arrStatusListener.end()); + } + else + { + // remove the listener only for the given URL + Dispatch::iterator iterSearch = std::find_if(m_arrStatusListener.begin(), m_arrStatusListener.end(), + [&aListener, &_rURL](const DispatchTarget& rCurrent) { + return (rCurrent.xListener == aListener) && (rCurrent.aURL.Complete == _rURL.Complete); }); + if (iterSearch != m_arrStatusListener.end()) + m_arrStatusListener.erase(iterSearch); + } + + OSL_PRECOND( !m_aSupportedFeatures.empty(), "OGenericUnoController::removeStatusListener: shouldn't this be filled at construction time?" ); + if ( m_aSupportedFeatures.empty() ) + fillSupportedFeatures(); + + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find(_rURL.Complete); + if (aIter != m_aSupportedFeatures.end()) + { // clear the cache for that feature + StateCache::const_iterator aCachePos = m_aStateCache.find( aIter->second.nFeatureId ); + if ( aCachePos != m_aStateCache.end() ) + m_aStateCache.erase( aCachePos ); + } + + // now remove the listener from the deque + ::osl::MutexGuard aGuard( m_aFeatureMutex ); + m_aFeaturesToInvalidate.erase( + std::remove_if( m_aFeaturesToInvalidate.begin(), + m_aFeaturesToInvalidate.end(), + FindFeatureListener(aListener)) + ,m_aFeaturesToInvalidate.end()); +} + +void OGenericUnoController::releaseNumberForComponent() +{ + try + { + Reference< XUntitledNumbers > xUntitledProvider(getPrivateModel(), UNO_QUERY ); + if ( xUntitledProvider.is() ) + xUntitledProvider->releaseNumberForComponent(static_cast(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; + { + ::osl::MutexGuard aGuard( m_aFeatureMutex); + m_aAsyncInvalidateAll.CancelCall(); + m_aFeaturesToInvalidate.clear(); + } + + releaseNumberForComponent(); + + // check out from all the objects we are listening + // the frame + stopFrameListening( m_aCurrentFrame.getFrame() ); + m_aCurrentFrame.attachFrame( nullptr ); + + m_xMasterDispatcher = nullptr; + m_xSlaveDispatcher = nullptr; + m_xTitleHelper.clear(); + m_xUrlTransformer.clear(); + m_aInitParameters.clear(); +} + +void SAL_CALL OGenericUnoController::addEventListener( const Reference< XEventListener >& xListener ) +{ + // disambiguate + OGenericUnoController_Base::WeakComponentImplHelperBase::addEventListener( xListener ); +} + +void SAL_CALL OGenericUnoController::removeEventListener( const Reference< XEventListener >& xListener ) +{ + // disambiguate + OGenericUnoController_Base::WeakComponentImplHelperBase::removeEventListener( xListener ); +} + +void OGenericUnoController::frameAction(const FrameActionEvent& aEvent) +{ + ::osl::MutexGuard aGuard( getMutex() ); + if ( aEvent.Frame == m_aCurrentFrame.getFrame() ) + m_aCurrentFrame.frameAction( aEvent.Action ); +} + +void OGenericUnoController::implDescribeSupportedFeature( const char* _pAsciiCommandURL, + sal_uInt16 _nFeatureId, sal_Int16 _nCommandGroup ) +{ +#ifdef DBG_UTIL + OSL_ENSURE( m_bDescribingSupportedFeatures, "OGenericUnoController::implDescribeSupportedFeature: bad timing for this call!" ); +#endif + OSL_PRECOND( _nFeatureId < FIRST_USER_DEFINED_FEATURE, "OGenericUnoController::implDescribeSupportedFeature: invalid feature id!" ); + + ControllerFeature aFeature; + aFeature.Command = OUString::createFromAscii( _pAsciiCommandURL ); + aFeature.nFeatureId = _nFeatureId; + aFeature.GroupId = _nCommandGroup; + +#if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE( m_aSupportedFeatures.find( aFeature.Command ) == m_aSupportedFeatures.end(), + "OGenericUnoController::implDescribeSupportedFeature: this feature is already there!" ); +#endif + m_aSupportedFeatures[ aFeature.Command ] = aFeature; +} + +void OGenericUnoController::describeSupportedFeatures() +{ + // add all supported features + implDescribeSupportedFeature( ".uno:Copy", ID_BROWSER_COPY, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Cut", ID_BROWSER_CUT, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Paste", ID_BROWSER_PASTE, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:ClipboardFormatItems", ID_BROWSER_CLIPBOARD_FORMAT_ITEMS ); + implDescribeSupportedFeature( ".uno:DSBEditDoc", ID_BROWSER_EDITDOC, CommandGroup::DOCUMENT ); +} + +FeatureState OGenericUnoController::GetState( sal_uInt16 _nId ) const +{ + FeatureState aReturn; + // (disabled automatically) + + switch ( _nId ) + { + case ID_BROWSER_UNDO: + case ID_BROWSER_SAVEDOC: + aReturn.bEnabled = true; + break; + default: + // for now, enable all the time + // TODO: we should ask the dispatcher. However, this is laborious, since you cannot ask a dispatcher + // directly, but need to add a status listener. + aReturn.bEnabled = true; + break; + } + + return aReturn; +} + +void OGenericUnoController::Execute( sal_uInt16 _nId, const Sequence< PropertyValue>& _rArgs ) +{ + OSL_ENSURE( isUserDefinedFeature( _nId ), + "OGenericUnoController::Execute: responsible for user defined features only!" ); + + // user defined features can be handled by dispatch interceptors resp. protocol handlers only. + // So, we need to do a queryDispatch, and dispatch the URL + m_pData->m_aUserDefinedFeatures.execute( getURLForId( _nId ), _rArgs ); +} + +URL OGenericUnoController::getURLForId(sal_Int32 _nId) const +{ + URL aReturn; + if ( m_xUrlTransformer.is() ) + { + SupportedFeatures::const_iterator aIter = std::find_if( + m_aSupportedFeatures.begin(), + m_aSupportedFeatures.end(), + CompareFeatureById( _nId ) + ); + + if ( m_aSupportedFeatures.end() != aIter && !aIter->first.isEmpty() ) + { + aReturn.Complete = aIter->first; + m_xUrlTransformer->parseStrict( aReturn ); + } + } + return aReturn; +} + +bool OGenericUnoController::isUserDefinedFeature( const sal_uInt16 _nFeatureId ) +{ + return ( _nFeatureId >= FIRST_USER_DEFINED_FEATURE ) && ( _nFeatureId < 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 dispoing 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 dispoing 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() +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + + if ( ! m_xTitleHelper.is ()) + { + Reference< XUntitledNumbers > xUntitledProvider(getPrivateModel(), UNO_QUERY ); + Reference< XController > xThis(static_cast< XController* >(this), UNO_QUERY_THROW); + + ::framework::TitleHelper* pHelper = new ::framework::TitleHelper( m_xContext ); + m_xTitleHelper.set( static_cast< ::cppu::OWeakObject* >(pHelper), UNO_QUERY_THROW); + + pHelper->setOwner (xThis ); + pHelper->connectWithUntitledNumbers (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(), UNO_QUERY); + if (xBroadcaster.is ()) + xBroadcaster->removeTitleChangeListener (xListener); +} + +// XUserInputInterception +void SAL_CALL OGenericUnoController::addKeyHandler( const Reference< XKeyHandler >& _rxHandler ) +{ + if ( _rxHandler.is() ) + m_pData->m_aUserInputInterception.addKeyHandler( _rxHandler ); +} + +void SAL_CALL OGenericUnoController::removeKeyHandler( const Reference< XKeyHandler >& _rxHandler ) +{ + m_pData->m_aUserInputInterception.removeKeyHandler( _rxHandler ); +} + +void SAL_CALL OGenericUnoController::addMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler ) +{ + if ( _rxHandler.is() ) + m_pData->m_aUserInputInterception.addMouseClickHandler( _rxHandler ); +} + +void SAL_CALL OGenericUnoController::removeMouseClickHandler( const Reference< XMouseClickHandler >& _rxHandler ) +{ + m_pData->m_aUserInputInterception.removeMouseClickHandler( _rxHandler ); +} + +void OGenericUnoController::executeChecked(sal_uInt16 _nCommandId, const Sequence< PropertyValue >& aArgs) +{ + if ( isCommandEnabled(_nCommandId) ) + Execute(_nCommandId, aArgs); +} + +bool OGenericUnoController::isCommandEnabled(sal_uInt16 _nCommandId) const +{ + return GetState( _nCommandId ).bEnabled; +} + +void OGenericUnoController::notifyHiContrastChanged() +{ +} + +bool OGenericUnoController::isDataSourceReadOnly() const +{ + return false; +} + +Reference< XController > OGenericUnoController::getXController() +{ + return this; +} + +bool OGenericUnoController::interceptUserInput( const NotifyEvent& _rEvent ) +{ + return m_pData->m_aUserInputInterception.handleNotifyEvent( _rEvent ); +} + +bool OGenericUnoController::isCommandChecked(sal_uInt16 _nCommandId) const +{ + FeatureState aState = GetState( _nCommandId ); + + return aState.bChecked && *aState.bChecked; +} + +bool OGenericUnoController::isCommandEnabled( const OUString& _rCompleteCommandURL ) const +{ + OSL_ENSURE( !_rCompleteCommandURL.isEmpty(), "OGenericUnoController::isCommandEnabled: Empty command url!" ); + + bool bIsEnabled = false; + SupportedFeatures::const_iterator aIter = m_aSupportedFeatures.find( _rCompleteCommandURL ); + if ( aIter != m_aSupportedFeatures.end() ) + bIsEnabled = isCommandEnabled( aIter->second.nFeatureId ); + + return bIsEnabled; +} + +Sequence< ::sal_Int16 > SAL_CALL OGenericUnoController::getSupportedCommandGroups() +{ + CommandHashMap aCmdHashMap; + for (auto const& supportedFeature : m_aSupportedFeatures) + if ( supportedFeature.second.GroupId != CommandGroup::INTERNAL ) + aCmdHashMap.emplace( supportedFeature.second.GroupId, 0 ); + + return comphelper::mapKeysToSequence( aCmdHashMap ); +} + +Sequence< DispatchInformation > SAL_CALL OGenericUnoController::getConfigurableDispatchInformation( ::sal_Int16 CommandGroup ) +{ + std::vector< DispatchInformation > aInformationVector; + for (auto const& supportedFeature : m_aSupportedFeatures) + { + if ( sal_Int16( supportedFeature.second.GroupId ) == CommandGroup ) + { + aInformationVector.push_back( supportedFeature.second ); + } + } + + return comphelper::containerToSequence( aInformationVector ); +} + +void OGenericUnoController::fillSupportedFeatures() +{ +#ifdef DBG_UTIL + m_bDescribingSupportedFeatures = true; +#endif + describeSupportedFeatures(); +#ifdef DBG_UTIL + m_bDescribingSupportedFeatures = false; +#endif +} + +void SAL_CALL OGenericUnoController::dispose() +{ + SolarMutexGuard aSolarGuard; + OGenericUnoController_Base::dispose(); +} + +weld::Window* OGenericUnoController::getFrameWeld() const +{ + return m_pView ? m_pView->GetFrameWeld() : nullptr; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/sbagrid.cxx b/dbaccess/source/ui/browser/sbagrid.cxx new file mode 100644 index 000000000..b035a9eeb --- /dev/null +++ b/dbaccess/source/ui/browser/sbagrid.cxx @@ -0,0 +1,1419 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 ::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" void createRegistryInfo_SbaXGridControl() +{ + static OMultiInstanceAutoRegistration< SbaXGridControl > aAutoRegistration; +} + +css::uno::Sequence SAL_CALL SbaXGridControl::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference< XInterface > SbaXGridControl::Create(const Reference& _rxFactory) +{ + return *(new SbaXGridControl( comphelper::getComponentContext(_rxFactory) )); +} + +// SbaXGridControl + +OUString SAL_CALL SbaXGridControl::getImplementationName() +{ + return getImplementationName_Static(); +} + +OUString SbaXGridControl::getImplementationName_Static() +{ + return "com.sun.star.comp.dbu.SbaXGridControl"; +} + +Sequence< OUString> SbaXGridControl::getSupportedServiceNames_Static() +{ + return { "com.sun.star.form.control.InteractionGridControl", "com.sun.star.form.control.GridControl", + "com.sun.star.awt.UnoControl" }; +} + +SbaXGridControl::SbaXGridControl(const Reference< XComponentContext >& _rM) + : FmXGridControl(_rM) +{ +} + +SbaXGridControl::~SbaXGridControl() +{ +} + +FmXGridPeer* SbaXGridControl::imp_CreatePeer(vcl::Window* pParent) +{ + FmXGridPeer* pReturn = new SbaXGridPeer(m_xContext); + + // translate properties into WinBits + WinBits nStyle = WB_TABSTOP; + Reference< XPropertySet > xModelSet(getModel(), UNO_QUERY); + if (xModelSet.is()) + { + try + { + if (::comphelper::getINT16(xModelSet->getPropertyValue(PROPERTY_BORDER))) + nStyle |= WB_BORDER; + } + catch(Exception&) + { + } + + } + + pReturn->Create(pParent, nStyle); + return pReturn; +} + +Any SAL_CALL SbaXGridControl::queryInterface(const Type& _rType) +{ + Any aRet = FmXGridControl::queryInterface(_rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface(_rType,static_cast(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.get(), 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.get(), _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.get(), _rURL); + } + xMultiplexer->removeInterface( _rxListener ); +} + +void SAL_CALL SbaXGridControl::dispose() +{ + SolarMutexGuard aGuard; + + EventObject aEvt; + aEvt.Source = *this; + + for (auto & elem : m_aStatusMultiplexer) + { + if (elem.second.is()) + { + elem.second->disposeAndClear(aEvt); + elem.second.clear(); + } + } + StatusMultiplexerArray().swap(m_aStatusMultiplexer); + + FmXGridControl::dispose(); +} + +// SbaXGridPeer +SbaXGridPeer::SbaXGridPeer(const Reference< XComponentContext >& _rM) +: FmXGridPeer(_rM) +,m_aStatusListeners(m_aMutex) +{ +} + +SbaXGridPeer::~SbaXGridPeer() +{ +} + +void SAL_CALL SbaXGridPeer::dispose() +{ + EventObject aEvt(*this); + + m_aStatusListeners.disposeAndClear(aEvt); + + FmXGridPeer::dispose(); +} + +void SbaXGridPeer::NotifyStatusChanged(const css::util::URL& _rUrl, const Reference< css::frame::XStatusListener > & xControl) +{ + VclPtr< SbaGridControl > pGrid = GetAs< SbaGridControl >(); + if (!pGrid) + return; + + css::frame::FeatureStateEvent aEvt; + aEvt.Source = *this; + aEvt.IsEnabled = !pGrid->IsReadOnlyDB(); + aEvt.FeatureURL = _rUrl; + + MapDispatchToBool::const_iterator aURLStatePos = m_aDispatchStates.find( classifyDispatchURL( _rUrl ) ); + if ( m_aDispatchStates.end() != aURLStatePos ) + aEvt.State <<= aURLStatePos->second; + else + aEvt.State <<= false; + + if (xControl.is()) + xControl->statusChanged(aEvt); + else + { + ::cppu::OInterfaceContainerHelper * pIter = m_aStatusListeners.getContainer(_rUrl); + + if (pIter) + { + ::cppu::OInterfaceIteratorHelper aListIter(*pIter); + while (aListIter.hasMoreElements()) + static_cast< css::frame::XStatusListener*>(aListIter.next())->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) +{ + ::cppu::OInterfaceContainerHelper* pCont = m_aStatusListeners.getContainer(aURL); + if (!pCont) + m_aStatusListeners.addInterface(aURL,xControl); + else + pCont->addInterface(xControl); + NotifyStatusChanged(aURL, xControl); +} + +void SAL_CALL SbaXGridPeer::removeStatusListener(const Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) +{ + ::cppu::OInterfaceContainerHelper* pCont = m_aStatusListeners.getContainer(aURL); + if ( pCont ) + pCont->removeInterface(xControl); +} + +Sequence< Type > SAL_CALL SbaXGridPeer::getTypes() +{ + return comphelper::concatSequences( + FmXGridPeer::getTypes(), + Sequence { cppu::UnoType::get() }); +} + +UNO3_GETIMPLEMENTATION2_IMPL(SbaXGridPeer, FmXGridPeer); + +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.IsInside(_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, PopupMenu& rMenu) +{ + FmGridHeader::PreExecuteColumnContextMenu(nColId, rMenu); + + // some items are valid only if the db isn't readonly + bool bDBIsReadOnly = static_cast(GetParent())->IsReadOnlyDB(); + + if (bDBIsReadOnly) + { + rMenu.EnableItem(rMenu.GetItemId("hide"), false); + PopupMenu* pShowColsMenu = rMenu.GetPopupMenu(rMenu.GetItemId("show")); + if (pShowColsMenu) + { + // at most 16 items which mean "show column " + for (sal_uInt16 i=1; i<16; ++i) + pShowColsMenu->EnableItem(i, false); + // "show cols/more..." and "show cols/all" + pShowColsMenu->EnableItem(pShowColsMenu->GetItemId("more"), false); + pShowColsMenu->EnableItem(pShowColsMenu->GetItemId("all"), 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.InsertItem(ID_BROWSER_COLATTRSET, DBA_RES(RID_STR_COLUMN_FORMAT), MenuItemBits::NONE, OString(), nPos++); + rMenu.SetHelpId(ID_BROWSER_COLATTRSET, HID_BROWSER_COLUMNFORMAT); + rMenu.InsertSeparator(OString(), nPos++); + } + } + + rMenu.InsertItem(ID_BROWSER_COLWIDTH, DBA_RES(RID_STR_COLUMN_WIDTH), MenuItemBits::NONE, OString(), nPos++); + rMenu.SetHelpId(ID_BROWSER_COLWIDTH, HID_BROWSER_COLUMNWIDTH); + rMenu.InsertSeparator(OString(), nPos++); +} + +void SbaGridHeader::PostExecuteColumnContextMenu(sal_uInt16 nColId, const PopupMenu& rMenu, sal_uInt16 nExecutionResult) +{ + switch (nExecutionResult) + { + case ID_BROWSER_COLWIDTH: + static_cast(GetParent())->SetColWidth(nColId); + break; + + case ID_BROWSER_COLATTRSET: + static_cast(GetParent())->SetColAttrs(nColId); + break; + case ID_BROWSER_COLUMNINFO: + { + sal_uInt16 nModelPos = static_cast(GetParent())->GetModelColumnPos(nColId); + Reference< XPropertySet > xField = static_cast(GetParent())->getField(nModelPos); + + if(!xField.is()) + break; + std::vector< std::shared_ptr > vClipboardList; + // send it to the clipboard + vClipboardList.push_back(std::make_shared(xField)); + rtl::Reference pData = new OTableRowExchange(vClipboardList); + pData->CopyToClipboard(GetParent()); + } + break; + + default: FmGridHeader::PostExecuteColumnContextMenu(nColId, rMenu, nExecutionResult); + } +} + +// 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(long nRow, sal_uInt16 nCol) +{ + if ( m_bActivatingForDrop ) + return nullptr; + + return FmGridControl::GetController(nRow, nCol); +} + +void SbaGridControl::PreExecuteRowContextMenu(sal_uInt16 nRow, PopupMenu& rMenu) +{ + FmGridControl::PreExecuteRowContextMenu(nRow, rMenu); + + sal_uInt16 nPos = 0; + + if (!IsReadOnlyDB()) + { + rMenu.InsertItem(ID_BROWSER_TABLEATTR, DBA_RES(RID_STR_TABLE_FORMAT), MenuItemBits::NONE, OString(), nPos++); + rMenu.SetHelpId(ID_BROWSER_TABLEATTR, HID_BROWSER_TABLEFORMAT); + + rMenu.InsertItem(ID_BROWSER_ROWHEIGHT, DBA_RES(RID_STR_ROW_HEIGHT), MenuItemBits::NONE, OString(), nPos++); + rMenu.SetHelpId(ID_BROWSER_ROWHEIGHT, HID_BROWSER_ROWHEIGHT); + rMenu.InsertSeparator(OString(), nPos++); + } + + if ( GetSelectRowCount() > 0 ) + { + rMenu.InsertItem(ID_BROWSER_COPY, DBA_RES(RID_STR_COPY), MenuItemBits::NONE, OString(), nPos++); + rMenu.InsertSeparator(OString(), nPos++); + } +} + +SvNumberFormatter* SbaGridControl::GetDatasourceFormatter() +{ + Reference< css::util::XNumberFormatsSupplier > xSupplier = ::dbtools::getNumberFormats(::dbtools::getConnection(Reference< XRowSet > (getDataSource(),UNO_QUERY)), true, getContext()); + + SvNumberFormatsSupplierObj* pSupplierImpl = comphelper::getUnoTunnelImplementation( 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&) + { + OSL_FAIL("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,this);//(Window::GetSettings().GetLanguage()); +} + +void SbaGridControl::SetBrowserAttrs() +{ + Reference< XPropertySet > xGridModel(GetPeer()->getColumns(), UNO_QUERY); + if (!xGridModel.is()) + return; + + try + { + Reference< XComponentContext > xContext = getContext(); + css::beans::PropertyValue aArg; + css::uno::Sequence aArguments(2); + aArg.Name = "IntrospectedObject"; + aArg.Value <<= xGridModel; + aArguments[0] <<= aArg; + aArg.Name = "ParentWindow"; + aArg.Value <<= VCLUnoHelper::GetInterface(this); + aArguments[1] <<= aArg; + 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(sal_uInt16 nRow, const PopupMenu& rMenu, sal_uInt16 nExecutionResult) +{ + switch (nExecutionResult) + { + case ID_BROWSER_TABLEATTR: + SetBrowserAttrs(); + break; + case ID_BROWSER_ROWHEIGHT: + SetRowHeight(); + break; + case ID_BROWSER_COPY: + CopySelectedRowsToClipboard(); + break; + + default: + FmGridControl::PostExecuteRowContextMenu(nRow, rMenu, nExecutionResult); + break; + } +} + +void SbaGridControl::Select() +{ + // Some selection has changed ... + FmGridControl::Select(); + + if (m_pMasterListener) + m_pMasterListener->SelectionChanged(); +} + +void SbaGridControl::ActivateCell(long 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) +{ + long 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'...) + long 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 + + long 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 !"); + + 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.realloc( 1 ); + aSelectedRows[0] <<= 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) + + OUString sCellText; + try + { + Reference< XGridFieldDataSupplier > xFieldData(static_cast< XGridPeer* >(GetPeer()), UNO_QUERY); + 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 long nRow = GetRowAtYPosPixel(rEvt.maPosPixel.Y(), false); + const sal_uInt16 nCol = GetColumnId(GetColumnAtXPosPixel(rEvt.maPosPixel.X())); + + long 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.IsInside(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->IsModified() && ((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(static_cast(GetPeer()), UNO_QUERY); + 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 ) ) + { + long nRow = GetRowAtYPosPixel(rEvt.maPosPixel.Y(), false); + sal_uInt16 nCol = GetColumnAtXPosPixel(rEvt.maPosPixel.X()); + + long 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(); + if (!xCurrentController.is() || nullptr == dynamic_cast< const EditCellController* >(xCurrentController.get())) + return DND_ACTION_NONE; + Edit& rEdit = static_cast(xCurrentController->GetWindow()); + + // get the dropped string + TransferableDataHelper aDropped( rEvt.maDropEvent.Transferable ); + OUString sDropped; + if ( !aDropped.GetString( SotClipboardFormatId::STRING, sDropped ) ) + return DND_ACTION_NONE; + + rEdit.SetText( sDropped ); + xCurrentController->SetModified(); + rEdit.Modify(); + // SetText itself doesn't call a Modify as it isn't a user interaction + + 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( ::vcl::AccessibleBrowseBoxObjType eObjType,sal_Int32 _nPosition) const +{ + OUString sRet; + if ( ::vcl::BBTYPE_BROWSEBOX == eObjType ) + { + SolarMutexGuard aGuard; + sRet = DBA_RES(STR_DATASOURCE_GRIDCONTROL_DESC); + } + else + sRet = FmGridControl::GetAccessibleObjectDescription( eObjType,_nPosition); + return sRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/sbamultiplex.cxx b/dbaccess/source/ui/browser/sbamultiplex.cxx new file mode 100644 index 000000000..68673fd06 --- /dev/null +++ b/dbaccess/source/ui/browser/sbamultiplex.cxx @@ -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 . + */ + +#include +using namespace dbaui; + +// the listener multiplexers + +// XStatusListener +IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXStatusMultiplexer, css::frame::XStatusListener) + +void SAL_CALL SbaXStatusMultiplexer::statusChanged(const css::frame::FeatureStateEvent& e) +{ + m_aLastKnownStatus = e; + m_aLastKnownStatus.Source = &m_rParent; + ::comphelper::OInterfaceIteratorHelper2 aIt( *this ); + while ( aIt.hasMoreElements() ) + static_cast< css::frame::XStatusListener* >( aIt.next() )->statusChanged( m_aLastKnownStatus ); +} + +// LoadListener +IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXLoadMultiplexer, css::form::XLoadListener) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, css::form::XLoadListener, loaded, css::lang::EventObject) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, css::form::XLoadListener, unloaded, css::lang::EventObject) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, css::form::XLoadListener, unloading, css::lang::EventObject) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, css::form::XLoadListener, reloading, css::lang::EventObject) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXLoadMultiplexer, css::form::XLoadListener, reloaded, css::lang::EventObject) + +// css::sdbc::XRowSetListener +IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXRowSetMultiplexer, css::sdbc::XRowSetListener) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXRowSetMultiplexer, css::sdbc::XRowSetListener, cursorMoved, css::lang::EventObject) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXRowSetMultiplexer, css::sdbc::XRowSetListener, rowChanged, css::lang::EventObject) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXRowSetMultiplexer, css::sdbc::XRowSetListener, rowSetChanged, css::lang::EventObject) + +// css::sdb::XRowSetApproveListener +IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXRowSetApproveMultiplexer, css::sdb::XRowSetApproveListener) +IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXRowSetApproveMultiplexer, css::sdb::XRowSetApproveListener, approveCursorMove, css::lang::EventObject) +IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXRowSetApproveMultiplexer, css::sdb::XRowSetApproveListener, approveRowChange, css::sdb::RowChangeEvent) +IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXRowSetApproveMultiplexer, css::sdb::XRowSetApproveListener, approveRowSetChange, css::lang::EventObject) + +// css::sdb::XSQLErrorListener +IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXSQLErrorMultiplexer, css::sdb::XSQLErrorListener) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXSQLErrorMultiplexer, css::sdb::XSQLErrorListener, errorOccured, css::sdb::SQLErrorEvent) + +// css::form::XDatabaseParameterListener +IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXParameterMultiplexer, css::form::XDatabaseParameterListener) +IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXParameterMultiplexer, css::form::XDatabaseParameterListener, approveParameter, css::form::DatabaseParameterEvent) + +// css::form::XSubmitListener +IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXSubmitMultiplexer, css::form::XSubmitListener) +IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXSubmitMultiplexer, css::form::XSubmitListener, approveSubmit, css::lang::EventObject) + +// css::form::XResetListener +IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXResetMultiplexer, css::form::XResetListener) +IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(SbaXResetMultiplexer, css::form::XResetListener, approveReset, css::lang::EventObject) +IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(SbaXResetMultiplexer, css::form::XResetListener, resetted, css::lang::EventObject) + +// css::beans::XPropertyChangeListener +IMPLEMENT_PROPERTY_MULTIPLEXER(SbaXPropertyChangeMultiplexer, css::beans::XPropertyChangeListener, propertyChange, css::beans::PropertyChangeEvent) + +// css::beans::XVetoableChangeListener +IMPLEMENT_PROPERTY_MULTIPLEXER(SbaXVetoableChangeMultiplexer, css::beans::XVetoableChangeListener, vetoableChange, css::beans::PropertyChangeEvent) + +// css::beans::XPropertiesChangeListener +IMPLEMENT_LISTENER_MULTIPLEXER_CORE(SbaXPropertiesChangeMultiplexer, css::beans::XPropertiesChangeListener); +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 : aMulti) + rEvent.Source = &m_rParent; + + ::comphelper::OInterfaceIteratorHelper2 aIt(*this); + while (aIt.hasMoreElements()) + static_cast< css::beans::XPropertiesChangeListener*>(aIt.next())->propertiesChange(aMulti); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/browser/unodatbr.cxx b/dbaccess/source/ui/browser/unodatbr.cxx new file mode 100644 index 000000000..cd0aed665 --- /dev/null +++ b/dbaccess/source/ui/browser/unodatbr.cxx @@ -0,0 +1,3723 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "dbtreeview.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 +#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" void createRegistryInfo_OBrowser() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::SbaTableQueryBrowser > aAutoRegistration; +} + +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 getImplementationName_Static(); +} + +css::uno::Sequence SAL_CALL SbaTableQueryBrowser::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +OUString SbaTableQueryBrowser::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.ODatasourceBrowser"; +} + +css::uno::Sequence SbaTableQueryBrowser::getSupportedServiceNames_Static() +{ + return { "com.sun.star.sdb.DataSourceBrowser" }; +} + +Reference< XInterface > SbaTableQueryBrowser::Create(const Reference& _rxFactory) +{ + SolarMutexGuard aGuard; + return *(new SbaTableQueryBrowser(comphelper::getComponentContext(_rxFactory))); +} + +SbaTableQueryBrowser::SbaTableQueryBrowser(const Reference< XComponentContext >& _rM) + :SbaXDataBrowserController(_rM) + ,m_aSelectionListeners( getMutex() ) + ,m_aContextMenuInterceptors( getMutex() ) + ,m_aTableCopyHelper(this) + ,m_pTreeView(nullptr) + ,m_pSplitter(nullptr) + ,m_pCurrentlyDisplayed(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, "SbaTableQueryBrowser::queryInterface: did not initialize this, yet!" ); + if ( !!m_aDocScriptSupport && *m_aDocScriptSupport ) + return makeAny( Reference< XScriptInvocationContext >( this ) ); + return Any(); + } + + Any aReturn = SbaXDataBrowserController::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = SbaTableQueryBrowser_Base::queryInterface(_rType); + return aReturn; +} + +Sequence< Type > SAL_CALL SbaTableQueryBrowser::getTypes( ) +{ + Sequence< Type > aTypes( ::comphelper::concatSequences( + SbaXDataBrowserController::getTypes(), + SbaTableQueryBrowser_Base::getTypes() + ) ); + + OSL_PRECOND( !!m_aDocScriptSupport, "SbaTableQueryBrowser::getTypes: did not initialize this, yet!" ); + if ( !m_aDocScriptSupport || !*m_aDocScriptSupport ) + { + auto newEnd = std::remove_if( aTypes.begin(), aTypes.end(), + [](const Type& type) + { return type == cppu::UnoType::get(); } ); + aTypes.realloc( std::distance(aTypes.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 cleaup 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(); + + // 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"); + } + + // check out from all the objects we are listening + // the frame + if (m_xCurrentFrameParent.is()) + m_xCurrentFrameParent->removeFrameActionListener(static_cast(this)); + 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()) + { + + // create controls and set sizes + const 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(), WB_TABSTOP | WB_BORDER); + m_pTreeView->SetPreExpandHandler(LINK(this, SbaTableQueryBrowser, OnExpandEntry)); + + m_pTreeView->setCopyHandler(LINK(this, SbaTableQueryBrowser, OnCopyEntry)); + + m_pTreeView->getListBox().setContextMenuProvider( this ); + m_pTreeView->getListBox().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 + auto pTreeModel = m_pTreeView->GetTreeModel(); + pTreeModel->SetSortMode(SortAscending); + pTreeModel->SetCompareHdl(LINK(this, SbaTableQueryBrowser, OnTreeEntryCompare)); + m_pTreeView->setSelChangeHdl( LINK( this, SbaTableQueryBrowser, OnSelectionChange ) ); + + // 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, makeAny( 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_pCurrentlyDisplayed) + return true; + + // this method set all format settings from the original table or query + try + { + DBTreeListUserData* pData = static_cast(m_pCurrentlyDisplayed->GetUserData()); + ENSURE_OR_RETURN_FALSE( pData, "SbaTableQueryBrowser::InitializeForm: No user data set at the currently displayed entry!" ); + ENSURE_OR_RETURN_FALSE( pData->xObjectProperties.is(), "SbaTableQueryBrowser::InitializeForm: No table available!" ); + + Reference< XPropertySetInfo > xPSI( pData->xObjectProperties->getPropertySetInfo(), UNO_SET_THROW ); + + ::comphelper::NamedValueCollection aPropertyValues; + + const OUString aTransferProperties[] = + { + OUString(PROPERTY_APPLYFILTER), + OUString(PROPERTY_FILTER), + OUString(PROPERTY_HAVING_CLAUSE), + OUString(PROPERTY_ORDER) + }; + for (const auto & aTransferPropertie : aTransferProperties) + { + if ( !xPSI->hasPropertyByName( aTransferPropertie ) ) + continue; + aPropertyValues.put( aTransferPropertie, pData->xObjectProperties->getPropertyValue( aTransferPropertie ) ); + } + + 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",makeAny(false)); + xDataSourceSet->setPropertyValue("AllowUpdates",makeAny(false)); + xDataSourceSet->setPropertyValue("AllowDeletes",makeAny(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_pCurrentlyDisplayed) + { + Sequence< OUString> aProperties(6 + ( m_bPreview ? 5 : 0 )); + Sequence< Any> aValues(7 + ( m_bPreview ? 5 : 0 )); + + DBTreeListUserData* pData = static_cast(m_pCurrentlyDisplayed->GetUserData()); + 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", makeAny( VisualEffect::FLAT ) ); + sDefaultProperty = PROPERTY_DEFAULTSTATE; + + sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN; + OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable ); + aInitialValues.emplace_back( + "TriState", + makeAny( 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", makeAny( 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", makeAny( xSupplier ) ); + aInitialValues.emplace_back( "TreatAsNumber", makeAny( bFormattedIsNumeric ) ); + aCopyProperties.emplace_back(PROPERTY_FORMATKEY ); + break; + } + + aInitialValues.emplace_back( PROPERTY_CONTROLSOURCE, makeAny( rName ) ); + OUString sLabel; + xColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel; + if ( !sLabel.isEmpty() ) + aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( sLabel ) ); + else + aInitialValues.emplace_back( PROPERTY_LABEL, makeAny( 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, makeAny( 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, makeAny(xGridCol)); + } + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +static Reference getColumnHelper(SvTreeListEntry const * _pCurrentlyDisplayed, const Reference& _rxSource) +{ + Reference xRet; + if(_pCurrentlyDisplayed) + { + DBTreeListUserData* pData = static_cast(_pCurrentlyDisplayed->GetUserData()); + 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_pCurrentlyDisplayed) + { + DBTreeListUserData* pData = static_cast(m_pCurrentlyDisplayed->GetUserData()); + 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); + + 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(m_pCurrentlyDisplayed,xSource); + if(xProp.is()) + { + if(!evt.NewValue.hasValue()) + xProp->setPropertyValue(PROPERTY_WIDTH,makeAny(sal_Int32(227))); + else + xProp->setPropertyValue(PROPERTY_WIDTH,evt.NewValue); + } + } + + // a column's 'visible' state ? + else if (evt.PropertyName == PROPERTY_HIDDEN) + { + Reference xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource); + if(xProp.is()) + xProp->setPropertyValue(PROPERTY_HIDDEN,evt.NewValue); + } + + // a columns alignment ? + else if (evt.PropertyName == PROPERTY_ALIGN) + { + Reference xProp = getColumnHelper(m_pCurrentlyDisplayed,xSource); + try + { + if(xProp.is()) + { + if(evt.NewValue.hasValue()) + { + sal_Int16 nAlign = 0; + if(evt.NewValue >>= nAlign) + xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(sal_Int32(nAlign))); + else + xProp->setPropertyValue(PROPERTY_ALIGN,evt.NewValue); + } + else + xProp->setPropertyValue(PROPERTY_ALIGN,makeAny(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(m_pCurrentlyDisplayed,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_pCurrentlyDisplayed) + { + DBTreeListUserData* pData = static_cast(m_pCurrentlyDisplayed->GetUserData()); + OSL_ENSURE( pData->xObjectProperties.is(), "No table available!" ); + + bool bDefault = !evt.NewValue.hasValue(); + if (bDefault) + pData->xObjectProperties->setPropertyValue(PROPERTY_ROW_HEIGHT,makeAny(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() +{ + SvTreeListEntry* pDataSourceEntry = nullptr; + SvTreeListEntry* pContainerEntry = nullptr; + SvTreeListEntry* pObjectEntry = getObjectEntry( m_aDocumentDataSource, &pDataSourceEntry, &pContainerEntry ); + bool bKnownDocDataSource = (nullptr != pObjectEntry); + if (!bKnownDocDataSource) + { + if (nullptr != pDataSourceEntry) + { // at least the data source is known + if (nullptr != pContainerEntry) + bKnownDocDataSource = true; // assume we know it. + // TODO: should we expand the object container? This may be too expensive just for checking... + else + { + if (m_aDocumentDataSource.has(DataAccessDescriptorProperty::CommandType) + && m_aDocumentDataSource.has(DataAccessDescriptorProperty::Command)) + { // maybe we have a command to be displayed ? + sal_Int32 nCommandType = CommandType::TABLE; + m_aDocumentDataSource[DataAccessDescriptorProperty::CommandType] >>= nCommandType; + + OUString sCommand; + m_aDocumentDataSource[DataAccessDescriptorProperty::Command] >>= sCommand; + + bKnownDocDataSource = (CommandType::COMMAND == nCommandType) && (!sCommand.isEmpty()); + } + } + } + } + + if ( !bKnownDocDataSource ) + m_aExternalFeatures[ ID_BROWSER_DOCUMENT_DATASOURCE ].bEnabled = false; + + // update the toolbox + implCheckExternalSlot(ID_BROWSER_DOCUMENT_DATASOURCE); +} + +void SbaTableQueryBrowser::extractDescriptorProps(const svx::ODataAccessDescriptor& _rDescriptor, OUString& _rDataSource, OUString& _rCommand, sal_Int32& _rCommandType, bool& _rEscapeProcessing) +{ + _rDataSource = _rDescriptor.getDataSource(); + if ( _rDescriptor.has(DataAccessDescriptorProperty::Command) ) + _rDescriptor[DataAccessDescriptorProperty::Command] >>= _rCommand; + if ( _rDescriptor.has(DataAccessDescriptorProperty::CommandType) ) + _rDescriptor[DataAccessDescriptorProperty::CommandType] >>= _rCommandType; + + // escape processing is the only one allowed not to be present + _rEscapeProcessing = true; + if (_rDescriptor.has(DataAccessDescriptorProperty::EscapeProcessing)) + _rEscapeProcessing = ::cppu::any2bool(_rDescriptor[DataAccessDescriptorProperty::EscapeProcessing]); +} + +namespace +{ + bool getDataSourceDisplayName_isURL( const OUString& _rDS, OUString& _rDisplayName, OUString& _rUniqueId ) + { + INetURLObject aURL( _rDS ); + if ( aURL.GetProtocol() != INetProtocol::NotValid ) + { + _rDisplayName = aURL.getBase(INetURLObject::LAST_SEGMENT,true,INetURLObject::DecodeMechanism::WithCharset); + _rUniqueId = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + return true; + } + _rDisplayName = _rDS; + _rUniqueId.clear(); + return false; + } + + struct FilterByEntryDataId : public IEntryFilter + { + OUString sId; + explicit FilterByEntryDataId( const OUString& _rId ) : sId( _rId ) { } + + virtual ~FilterByEntryDataId() {} + + virtual bool includeEntry(const void* pEntry) const override; + }; + + bool FilterByEntryDataId::includeEntry(const void* pUserData) const + { + const DBTreeListUserData* pData = static_cast(pUserData); + return ( !pData || ( pData->sAccessor == sId ) ); + } +} + +OUString SbaTableQueryBrowser::getDataSourceAccessor( SvTreeListEntry* _pDataSourceEntry ) const +{ + OSL_ENSURE( _pDataSourceEntry, "SbaTableQueryBrowser::getDataSourceAccessor: invalid entry!" ); + + DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( _pDataSourceEntry->GetUserData() ); + 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( _pDataSourceEntry ); +} + +SvTreeListEntry* SbaTableQueryBrowser::getObjectEntry(const OUString& _rDataSource, const OUString& _rCommand, sal_Int32 _nCommandType, + SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _ppContainerEntry, bool _bExpandAncestors, + const SharedConnection& _rxConnection ) +{ + if (_ppDataSourceEntry) + *_ppDataSourceEntry = nullptr; + if (_ppContainerEntry) + *_ppContainerEntry = nullptr; + + SvTreeListEntry* pObject = nullptr; + 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 ); + SvTreeListEntry* pDataSource = m_pTreeView->getListBox().GetEntryPosByName( sDisplayName, nullptr, &aFilter ); + if ( !pDataSource ) // 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 ); + pDataSource = m_pTreeView->getListBox().GetEntryPosByName( sDisplayName, nullptr, &aFilter ); + OSL_ENSURE( pDataSource, "SbaTableQueryBrowser::getObjectEntry: hmm - did not find it again!" ); + } + } + if (_ppDataSourceEntry) + // (caller wants to have it...) + *_ppDataSourceEntry = pDataSource; + + if (pDataSource) + { + // expand if required so + if (_bExpandAncestors) + m_pTreeView->getListBox().Expand(pDataSource); + + // look for the object container + SvTreeListEntry* pCommandType = nullptr; + switch (_nCommandType) + { + case CommandType::TABLE: + pCommandType = m_pTreeView->getListBox().GetModel()->GetEntry(pDataSource, CONTAINER_TABLES); + break; + + case CommandType::QUERY: + pCommandType = m_pTreeView->getListBox().GetModel()->GetEntry(pDataSource, CONTAINER_QUERIES); + break; + } + + if (_ppContainerEntry) + *_ppContainerEntry = pCommandType; + + if (pCommandType) + { + // expand if required so + if (_bExpandAncestors) + { + m_pTreeView->getListBox().Expand(pCommandType); + } + + // 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); + } + pObject = m_pTreeView->getListBox().GetEntryPosByName(sPath, pCommandType); + pCommandType = pObject; + if ( nIndex >= 0 ) + { + if (ensureEntryObject(pObject)) + { + DBTreeListUserData* pParentData = static_cast< DBTreeListUserData* >( pObject->GetUserData() ); + Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY ); + sal_Int32 nIndex2 = nIndex; + sPath = _rCommand.getToken( 0, '/', nIndex2 ); + try + { + if ( xCollection->hasByName(sPath) ) + { + if(!m_pTreeView->getListBox().GetEntryPosByName(sPath,pObject)) + { + Reference xChild(xCollection->getByName(sPath),UNO_QUERY); + DBTreeListUserData* pEntryData = new DBTreeListUserData; + pEntryData->eType = etQuery; + if ( xChild.is() ) + { + pEntryData->eType = etQueryContainer; + } + implAppendEntry( pObject, sPath, pEntryData, pEntryData->eType ); + } + } + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree"); + } + } + } + } + while ( nIndex >= 0 ); + } + } + } + return pObject; +} + +SvTreeListEntry* SbaTableQueryBrowser::getObjectEntry(const svx::ODataAccessDescriptor& _rDescriptor, + SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _ppContainerEntry) +{ + // extract the props from the descriptor + OUString sDataSource; + OUString sCommand; + sal_Int32 nCommandType = CommandType::COMMAND; + bool bEscapeProcessing = true; + extractDescriptorProps(_rDescriptor, sDataSource, sCommand, nCommandType, bEscapeProcessing); + + return getObjectEntry( sDataSource, sCommand, nCommandType, _ppDataSourceEntry, _ppContainerEntry, false/*_bExpandAncestors*/ ); +} + +void SbaTableQueryBrowser::connectExternalDispatches() +{ + Reference< XDispatchProvider > xProvider( getFrame(), UNO_QUERY ); + OSL_ENSURE(xProvider.is(), "SbaTableQueryBrowser::connectExternalDispatches: no DispatchProvider !"); + if (!xProvider.is()) + return; + + if ( m_aExternalFeatures.empty() ) + { + const char* pURLs[] = { + ".uno:DataSourceBrowser/DocumentDataSource", + ".uno:DataSourceBrowser/FormLetter", + ".uno:DataSourceBrowser/InsertColumns", + ".uno:DataSourceBrowser/InsertContent", + }; + const sal_uInt16 nIds[] = { + ID_BROWSER_DOCUMENT_DATASOURCE, + ID_BROWSER_FORMLETTER, + ID_BROWSER_INSERTCOLUMNS, + ID_BROWSER_INSERTCONTENT + }; + + for ( size_t i=0; i < SAL_N_ELEMENTS( pURLs ); ++i ) + { + URL aURL; + aURL.Complete = OUString::createFromAscii( pURLs[i] ); + if ( m_xUrlTransformer.is() ) + m_xUrlTransformer->parseStrict( aURL ); + m_aExternalFeatures[ nIds[ i ] ] = ExternalFeature( aURL ); + } + } + + for (auto & externalFeature : m_aExternalFeatures) + { + externalFeature.second.xDispatcher = xProvider->queryDispatch( + externalFeature.second.aURL, "_parent", FrameSearchFlag::PARENT + ); + + if ( externalFeature.second.xDispatcher.get() == static_cast< XDispatch* >( this ) ) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::connectExternalDispatches: this should not happen anymore!" ); + // (nowadays, the URLs aren't in our SupportedFeatures list anymore, so we should + // not supply a dispatcher for this) + externalFeature.second.xDispatcher.clear(); + } + + if ( externalFeature.second.xDispatcher.is() ) + { + try + { + externalFeature.second.xDispatcher->addStatusListener( this, externalFeature.second.aURL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + implCheckExternalSlot( externalFeature.first ); + } +} + +void SbaTableQueryBrowser::implCheckExternalSlot( sal_uInt16 _nId ) +{ + if ( !m_xMainToolbar.is() ) + return; + + VclPtr 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( _nId ) ) + bHaveDispatcher ? pToolbox->ShowItem( _nId ) : pToolbox->HideItem( _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 + SvTreeListEntry* pDSLoop = m_pTreeView->getListBox().FirstChild(nullptr); + while (pDSLoop) + { + DBTreeListUserData* pData = static_cast(pDSLoop->GetUserData()); + if ( pData && pData->xConnection == xCon ) + { + // we set the connection to null to avoid a second disposing of the connection + pData->xConnection.clear(); + closeConnection(pDSLoop,false); + break; + } + + pDSLoop = pDSLoop->NextSibling(); + } + } + 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: + { + SvTreeListEntry* pCurrentEntry( m_pTreeView->getListBox().GetCurEntry() ); + EntryType eType = getEntryType( pCurrentEntry ); + if ( eType == etUnknown ) + return aReturn; + + SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().GetRootLevelParent( pCurrentEntry ); + DBTreeListUserData* pDSData + = pDataSourceEntry + ? static_cast< DBTreeListUserData* >( pDataSourceEntry->GetUserData() ) + : 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() && ( pDataSourceEntry != nullptr ) && bHaveEditDatabase; + } + else if ( nId == ID_BROWSER_COPY ) + { + aReturn.bEnabled = isEntryCopyAllowed( pCurrentEntry ); + } + + 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: + implAdministrate( m_pTreeView->getListBox().GetCurEntry() ); + break; + + case ID_TREE_CLOSE_CONN: + closeConnection( m_pTreeView->getListBox().GetRootLevelParent( m_pTreeView->getListBox().GetCurEntry() ) ); + 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; + + SvTreeListEntry* pSelected = m_pCurrentlyDisplayed; + // unload + unloadAndCleanup( false ); + + // reselect the entry + if ( pSelected ) + { + implSelect( pSelected ); + } + 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()); + 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()) + { + copyEntry(m_pTreeView->getListBox().GetCurEntry()); + } + 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 ) +{ + Image a, b, c; + OUString d, e; + implAddDatasource( _rDataSourceName, a, d, b, e, c, _rxConnection ); +} + +void SbaTableQueryBrowser::implAddDatasource(const OUString& _rDbName, Image& _rDbImage, + OUString& _rQueryName, Image& _rQueryImage, OUString& _rTableName, Image& _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) + _rQueryImage = ImageProvider::getFolderImage( DatabaseObject::QUERY ); + if (!_rTableImage) + _rTableImage = ImageProvider::getFolderImage( DatabaseObject::TABLE ); + + if (!_rDbImage) + _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 ); + + SvTreeListEntry* pDatasourceEntry = m_pTreeView->getListBox().InsertEntry( sDSDisplayName, _rDbImage, _rDbImage ); + DBTreeListUserData* pDSData = new DBTreeListUserData; + pDSData->eType = etDatasource; + pDSData->sAccessor = sDataSourceId; + pDSData->xConnection = _rxConnection; + pDatasourceEntry->SetUserData(pDSData); + + // the child for the queries container + { + DBTreeListUserData* pQueriesData = new DBTreeListUserData; + pQueriesData->eType = etQueryContainer; + + m_pTreeView->getListBox().InsertEntry( + _rQueryName, _rQueryImage, _rQueryImage, pDatasourceEntry, + true /*ChildrenOnDemand*/, TREELIST_APPEND, pQueriesData ); + } + + // the child for the tables container + { + DBTreeListUserData* pTablesData = new DBTreeListUserData; + pTablesData->eType = etTableContainer; + + m_pTreeView->getListBox().InsertEntry( + _rTableName, _rTableImage, _rTableImage, pDatasourceEntry, + true /*ChildrenOnDemand*/, TREELIST_APPEND, pTablesData ); + } + +} + +void SbaTableQueryBrowser::initializeTreeModel() +{ + if (m_xDatabaseContext.is()) + { + Image 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, + SvTreeListEntry* _pParent, + EntryType _eEntryType) +{ + DBTreeListUserData* pData = static_cast(_pParent->GetUserData()); + 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->getListBox().GetEntryPosByName(rName,_pParent)) + { + DBTreeListUserData* pEntryData = new DBTreeListUserData; + pEntryData->eType = _eEntryType; + if ( _eEntryType == etQuery ) + { + Reference xChild(_xNameAccess->getByName(rName),UNO_QUERY); + if ( xChild.is() ) + pEntryData->eType = etQueryContainer; + } + implAppendEntry( _pParent, rName, pEntryData, pEntryData->eType ); + } + } + } + catch(const Exception&) + { + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::populateTree: could not fill the tree"); + } +} + +SvTreeListEntry* SbaTableQueryBrowser::implAppendEntry( SvTreeListEntry* _pParent, const OUString& _rName, void* _pUserData, EntryType _eEntryType ) +{ + std::unique_ptr< ImageProvider > pImageProvider( getImageProviderFor( _pParent ) ); + + Image aImage; + pImageProvider->getImages( _rName, getDatabaseObjectType( _eEntryType ), aImage ); + + SvTreeListEntry* pNewEntry = m_pTreeView->getListBox().InsertEntry( _rName, _pParent, _eEntryType == etQueryContainer , TREELIST_APPEND, _pUserData ); + + m_pTreeView->getListBox().SetExpandedEntryBmp( pNewEntry, aImage ); + m_pTreeView->getListBox().SetCollapsedEntryBmp( pNewEntry, aImage ); + + return pNewEntry; +} + +IMPL_LINK(SbaTableQueryBrowser, OnExpandEntry, SvTreeListEntry*, _pParent, bool) +{ + if (_pParent->HasChildren()) + // nothing to do... + return true; + + SvTreeListEntry* pFirstParent = m_pTreeView->getListBox().GetRootLevelParent(_pParent); + OSL_ENSURE(pFirstParent,"SbaTableQueryBrowser::OnExpandEntry: No rootlevelparent!"); + + DBTreeListUserData* pData = static_cast< DBTreeListUserData* >(_pParent->GetUserData()); + assert(pData && "SbaTableQueryBrowser::OnExpandEntry: No user data!"); +#if OSL_DEBUG_LEVEL > 0 + SvLBoxString* pString = static_cast(pFirstParent->GetFirstItem(SvLBoxItemType::String)); + OSL_ENSURE(pString,"SbaTableQueryBrowser::OnExpandEntry: No string item!"); +#endif + + if (etTableContainer == pData->eType) + { + weld::WaitObject aWaitCursor(getFrameWeld()); + + // it could be that we already have a connection + SharedConnection xConnection; + ensureConnection( pFirstParent, 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(), _pParent, etTableOrView ); + + Reference xTabSup(xConnection,UNO_QUERY); + if(xTabSup.is()) + { + populateTree( xTabSup->getTables(), _pParent, 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(_pParent)) + { + DBTreeListUserData* pParentData = static_cast< DBTreeListUserData* >( _pParent->GetUserData() ); + Reference< XNameAccess > xCollection( pParentData->xContainer, UNO_QUERY ); + populateTree( xCollection, _pParent, etQuery ); + } + } + return true; +} + +bool SbaTableQueryBrowser::ensureEntryObject( SvTreeListEntry* _pEntry ) +{ + OSL_ENSURE(_pEntry, "SbaTableQueryBrowser::ensureEntryObject: invalid argument!"); + if (!_pEntry) + return false; + + EntryType eType = getEntryType( _pEntry ); + + // the user data of the entry + DBTreeListUserData* pEntryData = static_cast(_pEntry->GetUserData()); + OSL_ENSURE(pEntryData,"ensureEntryObject: user data should already be set!"); + + SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().GetRootLevelParent(_pEntry); + + bool bSuccess = false; + switch (eType) + { + case etQueryContainer: + if ( pEntryData->xContainer.is() ) + { + // nothing to do + bSuccess = true; + break; + } + + { + SvTreeListEntry* pParent = m_pTreeView->getListBox().GetParent(_pEntry); + if ( pParent != pDataSourceEntry ) + { + SvLBoxString* pString = static_cast(_pEntry->GetFirstItem(SvLBoxItemType::String)); + OSL_ENSURE(pString,"There must be a string item!"); + OUString aName(pString->GetText()); + DBTreeListUserData* pData = static_cast(pParent->GetUserData()); + 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( pDataSourceEntry ) ) >>= 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, makeAny(_rDataSourceName)); + if(_rxConnection.is()) + xProp->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( _rxConnection.getTyped() ) ); + + // set this _before_ setting the connection, else the rowset would rebuild it ... + xProp->setPropertyValue(PROPERTY_COMMAND_TYPE, makeAny(_nCommandType)); + xProp->setPropertyValue(PROPERTY_COMMAND, makeAny(_rCommand)); + xProp->setPropertyValue(PROPERTY_ESCAPE_PROCESSING, css::uno::makeAny(_bEscapeProcessing)); + if ( m_bPreview ) + { + xProp->setPropertyValue(PROPERTY_FETCHDIRECTION, makeAny(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)) + { + SvTreeListEntry* pDataSource = nullptr; + SvTreeListEntry* pCommandType = nullptr; + SvTreeListEntry* pCommand = getObjectEntry( _rDataSourceName, _rCommand, _nCommandType, &pDataSource, &pCommandType, true, _rxConnection ); + + if (pCommand) + { + bool bSuccess = true; + if ( _bSelectDirect ) + { + bSuccess = implSelect( pCommand ); + } + else + { + m_pTreeView->getListBox().Select( pCommand ); + } + + if ( bSuccess ) + { + m_pTreeView->getListBox().MakeVisible(pCommand); + m_pTreeView->getListBox().SetCursor(pCommand); + } + } + else if (!pCommandType) + { + if ( m_pCurrentlyDisplayed ) + { // tell the old entry (if any) it has been deselected + selectPath(m_pCurrentlyDisplayed, false); + m_pCurrentlyDisplayed = nullptr; + } + + // 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) +{ + implSelect( m_pTreeView->getListBox().FirstSelected() ); +} + +SvTreeListEntry* SbaTableQueryBrowser::implGetConnectionEntry(SvTreeListEntry* _pEntry) const +{ + SvTreeListEntry* pCurrentEntry = _pEntry; + DBTreeListUserData* pEntryData = static_cast< DBTreeListUserData* >( pCurrentEntry->GetUserData() ); + while(pEntryData->eType != etDatasource ) + { + pCurrentEntry = m_pTreeView->GetTreeModel()->GetParent(pCurrentEntry); + pEntryData = static_cast< DBTreeListUserData* >( pCurrentEntry->GetUserData() ); + } + return pCurrentEntry; +} + +bool SbaTableQueryBrowser::implSelect( SvTreeListEntry* _pEntry ) +{ + if ( !_pEntry ) + return false; + + DBTreeListUserData* pEntryData = static_cast< DBTreeListUserData* >( _pEntry->GetUserData() ); + switch (pEntryData->eType) + { + case etTableOrView: + case etQuery: + break; + default: + // nothing to do + return false; + } + + OSL_ENSURE(m_pTreeView->GetTreeModel()->HasParent(_pEntry), "SbaTableQueryBrowser::implSelect: invalid entry (1)!"); + OSL_ENSURE(m_pTreeView->GetTreeModel()->HasParent(m_pTreeView->GetTreeModel()->GetParent(_pEntry)), "SbaTableQueryBrowser::implSelect: invalid entry (2)!"); + + // get the entry for the tables or queries + SvTreeListEntry* pContainer = m_pTreeView->GetTreeModel()->GetParent(_pEntry); + DBTreeListUserData* pContainerData = static_cast(pContainer->GetUserData()); + + // get the entry for the datasource + SvTreeListEntry* pConnection = implGetConnectionEntry(pContainer); + DBTreeListUserData* pConData = static_cast(pConnection->GetUserData()); + + // 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 + SvLBoxString* pString = static_cast(_pEntry->GetFirstItem(SvLBoxItemType::String)); + OSL_ENSURE(pString,"There must be a string item!"); + const OUString sSimpleName = pString->GetText(); + OUStringBuffer sNameBuffer(sSimpleName); + if ( etQueryContainer == pContainerData->eType ) + { + SvTreeListEntry* pTemp = pContainer; + while( m_pTreeView->GetTreeModel()->GetParent(pTemp) != pConnection ) + { + sNameBuffer.insert(0,'/'); + pString = static_cast(pTemp->GetFirstItem(SvLBoxItemType::String)); + OSL_ENSURE(pString,"There must be a string item!"); + sNameBuffer.insert(0,pString->GetText()); + pTemp = m_pTreeView->GetTreeModel()->GetParent(pTemp); + } + } + 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_pCurrentlyDisplayed, false); + m_pCurrentlyDisplayed = nullptr; + + // not really loaded + m_pCurrentlyDisplayed = _pEntry; + // tell the new entry it has been selected + selectPath(m_pCurrentlyDisplayed); + + // get the name of the data source currently selected + ensureConnection( m_pCurrentlyDisplayed, 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 = static_cast(_pEntry->GetUserData()); + 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( pConnection ) ); + 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; +} + +SvTreeListEntry* SbaTableQueryBrowser::getEntryFromContainer(const Reference& _rxNameAccess) +{ + DBTreeListBox& rListBox = m_pTreeView->getListBox(); + SvTreeListEntry* pContainer = nullptr; + SvTreeListEntry* pDSLoop = rListBox.FirstChild(nullptr); + while (pDSLoop) + { + pContainer = rListBox.GetEntry(pDSLoop, CONTAINER_QUERIES); + DBTreeListUserData* pQueriesData = static_cast(pContainer->GetUserData()); + if ( pQueriesData && pQueriesData->xContainer == _rxNameAccess ) + break; + + pContainer = rListBox.GetEntry(pDSLoop, CONTAINER_TABLES); + DBTreeListUserData* pTablesData = static_cast(pContainer->GetUserData()); + if ( pTablesData && pTablesData->xContainer == _rxNameAccess ) + break; + + pDSLoop = pDSLoop->NextSibling(); + pContainer = nullptr; + } + return pContainer; +} + +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 + + SvTreeListEntry* pEntry = getEntryFromContainer(xNames); + if(pEntry) // found one + { + // insert the new entry into the tree + DBTreeListUserData* pContainerData = static_cast(pEntry->GetUserData()); + 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 (static_cast(m_pTreeView->getListBox().GetChildCount(pEntry)) < ( 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, pEntry, etQuery ); + } + pNewData->eType = etQuery; + } + implAppendEntry( pEntry, ::comphelper::getString( _rEvent.Accessor ), pNewData, pNewData->eType ); + } + else + SbaXDataBrowserController::elementInserted(_rEvent); +} + +bool SbaTableQueryBrowser::isCurrentlyDisplayedChanged(const OUString& _sName, SvTreeListEntry const * _pContainer) +{ + return m_pCurrentlyDisplayed + && getEntryType(m_pCurrentlyDisplayed) == getChildType(_pContainer) + && m_pTreeView->getListBox().GetParent(m_pCurrentlyDisplayed) == _pContainer + && m_pTreeView->getListBox().GetEntryText(m_pCurrentlyDisplayed) == _sName; +} + +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 + SvTreeListEntry* pContainer = getEntryFromContainer(xNames); + if ( pContainer ) + { // a query or table has been removed + OUString aName = ::comphelper::getString(_rEvent.Accessor); + + if ( isCurrentlyDisplayedChanged( aName, pContainer) ) + { // the element displayed currently has been replaced + + // we need to remember the old value + SvTreeListEntry* pTemp = m_pCurrentlyDisplayed; + + // unload + unloadAndCleanup( false ); // don't dispose the connection + + DBTreeListUserData* pData = static_cast(pTemp->GetUserData()); + pTemp->SetUserData(nullptr); + delete pData; + // the data could be null because we have a table which isn't correct + m_pTreeView->GetTreeModel()->Remove(pTemp); + } + else + { + // remove the entry from the model + SvTreeListEntry* pChild = m_pTreeView->GetTreeModel()->FirstChild(pContainer); + while(pChild) + { + if (m_pTreeView->getListBox().GetEntryText(pChild) == aName) + { + DBTreeListUserData* pData = static_cast(pChild->GetUserData()); + pChild->SetUserData(nullptr); + delete pData; + m_pTreeView->GetTreeModel()->Remove(pChild); + break; + } + pChild = pChild->NextSibling(); + } + } + + // 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); + SvTreeListEntry* pContainer = getEntryFromContainer(xNames); + if ( pContainer ) + { // a table or query as been replaced + OUString aName = ::comphelper::getString(_rEvent.Accessor); + + if ( isCurrentlyDisplayedChanged( aName, pContainer) ) + { // the element displayed currently has been replaced + + // we need to remember the old value + SvTreeListEntry* pTemp = m_pCurrentlyDisplayed; + unloadAndCleanup( false ); // don't dispose the connection + + DBTreeListUserData* pData = static_cast(pTemp->GetUserData()); + 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 + { + pTemp->SetUserData(nullptr); + delete pData; + } + } + } + else + { + // find the entry for this name + SvTreeListEntry* pChild = m_pTreeView->GetTreeModel()->FirstChild(pContainer); + while(pChild) + { + if (m_pTreeView->getListBox().GetEntryText(pChild) == aName) + { + DBTreeListUserData* pData = static_cast(pChild->GetUserData()); + 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 + { + pChild->SetUserData(nullptr); + delete pData; + } + } + break; + } + pChild = pChild->NextSibling(); + } + } + + // 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( SvTreeListEntry* _pDSEntry ) +{ + OSL_ENSURE( _pDSEntry, "SbaTableQueryBrowser::disposeConnection: invalid entry (NULL)!" ); + OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::disposeConnection: invalid entry (not top-level)!" ); + + if ( _pDSEntry ) + { + DBTreeListUserData* pTreeListData = static_cast< DBTreeListUserData* >( _pDSEntry->GetUserData() ); + if ( pTreeListData ) + impl_releaseConnection( pTreeListData->xConnection ); + } +} + +void SbaTableQueryBrowser::closeConnection(SvTreeListEntry* _pDSEntry, bool _bDisposeConnection) +{ + OSL_ENSURE(_pDSEntry, "SbaTableQueryBrowser::closeConnection: invalid entry (NULL)!"); + OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::closeConnection: invalid entry (not top-level)!"); + + // if one of the entries of the given DS is displayed currently, unload the form + if (m_pCurrentlyDisplayed && (m_pTreeView->getListBox().GetRootLevelParent(m_pCurrentlyDisplayed) == _pDSEntry)) + unloadAndCleanup(_bDisposeConnection); + + // collapse the query/table container + for (SvTreeListEntry* pContainers = m_pTreeView->GetTreeModel()->FirstChild(_pDSEntry); pContainers; pContainers = pContainers->NextSibling()) + { + SvTreeListEntry* pElements = m_pTreeView->GetTreeModel()->FirstChild(pContainers); + if ( pElements ) + m_pTreeView->getListBox().Collapse(pContainers); + m_pTreeView->getListBox().EnableExpandHandler(pContainers); + // and delete their children (they are connection-relative) + for (; pElements; ) + { + SvTreeListEntry* pRemove = pElements; + pElements = pElements->NextSibling(); + DBTreeListUserData* pData = static_cast(pRemove->GetUserData()); + pRemove->SetUserData(nullptr); + delete pData; + m_pTreeView->GetTreeModel()->Remove(pRemove); + } + } + // collapse the entry itself + m_pTreeView->getListBox().Collapse(_pDSEntry); + + // dispose/reset the connection + if ( _bDisposeConnection ) + disposeConnection( _pDSEntry ); +} + +void SbaTableQueryBrowser::unloadAndCleanup( bool _bDisposeConnection ) +{ + if (!m_pCurrentlyDisplayed) + // nothing to do + return; + + SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent(m_pCurrentlyDisplayed); + + // de-select the path for the currently displayed table/query + if (m_pCurrentlyDisplayed) + { + selectPath(m_pCurrentlyDisplayed, false); + } + m_pCurrentlyDisplayed = nullptr; + + 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( pDSEntry ); + } + 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.get(); + } +} + +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(5); + Sequence< Any> aValues(5); + + OUString* pStringIter = aProperties.getArray(); + Any* pValueIter = aValues.getArray(); + *pStringIter++ = "AlwaysShowCursor"; + *pValueIter++ <<= false; + *pStringIter++ = PROPERTY_BORDER; + *pValueIter++ <<= sal_Int16(0); + + *pStringIter++ = "HasNavigationBar"; + *pValueIter++ <<= false; + *pStringIter++ = "HasRecordMarker"; + *pValueIter++ <<= false; + + *pStringIter++ = "Tabstop"; + *pValueIter++ <<= 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; + + 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 ); + m_pTreeView->getListBox().Expand( m_pTreeView->getListBox().First() ); + } + else + initializeTreeModel(); + + 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,makeAny(aCatalogName)); + xRowSetProps->setPropertyValue(PROPERTY_UPDATE_SCHEMANAME,makeAny(aSchemaName)); + xRowSetProps->setPropertyValue(PROPERTY_UPDATE_TABLENAME,makeAny(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(SvTreeListEntry* _pAnyEntry, SharedConnection& _rConnection) +{ + SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent(_pAnyEntry); + DBTreeListUserData* pDSData = + pDSEntry + ? static_cast(pDSEntry->GetUserData()) + : nullptr; + + return ensureConnection( pDSEntry, pDSData, _rConnection ); +} + +std::unique_ptr< ImageProvider > SbaTableQueryBrowser::getImageProviderFor( SvTreeListEntry* _pAnyEntry ) +{ + std::unique_ptr< ImageProvider > pImageProvider( new ImageProvider ); + SharedConnection xConnection; + if ( getExistentConnectionFor( _pAnyEntry, xConnection ) ) + pImageProvider.reset( new ImageProvider( xConnection ) ); + return pImageProvider; +} + +bool SbaTableQueryBrowser::getExistentConnectionFor( SvTreeListEntry* _pAnyEntry, SharedConnection& _rConnection ) +{ + SvTreeListEntry* pDSEntry = m_pTreeView->getListBox().GetRootLevelParent( _pAnyEntry ); + DBTreeListUserData* pDSData = + pDSEntry + ? static_cast< DBTreeListUserData* >( pDSEntry->GetUserData() ) + : nullptr; + if ( pDSData ) + _rConnection = pDSData->xConnection; + return _rConnection.is(); +} + +bool SbaTableQueryBrowser::impl_isDataSourceEntry( SvTreeListEntry* _pEntry ) const +{ + return m_pTreeView->GetTreeModel()->GetRootLevelParent( _pEntry ) == _pEntry; +} + +bool SbaTableQueryBrowser::ensureConnection( SvTreeListEntry* _pDSEntry, void* pDSData, SharedConnection& _rConnection ) +{ + OSL_ENSURE( impl_isDataSourceEntry( _pDSEntry ), "SbaTableQueryBrowser::ensureConnection: this entry does not denote a data source!" ); + if(_pDSEntry) + { + DBTreeListUserData* pTreeListData = static_cast(pDSData); + OUString aDSName = GetEntryText(_pDSEntry); + + 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(); +} + +IMPL_LINK( SbaTableQueryBrowser, OnTreeEntryCompare, const SvSortData&, _rSortData, sal_Int32 ) +{ + const SvTreeListEntry* pLHS = _rSortData.pLeft; + const SvTreeListEntry* pRHS = _rSortData.pRight; + OSL_ENSURE(pLHS && pRHS, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid tree entries!"); + // we want the table entry and the end so we have to do a check + + if (isContainer(pRHS)) + { + // don't use getEntryType (directly or indirecly) for the LHS: + // LHS is currently being inserted, so it is not "completely valid" at the moment + + const EntryType eRight = getEntryType(pRHS); + if (etTableContainer == eRight) + // every other container should be placed _before_ the bookmark container + return -1; + + const OUString sLeft = m_pTreeView->getListBox().GetEntryText(const_cast(pLHS)); + + 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; + } + + const SvLBoxString* pLeftTextItem = static_cast(pLHS->GetFirstItem(SvLBoxItemType::String)); + const SvLBoxString* pRightTextItem = static_cast(pRHS->GetFirstItem(SvLBoxItemType::String)); + OSL_ENSURE(pLeftTextItem && pRightTextItem, "SbaTableQueryBrowser::OnTreeEntryCompare: invalid text items!"); + + OUString sLeftText = pLeftTextItem->GetText(); + OUString sRightText = pRightTextItem->GetText(); + + 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( SvTreeListEntry* _pApplyTo ) +{ + OSL_PRECOND( _pApplyTo, "SbaTableQueryBrowser::implAdministrate: illegal entry!" ); + if ( !_pApplyTo ) + return; + + try + { + // get the desktop object + Reference< XDesktop2 > xFrameLoader = Desktop::create( getORB() ); + + // the initial selection + SvTreeListEntry* pTopLevelSelected = _pApplyTo; + while (pTopLevelSelected && m_pTreeView->getListBox().GetParent(pTopLevelSelected)) + pTopLevelSelected = m_pTreeView->getListBox().GetParent(pTopLevelSelected); + OUString sInitialSelection; + if (pTopLevelSelected) + sInitialSelection = getDataSourceAccessor( pTopLevelSelected ); + + 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 SvTreeListEntry* _pEntry, OUString& _rText ) const +{ + const DBTreeListUserData* pData = static_cast< const DBTreeListUserData* >( _pEntry->GetUserData() ); + if ( ( pData->eType == etDatasource ) && !pData->sAccessor.isEmpty() ) + { + _rText = ::svt::OFileNotation( pData->sAccessor ).get( ::svt::OFileNotation::N_SYSTEM ); + return true; + } + return false; +} + +OUString SbaTableQueryBrowser::getContextMenuResourceName( Control& _rControl ) const +{ + OSL_PRECOND( &m_pTreeView->getListBox() == &_rControl, + "SbaTableQueryBrowser::getContextMenuResourceName: where does this come from?" ); + if ( &m_pTreeView->getListBox() != &_rControl ) + return OUString(); + + return "explorer"; +} + +IController& SbaTableQueryBrowser::getCommandController() +{ + return *this; +} + +::comphelper::OInterfaceContainerHelper2* SbaTableQueryBrowser::getContextMenuInterceptors() +{ + return &m_aContextMenuInterceptors; +} + +Any SbaTableQueryBrowser::getCurrentSelection( Control& _rControl ) const +{ + OSL_PRECOND( &m_pTreeView->getListBox() == &_rControl, + "SbaTableQueryBrowser::getCurrentSelection: where does this come from?" ); + + if ( &m_pTreeView->getListBox() != &_rControl ) + return Any(); + + SvTreeListEntry* pSelected = m_pTreeView->getListBox().FirstSelected(); + if ( !pSelected ) + return Any(); + + OSL_ENSURE( m_pTreeView->getListBox().NextSelected( pSelected ) == nullptr, + "SbaTableQueryBrowser::getCurrentSelection: single-selection is expected here!" ); + + NamedDatabaseObject aSelectedObject; + DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( pSelected->GetUserData() ); + aSelectedObject.Type = static_cast< sal_Int32 >( pData->eType ); + + switch ( aSelectedObject.Type ) + { + case DatabaseObject::QUERY: + case DatabaseObject::TABLE: + aSelectedObject.Name = m_pTreeView->getListBox().GetEntryText( pSelected ); + break; + + case DatabaseObjectContainer::DATA_SOURCE: + case DatabaseObjectContainer::QUERIES: + case DatabaseObjectContainer::TABLES: + aSelectedObject.Name = getDataSourceAccessor( pSelected ); + break; + + default: + SAL_WARN("dbaccess.ui", "SbaTableQueryBrowser::getCurrentSelection: invalid (unexpected) object type!" ); + break; + } + + return makeAny( aSelectedObject ); +} + +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_pCurrentlyDisplayed ) + { + SvTreeListEntry* pContainer = m_pTreeView->GetTreeModel()->GetParent(m_pCurrentlyDisplayed); + // get the entry for the datasource + SvTreeListEntry* pConnection = implGetConnectionEntry(pContainer); + OUString sName = m_pTreeView->getListBox().GetEntryText(m_pCurrentlyDisplayed); + sTitle = GetEntryText( pConnection ); + 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_pCurrentlyDisplayed ) + { + // 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) ) + { + SvTreeListEntry* pDataSource = nullptr; + SvTreeListEntry* pCommandType = nullptr; + m_pCurrentlyDisplayed = getObjectEntry( sDataSource, sCommand, nCommandType, &pDataSource, &pCommandType ); + 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( const OUString& _rDataSourceName ) +{ + // get the top-level representing the removed data source + SvTreeListEntry* pDataSourceEntry = m_pTreeView->getListBox().FirstChild( nullptr ); + while ( pDataSourceEntry ) + { + if ( m_pTreeView->getListBox().GetEntryText( pDataSourceEntry ) == _rDataSourceName ) + break; + + pDataSourceEntry = pDataSourceEntry->NextSibling(); + } + + OSL_ENSURE( pDataSourceEntry, "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: do not know this data source!" ); + if ( !pDataSourceEntry ) + return; + + if ( isSelected( pDataSourceEntry ) ) + { // a table or query belonging to the deleted data source is currently being displayed. + OSL_ENSURE( m_pTreeView->getListBox().GetRootLevelParent( m_pCurrentlyDisplayed ) == pDataSourceEntry, + "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: inconsistence (1)!" ); + unloadAndCleanup(); + } + else + OSL_ENSURE( + ( nullptr == m_pCurrentlyDisplayed ) + || ( m_pTreeView->getListBox().GetRootLevelParent( m_pCurrentlyDisplayed ) != pDataSourceEntry ), + "SbaTableQueryBrowser::impl_cleanupDataSourceEntry: inconsistence (2)!"); + + // delete any user data of the child entries of the to-be-removed entry + std::pair aIters = + m_pTreeView->GetTreeModel()->GetChildIterators(pDataSourceEntry); + + SvTreeListEntries::const_iterator it = aIters.first, itEnd = aIters.second; + + for (; it != itEnd; ++it) + { + SvTreeListEntry* pEntry = (*it).get(); + const DBTreeListUserData* pData = static_cast(pEntry->GetUserData()); + pEntry->SetUserData(nullptr); + delete pData; + } + + // remove the entry + DBTreeListUserData* pData = static_cast< DBTreeListUserData* >( pDataSourceEntry->GetUserData() ); + pDataSourceEntry->SetUserData( nullptr ); + delete pData; + m_pTreeView->GetTreeModel()->Remove( pDataSourceEntry ); +} + +void SAL_CALL SbaTableQueryBrowser::revokedDatabaseLocation( const DatabaseRegistrationEvent& Event ) +{ + SolarMutexGuard aGuard; + + impl_cleanupDataSourceEntry( Event.Name ); + + // maybe the object which is part of the document data source has been removed + checkDocumentDataSource(); +} + +void SAL_CALL SbaTableQueryBrowser::changedDatabaseLocation( const DatabaseRegistrationEvent& Event ) +{ + SolarMutexGuard aGuard; + + // in case the data source was expanded, and connected, we need to clean it up + // for simplicity, just do as if the data source were completely removed and re-added + impl_cleanupDataSourceEntry( Event.Name ); + implAddDatasource( Event.Name, SharedConnection() ); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/ColumnControlWindow.cxx b/dbaccess/source/ui/control/ColumnControlWindow.cxx new file mode 100644 index 000000000..28a77291c --- /dev/null +++ b/dbaccess/source/ui/control/ColumnControlWindow.cxx @@ -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 . + */ + +#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; + +// OColumnControlWindow +OColumnControlWindow::OColumnControlWindow(vcl::Window* pParent + ,const Reference& _rxContext) + : OFieldDescControl(nullptr, 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(long /*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 && _nPos < static_cast(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 000000000..866014a99 --- /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, + const char* pHelpId, + short nPosition) + : OSQLNameEntry(std::move(xEntry), _rAllowedChars) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +OPropEditCtrl::OPropEditCtrl(std::unique_ptr xEntry, const char* 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, const char* 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, const char* pHelpId, short nPosition) + : OWidgetBase(xComboBox.get()) + , m_xComboBox(std::move(xComboBox)) + , m_nPos(nPosition) +{ + m_strHelpText = DBA_RES(pHelpId); +} + +} // end namespace dbaui diff --git a/dbaccess/source/ui/control/FieldDescControl.cxx b/dbaccess/source/ui/control/FieldDescControl.cxx new file mode 100644 index 000000000..c7bb190ab --- /dev/null +++ b/dbaccess/source/ui/control/FieldDescControl.cxx @@ -0,0 +1,1391 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 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, vcl::Window* pParent, OTableDesignHelpBar* pHelpBar) + :TabPage(pPage ? Application::GetDefDialogParent() : pParent, WB_3DLOOK | WB_DIALOGCONTROL) + ,pHelp( pHelpBar ) + ,m_pLastFocusWindow(nullptr) + ,m_pActFocusWindow(nullptr) + ,m_pPreviousType() + ,m_nPos(-1) + ,aYes(DBA_RES(STR_VALUE_YES)) + ,aNo(DBA_RES(STR_VALUE_NO)) + ,m_nEditWidth(50) + ,m_bAdded(false) + ,pActFieldDescr(nullptr) +{ + if (pPage) + m_xBuilder.reset(Application::CreateBuilder(pPage, "dbaccess/ui/fielddescpage.ui")); + else + { + m_xVclContentArea = VclPtr::Create(this); + m_xVclContentArea->Show(); + m_xBuilder.reset(Application::CreateInterimBuilder(m_xVclContentArea, "dbaccess/ui/fielddescpage.ui")); + + m_aLayoutIdle.SetPriority(TaskPriority::RESIZE); + m_aLayoutIdle.SetInvokeHandler( LINK( this, OFieldDescControl, ImplHandleLayoutTimerHdl ) ); + m_aLayoutIdle.SetDebugName( "OFieldDescControl m_aLayoutIdle" ); + } + + m_xContainer = m_xBuilder->weld_container("FieldDescPage"); +} + +void OFieldDescControl::queue_resize(StateChangedType eReason) +{ + TabPage::queue_resize(eReason); + if (!m_xVclContentArea) + return; + if (m_aLayoutIdle.IsActive()) + return; + m_aLayoutIdle.Start(); +} + +void OFieldDescControl::Resize() +{ + TabPage::Resize(); + if (!m_xVclContentArea) + return; + queue_resize(); +} + +IMPL_LINK_NOARG(OFieldDescControl, ImplHandleLayoutTimerHdl, Timer*, void) +{ + m_xVclContentArea->SetPosSizePixel(Point(0,0), GetSizePixel()); +} + +OFieldDescControl::~OFieldDescControl() +{ + disposeOnce(); +} + +void OFieldDescControl::dispose() +{ + m_aLayoutIdle.Stop(); + + if ( m_bAdded ) + ::dbaui::notifySystemWindow(this,this,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); + + // 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 ); + pHelp.clear(); + 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(); + m_xVclContentArea.disposeAndClear(); + TabPage::dispose(); +} + +OUString OFieldDescControl::BoolStringPersistent(const OUString& rUIString) const +{ + if (rUIString == aNo) + return OUString('0'); + if (rUIString == aYes) + return OUString('1'); + return OUString(); +} + +OUString OFieldDescControl::BoolStringUI(const OUString& rPersistentString) const +{ + // Older versions may store a language dependent string as a default + if (rPersistentString == aYes || rPersistentString == aNo) + return rPersistentString; + + if (rPersistentString == "0") + return aNo; + if (rPersistentString == "1") + return aYes; + + return DBA_RES(STR_VALUE_NONE); +} + +void OFieldDescControl::Init() +{ + Reference< css::util::XNumberFormatter > xFormatter = GetFormatter(); + ::dbaui::setEvalDateFormatForFormatter(xFormatter); +} + +void OFieldDescControl::SetReadOnly( bool bReadOnly ) +{ + // Enable/disable Controls + OWidgetBase* ppAggregates[] = { m_xRequired.get(), m_xNumType.get() + , m_xAutoIncrement.get(), m_xDefault.get() + , m_xTextLen.get(), m_xLength.get() + , m_xScale.get(), m_xColumnName.get() + , m_xType.get(), m_xAutoIncrementValue.get() + }; + weld::Widget* ppAggregatesText[] = { m_xRequiredText.get(), m_xNumTypeText.get() + , m_xAutoIncrementText.get(), m_xDefaultText.get() + , m_xTextLenText.get(), m_xLengthText.get() + , m_xScaleText.get(), m_xColumnNameText.get() + , m_xTypeText.get(), m_xAutoIncrementValueText.get() + }; + + OSL_ENSURE(SAL_N_ELEMENTS(ppAggregates) == SAL_N_ELEMENTS(ppAggregatesText),"Lists are not identical!"); + + for (size_t i=0; iset_sensitive( !bReadOnly ); + if ( ppAggregates[i] ) + ppAggregates[i]->set_sensitive( !bReadOnly ); + } + + if (m_xFormat) + { + assert(m_xFormatText); + m_xFormat->set_sensitive(!bReadOnly); + m_xFormatText->set_sensitive(!bReadOnly); + } +} + +void OFieldDescControl::SetControlText( sal_uInt16 nControlId, const OUString& rText ) +{ + // Set the Controls' texts + switch( nControlId ) + { + case FIELD_PROPERTY_BOOL_DEFAULT: + if (m_xBoolDefault) + { + OUString sOld = m_xBoolDefault->get_active_text(); + m_xBoolDefault->set_active_text(rText); + if (sOld != rText) + ChangeHdl(m_xBoolDefault->GetComboBox()); + } + break; + case FIELD_PROPERTY_DEFAULT: + if (m_xDefault) + { + m_xDefault->set_text(rText); + UpdateFormatSample(pActFieldDescr); + } + break; + + case FIELD_PROPERTY_REQUIRED: + if (m_xRequired) + m_xRequired->set_active_text(rText); + break; + + case FIELD_PROPERTY_TEXTLEN: + if (m_xTextLen) + m_xTextLen->set_text(rText); + break; + + case FIELD_PROPERTY_NUMTYPE: + if (m_xNumType) + m_xNumType->set_active_text(rText); + break; + + case FIELD_PROPERTY_AUTOINC: + if (m_xAutoIncrement) + { + OUString sOld = m_xAutoIncrement->get_active_text(); + m_xAutoIncrement->set_active_text(rText); + if (sOld != rText) + ChangeHdl(m_xAutoIncrement->GetComboBox()); + } + break; + + case FIELD_PROPERTY_LENGTH: + if (m_xLength) + m_xLength->set_text(rText); + break; + + case FIELD_PROPERTY_SCALE: + if (m_xScale) + m_xScale->set_text(rText); + break; + + case FIELD_PROPERTY_FORMAT: + if (pActFieldDescr) + UpdateFormatSample(pActFieldDescr); + break; + case FIELD_PROPERTY_COLUMNNAME: + if (m_xColumnName) + m_xColumnName->set_text(rText); + break; + case FIELD_PROPERTY_TYPE: + if (m_xType) + m_xType->set_active_text(rText); + break; + case FIELD_PROPERTY_AUTOINCREMENT: + if (m_xAutoIncrementValue) + m_xAutoIncrementValue->set_text(rText); + break; + } +} + +IMPL_LINK_NOARG(OFieldDescControl, FormatClickHdl, weld::Button&, void) +{ + // Create temporary Column, which is used for data exchange with Dialog + if( !pActFieldDescr ) + return; + + sal_Int32 nOldFormatKey(pActFieldDescr->GetFormatKey()); + SvxCellHorJustify rOldJustify = pActFieldDescr->GetHorJustify(); + Reference< XNumberFormatsSupplier > xSupplier = GetFormatter()->getNumberFormatsSupplier(); + SvNumberFormatsSupplierObj* pSupplierImpl = comphelper::getUnoTunnelImplementation( xSupplier ); + if (!pSupplierImpl) + return; + + SvNumberFormatter* pFormatter = pSupplierImpl->GetNumberFormatter(); + if(!::dbaui::callColumnFormatDialog(this,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; + } + + queue_resize(); +} + +void OFieldDescControl::InitializeControl(OPropListBoxCtrl* _pControl,const OString& _sHelpId,bool _bAddChangeHandler) +{ + if ( _bAddChangeHandler ) + _pControl->GetComboBox().connect_changed(LINK(this,OFieldDescControl,ChangeHdl)); + + InitializeControl(_pControl->GetWidget(), _sHelpId); +} + +void OFieldDescControl::InitializeControl(weld::Widget* pControl,const OString& _sHelpId) +{ + pControl->set_help_id(_sHelpId); + pControl->connect_focus_in(LINK(this, OFieldDescControl, OnControlFocusGot)); + pControl->connect_focus_out(LINK(this, OFieldDescControl, OnControlFocusLost)); + + if (dynamic_cast(pControl)) + { + int nWidthRequest = LogicToPixel(Size(m_nEditWidth, 0), MapMode(MapUnit::MapAppFont)).Width(); + pControl->set_size_request(nWidthRequest, -1); + } +} + +std::unique_ptr OFieldDescControl::CreateNumericControl(const OString& rId, const char* pHelpId, short _nProperty, const OString& _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; + } + + queue_resize(); +} + +void OFieldDescControl::DisplayData(OFieldDescription* pFieldDescr ) +{ + pActFieldDescr = pFieldDescr; + if(!pFieldDescr) + { + 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; + if ( m_bAdded ) + { + ::dbaui::notifySystemWindow(this,this,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); + m_bAdded = false; + } + return; + } + + if ( !m_bAdded ) + { + ::dbaui::notifySystemWindow(this,this,::comphelper::mem_fun(&TaskPaneList::AddWindow)); + m_bAdded = true; + } + + TOTypeInfoSP pFieldType(pFieldDescr->getTypeInfo()); + + ActivateAggregate( tpColumnName ); + ActivateAggregate( tpType ); + + OSL_ENSURE(pFieldType.get(),"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(makeAny(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() && (pHelp != nullptr)) + pHelp->SetHelpText(strHelpText); + + m_pActFocusWindow = &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) + { + sDefault = m_xDefault->get_text(); + } + else if (m_xBoolDefault) + { + sDefault = BoolStringPersistent(m_xBoolDefault->get_active_text()); + } + + if ( !sDefault.isEmpty() ) + pFieldDescr->SetControlDefault(makeAny(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::GetFocus() +{ + // Set the Focus to the Control that has been active last + TabPage::GetFocus(); + 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 (pHelp && !pHelp->HasChildPathFocus()) + pHelp->SetHelpText( OUString() ); +} + +void OFieldDescControl::LoseFocus() +{ + implFocusLost(nullptr); + + TabPage::LoseFocus(); +} + +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::isCopyAllowed() const +{ + int nStartPos, nEndPos; + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() && + dynamic_cast(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos); + return bAllowed; +} + +bool OFieldDescControl::isCutAllowed() const +{ + int nStartPos, nEndPos; + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget() && + dynamic_cast(*m_pActFocusWindow).get_selection_bounds(nStartPos, nEndPos); + return bAllowed; +} + +bool OFieldDescControl::isPasteAllowed() const +{ + bool bAllowed = (m_pActFocusWindow != nullptr) && IsFocusInEditableWidget(); + if ( bAllowed ) + { + TransferableDataHelper aTransferData(TransferableDataHelper::CreateFromSystemClipboard(GetParent())); + 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 ) + { + sal_uInt32 nFormatKey; + + try + { + double nValue = 0.0; + 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; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/RelationControl.cxx b/dbaccess/source/ui/control/RelationControl.cxx new file mode 100644 index 000000000..69f0a00ca --- /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; + 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, long nRow, sal_uInt16 nCol ) override; + virtual ::svt::CellController* GetController( long nRow, sal_uInt16 nCol ) override; + virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override; + virtual bool SeekRow( long nRow ) override; + virtual bool SaveModified() override; + virtual OUString GetCellText( long 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(); + long nOutputWidth = GetOutputSizePixel().Width() - 1; + SetColumnWidth(1, (nOutputWidth / 2)); + SetColumnWidth(2, (nOutputWidth / 2)); + } + + bool ORelationControl::PreNotify(NotifyEvent& rNEvt) + { + if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS && !HasChildPathFocus() && !ControlHasFocus()) + PostUserEvent(LINK(this, ORelationControl, AsynchDeactivate), nullptr, true); + else if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + PostUserEvent(LINK(this, ORelationControl, AsynchActivate), nullptr, true); + + return EditBrowseBox::PreNotify(rNEvt); + } + + IMPL_LINK_NOARG(ORelationControl, AsynchActivate, void*, void) + { + ActivateCell(); + } + + IMPL_LINK_NOARG(ORelationControl, AsynchDeactivate, void*, void) + { + DeactivateCell(); + } + + bool ORelationControl::IsTabAllowed(bool bForward) const + { + long 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() + { + long 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( long 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*/, long nRow, sal_uInt16 nColumnId ) + { + + OString sHelpId( HID_RELATIONDIALOG_LEFTFIELDCELL ); + + Reference< XPropertySet> xDef; + switch ( getColumnIdent(nColumnId) ) + { + case SOURCE_COLUMN: + xDef = m_xSourceDef; + sHelpId = HID_RELATIONDIALOG_LEFTFIELDCELL; + break; + case DEST_COLUMN: + xDef = m_xDestDef; + sHelpId = HID_RELATIONDIALOG_RIGHTFIELDCELL; + break; + default: + // ????????? + break; + } + + if ( !xDef.is() ) + return; + + fillListBox(xDef); + OUString sName = GetCellText( nRow, nColumnId ); + weld::ComboBox& rList = m_pListCell->get_widget(); + rList.set_active_text(sName); + if (rList.get_active_text() != sName) + { + rList.append_text(sName); + rList.set_active_text(sName); + } + + rList.set_help_id(sHelpId); + } + + CellController* ORelationControl::GetController( long /*nRow*/, sal_uInt16 /*nColumnId*/ ) + { + return new ListBoxCellController( m_pListCell.get() ); + } + + bool ORelationControl::SeekRow( long 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/ScrollHelper.cxx b/dbaccess/source/ui/control/ScrollHelper.cxx new file mode 100644 index 000000000..a9fcacca9 --- /dev/null +++ b/dbaccess/source/ui/control/ScrollHelper.cxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#define LISTBOX_SCROLLING_AREA 12 +namespace dbaui +{ + + OScrollHelper::OScrollHelper() + { + } + OScrollHelper::~OScrollHelper() + { + + } + void OScrollHelper::scroll(const Point& _rPoint, const Size& _rOutputSize) + { + // Scrolling Areas + tools::Rectangle aScrollArea( Point(0, _rOutputSize.Height() - LISTBOX_SCROLLING_AREA), + Size(_rOutputSize.Width(), LISTBOX_SCROLLING_AREA) ); + + // if pointer in bottom area begin scroll + if( aScrollArea.IsInside(_rPoint) ) + m_aUpScroll.Call(nullptr); + else + { + aScrollArea.SetPos(Point(0,0)); + // if pointer in top area begin scroll + if( aScrollArea.IsInside(_rPoint) ) + m_aDownScroll.Call(nullptr); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/SqlNameEdit.cxx b/dbaccess/source/ui/control/SqlNameEdit.cxx new file mode 100644 index 000000000..c24e9fd3c --- /dev/null +++ b/dbaccess/source/ui/control/SqlNameEdit.cxx @@ -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 . + */ + +#include + +namespace dbaui +{ + static bool isCharOk(sal_Unicode _cChar,bool _bFirstChar, const OUString& _sAllowedChars) + { + return ( + (_cChar >= 'A' && _cChar <= 'Z') || + _cChar == '_' || + _sAllowedChars.indexOf(_cChar) != -1 || + (!_bFirstChar && (_cChar >= '0' && _cChar <= '9')) || + (_cChar >= 'a' && _cChar <= 'z') + ); + } + bool OSQLNameChecker::checkString(const OUString& _sToCheck, + OUString& _rsCorrected) + { + bool bCorrected = false; + if ( m_bCheck ) + { + sal_Int32 nMatch = 0; + for (sal_Int32 i = nMatch; i < _sToCheck.getLength(); ++i) + { + if ( !isCharOk( _sToCheck[i], i == 0, m_sAllowedChars ) ) + { + _rsCorrected += _sToCheck.copy(nMatch, i - nMatch); + bCorrected = true; + nMatch = i + 1; + } + } + _rsCorrected += _sToCheck.copy( nMatch ); + } + return bCorrected; + } + void OSQLNameEdit::Modify() + { + OUString sCorrected; + if ( checkString( GetText(),sCorrected ) ) + { + Selection aSel = GetSelection(); + aSel.setMax( aSel.getMin() ); + SetText( sCorrected, aSel ); + + SaveValue(); + } + Edit::Modify(); + } + + IMPL_LINK_NOARG(OSQLNameEntry, ModifyHdl, weld::Entry&, void) + { + OUString sCorrected; + if (checkString(m_xEntry->get_text(), sCorrected)) + { + int nStartPos, nEndPos; + m_xEntry->get_selection_bounds(nStartPos, nEndPos); + int nMin = std::min(nStartPos, nEndPos); + m_xEntry->set_text(sCorrected); + m_xEntry->select_region(nMin, nMin); + + m_xEntry->save_value(); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/TableGrantCtrl.cxx b/dbaccess/source/ui/control/TableGrantCtrl.cxx new file mode 100644 index 000000000..373340afd --- /dev/null +++ b/dbaccess/source/ui/control/TableGrantCtrl.cxx @@ -0,0 +1,461 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 ::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->GetBox().EnableTriState(false); + + m_pEdit = VclPtr::Create( &GetDataWindow() ); + m_pEdit->SetReadOnly(); + m_pEdit->Enable(false); + } + + UpdateTables(); + // set browser mode + BrowserMode const nMode = BrowserMode::COLUMNSELECTION | BrowserMode::HLINES | BrowserMode::VLINES | + BrowserMode::HIDECURSOR | BrowserMode::HIDESELECT; + + SetMode(nMode); +} + +bool OTableGrantControl::PreNotify(NotifyEvent& rNEvt) +{ + if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS) + if (!HasChildPathFocus()) + { + if (m_nDeactivateEvent) + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchDeactivate), nullptr, true); + } + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if (m_nDeactivateEvent) + Application::RemoveUserEvent(m_nDeactivateEvent); + m_nDeactivateEvent = Application::PostUserEvent(LINK(this, OTableGrantControl, AsynchActivate), nullptr, true); + } + return EditBrowseBox::PreNotify(rNEvt); +} + +IMPL_LINK_NOARG(OTableGrantControl, AsynchActivate, void*, void) +{ + m_nDeactivateEvent = nullptr; + ActivateCell(); +} + +IMPL_LINK_NOARG(OTableGrantControl, AsynchDeactivate, void*, void) +{ + m_nDeactivateEvent = nullptr; + DeactivateCell(); +} + +bool OTableGrantControl::IsTabAllowed(bool bForward) const +{ + long 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); +} + +#define GRANT_REVOKE_RIGHT(what) \ + if(m_pCheckCell->GetBox().IsChecked()) \ + xAuth->grantPrivileges(sTableName,PrivilegeObject::TABLE,what);\ + else \ + xAuth->revokePrivileges(sTableName,PrivilegeObject::TABLE,what) + +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: + GRANT_REVOKE_RIGHT(Privilege::INSERT); + break; + case COL_DELETE: + GRANT_REVOKE_RIGHT(Privilege::DELETE); + break; + case COL_UPDATE: + GRANT_REVOKE_RIGHT(Privilege::UPDATE); + break; + case COL_ALTER: + GRANT_REVOKE_RIGHT(Privilege::ALTER); + break; + case COL_SELECT: + GRANT_REVOKE_RIGHT(Privilege::SELECT); + break; + case COL_REF: + GRANT_REVOKE_RIGHT(Privilege::REFERENCE); + break; + case COL_DROP: + GRANT_REVOKE_RIGHT(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()->ClearModified(); + if(!bErg) + UpdateTables(); + + return bErg; +} + +OUString OTableGrantControl::GetCellText( long 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*/, long nRow, sal_uInt16 nColumnId ) +{ + OUString sTablename = m_aTableNames[nRow]; + // special case for tablename + if(nColumnId == COL_TABLE_NAME) + m_pEdit->SetText(sTablename); + else + { + // get the privileges from the user + TTablePrivilegeMap::const_iterator aFind = findPrivilege(nRow); + m_pCheckCell->GetBox().Check(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( long 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( long 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/VertSplitView.cxx b/dbaccess/source/ui/control/VertSplitView.cxx new file mode 100644 index 000000000..35616d330 --- /dev/null +++ b/dbaccess/source/ui/control/VertSplitView.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 + +#include +#include +#include +#include + +#define SPLITTER_WIDTH 80 + +using namespace ::dbaui; + +OSplitterView::OSplitterView(vcl::Window* _pParent) : Window(_pParent,WB_DIALOGCONTROL) // ,WB_BORDER + ,m_pSplitter( nullptr ) + ,m_pLeft(nullptr) + ,m_pRight(nullptr) + ,m_pResizeId(nullptr) +{ + ImplInitSettings(); +} + +OSplitterView::~OSplitterView() +{ + disposeOnce(); +} + +void OSplitterView::dispose() +{ + if (m_pResizeId) + { + RemoveUserEvent(m_pResizeId); + m_pResizeId = nullptr; + } + m_pSplitter.clear(); + m_pLeft.clear(); + m_pRight.clear(); + vcl::Window::dispose(); +} + +IMPL_LINK_NOARG( OSplitterView, SplitHdl, Splitter*, void ) +{ + OSL_ENSURE(m_pSplitter, "Splitter is NULL!"); + m_pSplitter->SetPosPixel( Point( m_pSplitter->GetPosPixel().X(),m_pSplitter->GetSplitPosPixel() ) ); + + Resize(); +} + +void OSplitterView::ImplInitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + vcl::Font aFont = rStyleSettings.GetAppFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetPointFont(*this, aFont); +// Set/*Zoomed*/PointFont( aFont ); + + Color aTextColor = rStyleSettings.GetButtonTextColor(); + if ( IsControlForeground() ) + aTextColor = GetControlForeground(); + SetTextColor( aTextColor ); + + if( IsControlBackground() ) + SetBackground( GetControlBackground() ); + else + SetBackground( rStyleSettings.GetFaceColor() ); +} + +void OSplitterView::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +void OSplitterView::GetFocus() +{ + Window::GetFocus(); + + // forward the focus to the current cell of the editor control + if ( m_pLeft ) + m_pLeft->GrabFocus(); + else if ( m_pRight ) + m_pRight->GrabFocus(); +} + +IMPL_LINK_NOARG(OSplitterView, ResizeHdl, void*, void) +{ + m_pResizeId = nullptr; + + OSL_ENSURE( m_pRight, "No init called!"); + + Point aSplitPos; + Size aSplitSize; + Point aPlaygroundPos( 0,0 ); + Size aPlaygroundSize( GetOutputSizePixel() ); + + if ( m_pLeft && m_pLeft->IsVisible() && m_pSplitter ) + { + aSplitPos = m_pSplitter->GetPosPixel(); + aSplitSize = m_pSplitter->GetOutputSizePixel(); + aSplitPos.setX( aPlaygroundPos.X() ); + aSplitSize.setWidth( aPlaygroundSize.Width() ); + + 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.3) ); + + // the tree pos and size + Point aTreeViewPos( aPlaygroundPos ); + Size aTreeViewSize( aPlaygroundSize.Width() ,aSplitPos.Y()); + + // set the size of treelistbox + m_pLeft->SetPosSizePixel( aTreeViewPos, aTreeViewSize ); + + //set the size of the splitter + m_pSplitter->SetPosSizePixel( aSplitPos, Size( aPlaygroundSize.Width(), aSplitSize.Height() ) ); + m_pSplitter->SetDragRectPixel( tools::Rectangle(aPlaygroundPos,aPlaygroundSize) ); + } + + if ( m_pRight ) + { + m_pRight->setPosSizePixel( aSplitPos.X(), aPlaygroundPos.Y() + aSplitPos.Y() + aSplitSize.Height(), + aPlaygroundSize.Width() , aPlaygroundSize.Height() - aSplitSize.Height() - aSplitPos.Y()); + } +} + +void OSplitterView::Resize() +{ + Window::Resize(); + if (m_pResizeId) + RemoveUserEvent(m_pResizeId); + m_pResizeId = PostUserEvent(LINK(this, OSplitterView, ResizeHdl), this, true); +} + +void OSplitterView::set(vcl::Window* _pRight,Window* _pLeft) +{ + m_pLeft = _pLeft; + m_pRight = _pRight; +} + +void OSplitterView::setSplitter(Splitter* _pSplitter) +{ + m_pSplitter = _pSplitter; + if ( m_pSplitter ) + { + m_pSplitter->SetSplitPosPixel(LogicToPixel(Size(SPLITTER_WIDTH, 0), MapMode(MapUnit::MapAppFont)).Width()); + m_pSplitter->SetSplitHdl( LINK(this, OSplitterView, SplitHdl) ); + m_pSplitter->Show(); + LINK( this, OSplitterView, SplitHdl ).Call(m_pSplitter); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/charsetlistbox.cxx b/dbaccess/source/ui/control/charsetlistbox.cxx new file mode 100644 index 000000000..8915b65c9 --- /dev/null +++ b/dbaccess/source/ui/control/charsetlistbox.cxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#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( const OUString& _rIanaName ) + { + OCharsetDisplay::const_iterator aFind = m_aCharSets.findIanaName( _rIanaName ); + if (aFind == m_aCharSets.end()) + { + OSL_FAIL( "CharSetListBox::SelectEntryByIanaName: unknown charset falling back to system language!" ); + aFind = m_aCharSets.findEncoding( RTL_TEXTENCODING_DONTKNOW ); + } + + if (aFind == m_aCharSets.end()) + m_xControl->set_active(-1); + else + m_xControl->set_active_text((*aFind).getDisplayName()); + } + + bool CharSetListBox::StoreSelectedCharSet( SfxItemSet& _rSet, const sal_uInt16 _nItemId ) + { + bool bChangedSomething = false; + if (m_xControl->get_value_changed_from_saved()) + { + OCharsetDisplay::const_iterator aFind = m_aCharSets.findDisplayName(m_xControl->get_active_text()); + OSL_ENSURE( aFind != m_aCharSets.end(), "CharSetListBox::StoreSelectedCharSet: could not translate the selected character set!" ); + if ( aFind != m_aCharSets.end() ) + { + _rSet.Put( SfxStringItem( _nItemId, (*aFind).getIanaName() ) ); + bChangedSomething = true; + } + } + return bChangedSomething; + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/curledit.cxx b/dbaccess/source/ui/control/curledit.cxx new file mode 100644 index 000000000..9cccde370 --- /dev/null +++ b/dbaccess/source/ui/control/curledit.cxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +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 000000000..549a27c39 --- /dev/null +++ b/dbaccess/source/ui/control/dbtreelistbox.cxx @@ -0,0 +1,584 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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; + +#define SPACEBETWEENENTRIES 4 +DBTreeListBox::DBTreeListBox( vcl::Window* pParent, WinBits nWinStyle ) + :SvTreeListBox(pParent,nWinStyle) + ,m_pDragedEntry(nullptr) + ,m_pActionListener(nullptr) + ,m_pContextMenuProvider(nullptr) + ,m_pResetEvent(nullptr) +{ + init(); +} + +void DBTreeListBox::init() +{ + SetSpaceBetweenEntries(SPACEBETWEENENTRIES); + + m_aTimer.SetTimeout(900); + m_aTimer.SetInvokeHandler(LINK(this, DBTreeListBox, OnTimeOut)); + + m_aScrollHelper.setUpScrollMethod( LINK(this, DBTreeListBox, ScrollUpHdl) ); + m_aScrollHelper.setDownScrollMethod( LINK(this, DBTreeListBox, ScrollDownHdl) ); + + SetNodeDefaultImages( ); + + EnableContextMenuHandling(); + + SetQuickSearch( true ); +} + +DBTreeListBox::~DBTreeListBox() +{ + assert(!m_xMenuController.is()); + disposeOnce(); +} + +void DBTreeListBox::dispose() +{ + if (m_pResetEvent) + { + RemoveUserEvent(m_pResetEvent); + m_pResetEvent = nullptr; + } + implStopSelectionTimer(); + SvTreeListBox::dispose(); +} + +SvTreeListEntry* DBTreeListBox::GetEntryPosByName( const OUString& aName, SvTreeListEntry* pStart, const IEntryFilter* _pFilter ) const +{ + SvTreeList* myModel = GetModel(); + std::pair aIters = + myModel->GetChildIterators(pStart); + + SvTreeListEntry* pEntry = nullptr; + SvTreeListEntries::const_iterator it = aIters.first, itEnd = aIters.second; + for (; it != itEnd; ++it) + { + pEntry = (*it).get(); + const SvLBoxString* pItem = static_cast( + pEntry->GetFirstItem(SvLBoxItemType::String)); + + if (pItem && pItem->GetText() == aName) + { + if (!_pFilter || _pFilter->includeEntry(pEntry->GetUserData())) + // found + break; + } + pEntry = nullptr; + } + + return pEntry; +} + +void DBTreeListBox::RequestingChildren( SvTreeListEntry* pParent ) +{ + if (m_aPreExpandHandler.IsSet() && !m_aPreExpandHandler.Call(pParent)) + { + // an error occurred. The method calling us will reset the entry flags, so it can't be expanded again. + // But we want that the user may do a second try (i.e. because he mistypes a password in this try), so + // we have to reset these flags controlling the expand ability + m_pResetEvent = PostUserEvent(LINK(this, DBTreeListBox, OnResetEntryHdl), pParent, true); + } +} + +void DBTreeListBox::InitEntry(SvTreeListEntry* _pEntry, const OUString& aStr, const Image& _rCollEntryBmp, const Image& _rExpEntryBmp) +{ + SvTreeListBox::InitEntry( _pEntry, aStr, _rCollEntryBmp,_rExpEntryBmp); + SvLBoxItem* pTextItem(_pEntry->GetFirstItem(SvLBoxItemType::String)); + _pEntry->ReplaceItem(std::make_unique(aStr), _pEntry->GetPos(pTextItem)); +} + +void DBTreeListBox::implStopSelectionTimer() +{ + if ( m_aTimer.IsActive() ) + m_aTimer.Stop(); +} + +void DBTreeListBox::implStartSelectionTimer() +{ + implStopSelectionTimer(); + m_aTimer.Start(); +} + +void DBTreeListBox::DeselectHdl() +{ + m_aSelectedEntries.erase( GetHdlEntry() ); + SvTreeListBox::DeselectHdl(); + implStartSelectionTimer(); +} + +void DBTreeListBox::SelectHdl() +{ + m_aSelectedEntries.insert( GetHdlEntry() ); + SvTreeListBox::SelectHdl(); + implStartSelectionTimer(); +} + +void DBTreeListBox::MouseButtonDown( const MouseEvent& rMEvt ) +{ + bool bHitEmptySpace = (nullptr == GetEntry(rMEvt.GetPosPixel(), true)); + if (bHitEmptySpace && (rMEvt.GetClicks() == 2) && rMEvt.IsMod1()) + Control::MouseButtonDown(rMEvt); + else + SvTreeListBox::MouseButtonDown(rMEvt); +} + +void DBTreeListBox::EnableExpandHandler(SvTreeListEntry* pEntry) +{ + // set the flag which allows if the entry can be expanded + pEntry->SetFlags( (pEntry->GetFlags() & ~SvTLEntryFlags(SvTLEntryFlags::NO_NODEBMP | SvTLEntryFlags::HAD_CHILDREN)) | SvTLEntryFlags::CHILDREN_ON_DEMAND ); + // redraw the entry + GetModel()->InvalidateEntry(pEntry); +} + +IMPL_LINK(DBTreeListBox, OnResetEntryHdl, void*, p, void) +{ + m_pResetEvent = nullptr; + EnableExpandHandler(static_cast(p)); +} + +void DBTreeListBox::ModelHasEntryInvalidated( SvTreeListEntry* _pEntry ) +{ + SvTreeListBox::ModelHasEntryInvalidated( _pEntry ); + + if (m_aSelectedEntries.find(_pEntry) != m_aSelectedEntries.end()) + { + SvLBoxItem* pTextItem = _pEntry->GetFirstItem(SvLBoxItemType::String); + if ( pTextItem && !static_cast< OBoldListboxString* >( pTextItem )->isEmphasized() ) + { + implStopSelectionTimer(); + m_aSelectedEntries.erase(_pEntry); + // ehm - why? + } + } +} + +void DBTreeListBox::ModelHasRemoved( SvTreeListEntry* _pEntry ) +{ + SvTreeListBox::ModelHasRemoved(_pEntry); + if (m_aSelectedEntries.find(_pEntry) != m_aSelectedEntries.end()) + { + implStopSelectionTimer(); + m_aSelectedEntries.erase(_pEntry); + } +} + +sal_Int8 DBTreeListBox::AcceptDrop( const AcceptDropEvent& _rEvt ) +{ + sal_Int8 nDropOption = DND_ACTION_NONE; + if ( m_pActionListener ) + { + SvTreeListEntry* pDroppedEntry = GetEntry(_rEvt.maPosPixel); + // check if drag is on child entry, which is not allowed + SvTreeListEntry* pParent = nullptr; + if ( _rEvt.mnAction & DND_ACTION_MOVE ) + { + if ( !m_pDragedEntry ) // no entry to move + { + nDropOption = m_pActionListener->queryDrop( _rEvt, GetDataFlavorExVector() ); + m_aMousePos = _rEvt.maPosPixel; + m_aScrollHelper.scroll(m_aMousePos,GetOutputSizePixel()); + return nDropOption; + } + + pParent = pDroppedEntry ? GetParent(pDroppedEntry) : nullptr; + while ( pParent && pParent != m_pDragedEntry ) + pParent = GetParent(pParent); + } + + if ( !pParent ) + { + nDropOption = m_pActionListener->queryDrop( _rEvt, GetDataFlavorExVector() ); + // check if move is allowed + if ( nDropOption & DND_ACTION_MOVE ) + { + if ( m_pDragedEntry == pDroppedEntry || GetEntryPosByName(GetEntryText(m_pDragedEntry),pDroppedEntry) ) + nDropOption = nDropOption & ~DND_ACTION_MOVE;//DND_ACTION_NONE; + } + m_aMousePos = _rEvt.maPosPixel; + m_aScrollHelper.scroll(m_aMousePos,GetOutputSizePixel()); + } + } + + return nDropOption; +} + +sal_Int8 DBTreeListBox::ExecuteDrop( const ExecuteDropEvent& _rEvt ) +{ + if ( m_pActionListener ) + return m_pActionListener->executeDrop( _rEvt ); + + return DND_ACTION_NONE; +} + +void DBTreeListBox::StartDrag( sal_Int8 /*_nAction*/, const Point& _rPosPixel ) +{ + if ( m_pActionListener ) + { + m_pDragedEntry = GetEntry(_rPosPixel); + if ( m_pDragedEntry && m_pActionListener->requestDrag( _rPosPixel ) ) + { + // if the (asynchronous) drag started, stop the selection timer + implStopSelectionTimer(); + // and stop selecting entries by simply moving the mouse + EndSelection(); + } + } +} + +void DBTreeListBox::RequestHelp( const HelpEvent& rHEvt ) +{ + if ( !m_pActionListener ) + { + SvTreeListBox::RequestHelp( rHEvt ); + return; + } + + if( rHEvt.GetMode() & HelpEventMode::QUICK ) + { + Point aPos( ScreenToOutputPixel( rHEvt.GetMousePosPixel() )); + SvTreeListEntry* pEntry = GetEntry( aPos ); + if( pEntry ) + { + OUString sQuickHelpText; + if ( m_pActionListener->requestQuickHelp( pEntry, sQuickHelpText ) ) + { + Size aSize( GetOutputSizePixel().Width(), GetEntryHeight() ); + tools::Rectangle aScreenRect( OutputToScreenPixel( GetEntryPosition( pEntry ) ), aSize ); + + Help::ShowQuickHelp( this, aScreenRect, + sQuickHelpText, QuickHelpFlags::Left | QuickHelpFlags::VCenter ); + return; + } + } + } + + SvTreeListBox::RequestHelp( rHEvt ); +} + +void DBTreeListBox::KeyInput( const KeyEvent& rKEvt ) +{ + KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction(); + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + bool bHandled = false; + + if(eFunc != KeyFuncType::DONTKNOW) + { + switch(eFunc) + { + case KeyFuncType::COPY: + bHandled = ( m_aCopyHandler.IsSet() && !m_aSelectedEntries.empty() ); + if ( bHandled ) + m_aCopyHandler.Call( nullptr ); + break; + case KeyFuncType::PASTE: + bHandled = ( m_aPasteHandler.IsSet() && !m_aSelectedEntries.empty() ); + if ( bHandled ) + m_aPasteHandler.Call( nullptr ); + break; + case KeyFuncType::DELETE: + bHandled = ( m_aDeleteHandler.IsSet() && !m_aSelectedEntries.empty() ); + if ( bHandled ) + m_aDeleteHandler.Call( nullptr ); + break; + default: + break; + } + } + + if ( KEY_RETURN == nCode ) + { + bHandled = false; + m_aEnterKeyHdl.Call(this); + // this is a HACK. If the data source browser is opened in the "beamer", while the main frame + // + // contains a writer document, then pressing enter in the DSB would be rerouted to the writer + // + // document if we would not do this hack here. + // The problem is that the Writer uses RETURN as _accelerator_ (which is quite weird itself), + // + // so the SFX framework is _obligated_ to pass it to the Writer if nobody else handled it. There + // + // is no chance to distinguish between + // "accelerators which are to be executed if the main document has the focus" + // and + // "accelerators which are always to be executed" + // + // Thus we cannot prevent the handling of this key in the writer without declaring the key event + // as "handled" herein. + // + // The bad thing about this approach is that it does not scale. Every other accelerator which + // is used by the document will raise a similar bug once somebody discovers it. + // If this is the case, we should discuss a real solution with the framework (SFX) and the + // applications. + } + + if ( !bHandled ) + SvTreeListBox::KeyInput(rKEvt); +} + +bool DBTreeListBox::EditingEntry( SvTreeListEntry* /*pEntry*/, Selection& /*_aSelection*/) +{ + return false; +} + +bool DBTreeListBox::EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText ) +{ + DBTreeEditedEntry aEntry; + aEntry.aNewText = rNewText; + SetEntryText(pEntry,aEntry.aNewText); + + return false; // we never want that the base change our text +} + +bool DBTreeListBox::DoubleClickHdl() +{ + // continue default processing if the DoubleClickHandler didn't handle it + return !aDoubleClickHdl.Call( this ); +} + +static void scrollWindow(DBTreeListBox* _pListBox, const Point& _rPos,bool _bUp) +{ + SvTreeListEntry* pEntry = _pListBox->GetEntry( _rPos ); + if( pEntry && pEntry != _pListBox->Last() ) + { + _pListBox->ScrollOutputArea( _bUp ? -1 : 1 ); + } +} + +IMPL_LINK_NOARG( DBTreeListBox, ScrollUpHdl, LinkParamNone*, void ) +{ + scrollWindow(this,m_aMousePos,true); +} + +IMPL_LINK_NOARG( DBTreeListBox, ScrollDownHdl, LinkParamNone*, void ) +{ + scrollWindow(this,m_aMousePos,false); +} + +namespace +{ + // SelectionSupplier + typedef ::cppu::WeakImplHelper< XSelectionSupplier + > SelectionSupplier_Base; + class SelectionSupplier : public SelectionSupplier_Base + { + public: + explicit SelectionSupplier( const Any& _rSelection ) + :m_aSelection( _rSelection ) + { + } + + virtual sal_Bool SAL_CALL select( const Any& xSelection ) override; + virtual Any SAL_CALL getSelection( ) override; + virtual void SAL_CALL addSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) override; + virtual void SAL_CALL removeSelectionChangeListener( const Reference< XSelectionChangeListener >& xListener ) override; + + protected: + virtual ~SelectionSupplier() override + { + } + + private: + Any m_aSelection; + }; + + sal_Bool SAL_CALL SelectionSupplier::select( const Any& /*_Selection*/ ) + { + throw IllegalArgumentException(); + // API bug: this should be a NoSupportException + } + + Any SAL_CALL SelectionSupplier::getSelection( ) + { + return m_aSelection; + } + + void SAL_CALL SelectionSupplier::addSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ ) + { + OSL_FAIL( "SelectionSupplier::removeSelectionChangeListener: no support!" ); + // API bug: this should be a NoSupportException + } + + void SAL_CALL SelectionSupplier::removeSelectionChangeListener( const Reference< XSelectionChangeListener >& /*_Listener*/ ) + { + OSL_FAIL( "SelectionSupplier::removeSelectionChangeListener: no support!" ); + // API bug: this should be a NoSupportException + } +} + +VclPtr DBTreeListBox::CreateContextMenu() +{ + if ( !m_pContextMenuProvider ) + return nullptr; + + OUString aResourceName( m_pContextMenuProvider->getContextMenuResourceName( *this ) ); + if ( aResourceName.isEmpty() ) + return nullptr; + + css::uno::Sequence< css::uno::Any > aArgs( 3 ); + aArgs[0] <<= comphelper::makePropertyValue( "Value", aResourceName ); + aArgs[1] <<= comphelper::makePropertyValue( "Frame", m_pContextMenuProvider->getCommandController().getXController()->getFrame() ); + aArgs[2] <<= comphelper::makePropertyValue( "IsContextMenu", true ); + + css::uno::Reference< css::uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + m_xMenuController.set( xContext->getServiceManager()->createInstanceWithArgumentsAndContext( + "com.sun.star.comp.framework.ResourceMenuController", aArgs, xContext ), css::uno::UNO_QUERY ); + + if ( !m_xMenuController.is() ) + return nullptr; + + rtl::Reference xPopupMenu( new VCLXPopupMenu ); + m_xMenuController->setPopupMenu( xPopupMenu.get() ); + VclPtr pContextMenu( static_cast< PopupMenu* >( xPopupMenu->GetMenu() ) ); + pContextMenu->AddEventListener( LINK( this, DBTreeListBox, MenuEventListener ) ); + + // allow context menu interception + ::comphelper::OInterfaceContainerHelper2* pInterceptors = m_pContextMenuProvider->getContextMenuInterceptors(); + if ( !pInterceptors || !pInterceptors->getLength() ) + return pContextMenu; + + OUString aMenuIdentifier( "private:resource/popupmenu/" + aResourceName ); + + ContextMenuExecuteEvent aEvent; + aEvent.SourceWindow = VCLUnoHelper::GetInterface( this ); + aEvent.ExecutePosition.X = -1; + aEvent.ExecutePosition.Y = -1; + aEvent.ActionTriggerContainer = ::framework::ActionTriggerHelper::CreateActionTriggerContainerFromMenu( + pContextMenu.get(), &aMenuIdentifier ); + aEvent.Selection = new SelectionSupplier( m_pContextMenuProvider->getCurrentSelection( *this ) ); + + ::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 nullptr; + + 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 ) + { + pContextMenu->Clear(); + ::framework::ActionTriggerHelper::CreateMenuFromActionTriggerContainer( + pContextMenu, aEvent.ActionTriggerContainer ); + aEvent.ActionTriggerContainer.clear(); + } + + return pContextMenu; +} + +void DBTreeListBox::ExecuteContextMenuAction( sal_uInt16 ) +{ +} + +IMPL_LINK( DBTreeListBox, MenuEventListener, VclMenuEvent&, rMenuEvent, void ) +{ + if ( rMenuEvent.GetId() == VclEventId::ObjectDying ) + { + css::uno::Reference< css::lang::XComponent > xComponent( m_xMenuController, css::uno::UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + m_xMenuController.clear(); + } +} + +IMPL_LINK_NOARG(DBTreeListBox, OnTimeOut, Timer*, void) +{ + implStopSelectionTimer(); + + m_aSelChangeHdl.Call( nullptr ); +} + +void DBTreeListBox::StateChanged( StateChangedType nStateChange ) +{ + if ( nStateChange == StateChangedType::Visible ) + implStopSelectionTimer(); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/listviewitems.cxx b/dbaccess/source/ui/control/listviewitems.cxx new file mode 100644 index 000000000..1036ed3b3 --- /dev/null +++ b/dbaccess/source/ui/control/listviewitems.cxx @@ -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 . + */ + +#include +#include + +namespace dbaui +{ + + void OBoldListboxString::InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* _pViewData) + { + SvLBoxString::InitViewData( pView, pEntry, _pViewData ); + if ( !m_bEmphasized ) + return; + if (!_pViewData) + _pViewData = pView->GetViewDataItem( pEntry, this ); + pView->Push(); + vcl::Font aFont( pView->GetFont()); + aFont.SetWeight(WEIGHT_BOLD); + pView->Control::SetFont( aFont ); + _pViewData->mnWidth = pView->GetTextWidth(GetText()); + _pViewData->mnHeight = pView->GetTextHeight(); + pView->Pop(); + } + + SvLBoxItemType OBoldListboxString::GetType() const + { + return SvLBoxItemType::String; + } + + void OBoldListboxString::Paint(const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext, + const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) + { + if (m_bEmphasized) + { + rRenderContext.Push(); + vcl::Font aFont(rRenderContext.GetFont()); + aFont.SetWeight(WEIGHT_BOLD); + rRenderContext.SetFont(aFont); + Point aPos(rPos); + rRenderContext.DrawText(aPos, GetText()); + rRenderContext.Pop(); + } + else + { + SvLBoxString::Paint(rPos, rDev, rRenderContext, pView, rEntry); + } + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/marktree.cxx b/dbaccess/source/ui/control/marktree.cxx new file mode 100644 index 000000000..9bf664fa6 --- /dev/null +++ b/dbaccess/source/ui/control/marktree.cxx @@ -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 . + */ + +#include +#include +#include +#include +#include + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + +OMarkableTreeListBox::OMarkableTreeListBox( vcl::Window* pParent, WinBits nWinStyle ) + : DBTreeListBox(pParent, nWinStyle) +{ + + InitButtonData(); +} + +OMarkableTreeListBox::~OMarkableTreeListBox() +{ + disposeOnce(); +} + +void OMarkableTreeListBox::dispose() +{ + m_pCheckButton.reset(); + DBTreeListBox::dispose(); +} + +void OMarkableTreeListBox::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rRect) +{ + if (!IsEnabled()) + { + vcl::Font aOldFont = rRenderContext.GetFont(); + vcl::Font aNewFont(aOldFont); + + StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings(); + aNewFont.SetColor(aSystemStyle.GetDisableColor()); + + rRenderContext.SetFont(aNewFont); + DBTreeListBox::Paint(rRenderContext, _rRect); + rRenderContext.SetFont(aOldFont); + } + else + DBTreeListBox::Paint(rRenderContext, _rRect); +} + +void OMarkableTreeListBox::InitButtonData() +{ + m_pCheckButton.reset( new SvLBoxButtonData( this ) ); + EnableCheckButton( m_pCheckButton.get() ); +} + +void OMarkableTreeListBox::KeyInput( const KeyEvent& rKEvt ) +{ + // only if there are spaces + if (rKEvt.GetKeyCode().GetCode() == KEY_SPACE && !rKEvt.GetKeyCode().IsShift() && !rKEvt.GetKeyCode().IsMod1()) + { + SvTreeListEntry* pCurrentHandlerEntry = GetHdlEntry(); + if(pCurrentHandlerEntry) + { + SvButtonState eState = GetCheckButtonState( pCurrentHandlerEntry); + if(eState == SvButtonState::Checked) + SetCheckButtonState( pCurrentHandlerEntry, SvButtonState::Unchecked); + else + SetCheckButtonState( pCurrentHandlerEntry, SvButtonState::Checked); + + CheckButtonHdl(); + } + else + DBTreeListBox::KeyInput(rKEvt); + } + else + DBTreeListBox::KeyInput(rKEvt); +} + +SvButtonState OMarkableTreeListBox::implDetermineState(SvTreeListEntry* _pEntry) +{ + SvButtonState eState = GetCheckButtonState(_pEntry); + if (!GetModel()->HasChildren(_pEntry)) + // 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; + + SvTreeListEntry* pChildLoop = GetModel()->FirstChild(_pEntry); + while (pChildLoop) + { + SvButtonState eChildState = implDetermineState(pChildLoop); + if (SvButtonState::Tristate == eChildState) + break; + + if (SvButtonState::Checked == eChildState) + ++nCheckedChildren; + ++nChildrenOverall; + + pChildLoop = pChildLoop->NextSibling(); + } + + if (pChildLoop) + { + // we did not finish the loop because at least one of the children is in tristate + eState = SvButtonState::Tristate; + + // 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 (pChildLoop) + { + implDetermineState(pChildLoop); + pChildLoop = pChildLoop->NextSibling(); + } + } + 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 = SvButtonState::Tristate; + else + // all children are checked + eState = SvButtonState::Checked; + else + // no children are checked + eState = SvButtonState::Unchecked; + + // finally set the entry to the state we just determined + SetCheckButtonState(_pEntry, eState); + + return eState; +} + +void OMarkableTreeListBox::CheckButtons() +{ + SvTreeListEntry* pEntry = GetModel()->First(); + while (pEntry) + { + implDetermineState(pEntry); + pEntry = pEntry->NextSibling(); + } +} + +void OMarkableTreeListBox::CheckButtonHdl() +{ + checkedButton_noBroadcast(GetHdlEntry()); +} + +void OMarkableTreeListBox::checkedButton_noBroadcast(SvTreeListEntry* _pEntry) +{ + SvButtonState eState = GetCheckButtonState( _pEntry); + if (GetModel()->HasChildren(_pEntry)) // if it has children, check those too + { + SvTreeListEntry* pChildEntry = GetModel()->Next(_pEntry); + SvTreeListEntry* pSiblingEntry = _pEntry->NextSibling(); + while(pChildEntry && pChildEntry != pSiblingEntry) + { + SetCheckButtonState(pChildEntry, eState); + pChildEntry = GetModel()->Next(pChildEntry); + } + } + + SvTreeListEntry* pEntry = IsSelected(_pEntry) ? FirstSelected() : nullptr; + while(pEntry) + { + SetCheckButtonState(pEntry,eState); + if(GetModel()->HasChildren(pEntry)) // if it has children, check those too + { + SvTreeListEntry* pChildEntry = GetModel()->Next(pEntry); + SvTreeListEntry* pSiblingEntry = pEntry->NextSibling(); + while(pChildEntry && pChildEntry != pSiblingEntry) + { + SetCheckButtonState(pChildEntry,eState); + pChildEntry = GetModel()->Next(pChildEntry); + } + } + pEntry = NextSelected(pEntry); + } + CheckButtons(); +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/opendoccontrols.cxx b/dbaccess/source/ui/control/opendoccontrols.cxx new file mode 100644 index 000000000..a80ed3ede --- /dev/null +++ b/dbaccess/source/ui/control/opendoccontrols.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 +#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!" ); + + Sequence< Sequence< PropertyValue> > aHistory = SvtHistoryOptions().GetList( ePICKLIST ); + Reference< XNameAccess > xFilterFactory; + xFilterFactory.set(::comphelper::getProcessServiceFactory()->createInstance( + "com.sun.star.document.FilterFactory" ), css::uno::UNO_QUERY); + + sal_uInt32 nCount = aHistory.getLength(); + for ( sal_uInt32 nItem = 0; nItem < nCount; ++nItem ) + { + try + { + // Get the current history item's properties. + ::comphelper::SequenceAsHashMap aItemProperties( aHistory[ nItem ] ); + OUString sURL = aItemProperties.getUnpackedValueOrDefault( HISTORY_PROPERTYNAME_URL, OUString() ); + OUString sFilter = aItemProperties.getUnpackedValueOrDefault( HISTORY_PROPERTYNAME_FILTER, OUString() ); + OUString sTitle = aItemProperties.getUnpackedValueOrDefault( HISTORY_PROPERTYNAME_TITLE, OUString() ); + OUString sPassword = aItemProperties.getUnpackedValueOrDefault( HISTORY_PROPERTYNAME_PASSWORD, OUString() ); + + // If the entry is an impress 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(StringPair(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; + } + + OpenDocumentListBox::StringPair OpenDocumentListBox::impl_getDocumentAtIndex( sal_uInt16 _nListIndex ) const + { + return m_aURLs[_nListIndex]; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/sqledit.cxx b/dbaccess/source/ui/control/sqledit.cxx new file mode 100644 index 000000000..ccbe210af --- /dev/null +++ b/dbaccess/source/ui/control/sqledit.cxx @@ -0,0 +1,248 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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; + +class OSqlEdit::ChangesListener: + public cppu::WeakImplHelper< css::beans::XPropertiesChangeListener > +{ +public: + explicit ChangesListener(OSqlEdit & editor): editor_(editor) {} + +private: + virtual ~ChangesListener() override {} + + virtual void SAL_CALL disposing(css::lang::EventObject const &) override + { + osl::MutexGuard g(editor_.m_mutex); + editor_.m_notifier.clear(); + } + + virtual void SAL_CALL propertiesChange( + css::uno::Sequence< css::beans::PropertyChangeEvent > const &) override + { + SolarMutexGuard g; + editor_.ImplSetFont(); + } + + OSqlEdit & editor_; +}; + +OSqlEdit::OSqlEdit( OQueryTextView* pParent ) : + MultiLineEditSyntaxHighlight( pParent, WB_LEFT | WB_VSCROLL | WB_BORDER ) + ,m_pView(pParent) + ,m_bAccelAction( false ) + ,m_bStopTimer(false ) +{ + SetHelpId( HID_CTL_QRYSQLEDIT ); + SetModifyHdl( LINK(this, OSqlEdit, ModifyHdl) ); + + m_timerUndoActionCreation.SetTimeout(1000); + m_timerUndoActionCreation.SetInvokeHandler(LINK(this, OSqlEdit, OnUndoActionTimer)); + + m_timerInvalidate.SetTimeout(200); + m_timerInvalidate.SetInvokeHandler(LINK(this, OSqlEdit, OnInvalidateTimer)); + m_timerInvalidate.Start(); + + ImplSetFont(); + // Listen for change of Font and Color Settings: + // Using "this" in ctor is a little fishy, but should work here at least as + // long as there are no derivations: + m_listener = new ChangesListener(*this); + css::uno::Reference< css::beans::XMultiPropertySet > n( + officecfg::Office::Common::Font::SourceViewFont::get(), + css::uno::UNO_QUERY_THROW); + { + osl::MutexGuard g(m_mutex); + m_notifier = n; + } + css::uno::Sequence< OUString > s(2); + s[0] = "FontHeight"; + s[1] = "FontName"; + n->addPropertiesChangeListener(s, m_listener.get()); + m_ColorConfig.AddListener(this); + + //#i97044# + EnableFocusSelectionHide( false ); +} + +OSqlEdit::~OSqlEdit() +{ + disposeOnce(); +} + +void OSqlEdit::dispose() +{ + if (m_timerUndoActionCreation.IsActive()) + m_timerUndoActionCreation.Stop(); + css::uno::Reference< css::beans::XMultiPropertySet > n; + { + osl::MutexGuard g(m_mutex); + n = m_notifier; + } + if (n.is()) { + n->removePropertiesChangeListener(m_listener.get()); + } + m_ColorConfig.RemoveListener(this); + m_pView.clear(); + MultiLineEditSyntaxHighlight::dispose(); +} + +void OSqlEdit::KeyInput( const KeyEvent& rKEvt ) +{ + OJoinController& rController = m_pView->getContainerWindow()->getDesignView()->getController(); + rController.InvalidateFeature(SID_CUT); + rController.InvalidateFeature(SID_COPY); + + // Is this a cut, copy, paste event? + KeyFuncType aKeyFunc = rKEvt.GetKeyCode().GetFunction(); + if( (aKeyFunc==KeyFuncType::CUT)||(aKeyFunc==KeyFuncType::COPY)||(aKeyFunc==KeyFuncType::PASTE) ) + m_bAccelAction = true; + + MultiLineEditSyntaxHighlight::KeyInput( rKEvt ); + + if( m_bAccelAction ) + m_bAccelAction = false; +} + + +void OSqlEdit::GetFocus() +{ + m_strOrigText =GetText(); + MultiLineEditSyntaxHighlight::GetFocus(); +} + +IMPL_LINK_NOARG(OSqlEdit, OnUndoActionTimer, Timer *, void) +{ + OUString aText = GetText(); + if(aText == m_strOrigText) + return; + + OJoinController& rController = m_pView->getContainerWindow()->getDesignView()->getController(); + SfxUndoManager& rUndoMgr = rController.GetUndoManager(); + std::unique_ptr pUndoAct(new OSqlEditUndoAct( this )); + + pUndoAct->SetOriginalText( m_strOrigText ); + rUndoMgr.AddUndoAction( std::move(pUndoAct) ); + + rController.InvalidateFeature(SID_UNDO); + rController.InvalidateFeature(SID_REDO); + + m_strOrigText =aText; +} + +IMPL_LINK_NOARG(OSqlEdit, OnInvalidateTimer, Timer *, void) +{ + OJoinController& rController = m_pView->getContainerWindow()->getDesignView()->getController(); + rController.InvalidateFeature(SID_CUT); + rController.InvalidateFeature(SID_COPY); + if(!m_bStopTimer) + m_timerInvalidate.Start(); +} + +IMPL_LINK_NOARG(OSqlEdit, ModifyHdl, Edit&, void) +{ + if (m_timerUndoActionCreation.IsActive()) + m_timerUndoActionCreation.Stop(); + m_timerUndoActionCreation.Start(); + + OJoinController& rController = m_pView->getContainerWindow()->getDesignView()->getController(); + if (!rController.isModified()) + rController.setModified( true ); + + rController.InvalidateFeature(SID_SBA_QRY_EXECUTE); + rController.InvalidateFeature(SID_CUT); + rController.InvalidateFeature(SID_COPY); +} + +void OSqlEdit::SetText(const OUString& rNewText) +{ + if (m_timerUndoActionCreation.IsActive()) + { // create the trailing undo-actions + m_timerUndoActionCreation.Stop(); + LINK(this, OSqlEdit, OnUndoActionTimer).Call(nullptr); + } + + MultiLineEditSyntaxHighlight::SetText(rNewText); + m_strOrigText =rNewText; +} + +void OSqlEdit::stopTimer() +{ + m_bStopTimer = true; + if (m_timerInvalidate.IsActive()) + m_timerInvalidate.Stop(); +} + +void OSqlEdit::startTimer() +{ + m_bStopTimer = false; + if (!m_timerInvalidate.IsActive()) + m_timerInvalidate.Start(); +} + +void OSqlEdit::ConfigurationChanged( utl::ConfigurationBroadcaster* pOption, ConfigurationHints ) +{ + assert( pOption == &m_ColorConfig ); + (void) pOption; // avoid warnings + MultiLineEditSyntaxHighlight::UpdateData(); +} + +void OSqlEdit::ImplSetFont() +{ + AllSettings aSettings = GetSettings(); + StyleSettings aStyleSettings = aSettings.GetStyleSettings(); + 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::NONE, this ) ); + sFontName = aTmpFont.GetFamilyName(); + } + Size aFontSize( + 0, officecfg::Office::Common::Font::SourceViewFont::FontHeight::get() ); + vcl::Font aFont( sFontName, aFontSize ); + aStyleSettings.SetFieldFont(aFont); + aSettings.SetStyleSettings(aStyleSettings); + SetSettings(aSettings); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/tabletree.cxx b/dbaccess/source/ui/control/tabletree.cxx new file mode 100644 index 000000000..b3170487e --- /dev/null +++ b/dbaccess/source/ui/control/tabletree.cxx @@ -0,0 +1,1006 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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::sdb; +using namespace ::com::sun::star::lang; +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::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(vcl::Window* pParent, WinBits nWinStyle) + :OMarkableTreeListBox(pParent, nWinStyle) + ,m_xImageProvider( new ImageProvider ) +{ + implSetDefaultImages(); +} + +TableTreeListBox::TableTreeListBox(std::unique_ptr xTreeView) + : m_xImageProvider(new ImageProvider) + , m_bVirtualRoot(false) + , m_bNoEmptyFolders(false) + , m_bShowToggles(true) + , m_nTextColumn(1) + , m_xTreeView(std::move(xTreeView)) +{ +} + +void OTableTreeListBox::implSetDefaultImages() +{ + SetDefaultExpandedEntryBmp( ImageProvider::getFolderImage( DatabaseObject::TABLE ) ); + SetDefaultCollapsedEntryBmp( ImageProvider::getFolderImage( DatabaseObject::TABLE ) ); +} + +bool OTableTreeListBox::isFolderEntry( const SvTreeListEntry* _pEntry ) +{ + sal_Int32 nEntryType = reinterpret_cast< sal_IntPtr >( _pEntry->GetUserData() ); + return ( nEntryType == DatabaseObjectContainer::TABLES ) + || ( nEntryType == DatabaseObjectContainer::CATALOG ) + || ( nEntryType == DatabaseObjectContainer::SCHEMA ); +} + +void OTableTreeListBox::notifyHiContrastChanged() +{ + implSetDefaultImages(); + + SvTreeListEntry* pEntryLoop = First(); + while (pEntryLoop) + { + size_t nCount = pEntryLoop->ItemCount(); + for (size_t i=0;iGetItem(i); + if (rItem.GetType() == SvLBoxItemType::ContextBmp) + { + SvLBoxContextBmp& rContextBitmapItem = static_cast< SvLBoxContextBmp& >( rItem ); + + Image aImage; + if ( isFolderEntry( pEntryLoop ) ) + { + aImage = ImageProvider::getFolderImage( DatabaseObject::TABLE ); + } + else + { + OUString sCompleteName( getQualifiedTableName( pEntryLoop ) ); + m_xImageProvider->getImages( sCompleteName, DatabaseObject::TABLE, aImage ); + } + + rContextBitmapItem.SetBitmap1( aImage ); + rContextBitmapItem.SetBitmap2( aImage ); + break; + } + } + pEntryLoop = Next(pEntryLoop); + } +} + +void OTableTreeListBox::implOnNewConnection( const Reference< XConnection >& _rxConnection ) +{ + m_xConnection = _rxConnection; + m_xImageProvider.reset( new ImageProvider( m_xConnection ) ); +} + +void TableTreeListBox::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&) + { + OSL_FAIL("OTableTreeListBox::UpdateTableList : caught a RuntimeException!"); + } + 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 ); +} + +void TableTreeListBox::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&) + { + OSL_FAIL("OTableTreeListBox::UpdateTableList : caught a RuntimeException!"); + } + 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 ); +} + +void TableTreeListBox::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 + Clear(); + + try + { + 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 ( 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; + + for (auto const& folderName : aFolderNames) + { + SvTreeListEntry* pFolder = GetEntryPosByName( folderName, nullptr ); + if ( !pFolder ) + InsertEntry( folderName, nullptr, false, TREELIST_APPEND, reinterpret_cast< void* >( nFolderType ) ); + } + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +void TableTreeListBox::DisableCheckButtons() +{ + m_bShowToggles = false; + m_nTextColumn = 0; +} + +void TableTreeListBox::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, nullptr, false, xRet.get()); + m_xTreeView->set_image(*xRet, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE, 0); + m_xTreeView->set_text(*xRet, sRootEntryText, m_nTextColumn); + } + + 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); + } + + 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, nullptr, false, xRet.get()); + m_xTreeView->set_image(*xRet, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xRet, TRISTATE_FALSE, 0); + m_xTreeView->set_text(*xRet, folderName, m_nTextColumn); + } + } + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + m_xTreeView->make_sorted(); +} + +bool TableTreeListBox::isWildcardChecked(const weld::TreeIter& rEntry) +{ + return m_xTreeView->get_text_emphasis(rEntry, m_nTextColumn); +} + +void TableTreeListBox::checkWildcard(weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return; + m_xTreeView->set_toggle(rEntry, TRISTATE_TRUE, 0); + checkedButton_noBroadcast(rEntry); +} + +std::unique_ptr TableTreeListBox::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(SvTreeListEntry* _pEntry) +{ + OMarkableTreeListBox::checkedButton_noBroadcast(_pEntry); + + // 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 + + SvButtonState eState = GetCheckButtonState(_pEntry); + OSL_ENSURE(SvButtonState::Tristate != eState, "OTableTreeListBox::CheckButtonHdl: user action which lead to TRISTATE?"); + implEmphasize(_pEntry, SvButtonState::Checked == eState); +} + +void TableTreeListBox::checkedButton_noBroadcast(weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return; + TriState eState = m_xTreeView->get_toggle(rEntry, 0); + 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, 0); + 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, 0); + 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, 0); + 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(SvTreeListEntry* _pEntry, bool _bChecked, bool _bUpdateDescendants, bool _bUpdateAncestors) +{ + OSL_ENSURE(_pEntry, "OTableTreeListBox::implEmphasize: invalid entry (NULL)!"); + + if ( GetModel()->HasChildren(_pEntry) ) // the entry has children + { + OBoldListboxString* pTextItem = static_cast(_pEntry->GetFirstItem(SvLBoxItemType::String)); + if (pTextItem) + pTextItem->emphasize(_bChecked); + } + + if (_bUpdateDescendants) + { + // remove the mark for all children of the checked entry + SvTreeListEntry* pChildLoop = FirstChild(_pEntry); + while (pChildLoop) + { + if (GetModel()->HasChildren(pChildLoop)) + implEmphasize(pChildLoop, false, true, false); + pChildLoop = pChildLoop->NextSibling(); + } + } + + if (_bUpdateAncestors) + { + // remove the mark for all ancestors of the entry + if (GetModel()->HasParent(_pEntry)) + implEmphasize(GetParent(_pEntry), false, false); + } +} + +void TableTreeListBox::implEmphasize(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, m_nTextColumn); + } + + 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); + } +} + +void OTableTreeListBox::InitEntry(SvTreeListEntry* _pEntry, const OUString& _rString, const Image& _rCollapsedBitmap, const Image& _rExpandedBitmap) +{ + OMarkableTreeListBox::InitEntry(_pEntry, _rString, _rCollapsedBitmap, _rExpandedBitmap); + + // replace the text item with our own one + SvLBoxItem* pTextItem = _pEntry->GetFirstItem(SvLBoxItemType::String); + OSL_ENSURE(pTextItem, "OTableTreeListBox::InitEntry: no text item!?"); + size_t nTextPos = _pEntry->GetPos(pTextItem); + OSL_ENSURE(SvTreeListEntry::ITEM_NOT_FOUND != nTextPos, "OTableTreeListBox::InitEntry: no text item pos!"); + + _pEntry->ReplaceItem(std::make_unique(_rString), nTextPos); +} + +SvTreeListEntry* 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 ); + + SvTreeListEntry* pParentEntry = nullptr; + + // 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() ) + { + SvTreeListEntry* pFolder = GetEntryPosByName( rFirstName, pParentEntry ); + if ( !pFolder ) + pFolder = InsertEntry( rFirstName, pParentEntry, false, TREELIST_APPEND, reinterpret_cast< void* >( nFirstFolderType ) ); + pParentEntry = pFolder; + } + + if ( !rSecondName.isEmpty() ) + { + SvTreeListEntry* pFolder = GetEntryPosByName( rSecondName, pParentEntry ); + if ( !pFolder ) + pFolder = InsertEntry( rSecondName, pParentEntry, false, TREELIST_APPEND, reinterpret_cast< void* >( nSecondFolderType ) ); + pParentEntry = pFolder; + } + + SvTreeListEntry* pRet = nullptr; + if ( !_bCheckName || !GetEntryPosByName( sName, pParentEntry ) ) + { + pRet = InsertEntry( sName, pParentEntry ); + + Image aImage; + m_xImageProvider->getImages( _rTableName, DatabaseObject::TABLE, aImage ); + + SetExpandedEntryBmp( pRet, aImage ); + SetCollapsedEntryBmp( pRet, aImage ); + } + return pRet; +} + +void TableTreeListBox::implAddEntry( + const Reference< XDatabaseMetaData >& _rxMeta, + const OUString& _rTableName + ) +{ + OSL_PRECOND( _rxMeta.is(), "OTableTreeListBox::implAddEntry: invalid meta data!" ); + if ( !_rxMeta.is() ) + return; + + // 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, nullptr, false, xFolder.get()); + m_xTreeView->set_image(*xFolder, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE, 0); + m_xTreeView->set_text(*xFolder, rFirstName, m_nTextColumn); + } + 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, nullptr, false, xFolder.get()); + m_xTreeView->set_image(*xFolder, sImageId, -1); + if (m_bShowToggles) + m_xTreeView->set_toggle(*xFolder, TRISTATE_FALSE, 0); + m_xTreeView->set_text(*xFolder, rSecondName, m_nTextColumn); + } + xParentEntry = std::move(xFolder); + } + + std::unique_ptr xEntry = m_xTreeView->make_iterator(); + m_xTreeView->insert(xParentEntry.get(), -1, nullptr, 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, 0); + m_xTreeView->set_text(*xEntry, sName, m_nTextColumn); +} + +NamedDatabaseObject OTableTreeListBox::describeObject( SvTreeListEntry* _pEntry ) +{ + NamedDatabaseObject aObject; + + sal_Int32 nEntryType = reinterpret_cast< sal_IntPtr >( _pEntry->GetUserData() ); + + 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( _pEntry ); + } + + return aObject; +} + +SvTreeListEntry* 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( SvTreeListEntry* _pEntry ) const +{ + OSL_PRECOND( !isFolderEntry( _pEntry ), "OTableTreeListBox::getQualifiedTableName: folder entries not allowed here!" ); + + try + { + Reference< XDatabaseMetaData > xMeta; + if ( !impl_getAndAssertMetaData( xMeta ) ) + return OUString(); + + OUString sCatalog; + OUString sSchema; + OUString sTable; + + SvTreeListEntry* pSchema = GetParent( _pEntry ); + if ( pSchema ) + { + SvTreeListEntry* pCatalog = GetParent( pSchema ); + if ( pCatalog + || ( xMeta->supportsCatalogsInDataManipulation() + && !xMeta->supportsSchemasInDataManipulation() + ) // here we support catalog but no schema + ) + { + if ( pCatalog == nullptr ) + { + pCatalog = pSchema; + pSchema = nullptr; + } + sCatalog = GetEntryText( pCatalog ); + } + if ( pSchema ) + sSchema = GetEntryText(pSchema); + } + sTable = GetEntryText( _pEntry ); + + return ::dbtools::composeTableName( xMeta, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return OUString(); +} + +SvTreeListEntry* 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); + + SvTreeListEntry* pParent = nullptr; + SvTreeListEntry* pCat = nullptr; + SvTreeListEntry* pSchema = nullptr; + if ( !sCatalog.isEmpty() ) + { + pCat = GetEntryPosByName(sCatalog, pParent); + if ( pCat ) + pParent = pCat; + } + + if ( !sSchema.isEmpty() ) + { + pSchema = GetEntryPosByName(sSchema, pParent); + if ( pSchema ) + pParent = pSchema; + } + + return GetEntryPosByName(sName, pParent); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return nullptr; +} + +void OTableTreeListBox::removedTable( const OUString& _rName ) +{ + try + { + SvTreeListEntry* pEntry = getEntryByQualifiedName( _rName ); + if ( pEntry ) + GetModel()->Remove( pEntry ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +std::unique_ptr TableTreeListBox::GetEntryPosByName(const OUString& aName, const weld::TreeIter* pStart, const IEntryFilter* _pFilter) const +{ + auto xEntry(m_xTreeView->make_iterator(pStart)); + if (!pStart && !m_xTreeView->get_iter_first(*xEntry)) + return nullptr; + + do + { + if (m_xTreeView->get_text(*xEntry) == aName) + { + if (!_pFilter || _pFilter->includeEntry(reinterpret_cast(m_xTreeView->get_id(*xEntry).toUInt64()))) + { + // found + return xEntry; + } + } + } while (m_xTreeView->iter_next(*xEntry)); + + return nullptr; +} + +void TableTreeListBox::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 TableTreeListBox::implDetermineState(weld::TreeIter& rEntry) +{ + if (!m_bShowToggles) + return TRISTATE_FALSE; + + TriState eState = m_xTreeView->get_toggle(rEntry, 0); + 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, 0); + + return eState; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/control/undosqledit.cxx b/dbaccess/source/ui/control/undosqledit.cxx new file mode 100644 index 000000000..d32774292 --- /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_pOwner->GetText(); + m_pOwner->SetText(m_strNextText); + m_strNextText = strNext; +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/CollectionView.cxx b/dbaccess/source/ui/dlg/CollectionView.cxx new file mode 100644 index 000000000..6b978bc30 --- /dev/null +++ b/dbaccess/source/ui/dlg/CollectionView.cxx @@ -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 . + */ + +#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, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext) + : GenericDialogController(pParent, "dbaccess/ui/collectionviewdialog.ui", "CollectionView") + , m_xContent(_xContent) + , m_xContext(_rxContext) + , m_bCreateForm(true) + , m_xFTCurrentPath(m_xBuilder->weld_label("currentPathLabel")) + , m_xNewFolder(m_xBuilder->weld_button("newFolderButton")) + , m_xUp(m_xBuilder->weld_button("upButton")) + , m_xView(m_xBuilder->weld_tree_view("viewTreeview")) + , m_xName(m_xBuilder->weld_entry("fileNameEntry")) + , m_xPB_OK(m_xBuilder->weld_button("ok")) +{ + Reference 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())); + OInteractionRequest* pRequest = new OInteractionRequest(makeAny(aException)); + Reference< XInteractionRequest > xRequest(pRequest); + + OInteractionApprove* pApprove = new OInteractionApprove; + pRequest->addContinuation(pApprove); + xHandler->handle(xRequest); + + 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::insertHierachyElement(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 && sCID.getLength() != static_cast(strlen(s_sFormsCID))) + sPath = sCID.copy(strlen(s_sFormsCID)); + else if ( !m_bCreateForm && sCID.getLength() != static_cast(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(2); + aProps[0] = "Title"; + aProps[1] = "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 000000000..a9f4418a2 --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionHelper.cxx @@ -0,0 +1,726 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 OString& _rId, const SfxItemSet& _rCoreAttrs) + : OGenericAdministrationPage(pPage, pController, _rUIXMLDescription, _rId, _rCoreAttrs) + , m_bUserGrabFocus(false) + , m_pCollection(nullptr) + , m_xFT_Connection(m_xBuilder->weld_label("browseurllabel")) + , m_xPB_Connection(m_xBuilder->weld_button("browse")) + , m_xPB_CreateDB(m_xBuilder->weld_button("create")) + , m_xConnectionURL(new OConnectionURLEdit(m_xBuilder->weld_entry("browseurl"), m_xBuilder->weld_label("browselabel"))) + { + // extract the datasource type collection from the item set + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast( _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 = FolderPicker::create(m_xORB); + + 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: + { + const OUString sExt("*.mdb;*.mde"); + OUString sFilterName(DBA_RES (STR_MSACCESS_FILTERNAME)); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, GetFrameWeld()); + aFileDlg.AddFilter(sFilterName,sExt); + aFileDlg.SetCurrentFilter(sFilterName); + askForFileName(aFileDlg); + } + break; + case ::dbaccess::DST_MSACCESS_2007: + { + const OUString sAccdb("*.accdb;*.accde"); + OUString sFilterName2(DBA_RES (STR_MSACCESS_2007_FILTERNAME)); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, GetFrameWeld()); + aFileDlg.AddFilter(sFilterName2,sAccdb); + 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: + { + const OUString sExt("*.fdb"); + OUString sFilterName(DBA_RES (STR_FIREBIRD_FILTERNAME)); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, GetFrameWeld()); + aFileDlg.AddFilter(sFilterName,sExt); + 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: + { + const OUString sExt("*.fdb"); + OUString sFilterName(DBA_RES (STR_FIREBIRD_FILTERNAME)); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, GetFrameWeld()); + aFileDlg.AddFilter(sFilterName,sExt); + aFileDlg.SetCurrentFilter(sFilterName); + askForFileName(aFileDlg); + break; + } + default: + break; + } + + checkTestConnection(); + } + + bool OConnectionHelper::checkTestConnection() + { + return true; + } + + void OConnectionHelper::impl_setURL( const OUString& _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( const OUString& _rURL ) + { + impl_setURL( _rURL, true ); + } + + OUString OConnectionHelper::getURLNoPrefix( ) const + { + return impl_getURL(); + } + + void OConnectionHelper::setURLNoPrefix( const OUString& _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); + OFilePickerInteractionHandler* pHandler = new OFilePickerInteractionHandler(xInteractionHandler); + xInteractionHandler = pHandler; + + Reference< XCommandEnvironment > xCmdEnv = new ::ucbhelper::CommandEnvironment( xInteractionHandler, Reference< XProgressHandler >() ); + try + { + aCheckExistence = ::ucbhelper::Content(_rURL, xCmdEnv, comphelper::getProcessComponentContext()); + const bool bExists = bIsFile? aCheckExistence.isDocument(): aCheckExistence.isFolder(); + eExists = bExists? PATH_EXIST: PATH_NOT_EXIST; + } + catch (const Exception&) + { + eExists = pHandler->isDoesNotExist() ? PATH_NOT_EXIST : (bIsFile ? PATH_NOT_EXIST : PATH_NOT_KNOWN); + } + return eExists; + } + + IMPL_LINK_NOARG(OConnectionHelper, GetFocusHdl, weld::Widget&, void) + { + if (!m_pCollection->isFileSystemBased(m_eType)) + return; + if (!m_bUserGrabFocus) + return; + // URL edit field got the focus + m_xConnectionURL->SaveValueNoPrefix(); + } + + IMPL_LINK_NOARG(OConnectionHelper, LoseFocusHdl, weld::Widget&, void) + { + if (!m_pCollection->isFileSystemBased(m_eType)) + return; + if (!m_bUserGrabFocus) + return; + // URL edit field lost the focus + commitURL(); + } + + bool OConnectionHelper::createDirectoryDeep(const OUString& _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" }; + + // the values to be set + Sequence< Any > aNewDirectoryAttributes(1); + + // loop + for ( std::vector< OUString >::const_reverse_iterator aLocalName = aToBeCreated.rbegin(); + aLocalName != aToBeCreated.rend(); + ++aLocalName + ) + { + aNewDirectoryAttributes[0] <<= *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 000000000..ed58eac07 --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionHelper.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_CONNECTIONHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_CONNECTIONHELPER_HXX + +#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 OString& _rId, const SfxItemSet& _rCoreAttrs); + virtual ~OConnectionHelper() override; + + OUString m_eType; // the type can't be changed in this class, so we hold it as member. + // setting/retrieving the current connection URL + // necessary because for some types, the URL must be decoded for display purposes + ::dbaccess::ODsnTypeCollection* m_pCollection; /// the DSN type collection instance + + std::unique_ptr 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( const OUString& _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(const OUString& _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( const OUString& _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( const OUString& _rURL, bool _bPrefix ); + void implUpdateURLDependentStates() const; + }; + + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_CONNECTIONHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionPage.cxx b/dbaccess/source/ui/dlg/ConnectionPage.cxx new file mode 100644 index 000000000..5082abf9e --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionPage.cxx @@ -0,0 +1,283 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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( !m_xJavaDriver->get_text().trim().isEmpty() ); + m_xFL3->set_visible(bEnableJDBC); + + checkTestConnection(); + + m_xUserName->save_value(); + m_xConnectionURL->save_value(); + m_xJavaDriver->save_value(); + m_xPasswordRequired->save_state(); + } + + bool OConnectionTabPage::FillItemSet(SfxItemSet* _rSet) + { + bool bChangedSomething = false; + + if (m_xUserName->get_value_changed_from_saved()) + { + _rSet->Put(SfxStringItem(DSID_USER, m_xUserName->get_text())); + _rSet->Put(SfxStringItem(DSID_PASSWORD, OUString())); + bChangedSomething = true; + } + + fillBool(*_rSet,m_xPasswordRequired.get(),DSID_PASSWORDREQUIRED,false, bChangedSomething); + + if ( m_pCollection->determineType(m_eType) == ::dbaccess::DST_JDBC ) + { + fillString(*_rSet,m_xJavaDriver.get(), DSID_JDBCDRIVERCLASS, bChangedSomething); + } + + fillString(*_rSet,m_xConnectionURL.get(), DSID_CONNECTURL, bChangedSomething); + + return bChangedSomething; + } + IMPL_LINK_NOARG(OConnectionTabPage, OnTestJavaClickHdl, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + bool bSuccess = false; +#if HAVE_FEATURE_JAVA + try + { + if ( !m_xJavaDriver->get_text().trim().isEmpty() ) + { + ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() ); + m_xJavaDriver->set_text(m_xJavaDriver->get_text().trim()); // fdo#68341 + bSuccess = ::connectivity::existsJavaClassByName(xJVM,m_xJavaDriver->get_text().trim()); + } + } + catch(Exception&) + { + } +#endif + + const char* pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS; + const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error; + OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt); + aMsg.run(); + } + bool OConnectionTabPage::checkTestConnection() + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + bool bEnableTestConnection = !m_xConnectionURL->get_visible() || !m_xConnectionURL->GetTextNoPrefix().isEmpty(); + if ( m_pCollection->determineType(m_eType) == ::dbaccess::DST_JDBC ) + bEnableTestConnection = bEnableTestConnection && (!m_xJavaDriver->get_text().trim().isEmpty()); + m_xTestConnection->set_sensitive(bEnableTestConnection); + return true; + } + IMPL_LINK(OConnectionTabPage, OnEditModified, weld::Entry&, rEdit, void) + { + if (&rEdit == m_xJavaDriver.get()) + m_xTestJavaDriver->set_sensitive( !m_xJavaDriver->get_text().trim().isEmpty() ); + + checkTestConnection(); + // tell the listener we were modified + callModifiedHdl(); + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionPage.hxx b/dbaccess/source/ui/dlg/ConnectionPage.hxx new file mode 100644 index 000000000..3b514f866 --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionPage.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_CONNECTIONPAGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_CONNECTIONPAGE_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_CONNECTIONPAGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionPageSetup.cxx b/dbaccess/source/ui/dlg/ConnectionPageSetup.cxx new file mode 100644 index 000000000..bee1b1f11 --- /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, nullptr, nullptr, STR_COMMONURL); + } + + OConnectionTabPageSetup::OConnectionTabPageSetup(weld::Container* pPage, weld::DialogController* pController, const OUString& _rUIXMLDescription, const OString& _rId, const SfxItemSet& _rCoreAttrs, const char* pHelpTextResId, const char* pHeaderResId, const char* pUrlResId) + : OConnectionHelper(pPage, pController, _rUIXMLDescription, _rId, _rCoreAttrs) + , m_xHelpText(m_xBuilder->weld_label("helptext")) + , m_xHeaderText(m_xBuilder->weld_label("header")) + { + + if (pHelpTextResId != nullptr) + { + OUString sHelpText = DBA_RES(pHelpTextResId); + m_xHelpText->set_label(sHelpText); + } + else + m_xHelpText->hide(); + + if (pHeaderResId != nullptr) + m_xHeaderText->set_label(DBA_RES(pHeaderResId)); + + if (pUrlResId != nullptr) + { + OUString sLabelText = DBA_RES(pUrlResId); + m_xFT_Connection->set_label(sLabelText); + } + else + m_xFT_Connection->hide(); + + m_xConnectionURL->connect_changed(LINK(this, OConnectionTabPageSetup, OnEditModified)); + + SetRoadmapStateValue(false); + } + + OConnectionTabPageSetup::~OConnectionTabPageSetup() + { + } + + void OConnectionTabPageSetup::implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) + { + m_eType = m_pAdminDialog->getDatasourceType(_rSet); + // special handling for oracle, this can only happen + // if the user enters the same url as used for Oracle and we are on the JDBC path + //! TODO + //if ( ::dbaccess::DST_ORACLE_JDBC == m_eType ) + // m_eType = ::dbaccess::DST_JDBC; + if(m_pCollection->determineType(m_eType) == ::dbaccess::DST_POSTGRES){ + SetRoadmapStateValue(true); + } + + OConnectionHelper::implInitControls(_rSet, _bSaveValue); + + //! TODO + //if ( m_eType >= ::dbaccess::DST_USERDEFINE1 ) + //{ + // OUString sDisplayName = m_pCollection->getTypeDisplayName(m_eType); + // FixedText* ppTextControls[] ={&m_aFT_Connection}; + // for (size_t i = 0; i < sizeof(ppTextControls)/sizeof(ppTextControls[0]); ++i) + // { + // ppTextControls[i]->SetText(sDisplayName); + // } + //} + + callModifiedHdl(); + } + + bool OConnectionTabPageSetup::commitPage( ::vcl::WizardTypes::CommitPageReason /*_eReason*/ ) + { + return commitURL(); + } + + bool OConnectionTabPageSetup::FillItemSet(SfxItemSet* _rSet) + { + bool bChangedSomething = false; + fillString(*_rSet,m_xConnectionURL.get(), DSID_CONNECTURL, bChangedSomething); + return bChangedSomething; + } + + bool OConnectionTabPageSetup::checkTestConnection() + { + if ( m_pCollection->determineType(m_eType) == ::dbaccess::DST_POSTGRES ) + return true; + return !m_xConnectionURL->get_visible() || !m_xConnectionURL->GetTextNoPrefix().isEmpty(); + } + + IMPL_LINK_NOARG(OConnectionTabPageSetup, OnEditModified, weld::Entry&, void) + { + SetRoadmapStateValue(checkTestConnection()); + callModifiedHdl(); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/ConnectionPageSetup.hxx b/dbaccess/source/ui/dlg/ConnectionPageSetup.hxx new file mode 100644 index 000000000..f7cfe37ad --- /dev/null +++ b/dbaccess/source/ui/dlg/ConnectionPageSetup.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_CONNECTIONPAGESETUP_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_CONNECTIONPAGESETUP_HXX +#include "ConnectionHelper.hxx" + +#include "adminpages.hxx" + +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 OString& _rId, const SfxItemSet& _rCoreAttrs, const char* pHelpTextResId, const char* pHeaderResId, const char* 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 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx b/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx new file mode 100644 index 000000000..9c8d0fdd8 --- /dev/null +++ b/dbaccess/source/ui/dlg/DBSetupConnectionPages.cxx @@ -0,0 +1,786 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#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 + +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( "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::ToggleButton&, 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, const char* pDefaultPortResId, const char* pHelpTextResId, const char* pHeaderTextResId, const char* 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 ( m_xETDriverClass->get_text().trim().isEmpty() ) + { + m_xETDriverClass->set_text(m_sDefaultJdbcDriverName); + m_xETDriverClass->save_value(); + } + callModifiedHdl(); + + bool bRoadmapState = ((!m_xETDatabasename->get_text().isEmpty() ) && (!m_xETHostname->get_text().isEmpty()) && (!m_xNFPortNumber->get_text().isEmpty() ) && ( !m_xETDriverClass->get_text().isEmpty() )); + SetRoadmapStateValue(bRoadmapState); + } + + IMPL_LINK_NOARG(OGeneralSpecialJDBCConnectionPageSetup, OnTestJavaClickHdl, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + + bool bSuccess = false; +#if HAVE_FEATURE_JAVA + try + { + if ( !m_xETDriverClass->get_text().trim().isEmpty() ) + { +// TODO change jvmaccess + ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() ); + m_xETDriverClass->set_text(m_xETDriverClass->get_text().trim()); // fdo#68341 + bSuccess = ::connectivity::existsJavaClassByName(xJVM,m_xETDriverClass->get_text()); + } + } + catch(css::uno::Exception&) + { + } +#endif + const char *pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS; + const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error; + OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt); + aMsg.run(); + } + + void OGeneralSpecialJDBCConnectionPageSetup::callModifiedHdl(weld::Widget* pControl) + { + if (pControl == m_xETDriverClass.get()) + m_xPBTestJavaDriver->set_sensitive( !m_xETDriverClass->get_text().trim().isEmpty() ); + bool bRoadmapState = ((!m_xETDatabasename->get_text().isEmpty() ) && ( !m_xETHostname->get_text().isEmpty() ) && (!m_xNFPortNumber->get_text().isEmpty() ) && ( !m_xETDriverClass->get_text().trim().isEmpty() )); + SetRoadmapStateValue(bRoadmapState); + OGenericAdministrationPage::callModifiedHdl(); + } + + std::unique_ptr OJDBCConnectionPageSetup::CreateJDBCTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rAttrSet) + { + return std::make_unique(pPage, pController, _rAttrSet); + } + + // OMySQLJDBCConnectionPageSetup + OJDBCConnectionPageSetup::OJDBCConnectionPageSetup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OConnectionTabPageSetup(pPage, pController, "dbaccess/ui/jdbcconnectionpage.ui", "JDBCConnectionPage", rCoreAttrs, + STR_JDBC_HELPTEXT, STR_JDBC_HEADERTEXT, STR_COMMONURL) + , m_xFTDriverClass(m_xBuilder->weld_label("jdbcLabel")) + , m_xETDriverClass(m_xBuilder->weld_entry("jdbcEntry")) + , m_xPBTestJavaDriver(m_xBuilder->weld_button("jdbcButton")) + { + m_xETDriverClass->connect_changed(LINK(this, OJDBCConnectionPageSetup, OnEditModified)); + m_xPBTestJavaDriver->connect_clicked(LINK(this,OJDBCConnectionPageSetup,OnTestJavaClickHdl)); + } + + OJDBCConnectionPageSetup::~OJDBCConnectionPageSetup() + { + } + + void OJDBCConnectionPageSetup::fillControls(std::vector< std::unique_ptr >& _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 + const char* 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::ToggleButton&, rBox, void) + { + m_xCBStartTableWizard->set_sensitive(rBox.get_sensitive() && rBox.get_active()); + } +} + +// namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx b/dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx new file mode 100644 index 000000000..057e7e584 --- /dev/null +++ b/dbaccess/source/ui/dlg/DBSetupConnectionPages.hxx @@ -0,0 +1,273 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_DLG_DBSETUPCONNECTIONPAGES_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_DBSETUPCONNECTIONPAGES_HXX + +#include "ConnectionPageSetup.hxx" + +#include "adminpages.hxx" +#include "admincontrols.hxx" +#include "TextConnectionHelper.hxx" + +namespace dbaui +{ + class ODbTypeWizDialogSetup; + + // OSpreadSheetConnectionPageSetup + class OSpreadSheetConnectionPageSetup final : public OConnectionTabPageSetup + { + public: + virtual bool FillItemSet ( SfxItemSet* _rCoreAttrs ) override; + static std::unique_ptr 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 + , const char* pDefaultPortResId + , const char* pHelpTextResId + , const char* pHeaderTextResId + , const char* 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; + sal_uInt16 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::ToggleButton&, void); + }; + + // 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::ToggleButton&, 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 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/DbAdminImpl.cxx b/dbaccess/source/ui/dlg/DbAdminImpl.cxx new file mode 100644 index 000000000..2437196f1 --- /dev/null +++ b/dbaccess/source/ui/dlg/DbAdminImpl.cxx @@ -0,0 +1,1076 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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, "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, + makeAny(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, nullptr); + } + + 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 + + comphelper::OInteractionRequest* pRequest = new comphelper::OInteractionRequest(makeAny(aRequest)); + uno::Reference< XInteractionRequest > xRequest(pRequest); + + // 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.get()); + pRequest->addContinuation(pAuthenticate.get()); + + // handle the request + try + { + SolarMutexGuard aSolarGuard; + // release the mutex when calling the handler, it may need to lock the SolarMutex + xHandler->handle(xRequest); + } + 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, + makeAny(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], makeAny(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_JDBC: + // run through + default: + break; + } + if ( !sNewUrl.isEmpty() ) + sNewUrl = pCollection->getPrefix(eType) + sNewUrl; + else + sNewUrl = pUrlItem->GetValue(); + + return sNewUrl; +} + +namespace { + +struct PropertyValueLess +{ + bool operator() (const PropertyValue& x, const PropertyValue& y) const + { return x.Name < y.Name; } // construct prevents a MSVC6 warning +}; + +} + +typedef std::set 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&) { } + + const OUString sUrlProp("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(makeAny(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, makeAny(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, makeAny(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, makeAny(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; + } + + OString aReturn( aString.getStr(), aString.getLength(), RTL_TEXTENCODING_ASCII_US ); + return aReturn; +} +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( _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!"); + + sal_uInt16 nPortNumberId = 0; + sal_Int32 nPortNumber = -1; + OUString sNewHostName; + OUString sUrlPart; + + pCollection->extractHostNamePort(pUrlItem->GetValue(),sUrlPart,sNewHostName,nPortNumber); + const ::dbaccess::DATASOURCE_TYPE eTy = pCollection->determineType(eType); + + switch( eTy ) + { + case ::dbaccess::DST_MYSQL_NATIVE: + case ::dbaccess::DST_MYSQL_JDBC: + nPortNumberId = DSID_MYSQL_PORTNUMBER; + break; + case ::dbaccess::DST_ORACLE_JDBC: + nPortNumberId = DSID_ORACLE_PORTNUMBER; + break; + case ::dbaccess::DST_LDAP: + nPortNumberId = DSID_CONN_LDAP_PORTNUMBER; + break; + default: + break; + } + + if ( !sUrlPart.isEmpty() ) + { + if ( eTy == ::dbaccess::DST_MYSQL_NATIVE ) + { + _rDest.Put( SfxStringItem( DSID_DATABASENAME, sUrlPart ) ); + } + else + { + OUString sNewUrl = pCollection->getPrefix(eType) + sUrlPart; + _rDest.Put( SfxStringItem( DSID_CONNECTURL, sNewUrl ) ); + } + } + + if ( !sNewHostName.isEmpty() ) + _rDest.Put(SfxStringItem(DSID_CONN_HOSTNAME, sNewHostName)); + + if ( nPortNumber != -1 && nPortNumberId != 0 ) + _rDest.Put(SfxInt32Item(nPortNumberId, nPortNumber)); + +} + +bool ODbDataSourceAdministrationHelper::saveChanges(const SfxItemSet& _rSource) +{ + // put the remembered settings into the property set + Reference 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 000000000..c7fbcdc6d --- /dev/null +++ b/dbaccess/source/ui/dlg/DbAdminImpl.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_DBADMINIMPL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_DBADMINIMPL_HXX + +#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, + const OUString& _sOldURLPrefix, + const OUString& _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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_DBADMINIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/DriverSettings.hxx b/dbaccess/source/ui/dlg/DriverSettings.hxx new file mode 100644 index 000000000..3fc4e9792 --- /dev/null +++ b/dbaccess/source/ui/dlg/DriverSettings.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_DRIVERSETTINGS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_DRIVERSETTINGS_HXX + +#include + +class SfxTabPage; +namespace vcl { class Window; } +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 ); + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_DRIVERSETTINGS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx b/dbaccess/source/ui/dlg/QueryPropertiesDialog.cxx new file mode 100644 index 000000000..41ed0e867 --- /dev/null +++ b/dbaccess/source/ui/dlg/QueryPropertiesDialog.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/. + */ + +#include +#include +#include + +#define ALL_STRING DBA_RES(STR_QUERY_LIMIT_ALL) +#define ALL_INT -1 + +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(ALL_INT), ALL_STRING); + /// Default values + sal_Int64 const aDefLimitAry[] = + { + 5, + 10, + 20, + 50 + }; + for (auto a : aDefLimitAry) + m_xLB_Limit->append(OUString::number(a), OUString::number(a)); + OUString sInitial = OUString::number(nLimit); + auto nPos = m_xLB_Limit->find_id(sInitial); + if (nPos != -1) + m_xLB_Limit->set_active(nPos); + else + m_xLB_Limit->set_entry_text(OUString::number(nLimit)); +} + +sal_Int64 QueryPropertiesDialog::getLimit() const +{ + OUString sSelectedId = m_xLB_Limit->get_active_id(); + if (!sSelectedId.isEmpty()) + return sSelectedId.toInt64(); + return m_xLB_Limit->get_active_text().toInt64(); +} + +QueryPropertiesDialog::~QueryPropertiesDialog() +{ +} + +} ///dbaui namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/RelationDlg.cxx b/dbaccess/source/ui/dlg/RelationDlg.cxx new file mode 100644 index 000000000..cc449d9b7 --- /dev/null +++ b/dbaccess/source/ui/dlg/RelationDlg.cxx @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#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 000000000..52babf2b1 --- /dev/null +++ b/dbaccess/source/ui/dlg/TablesSingleDlg.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#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(); +} + +OUString OTableSubscriptionDialog::getConnectionURL() const +{ + return m_pImpl->getConnectionURL(); +} + +Reference< XPropertySet > const & OTableSubscriptionDialog::getCurrentDataSource() +{ + return m_pImpl->getCurrentDataSource(); +} + +const SfxItemSet* OTableSubscriptionDialog::getOutputSet() const +{ + return m_pOutSet.get(); +} + +SfxItemSet* OTableSubscriptionDialog::getWriteOutputSet() +{ + return m_pOutSet.get(); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/TextConnectionHelper.cxx b/dbaccess/source/ui/dlg/TextConnectionHelper.cxx new file mode 100644 index 000000000..bacc0f7cb --- /dev/null +++ b/dbaccess/source/ui/dlg/TextConnectionHelper.cxx @@ -0,0 +1,391 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +namespace +{ + +OUString lcl_getListEntry(const OUString& rStr, sal_Int32& rIdx) +{ + const OUString sTkn {rStr.getToken( 0, '\t', rIdx )}; + if (rIdx>=0) + { + rIdx = rStr.indexOf('\t', rIdx); + if (rIdx>=0 && ++rIdx>=rStr.getLength()) + rIdx = -1; + } + return sTkn; +} + +} + +namespace dbaui +{ + + OTextConnectionHelper::OTextConnectionHelper(weld::Widget* pParent, const short _nAvailableSections) + : m_aFieldSeparatorList (DBA_RES(STR_AUTOFIELDSEPARATORLIST)) + , m_aTextSeparatorList (STR_AUTOTEXTSEPARATORLIST) + , m_aTextNone (DBA_RES(STR_AUTOTEXT_FIELD_SEP_NONE)) + , m_nAvailableSections( _nAvailableSections ) + , m_xBuilder(Application::CreateBuilder(pParent, "dbaccess/ui/textpage.ui")) + , m_xContainer(m_xBuilder->weld_widget("TextPage")) + , m_xExtensionHeader(m_xBuilder->weld_widget("extensionframe")) + , m_xAccessTextFiles(m_xBuilder->weld_radio_button("textfile")) + , m_xAccessCSVFiles(m_xBuilder->weld_radio_button("csvfile")) + , m_xAccessOtherFiles(m_xBuilder->weld_radio_button("custom")) + , m_xOwnExtension(m_xBuilder->weld_entry("extension")) + , m_xExtensionExample(m_xBuilder->weld_label("example")) + , m_xFormatHeader(m_xBuilder->weld_widget("formatframe")) + , m_xFieldSeparatorLabel(m_xBuilder->weld_label("fieldlabel")) + , m_xFieldSeparator(m_xBuilder->weld_combo_box("fieldseparator")) + , m_xTextSeparatorLabel(m_xBuilder->weld_label("textlabel")) + , m_xTextSeparator(m_xBuilder->weld_combo_box("textseparator")) + , m_xDecimalSeparatorLabel(m_xBuilder->weld_label("decimallabel")) + , m_xDecimalSeparator(m_xBuilder->weld_combo_box("decimalseparator")) + , m_xThousandsSeparatorLabel(m_xBuilder->weld_label("thousandslabel")) + , m_xThousandsSeparator(m_xBuilder->weld_combo_box("thousandsseparator")) + , m_xRowHeader(m_xBuilder->weld_check_button("containsheaders")) + , m_xCharSetHeader(m_xBuilder->weld_widget("charsetframe")) + , m_xCharSetLabel(m_xBuilder->weld_label("charsetlabel")) + , m_xCharSet(new CharSetListBox(m_xBuilder->weld_combo_box("charset"))) + { + for(sal_Int32 nIdx {0}; nIdx>=0;) + m_xFieldSeparator->append_text( lcl_getListEntry(m_aFieldSeparatorList, nIdx) ); + + for(sal_Int32 nIdx {0}; nIdx>=0;) + m_xTextSeparator->append_text( lcl_getListEntry(m_aTextSeparatorList, nIdx) ); + m_xTextSeparator->append_text(m_aTextNone); + + m_xOwnExtension->connect_changed(LINK(this, OTextConnectionHelper, OnEditModified)); + m_xAccessTextFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl)); + m_xAccessCSVFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl)); + m_xAccessOtherFiles->connect_toggled(LINK(this, OTextConnectionHelper, OnSetExtensionHdl)); + m_xAccessCSVFiles->set_active(true); + + struct SectionDescriptor + { + short nFlag; + weld::Widget* pFrame; + } aSections[] = { + { TC_EXTENSION, m_xExtensionHeader.get() }, + { TC_SEPARATORS, m_xFormatHeader.get() }, + { TC_HEADER, m_xRowHeader.get() }, + { TC_CHARSET, m_xCharSetHeader.get() }, + { 0, nullptr } + }; + + for ( size_t section=0; section < SAL_N_ELEMENTS( aSections ) - 1; ++section ) + { + if ( ( m_nAvailableSections & aSections[section].nFlag ) != 0 ) + { + // the section is visible, no need to do anything here + continue; + } + + // hide all elements from this section + aSections[section].pFrame->hide(); + } + + m_xContainer->show(); + } + + IMPL_LINK_NOARG(OTextConnectionHelper, OnEditModified, weld::Entry&, void) + { + m_aGetExtensionHandler.Call(this); + } + + IMPL_LINK_NOARG(OTextConnectionHelper, OnSetExtensionHdl, weld::ToggleButton&, 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, const OUString& rList) + { + sal_Unicode const nTok = '\t'; + int nPos(rBox.find_text(rBox.get_active_text())); + + if (nPos == -1) + return rBox.get_active_text().copy(0); + + if ( !( m_xTextSeparator.get() == &rBox && nPos == (rBox.get_count()-1) ) ) + return OUString( + static_cast< sal_Unicode >( rList.getToken((nPos*2)+1, nTok ).toInt32() )); + // somewhat strange ... translates for instance an "32" into " " + return OUString(); + } + + void OTextConnectionHelper::SetSeparator( weld::ComboBox& rBox, const OUString& 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(rList.getToken(1, '\t', nIdx).toInt32()) == nVal) + { + rBox.set_entry_text(rList.getToken(0, '\t', nPrevIdx)); + return; + } + } + rBox.set_entry_text( rVal ); + } + else if ( m_xTextSeparator.get() == &rBox && rVal.isEmpty() ) + rBox.set_entry_text(m_aTextNone); + else + rBox.set_entry_text(rVal.copy(0, 1)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/TextConnectionHelper.hxx b/dbaccess/source/ui/dlg/TextConnectionHelper.hxx new file mode 100644 index 000000000..e002c77e8 --- /dev/null +++ b/dbaccess/source/ui/dlg/TextConnectionHelper.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_TEXTCONNECTIONHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_TEXTCONNECTIONHELPER_HXX + +#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::ToggleButton&, void); + DECL_LINK(OnEditModified, weld::Entry&, void); + + OUString GetSeparator(const weld::ComboBox& rBox, const OUString& rList); + void SetSeparator(weld::ComboBox& rBox, const OUString& 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_TEXTCONNECTIONHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/UserAdmin.cxx b/dbaccess/source/ui/dlg/UserAdmin.cxx new file mode 100644 index 000000000..3e63f9424 --- /dev/null +++ b/dbaccess/source/ui/dlg/UserAdmin.cxx @@ -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 . + */ + +#include "UserAdmin.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::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 ucbhelper; +using namespace comphelper; + +namespace { + +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,const OUString& rUserName); + + OUString GetOldPassword() const { return m_xEDOldPassword->get_text(); } + OUString GetNewPassword() const { return m_xEDPassword->get_text(); } +}; + +} + +OPasswordDialog::OPasswordDialog(weld::Window* _pParent,const OUString& 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) + , m_xUSER(m_xBuilder->weld_combo_box("user")) + , m_xNEWUSER(m_xBuilder->weld_button("add")) + , m_xCHANGEPWD(m_xBuilder->weld_button("changepass")) + , m_xDELETEUSER(m_xBuilder->weld_button("delete")) + , m_xTable(m_xBuilder->weld_container("table")) + , m_xTableCtrlParent(m_xTable->CreateChildFrame()) + , m_xTableCtrl(VclPtr::Create(m_xTableCtrlParent)) +{ + m_xTableCtrl->Show(); + + m_xUSER->connect_changed(LINK(this, OUserAdmin, ListDblClickHdl)); + m_xNEWUSER->connect_clicked(LINK(this, OUserAdmin, UserHdl)); + m_xCHANGEPWD->connect_clicked(LINK(this, OUserAdmin, UserHdl)); + m_xDELETEUSER->connect_clicked(LINK(this, OUserAdmin, UserHdl)); +} + +OUserAdmin::~OUserAdmin() +{ + m_xConnection = nullptr; + m_xTableCtrl.disposeAndClear(); + m_xTableCtrlParent->dispose(); + m_xTableCtrlParent.clear(); +} + +void OUserAdmin::FillUserNames() +{ + if(m_xConnection.is()) + { + m_xUSER->clear(); + + Reference 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); + m_xNEWUSER->set_sensitive(xAppend.is()); + Reference xDrop(m_xUsers,UNO_QUERY); + m_xDELETEUSER->set_sensitive(xDrop.is()); + + m_xCHANGEPWD->set_sensitive(m_xUsers.is()); + m_xTableCtrl->Enable(m_xUsers.is()); +} + +std::unique_ptr OUserAdmin::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* _rAttrSet ) +{ + return std::make_unique( pPage, pController, *_rAttrSet ); +} + +IMPL_LINK(OUserAdmin, UserHdl, weld::Button&, rButton, void) +{ + try + { + if (&rButton == m_xNEWUSER.get()) + { + SfxPasswordDialog aPwdDlg(GetFrameWeld()); + aPwdDlg.ShowExtras(SfxShowExtras::ALL); + if (aPwdDlg.run()) + { + Reference xUserFactory(m_xUsers,UNO_QUERY); + Reference xNewUser = xUserFactory->createDataDescriptor(); + if(xNewUser.is()) + { + xNewUser->setPropertyValue(PROPERTY_NAME,makeAny(aPwdDlg.GetUser())); + xNewUser->setPropertyValue(PROPERTY_PASSWORD,makeAny(aPwdDlg.GetPassword())); + Reference xAppend(m_xUsers,UNO_QUERY); + if(xAppend.is()) + xAppend->appendByDescriptor(xNewUser); + } + } + } + else if (&rButton == m_xCHANGEPWD.get()) + { + OUString sName = GetUser(); + + if(m_xUsers->hasByName(sName)) + { + Reference xUser; + m_xUsers->getByName(sName) >>= xUser; + if(xUser.is()) + { + OUString sNewPassword,sOldPassword; + OPasswordDialog aDlg(GetFrameWeld(), sName); + if (aDlg.run() == RET_OK) + { + sNewPassword = aDlg.GetNewPassword(); + sOldPassword = aDlg.GetOldPassword(); + + if(!sNewPassword.isEmpty()) + xUser->changePassword(sOldPassword,sNewPassword); + } + } + } + } + else + {// delete user + if(m_xUsers.is() && m_xUsers->hasByName(GetUser())) + { + Reference xDrop(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()); + } + } + } + FillUserNames(); + } + catch(const SQLException& e) + { + ::dbtools::showError(::dbtools::SQLExceptionInfo(e), GetDialogController()->getDialog()->GetXWindow(), m_xORB); + } + catch(Exception& ) + { + } +} + +IMPL_LINK_NOARG(OUserAdmin, ListDblClickHdl, weld::ComboBox&, void) +{ + m_xTableCtrl->setUserName(GetUser()); + m_xTableCtrl->UpdateTables(); + m_xTableCtrl->DeactivateCell(); + m_xTableCtrl->ActivateCell(m_xTableCtrl->GetCurRow(),m_xTableCtrl->GetCurColumnId()); +} + +OUString OUserAdmin::GetUser() const +{ + return m_xUSER->get_active_text(); +} + +void OUserAdmin::fillControls(std::vector< std::unique_ptr >& /*_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 000000000..09098e30a --- /dev/null +++ b/dbaccess/source/ui/dlg/UserAdmin.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_USERADMIN_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_USERADMIN_HXX + +#include +#include "adminpages.hxx" + +namespace com::sun::star { + namespace sdbc { + class XConnection; + } +} + +namespace dbaui +{ + +class OUserAdmin final : public OGenericAdministrationPage +{ + std::unique_ptr m_xUSER; + std::unique_ptr m_xNEWUSER; + std::unique_ptr m_xCHANGEPWD; + std::unique_ptr m_xDELETEUSER; + 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(UserHdl, weld::Button&, 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; +}; + +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_USERADMIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/UserAdminDlg.cxx b/dbaccess/source/ui/dlg/UserAdminDlg.cxx new file mode 100644 index 000000000..ec44c3399 --- /dev/null +++ b/dbaccess/source/ui/dlg/UserAdminDlg.cxx @@ -0,0 +1,162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 OString& 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 000000000..88a3bdc14 --- /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::ToggleButton&, 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 000000000..219f93f0e --- /dev/null +++ b/dbaccess/source/ui/dlg/admincontrols.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_ADMINCONTROLS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_ADMINCONTROLS_HXX + +#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::ToggleButton&, 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_ADMINCONTROLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/adminpages.cxx b/dbaccess/source/ui/dlg/adminpages.cxx new file mode 100644 index 000000000..4dbdb3d6a --- /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 OString& rId, const SfxItemSet& rAttrSet) + : SfxTabPage(pPage, pController, rUIXMLDescription, rId, &rAttrSet) + , m_abEnableRoadmap(false) + , m_pAdminDialog(nullptr) + , m_pItemSetHelper(nullptr) + { + SetExchangeSupport(); + + m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * WIZARD_PAGE_X, + m_xContainer->get_text_height() * WIZARD_PAGE_Y); + } + + DeactivateRC OGenericAdministrationPage::DeactivatePage(SfxItemSet* _pSet) + { + if (_pSet) + { + if (!prepareLeave()) + return DeactivateRC::KeepPage; + FillItemSet(_pSet); + } + + return DeactivateRC::LeavePage; + } + + void OGenericAdministrationPage::Reset(const SfxItemSet* _rCoreAttrs) + { + implInitControls(*_rCoreAttrs, false); + } + + void OGenericAdministrationPage::Activate() + { + BuilderPage::Activate(); + OSL_ENSURE(m_pItemSetHelper,"NO ItemSetHelper set!"); + if ( m_pItemSetHelper ) + ActivatePage(*m_pItemSetHelper->getOutputSet()); + } + + void OGenericAdministrationPage::ActivatePage(const SfxItemSet& _rSet) + { + implInitControls(_rSet, true); + } + + void OGenericAdministrationPage::getFlags(const SfxItemSet& _rSet, bool& _rValid, bool& _rReadonly) + { + const SfxBoolItem* pInvalid = _rSet.GetItem(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::ToggleButton&, 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, sal_uInt16 _nID, bool& _bChangedSomething) + { + if (pEdit && pEdit->get_value_changed_from_saved()) + { + _rSet.Put(SfxInt32Item(_nID, pEdit->get_value())); + _bChangedSomething = true; + } + } + void OGenericAdministrationPage::fillString(SfxItemSet& _rSet, const weld::Entry* pEdit, sal_uInt16 _nID, bool& _bChangedSomething) + { + if (pEdit && pEdit->get_value_changed_from_saved()) + { + _rSet.Put(SfxStringItem(_nID, pEdit->get_text())); + _bChangedSomething = true; + } + } + void OGenericAdministrationPage::fillString(SfxItemSet& _rSet, const dbaui::OConnectionURLEdit* pEdit, sal_uInt16 _nID, bool& _bChangedSomething) + { + if (pEdit && pEdit->get_value_changed_from_saved()) + { + _rSet.Put(SfxStringItem(_nID, pEdit->GetText())); + _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 000000000..cbdec09d0 --- /dev/null +++ b/dbaccess/source/ui/dlg/adminpages.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_ADMINPAGES_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_ADMINPAGES_HXX + +#include +#include +#include + +class NumericField; +class Edit; +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::ToggleButton* m_pSaveValue; + public: + explicit OSaveValueWidgetWrapper(weld::ToggleButton* _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 OString& 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,sal_uInt16 _nID, bool& _bChangedSomething); + + /** fills the String value into the item set when the value changed. + @param _rSet + The item set where to put the new value into. + @param _pEdit + The check box which is checked. + @param _nID + The id in the itemset to set with the new value. + @param _bChangedSomething + if something changed otherwise + */ + static void fillString(SfxItemSet& _rSet,const weld::Entry* pEdit,sal_uInt16 _nID, bool& _bChangedSomething); + static void fillString(SfxItemSet& _rSet,const dbaui::OConnectionURLEdit* pEdit,sal_uInt16 _nID, bool& _bChangedSomething); + + protected: + /** This link be used for controls where the tabpage does not need to take any special action when the control + is modified. The implementation just calls callModifiedHdl. + */ + DECL_LINK(OnControlModified, weld::Widget*, void); + DECL_LINK(OnControlEntryModifyHdl, weld::Entry&, void); + DECL_LINK(OnControlSpinButtonModifyHdl, weld::SpinButton&, void); + DECL_LINK(OnControlModifiedButtonClick, weld::ToggleButton&, void); + DECL_LINK(OnTestConnectionButtonClickHdl, weld::Button&, void); + }; +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_ADMINPAGES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/adodatalinks.cxx b/dbaccess/source/ui/dlg/adodatalinks.cxx new file mode 100644 index 000000000..fc129b2de --- /dev/null +++ b/dbaccess/source/ui/dlg/adodatalinks.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 . + */ + + +#if defined(_WIN32) +// LO/windows.h conflict +#undef WB_LEFT +#undef WB_RIGHT +#include + +#include + +#include +#include +#include + +#include "adodatalinks.hxx" + +namespace { + +OUString PromptNew(long hWnd) +{ + HRESULT hr; + IDataSourceLocator* dlPrompt = nullptr; + ADOConnection* piTmpConnection = nullptr; + BSTR _result=nullptr; + + // Initialize COM + ::CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED ); + + // Instantiate DataLinks object. + hr = CoCreateInstance( + CLSID_DataLinks, //clsid -- Data Links UI + nullptr, //pUnkOuter + CLSCTX_INPROC_SERVER, //dwClsContext + IID_IDataSourceLocator, //riid + reinterpret_cast(&dlPrompt) //ppvObj + ); + if( FAILED( hr ) ) + { + return OUString(); + } + + dlPrompt->put_hWnd(hWnd); + if( FAILED( hr ) ) + { + dlPrompt->Release( ); + return OUString(); + } + + // Prompt for connection information. + hr = dlPrompt->PromptNew(reinterpret_cast(&piTmpConnection)); + + if( FAILED( hr ) || !piTmpConnection ) + { + dlPrompt->Release( ); + return OUString(); + } + + hr = piTmpConnection->get_ConnectionString(&_result); + if( FAILED( hr ) ) + { + piTmpConnection->Release( ); + dlPrompt->Release( ); + return OUString(); + } + + piTmpConnection->Release( ); + dlPrompt->Release( ); + CoUninitialize(); + // Don't we need SysFreeString(_result)? + return o3tl::toU(_result); +} + +OUString PromptEdit(long hWnd, OUString const & connstr) +{ + HRESULT hr; + IDataSourceLocator* dlPrompt = nullptr; + ADOConnection* piTmpConnection = nullptr; + BSTR _result=nullptr; + + // Initialize COM + ::CoInitializeEx( nullptr, COINIT_APARTMENTTHREADED ); + + hr = CoCreateInstance(CLSID_CADOConnection, + nullptr, + CLSCTX_INPROC_SERVER, + IID_IADOConnection, + reinterpret_cast(&piTmpConnection)); + if( FAILED( hr ) ) + { + piTmpConnection->Release( ); + return connstr; + } + + + hr = piTmpConnection->put_ConnectionString( + const_cast(o3tl::toW(connstr.getStr()))); + if( FAILED( hr ) ) + { + piTmpConnection->Release( ); + return connstr; + } + + // Instantiate DataLinks object. + hr = CoCreateInstance( + CLSID_DataLinks, //clsid -- Data Links UI + nullptr, //pUnkOuter + CLSCTX_INPROC_SERVER, //dwClsContext + IID_IDataSourceLocator, //riid + reinterpret_cast(&dlPrompt) //ppvObj + ); + if( FAILED( hr ) ) + { + piTmpConnection->Release( ); + dlPrompt->Release( ); + return connstr; + } + + dlPrompt->put_hWnd(hWnd); + if( FAILED( hr ) ) + { + piTmpConnection->Release( ); + dlPrompt->Release( ); + return connstr; + } + + VARIANT_BOOL pbSuccess; + + // Prompt for connection information. + hr = dlPrompt->PromptEdit(reinterpret_cast(&piTmpConnection),&pbSuccess); + if( SUCCEEDED( hr ) && !pbSuccess ) //if user press cancel then sal_False == pbSuccess + { + piTmpConnection->Release( ); + dlPrompt->Release( ); + return connstr; + } + + if( FAILED( hr ) ) + { + // Prompt for new connection information. + piTmpConnection->Release( ); + piTmpConnection = nullptr; + hr = dlPrompt->PromptNew(reinterpret_cast(&piTmpConnection)); + if( FAILED( hr ) || !piTmpConnection ) + { + dlPrompt->Release( ); + return connstr; + } + } + + hr = piTmpConnection->get_ConnectionString(&_result); + if( FAILED( hr ) ) + { + piTmpConnection->Release( ); + dlPrompt->Release( ); + return connstr; + } + + piTmpConnection->Release( ); + dlPrompt->Release( ); + CoUninitialize(); + // Don't we need SysFreeString(_result)? + return o3tl::toU(_result); +} + +} + +OUString getAdoDatalink(long hWnd,OUString const & oldLink) +{ + OUString dataLink; + if (!oldLink.isEmpty()) + { + dataLink=PromptEdit(hWnd,oldLink); + } + else + dataLink=PromptNew(hWnd); + return dataLink; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/adodatalinks.hxx b/dbaccess/source/ui/dlg/adodatalinks.hxx new file mode 100644 index 000000000..d13203ad8 --- /dev/null +++ b/dbaccess/source/ui/dlg/adodatalinks.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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_DLG_ADODATALINKS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_ADODATALINKS_HXX + +#include + +OUString getAdoDatalink(long hWnd, OUString const& oldLink); +#endif +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/adtabdlg.cxx b/dbaccess/source/ui/dlg/adtabdlg.cxx new file mode 100644 index 000000000..35e29ed17 --- /dev/null +++ b/dbaccess/source/ui/dlg/adtabdlg.cxx @@ -0,0 +1,468 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +{ + TableTreeListBox& m_rTableList; + Reference< XConnection > m_xConnection; + ::rtl::Reference< comphelper::OContainerListenerAdapter> + m_pContainerListener; + bool m_bAllowViews; + +public: + TableListFacade( TableTreeListBox& _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) + aTables.erase(std::remove_if(aTables.begin(),aTables.end(), + [&aEqualFunctor, pViewBegin](const OUString& lhs) + { return aEqualFunctor(lhs, *pViewBegin); } ) + , aTables.end()); + sTables = Sequence< OUString>(aTables.data(), aTables.size()); + sViews = Sequence< OUString>(); + } + + m_rTableList.UpdateTableList( m_xConnection, sTables, sViews ); + + std::unique_ptr 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")) + , m_xTableList(new TableTreeListBox(m_xBuilder->weld_tree_view("tablelist"))) + , 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_clicked( LINK( this, OAddTableDlg, OnTypeSelected ) ); + m_xCaseQueries->connect_clicked( 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->DisableCheckButtons(); // do not show any buttons + 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::Button&, void ) +{ + if ( m_xCaseTables->get_active() ) + impl_switchTo( Tables ); + else + impl_switchTo( Queries ); +} + +void OAddTableDlg::OnClose() +{ + m_rContext.onWindowClosing(); +} + +bool OAddTableDlg::impl_isAddAllowed() +{ + return m_rContext.allowAddition(); +} + +OUString OAddTableDlg::getDialogTitleForContext( IAddTableDialogContext const & _rContext ) +{ + OUString sTitle; + + if ( _rContext.allowQueries() ) + sTitle = DBA_RES( STR_ADD_TABLE_OR_QUERY ); + else + sTitle = DBA_RES( STR_ADD_TABLES ); + + return sTitle; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/advancedsettings.cxx b/dbaccess/source/ui/dlg/advancedsettings.cxx new file mode 100644 index 000000000..6ec06a9db --- /dev/null +++ b/dbaccess/source/ui/dlg/advancedsettings.cxx @@ -0,0 +1,472 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#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 + OString sControlId; // the widget name of the control in the .ui + sal_uInt16 nItemId; // the ID of the item (in an SfxItemSet) which corresponds to this setting + bool bInvertedDisplay; // true if and only if the checkbox is checked when the item is sal_False, and vice versa + bool bOptionalBool; // type is OptionalBool + }; + + // SpecialSettingsPage + SpecialSettingsPage::SpecialSettingsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& _rCoreAttrs, const DataSourceMetaData& _rDSMeta) + : OGenericAdministrationPage(pPage, pController, "dbaccess/ui/specialsettingspage.ui", "SpecialSettingsPage", _rCoreAttrs) + , m_aBooleanSettings { + { m_xIsSQL92Check, "usesql92", DSID_SQL92CHECK, false, false }, + { m_xAppendTableAlias, "append", DSID_APPEND_TABLE_ALIAS, false, false }, + { m_xAsBeforeCorrelationName, "useas", DSID_AS_BEFORE_CORRNAME, false, false }, + { m_xEnableOuterJoin, "useoj", DSID_ENABLEOUTERJOIN, false, false }, + { m_xIgnoreDriverPrivileges, "ignoreprivs", DSID_IGNOREDRIVER_PRIV, false, false }, + { m_xParameterSubstitution, "replaceparams", DSID_PARAMETERNAMESUBST, false, false }, + { m_xSuppressVersionColumn, "displayver", DSID_SUPPRESSVERSIONCL, true, false }, + { m_xCatalog, "usecatalogname", DSID_CATALOG, false, false }, + { m_xSchema, "useschemaname", DSID_SCHEMA, false, false }, + { m_xIndexAppendix, "createindex", DSID_INDEXAPPENDIX, false, false }, + { m_xDosLineEnds, "eol", DSID_DOSLINEENDS, false, false }, + { m_xCheckRequiredFields, "inputchecks", DSID_CHECK_REQUIRED_FIELDS, false, false }, + { m_xIgnoreCurrency, "ignorecurrency", DSID_IGNORECURRENCY, false, false }, + { m_xEscapeDateTime, "useodbcliterals", DSID_ESCAPE_DATETIME, false, false }, + { m_xPrimaryKeySupport, "primarykeys", DSID_PRIMARY_KEY_SUPPORT, false, false }, + { m_xRespectDriverResultSetType, "resulttype", DSID_RESPECTRESULTSETTYPE, false, false } } + , m_bHasBooleanComparisonMode( _rDSMeta.getFeatureSet().has( DSID_BOOLEANCOMPARISON ) ) + , m_bHasMaxRowScan( _rDSMeta.getFeatureSet().has( DSID_MAX_ROW_SCAN ) ) + { + const FeatureSet& rFeatures( _rDSMeta.getFeatureSet() ); + // create all the check boxes for the boolean settings + for (auto & booleanSetting : m_aBooleanSettings) + { + sal_uInt16 nItemId = booleanSetting.nItemId; + if ( rFeatures.has( nItemId ) ) + { + // check whether this must be a tristate check box + const SfxPoolItem& rItem = _rCoreAttrs.Get(nItemId); + booleanSetting.bOptionalBool = dynamic_cast(&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::ToggleButton&, 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::ToggleButton&, 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 ) + { + 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_xAutoIncrementLabel(m_xBuilder->weld_label("statementft")) + , m_xAutoIncrement(m_xBuilder->weld_entry("statement")) + , m_xAutoRetrievingLabel(m_xBuilder->weld_label("queryft")) + , m_xAutoRetrieving(m_xBuilder->weld_entry("query")) + { + m_xAutoRetrievingEnabled->connect_toggled(LINK(this, GeneratedValuesPage, OnAutoToggleHdl)); + m_xAutoIncrement->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + m_xAutoRetrieving->connect_changed(LINK(this, OGenericAdministrationPage, OnControlEntryModifyHdl)); + } + + IMPL_LINK(GeneratedValuesPage, OnAutoToggleHdl, weld::ToggleButton&, 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 OString& 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 000000000..8efc86428 --- /dev/null +++ b/dbaccess/source/ui/dlg/advancedsettings.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_ADVANCEDSETTINGS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_ADVANCEDSETTINGS_HXX + +#include "adminpages.hxx" +#include +#include + +namespace dbaui +{ + struct BooleanSettingDesc; + typedef std::vector< BooleanSettingDesc > BooleanSettingDescs; + + // 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; + + BooleanSettingDescs m_aBooleanSettings; + + bool m_bHasBooleanComparisonMode; + bool m_bHasMaxRowScan; + + public: + DECL_LINK(OnToggleHdl, weld::ToggleButton&, void); + DECL_LINK(OnTriStateToggleHdl, weld::ToggleButton&, 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_xAutoIncrementLabel; + std::unique_ptr m_xAutoIncrement; + std::unique_ptr m_xAutoRetrievingLabel; + 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::ToggleButton&, 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; + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_ADVANCEDSETTINGS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dbadmin.cxx b/dbaccess/source/ui/dlg/dbadmin.cxx new file mode 100644 index 000000000..e37541bfd --- /dev/null +++ b/dbaccess/source/ui/dlg/dbadmin.cxx @@ -0,0 +1,432 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 OString& 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 OString& rPageId, const char* 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& rCollectionItem = dynamic_cast(*getOutputSet()->GetItem(DSID_TYPECOLLECTION)); + ::dbaccess::ODsnTypeCollection* pCollection = rCollectionItem.getCollection(); + ::dbaccess::DATASOURCE_TYPE eType = pCollection->determineType(getDatasourceType(*getOutputSet())); + + // and insert the new ones + switch ( eType ) + { + case ::dbaccess::DST_DBASE: + addDetailPage("dbase", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateDbase); + break; + + case ::dbaccess::DST_ADO: + addDetailPage("ado", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateAdo); + break; + + case ::dbaccess::DST_FLAT: + addDetailPage("text", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateText); + break; + + case ::dbaccess::DST_ODBC: + addDetailPage("odbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateODBC); + break; + + case ::dbaccess::DST_MYSQL_ODBC: + addDetailPage("mysqlodbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateMySQLODBC); + break; + + case ::dbaccess::DST_MYSQL_JDBC: + addDetailPage("mysqljdbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateMySQLJDBC); + break; + + case ::dbaccess::DST_ORACLE_JDBC: + addDetailPage("oraclejdbc", STR_PAGETITLE_ADVANCED, ODriversSettings::CreateOracleJDBC); + break; + + case ::dbaccess::DST_LDAP: + addDetailPage("ldap",STR_PAGETITLE_ADVANCED,ODriversSettings::CreateLDAP); + break; + case ::dbaccess::DST_USERDEFINE1: /// first user defined driver + case ::dbaccess::DST_USERDEFINE2: + case ::dbaccess::DST_USERDEFINE3: + case ::dbaccess::DST_USERDEFINE4: + case ::dbaccess::DST_USERDEFINE5: + case ::dbaccess::DST_USERDEFINE6: + case ::dbaccess::DST_USERDEFINE7: + case ::dbaccess::DST_USERDEFINE8: + case ::dbaccess::DST_USERDEFINE9: + case ::dbaccess::DST_USERDEFINE10: + { + OUString aTitle(DBA_RES(STR_PAGETITLE_ADVANCED)); + AddTabPage("user" + OString::number(eType - dbaccess::DST_USERDEFINE1 + 1), aTitle, ODriversSettings::CreateUser); + } + break; + default: + break; + } +} + +void ODbAdminDialog::impl_resetPages(const Reference< XPropertySet >& _rxDatasource) +{ + // the selection is valid if and only if we have a datasource now + GetInputSetImpl()->Put(SfxBoolItem(DSID_INVALID_SELECTION, !_rxDatasource.is())); + // (sal_False tells the tab pages to disable and reset all their controls, which is different + // from "just set them to readonly") + + // reset the pages + + // prevent flicker + m_xDialog->freeze(); + + // remove all items which relate to indirect properties from the input set + // (without this, the following may happen: select an arbitrary data source where some indirect properties + // are set. Select another data source of the same type, where the indirect props are not set (yet). Then, + // the indirect property values of the first ds are shown in the second ds ...) + const ODbDataSourceAdministrationHelper::MapInt2String& rMap = m_pImpl->getIndirectProperties(); + for (auto const& elem : rMap) + GetInputSetImpl()->ClearItem( static_cast(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& rCollectionItem = dynamic_cast(*getOutputSet()->GetItem(DSID_TYPECOLLECTION)); + ::dbaccess::ODsnTypeCollection* pCollection = rCollectionItem.getCollection(); + if ( pCollection->determineType(getDatasourceType( *m_xExampleSet )) == ::dbaccess::DST_MYSQL_NATIVE ) + { + OString sMySqlNative("mysqlnative"); + AddTabPage(sMySqlNative, DBA_RES(STR_PAGETITLE_CONNECTION), ODriversSettings::CreateMySQLNATIVE); + RemoveTabPage("advanced"); + m_sMainPageID = sMySqlNative; + } + + SetCurPageId(m_sMainPageID); + SfxTabPage* pConnectionPage = GetTabPage(m_sMainPageID); + if ( pConnectionPage ) + pConnectionPage->Reset(GetInputSetImpl()); + // if this is NULL, the page has not been created yet, which means we're called before the + // dialog was displayed (probably from inside the ctor) + + m_xDialog->thaw(); +} + +void ODbAdminDialog::setTitle(const OUString& rTitle) +{ + m_xDialog->set_title(rTitle); +} + +void ODbAdminDialog::enableConfirmSettings( bool ) {} + +void ODbAdminDialog::saveDatasource() +{ + PrepareLeaveCurrentPage(); +} + +ODbAdminDialog::ApplyResult ODbAdminDialog::implApplyChanges() +{ + if (!PrepareLeaveCurrentPage()) + { // the page did not allow us to leave + return AR_KEEP; + } + + if ( !m_pImpl->saveChanges(*m_xExampleSet) ) + return AR_KEEP; + + return AR_LEAVE_MODIFIED; +} + +void ODbAdminDialog::selectDataSource(const css::uno::Any& _aDataSourceName) +{ + impl_selectDataSource(_aDataSourceName); +} + +const SfxItemSet* ODbAdminDialog::getOutputSet() const +{ + return GetExampleSet(); +} + +SfxItemSet* ODbAdminDialog::getWriteOutputSet() +{ + return m_xExampleSet.get(); +} + +std::pair< Reference,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, SfxItemPool*& _rpPool, std::vector*& _rpDefaults, ::dbaccess::ODsnTypeCollection* _pTypeCollection) +{ + // just to be sure... + _rpSet = nullptr; + _rpPool = nullptr; + _rpDefaults = nullptr; + + const OUString sFilterAll( "%" ); + // create and initialize the defaults + _rpDefaults = new std::vector(DSID_LAST_ITEM_ID - DSID_FIRST_ITEM_ID + 1); + SfxPoolItem** pCounter = _rpDefaults->data(); // want to modify this without affecting the out param _rppDefaults + *pCounter++ = new SfxStringItem(DSID_NAME, OUString()); + *pCounter++ = new SfxStringItem(DSID_ORIGINALNAME, OUString()); + *pCounter++ = new SfxStringItem(DSID_CONNECTURL, OUString()); + *pCounter++ = new OStringListItem(DSID_TABLEFILTER, Sequence< OUString >(&sFilterAll, 1)); + *pCounter++ = new DbuTypeCollectionItem(DSID_TYPECOLLECTION, _pTypeCollection); + *pCounter++ = new SfxBoolItem(DSID_INVALID_SELECTION, false); + *pCounter++ = new SfxBoolItem(DSID_READONLY, false); + *pCounter++ = new SfxStringItem(DSID_USER, OUString()); + *pCounter++ = new SfxStringItem(DSID_PASSWORD, OUString()); + *pCounter++ = new SfxStringItem(DSID_ADDITIONALOPTIONS, OUString()); + *pCounter++ = new SfxStringItem(DSID_CHARSET, OUString()); + *pCounter++ = new SfxBoolItem(DSID_PASSWORDREQUIRED, false); + *pCounter++ = new SfxBoolItem(DSID_SHOWDELETEDROWS, false); + *pCounter++ = new SfxBoolItem(DSID_ALLOWLONGTABLENAMES, false); + *pCounter++ = new SfxStringItem(DSID_JDBCDRIVERCLASS, OUString()); + *pCounter++ = new SfxStringItem(DSID_FIELDDELIMITER, OUString(',')); + *pCounter++ = new SfxStringItem(DSID_TEXTDELIMITER, OUString('"')); + *pCounter++ = new SfxStringItem(DSID_DECIMALDELIMITER, OUString('.')); + *pCounter++ = new SfxStringItem(DSID_THOUSANDSDELIMITER, OUString()); + *pCounter++ = new SfxStringItem(DSID_TEXTFILEEXTENSION, "txt"); + *pCounter++ = new SfxBoolItem(DSID_TEXTFILEHEADER, true); + *pCounter++ = new SfxBoolItem(DSID_PARAMETERNAMESUBST, false); + *pCounter++ = new SfxInt32Item(DSID_CONN_PORTNUMBER, 8100); + *pCounter++ = new SfxBoolItem(DSID_SUPPRESSVERSIONCL, false); + *pCounter++ = new SfxBoolItem(DSID_CONN_SHUTSERVICE, false); + *pCounter++ = new SfxInt32Item(DSID_CONN_DATAINC, 20); + *pCounter++ = new SfxInt32Item(DSID_CONN_CACHESIZE, 20); + *pCounter++ = new SfxStringItem(DSID_CONN_CTRLUSER, OUString()); + *pCounter++ = new SfxStringItem(DSID_CONN_CTRLPWD, OUString()); + *pCounter++ = new SfxBoolItem(DSID_USECATALOG, false); + *pCounter++ = new SfxStringItem(DSID_CONN_HOSTNAME, OUString()); + *pCounter++ = new SfxStringItem(DSID_CONN_LDAP_BASEDN, OUString()); + *pCounter++ = new SfxInt32Item(DSID_CONN_LDAP_PORTNUMBER, 389); + *pCounter++ = new SfxInt32Item(DSID_CONN_LDAP_ROWCOUNT, 100); + *pCounter++ = new SfxBoolItem(DSID_SQL92CHECK, false); + *pCounter++ = new SfxStringItem(DSID_AUTOINCREMENTVALUE, OUString()); + *pCounter++ = new SfxStringItem(DSID_AUTORETRIEVEVALUE, OUString()); + *pCounter++ = new SfxBoolItem(DSID_AUTORETRIEVEENABLED, false); + *pCounter++ = new SfxBoolItem(DSID_APPEND_TABLE_ALIAS, false); + *pCounter++ = new SfxInt32Item(DSID_MYSQL_PORTNUMBER, 3306); + *pCounter++ = new SfxBoolItem(DSID_IGNOREDRIVER_PRIV, true); + *pCounter++ = new SfxInt32Item(DSID_BOOLEANCOMPARISON, 0); + *pCounter++ = new SfxInt32Item(DSID_ORACLE_PORTNUMBER, 1521); + *pCounter++ = new SfxBoolItem(DSID_ENABLEOUTERJOIN, true); + *pCounter++ = new SfxBoolItem(DSID_CATALOG, true); + *pCounter++ = new SfxBoolItem(DSID_SCHEMA, true); + *pCounter++ = new SfxBoolItem(DSID_INDEXAPPENDIX, true); + *pCounter++ = new SfxBoolItem(DSID_CONN_LDAP_USESSL, false); + *pCounter++ = new SfxStringItem(DSID_DOCUMENT_URL, OUString()); + *pCounter++ = new SfxBoolItem(DSID_DOSLINEENDS, false); + *pCounter++ = new SfxStringItem(DSID_DATABASENAME, OUString()); + *pCounter++ = new SfxBoolItem(DSID_AS_BEFORE_CORRNAME, false); + *pCounter++ = new SfxBoolItem(DSID_CHECK_REQUIRED_FIELDS, true); + *pCounter++ = new SfxBoolItem(DSID_IGNORECURRENCY, false); + *pCounter++ = new SfxStringItem(DSID_CONN_SOCKET, OUString()); + *pCounter++ = new SfxBoolItem(DSID_ESCAPE_DATETIME, true); + *pCounter++ = new SfxStringItem(DSID_NAMED_PIPE, OUString()); + *pCounter++ = new OptionalBoolItem( DSID_PRIMARY_KEY_SUPPORT ); + *pCounter++ = new SfxInt32Item(DSID_MAX_ROW_SCAN, 100); + *pCounter++ = new SfxBoolItem( DSID_RESPECTRESULTSETTYPE,false ); + + // create the pool + static SfxItemInfo const aItemInfos[DSID_LAST_ITEM_ID - DSID_FIRST_ITEM_ID + 1] = + { + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + {0,false}, + }; + + OSL_ENSURE(SAL_N_ELEMENTS(aItemInfos) == DSID_LAST_ITEM_ID,"Invalid Ids!"); + _rpPool = new SfxItemPool("DSAItemPool", DSID_FIRST_ITEM_ID, DSID_LAST_ITEM_ID, + aItemInfos, _rpDefaults); + _rpPool->FreezeIdRanges(); + + // and, finally, the set + _rpSet.reset(new SfxItemSet(*_rpPool)); +} + +void ODbAdminDialog::destroyItemSet(std::unique_ptr& _rpSet, SfxItemPool*& _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 + SfxItemPool::Free(_rpPool); + _rpPool = nullptr; + } + + // reset the defaults ptr + _rpDefaults = nullptr; + // no need to explicitly delete the defaults, this has been done by the ReleaseDefaults +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dbfindex.cxx b/dbaccess/source/ui/dlg/dbfindex.cxx new file mode 100644 index 000000000..84635980b --- /dev/null +++ b/dbaccess/source/ui/dlg/dbfindex.cxx @@ -0,0 +1,430 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "dbfindex.hxx" +#include +#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; + +const OString aGroupIdent("dBase III"); + + +ODbaseIndexDialog::ODbaseIndexDialog(weld::Window * pParent, const OUString& aDataSrcName) + : GenericDialogController(pParent, "dbaccess/ui/dbaseindexdialog.ui", "DBaseIndexDialog") + , m_aDSN(aDataSrcName) + , m_xPB_OK(m_xBuilder->weld_button("ok")) + , m_xCB_Tables(m_xBuilder->weld_combo_box("table")) + , m_xIndexes(m_xBuilder->weld_widget("frame")) + , m_xLB_TableIndexes(m_xBuilder->weld_tree_view("tableindex")) + , m_xLB_FreeIndexes(m_xBuilder->weld_tree_view("freeindex")) + , m_xAdd(m_xBuilder->weld_button("add")) + , m_xRemove(m_xBuilder->weld_button("remove")) + , m_xAddAll(m_xBuilder->weld_button("addall")) + , m_xRemoveAll(m_xBuilder->weld_button("removeall")) +{ + int nWidth = m_xLB_TableIndexes->get_approximate_digit_width() * 18; + int nHeight = m_xLB_TableIndexes->get_height_rows(10); + m_xLB_TableIndexes->set_size_request(nWidth, nHeight); + m_xLB_FreeIndexes->set_size_request(nWidth, nHeight); + + m_xCB_Tables->connect_changed( LINK(this, ODbaseIndexDialog, TableSelectHdl) ); + m_xAdd->connect_clicked( LINK(this, ODbaseIndexDialog, AddClickHdl) ); + m_xRemove->connect_clicked( LINK(this, ODbaseIndexDialog, RemoveClickHdl) ); + m_xAddAll->connect_clicked( LINK(this, ODbaseIndexDialog, AddAllClickHdl) ); + m_xRemoveAll->connect_clicked( LINK(this, ODbaseIndexDialog, RemoveAllClickHdl) ); + m_xPB_OK->connect_clicked( LINK(this, ODbaseIndexDialog, OKClickHdl) ); + + m_xLB_FreeIndexes->connect_changed( LINK(this, ODbaseIndexDialog, OnListEntrySelected) ); + m_xLB_TableIndexes->connect_changed( LINK(this, ODbaseIndexDialog, OnListEntrySelected) ); + + Init(); + SetCtrls(); +} + +ODbaseIndexDialog::~ODbaseIndexDialog() +{ +} + +void ODbaseIndexDialog::checkButtons() +{ + m_xAdd->set_sensitive(0 != m_xLB_FreeIndexes->count_selected_rows()); + m_xAddAll->set_sensitive(0 != m_xLB_FreeIndexes->n_children()); + + m_xRemove->set_sensitive(0 != m_xLB_TableIndexes->count_selected_rows()); + m_xRemoveAll->set_sensitive(0 != m_xLB_TableIndexes->n_children()); +} + +OTableIndex ODbaseIndexDialog::implRemoveIndex(const OUString& _rName, TableIndexList& _rList, weld::TreeView& _rDisplay, bool _bMustExist) +{ + OTableIndex aReturn; + + TableIndexList::iterator aSearch = std::find_if(_rList.begin(), _rList.end(), + [&_rName](const OTableIndex& rIndex) { return rIndex.GetIndexFileName() == _rName; }); + if (aSearch != _rList.end()) + { + sal_Int32 nPos = static_cast(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( const OUString& _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( const OUString& _rTableName, const OTableIndex& _rIndex) +{ + TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(), + [&] (const OTableInfo& arg) { return arg.aTableName == _rTableName; }); + + if (aTablePos == m_aTableInfoList.end()) + return; + + implInsertIndex(_rIndex, aTablePos->aIndexList, *m_xLB_TableIndexes); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, OKClickHdl, weld::Button&, void) +{ + // let all tables write their INF file + + for (auto const& tableInfo : m_aTableInfoList) + tableInfo.WriteInfFile(m_aDSN); + + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, AddClickHdl, weld::Button&, void) +{ + OUString aSelection = m_xLB_FreeIndexes->get_selected_text(); + OUString aTableName = m_xCB_Tables->get_active_text(); + OTableIndex aIndex = RemoveFreeIndex( aSelection, true ); + InsertTableIndex( aTableName, aIndex ); + + checkButtons(); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, RemoveClickHdl, weld::Button&, void) +{ + OUString aSelection = m_xLB_TableIndexes->get_selected_text(); + OUString aTableName = m_xCB_Tables->get_active_text(); + OTableIndex aIndex = RemoveTableIndex( aTableName, aSelection ); + InsertFreeIndex( aIndex ); + + checkButtons(); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, AddAllClickHdl, weld::Button&, void) +{ + const sal_Int32 nCnt = m_xLB_FreeIndexes->n_children(); + OUString aTableName = m_xCB_Tables->get_active_text(); + + for (sal_Int32 nPos = 0; nPos < nCnt; ++nPos) + InsertTableIndex(aTableName, RemoveFreeIndex(m_xLB_FreeIndexes->get_text(0), true)); + + checkButtons(); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, RemoveAllClickHdl, weld::Button&, void) +{ + const sal_Int32 nCnt = m_xLB_TableIndexes->n_children(); + OUString aTableName = m_xCB_Tables->get_active_text(); + + for (sal_Int32 nPos = 0; nPos < nCnt; ++nPos) + InsertFreeIndex(RemoveTableIndex(aTableName, m_xLB_TableIndexes->get_text(0))); + + checkButtons(); +} + +IMPL_LINK_NOARG(ODbaseIndexDialog, OnListEntrySelected, weld::TreeView&, void) +{ + checkButtons(); +} + +IMPL_LINK(ODbaseIndexDialog, TableSelectHdl, weld::ComboBox&, rComboBox, void) +{ + // search the table + TableInfoList::iterator aTablePos = std::find_if(m_aTableInfoList.begin(), m_aTableInfoList.end(), + [&] (const OTableInfo& arg) { return arg.aTableName == rComboBox.get_active_text() ; }); + + if (aTablePos == m_aTableInfoList.end()) + return; + + // fill the listbox for the indexes + m_xLB_TableIndexes->clear(); + for (auto const& index : aTablePos->aIndexList) + m_xLB_TableIndexes->append_text(index.GetIndexFileName()); + + if (!aTablePos->aIndexList.empty()) + m_xLB_TableIndexes->select(0); + + checkButtons(); +} + +void ODbaseIndexDialog::Init() +{ + m_xPB_OK->set_sensitive(false); + m_xIndexes->set_sensitive(false); + + // All indices are first added to a list of free indices. + // Afterwards, check the index of each table in the Inf-file. + // These indices are removed from the list of free indices and + // entered in the indexlist of the table. + + // if the string does not contain a path, cut the string + INetURLObject aURL; + aURL.SetSmartProtocol(INetProtocol::File); + { + SvtPathOptions aPathOptions; + m_aDSN = aPathOptions.SubstituteVariable(m_aDSN); + } + aURL.SetSmartURL(m_aDSN); + + // String aFileName = aURL.PathToFileName(); + m_aDSN = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + ::ucbhelper::Content aFile; + bool bFolder=true; + try + { + aFile = ::ucbhelper::Content(m_aDSN,Reference< css::ucb::XCommandEnvironment >(), comphelper::getProcessComponentContext()); + bFolder = aFile.isFolder(); + } + catch(Exception&) + { + return; + } + + // first assume for all indexes they're free + + OUString const aIndexExt("ndx"); + OUString const aTableExt("dbf"); + + std::vector< OUString > aUsedIndexes; + + aURL.SetSmartProtocol(INetProtocol::File); + const Sequence aFolderUrls = ::utl::LocalFileHelper::GetFolderContents(m_aDSN, bFolder); + for(const OUString& rURL : aFolderUrls) + { + OUString aName; + osl::FileBase::getSystemPathFromFileURL(rURL,aName); + aURL.SetSmartURL(aName); + OUString aExt = aURL.getExtension(); + if (aExt == aIndexExt) + { + m_aFreeIndexList.emplace_back(aURL.getName() ); + } + else if (aExt == aTableExt) + { + m_aTableInfoList.emplace_back(aURL.getName() ); + OTableInfo& rTabInfo = m_aTableInfoList.back(); + + // open the INF file + aURL.setExtension("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("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", makeAny( true ) ); + } + catch (const Exception& ) + { + // simply silent this. The strange algorithm here does a lot of + // things even if no files at all were created or accessed, so it's + // possible that the file we're trying to delete does not even + // exist, and this is a valid condition. + } +} + +} // namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dbfindex.hxx b/dbaccess/source/ui/dlg/dbfindex.hxx new file mode 100644 index 000000000..d0c23a416 --- /dev/null +++ b/dbaccess/source/ui/dlg/dbfindex.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_DBFINDEX_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_DBFINDEX_HXX + +#include +#include + +namespace dbaui +{ + +// OTableIndex +/// represents a single dbf index +class OTableIndex +{ +private: + OUString aIndexFileName; + +public: + OTableIndex() { } + explicit OTableIndex( const OUString& rFileName ) : aIndexFileName( rFileName ) { } + + const OUString& GetIndexFileName() const { return aIndexFileName; } +}; + +typedef std::deque< OTableIndex > TableIndexList; + +// OTableInfo +class ODbaseIndexDialog; +/** holds the INF file of a table +*/ +class OTableInfo +{ + friend class ODbaseIndexDialog; +private: + OUString aTableName; + TableIndexList aIndexList; + +public: + explicit OTableInfo( const OUString& rName ) : aTableName(rName) { } + + void WriteInfFile( const OUString& rDSN ) const; +}; + +typedef std::deque< OTableInfo > TableInfoList; + +// IndexDialog +class ODbaseIndexDialog : public weld::GenericDialogController +{ +protected: + OUString m_aDSN; + TableInfoList m_aTableInfoList; + TableIndexList m_aFreeIndexList; + + std::unique_ptr 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 ); + + 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( const OUString& _rTableName, const OUString& _rIndexName ); + void InsertTableIndex( const OUString& _rTableName, const OTableIndex& _rIndex ); + + void checkButtons(); + +public: + ODbaseIndexDialog(weld::Window * pParent, const OUString& rDataSrcName); + virtual ~ODbaseIndexDialog() override; +}; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_DBFINDEX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dbwiz.cxx b/dbaccess/source/ui/dlg/dbwiz.cxx new file mode 100644 index 000000000..d39fd3c79 --- /dev/null +++ b/dbaccess/source/ui/dlg/dbwiz.cxx @@ -0,0 +1,335 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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& rCollectionItem = dynamic_cast(*_pItems->GetItem(DSID_TYPECOLLECTION)); + m_pCollection = rCollectionItem.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) +{ + const char* pStringId = STR_PAGETITLE_ADVANCED; + std::unique_ptr xPage; + + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch(_nState) + { + case START_PAGE: // start state + { + xPage = std::make_unique(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 + // anormal 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 000000000..1dd342c12 --- /dev/null +++ b/dbaccess/source/ui/dlg/dbwizsetup.cxx @@ -0,0 +1,999 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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_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 ) + , m_pCollection( nullptr ) +{ + // no local resources needed anymore + // extract the datasource type collection from the item set + const DbuTypeCollectionItem* pCollectionItem = dynamic_cast( _pItems->GetItem(DSID_TYPECOLLECTION) ); + if (pCollectionItem) + m_pCollection = pCollectionItem->getCollection(); + + OSL_ENSURE(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); + + m_xPrevPage->set_help_id(HID_DBWIZ_PREVIOUS); + m_xNextPage->set_help_id(HID_DBWIZ_NEXT); + m_xCancel->set_help_id(HID_DBWIZ_CANCEL); + m_xFinish->set_help_id(HID_DBWIZ_FINISH); + ActivatePage(); + setTitleBase(DBA_RES(STR_DBWIZARDTITLE)); + m_xAssistant->set_current_page(0); +} + +void ODbTypeWizDialogSetup::declareAuthDepPath( const OUString& _sURL, PathId _nPathId, const WizardPath& _rPaths) +{ + bool bHasAuthentication = DataSourceMetaData::getAuthentication( _sURL ) != AuthNone; + + // collect the elements of the path + WizardPath aPath; + + for (auto const& path : _rPaths) + { + if ( bHasAuthentication || ( path != PAGE_DBSETUPWIZARD_AUTHENTIFICATION ) ) + aPath.push_back(path); + } + + // call base method + ::vcl::RoadmapWizardMachine::declarePath( _nPathId, aPath ); +} + +OUString ODbTypeWizDialogSetup::getStateDisplayName(WizardState _nState) const +{ + OUString sRoadmapItem; + switch( _nState ) + { + case PAGE_DBSETUPWIZARD_INTRO: + sRoadmapItem = m_sRM_IntroText; + break; + + case PAGE_DBSETUPWIZARD_DBASE: + sRoadmapItem = m_sRM_dBaseText; + break; + case PAGE_DBSETUPWIZARD_ADO: + sRoadmapItem = m_sRM_ADOText; + break; + case PAGE_DBSETUPWIZARD_TEXT: + sRoadmapItem = m_sRM_TextText; + break; + case PAGE_DBSETUPWIZARD_MSACCESS: + sRoadmapItem = m_sRM_MSAccessText; + break; + case PAGE_DBSETUPWIZARD_LDAP: + sRoadmapItem = m_sRM_LDAPText; + break; + case PAGE_DBSETUPWIZARD_JDBC: + sRoadmapItem = m_sRM_JDBCText; + break; + case PAGE_DBSETUPWIZARD_ORACLE: + sRoadmapItem = m_sRM_OracleText; + break; + case PAGE_DBSETUPWIZARD_MYSQL_INTRO: + sRoadmapItem = m_sRM_MySQLText; + break; + case PAGE_DBSETUPWIZARD_MYSQL_JDBC: + sRoadmapItem = m_sRM_JDBCText; + break; + case PAGE_DBSETUPWIZARD_MYSQL_NATIVE: + sRoadmapItem = m_sRM_MySQLNativePageTitle; + break; + case PAGE_DBSETUPWIZARD_MYSQL_ODBC: + sRoadmapItem = m_sRM_ODBCText; + break; + case PAGE_DBSETUPWIZARD_ODBC: + sRoadmapItem = m_sRM_ODBCText; + break; + case PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET: + sRoadmapItem = m_sRM_DocumentOrSpreadSheetText; + break; + case PAGE_DBSETUPWIZARD_AUTHENTIFICATION: + sRoadmapItem = m_sRM_AuthentificationText; + break; + case PAGE_DBSETUPWIZARD_USERDEFINED: + sRoadmapItem = DBA_RES(STR_PAGETITLE_CONNECTION); + break; + case PAGE_DBSETUPWIZARD_FINAL: + sRoadmapItem = m_sRM_FinalText; + break; + default: + break; + } + return sRoadmapItem; +} + +ODbTypeWizDialogSetup::~ODbTypeWizDialogSetup() +{ +} + +IMPL_LINK_NOARG(ODbTypeWizDialogSetup, OnTypeSelected, OGeneralPage&, void) +{ + activateDatabasePath(); +} + +static void lcl_removeUnused(const ::comphelper::NamedValueCollection& _aOld,const ::comphelper::NamedValueCollection& _aNew,::comphelper::NamedValueCollection& _rDSInfo) +{ + _rDSInfo.merge(_aNew,true); + uno::Sequence< beans::NamedValue > aOldValues = _aOld.getNamedValues(); + const beans::NamedValue* pIter = aOldValues.getConstArray(); + const beans::NamedValue* pEnd = pIter + aOldValues.getLength(); + for(;pIter != pEnd;++pIter) + { + if ( !_aNew.has(pIter->Name) ) + { + _rDSInfo.remove(pIter->Name); + } + } +} + +void DataSourceInfoConverter::convert(const Reference & xContext, const ::dbaccess::ODsnTypeCollection* _pCollection,const OUString& _sOldURLPrefix,const OUString& _sNewURLPrefix,const css::uno::Reference< css::beans::XPropertySet >& _xDatasource) +{ + if ( _pCollection->getPrefix(_sOldURLPrefix) == _pCollection->getPrefix(_sNewURLPrefix) ) + return ; + uno::Sequence< beans::PropertyValue> aInfo; + _xDatasource->getPropertyValue(PROPERTY_INFO) >>= aInfo; + ::comphelper::NamedValueCollection aDS(aInfo); + + ::connectivity::DriversConfig aDriverConfig(xContext); + + const ::comphelper::NamedValueCollection& aOldProperties = aDriverConfig.getProperties(_sOldURLPrefix); + const ::comphelper::NamedValueCollection& aNewProperties = aDriverConfig.getProperties(_sNewURLPrefix); + lcl_removeUnused(aOldProperties,aNewProperties,aDS); + + aDS >>= aInfo; + _xDatasource->setPropertyValue(PROPERTY_INFO,uno::makeAny(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( "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; + + OString sIdent(OString::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("sdbc:mysql:odbc:"))); + xPage = OConnectionTabPageSetup::CreateODBCTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_MYSQL_JDBC: + m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:jdbc:"))); + xPage = OGeneralSpecialJDBCConnectionPageSetup::CreateMySQLJDBCTabPage(pPageContainer, this, *m_pOutSet); + break; + case PAGE_DBSETUPWIZARD_MYSQL_NATIVE: + m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, m_pCollection->getPrefix("sdbc:mysql:mysqlc:"))); + xPage = MySQLNativeSetupPage::Create(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_ORACLE: + xPage = OGeneralSpecialJDBCConnectionPageSetup::CreateOracleJDBCTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_LDAP: + xPage = OLDAPConnectionPageSetup::CreateLDAPTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET: + xPage = OSpreadSheetConnectionPageSetup::CreateDocumentOrSpreadSheetTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_MSACCESS: + xPage = OConnectionTabPageSetup::CreateMSAccessTabPage(pPageContainer, this, *m_pOutSet); + break; + case PAGE_DBSETUPWIZARD_MYSQL_INTRO: + xPage = OMySQLIntroPageSetup::CreateMySQLIntroTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_AUTHENTIFICATION: + xPage = OAuthentificationPageSetup::CreateAuthentificationTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_USERDEFINED: + xPage = OConnectionTabPageSetup::CreateUserDefinedTabPage(pPageContainer, this, *m_pOutSet); + break; + + case PAGE_DBSETUPWIZARD_FINAL: + xPage = OFinalDBPageSetup::CreateFinalDBTabPageSetup(pPageContainer, this, *m_pOutSet); + break; + } + + if ( xPage ) + { + if ((_nState != PAGE_DBSETUPWIZARD_INTRO) && (_nState != PAGE_DBSETUPWIZARD_AUTHENTIFICATION)) + { + xPage->SetModifiedHandler(LINK( this, ODbTypeWizDialogSetup, ImplModifiedHdl ) ); + } + + xPage->SetServiceFactory( m_pImpl->getORB() ); + xPage->SetAdminDialog(this, this); + + defaultButton( _nState == PAGE_DBSETUPWIZARD_FINAL ? WizardButtonFlags::FINISH : WizardButtonFlags::NEXT ); + enableButtons( WizardButtonFlags::FINISH, _nState == PAGE_DBSETUPWIZARD_FINAL ); + enableButtons( WizardButtonFlags::NEXT, _nState != PAGE_DBSETUPWIZARD_FINAL ); + + m_xAssistant->set_page_title(sIdent, getStateDisplayName(_nState)); + } + return xPage; +} + +IMPL_LINK(ODbTypeWizDialogSetup, ImplModifiedHdl, OGenericAdministrationPage const *, _pConnectionPageSetup, void) +{ + m_bIsConnectable = _pConnectionPageSetup->GetRoadmapStateValue( ); + enableState(PAGE_DBSETUPWIZARD_FINAL, m_bIsConnectable); + enableState(PAGE_DBSETUPWIZARD_AUTHENTIFICATION, m_bIsConnectable); + if (getCurrentState() == PAGE_DBSETUPWIZARD_FINAL) + enableButtons( WizardButtonFlags::FINISH, true); + else + enableButtons( WizardButtonFlags::FINISH, m_bIsConnectable); + enableButtons( WizardButtonFlags::NEXT, m_bIsConnectable && (getCurrentState() != PAGE_DBSETUPWIZARD_FINAL)); +} + +IMPL_LINK(ODbTypeWizDialogSetup, ImplClickHdl, OMySQLIntroPageSetup*, _pMySQLIntroPageSetup, void) +{ + OUString sURLPrefix; + switch( _pMySQLIntroPageSetup->getMySQLMode() ) + { + case OMySQLIntroPageSetup::VIA_ODBC: + sURLPrefix = "sdbc:mysql:odbc:"; + break; + case OMySQLIntroPageSetup::VIA_JDBC: + sURLPrefix = "sdbc:mysql:jdbc:"; + break; + case OMySQLIntroPageSetup::VIA_NATIVE: + sURLPrefix = "sdbc:mysql:mysqlc:"; + break; + } + activatePath( static_cast(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 ) + { + OInteractionRequest* pRequest = new OInteractionRequest( _rRequest ); + Reference < XInteractionRequest > xRequest( pRequest ); + OInteractionAbort* pAbort = new OInteractionAbort; + pRequest->addContinuation( pAbort ); + + return _rxHandler->handleInteractionRequest( xRequest ); + } +} + +bool ODbTypeWizDialogSetup::SaveDatabaseDocument() +{ + Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(getORB(), nullptr) ); + try + { + if (callSaveAsDialog()) + { + m_pImpl->saveChanges(*m_pOutSet); + Reference< XPropertySet > xDatasource = m_pImpl->getCurrentDataSource(); + Reference< XModel > xModel( getDataSourceOrModel( xDatasource ), UNO_QUERY_THROW ); + Reference< XStorable > xStore( xModel, UNO_QUERY_THROW ); + + if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eCreateNew ) + CreateDatabase(); + + ::comphelper::NamedValueCollection aArgs( xModel->getArgs() ); + aArgs.put( "Overwrite", true ); + aArgs.put( "InteractionHandler", xHandler ); + aArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); + aArgs.put( "IgnoreFirebirdMigration", true ); + + OUString sPath = ODbDataSourceAdministrationHelper::getDocumentUrl( *m_pOutSet ); + xStore->storeAsURL( sPath, aArgs.getPropertyValues() ); + + if ( !m_pFinalPage || m_pFinalPage->IsDatabaseDocumentToBeRegistered() ) + RegisterDataSourceByLocation( sPath ); + + return true; + } + } + catch ( const Exception& e ) + { + Any aError = ::cppu::getCaughtException(); + if ( xHandler.is() ) + { + if ( !lcl_handle( xHandler, aError ) ) + { + InteractiveIOException aRequest; + aRequest.Classification = InteractionClassification_ERROR; + if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() ) ) + // assume saving the document failed + aRequest.Code = IOErrorCode_CANT_WRITE; + else + aRequest.Code = IOErrorCode_GENERAL; + aRequest.Message = e.Message; + aRequest.Context = e.Context; + lcl_handle( xHandler, makeAny( 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, makeAny( 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.concat(sUrl); + } + m_pOutSet->Put(SfxStringItem(DSID_CONNECTURL, sUrl)); + m_pImpl->saveChanges(*m_pOutSet); + } + + void ODbTypeWizDialogSetup::RegisterDataSourceByLocation(const OUString& _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()); + std::shared_ptr pFilter = getStandardDatabaseFilter(); + if ( pFilter ) + { + INetURLObject aWorkURL( m_sWorkPath ); + aFileDlg.SetDisplayFolder( aWorkURL.GetMainURL( INetURLObject::DecodeMechanism::NONE )); + + OUString sDefaultName = DBA_RES( STR_DATABASEDEFAULTNAME ); + OUString sExtension = pFilter->GetDefaultExtension(); + sDefaultName += sExtension.replaceAt( 0, 1, OUString() ); + 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(sLastSegmentName.concat(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( BaseName.concat( 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 >& _rxORB, const OUString& _rURL ); + + void doLoadAsync(); + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& Event ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& Event ) override; + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + private: + DECL_LINK( OnOpenDocument, void*, void ); + }; + + AsyncLoader::AsyncLoader( const Reference< XComponentContext >& _rxORB, const OUString& _rURL ) + :m_sURL( _rURL ) + ,m_aAsyncCaller( LINK( this, AsyncLoader, OnOpenDocument ) ) + { + try + { + m_xDesktop.set( Desktop::create(_rxORB) ); + m_xFrameLoader.set( m_xDesktop, UNO_QUERY_THROW ); + m_xInteractionHandler = InteractionHandler::createWithParent(_rxORB, nullptr); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void AsyncLoader::doLoadAsync() + { + OSL_ENSURE( !m_aAsyncCaller.IsRunning(), "AsyncLoader:doLoadAsync: already running!" ); + + acquire(); + try + { + if ( m_xDesktop.is() ) + m_xDesktop->addTerminateListener( this ); + } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + + m_aAsyncCaller.Call(); + } + + IMPL_LINK_NOARG( AsyncLoader, OnOpenDocument, void*, void ) + { + try + { + if ( m_xFrameLoader.is() ) + { + ::comphelper::NamedValueCollection aLoadArgs; + aLoadArgs.put( "InteractionHandler", m_xInteractionHandler ); + aLoadArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG ); + + Sequence< PropertyValue > aLoadArgPV; + aLoadArgs >>= aLoadArgPV; + + m_xFrameLoader->loadComponentFromURL( m_sURL, + "_default", + FrameSearchFlag::ALL, + aLoadArgPV + ); + } + } + catch( const Exception& ) + { + // do not assert. + // Such an exception happens for instance of the to-be-loaded document does not exist anymore. + } + + try + { + if ( m_xDesktop.is() ) + m_xDesktop->removeTerminateListener( this ); + } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + + release(); + } + + void SAL_CALL AsyncLoader::queryTermination( const css::lang::EventObject& /*Event*/ ) + { + throw TerminationVetoException(); + } + + void SAL_CALL AsyncLoader::notifyTermination( const css::lang::EventObject& /*Event*/ ) + { + } + void SAL_CALL AsyncLoader::disposing( const css::lang::EventObject& /*Source*/ ) + { + } + } + + bool ODbTypeWizDialogSetup::onFinish() + { + if ( m_pGeneralPage->GetDatabaseCreationMode() == OGeneralPageWizard::eOpenExisting ) + { + // we're not going to re-use the XModel we have - since the document the user + // wants us to load could be a non-database document. Instead, we asynchronously + // open the selected document. Thus, the wizard's return value is RET_CANCEL, + // which means to not continue loading the database document + if ( !WizardMachine::Finish() ) + return false; + + try + { + AsyncLoader* pAsyncLoader = new AsyncLoader( getORB(), m_pGeneralPage->GetSelectedDocumentURL() ); + ::rtl::Reference< AsyncLoader > xKeepAlive( pAsyncLoader ); + pAsyncLoader->doLoadAsync(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return true; + } + + if (getCurrentState() != PAGE_DBSETUPWIZARD_FINAL) + { + skipUntil(PAGE_DBSETUPWIZARD_FINAL); + } + if (getCurrentState() == PAGE_DBSETUPWIZARD_FINAL) + return SaveDatabaseDocument() && WizardMachine::onFinish(); + else + { + enableButtons( WizardButtonFlags::FINISH, false ); + return false; + } + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/detailpages.cxx b/dbaccess/source/ui/dlg/detailpages.cxx new file mode 100644 index 000000000..1ce6475b6 --- /dev/null +++ b/dbaccess/source/ui/dlg/detailpages.cxx @@ -0,0 +1,718 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 OString& rId, const SfxItemSet& rCoreAttrs, + OCommonBehaviourTabPageFlags nControlFlags) + : OGenericAdministrationPage(pPage, pController, rUIXMLDescription, rId, rCoreAttrs) + , m_nControlFlags(nControlFlags) + { + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseOptions) + { + m_xOptionsLabel = m_xBuilder->weld_label("optionslabel"); + m_xOptionsLabel->show(); + m_xOptions = m_xBuilder->weld_entry("options"); + m_xOptions->show(); + m_xOptions->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl)); + } + + if (m_nControlFlags & OCommonBehaviourTabPageFlags::UseCharset) + { + m_xDataConvertLabel = m_xBuilder->weld_label("charsetheader"); + m_xDataConvertLabel->show(); + m_xCharsetLabel = m_xBuilder->weld_label("charsetlabel"); + m_xCharsetLabel->show(); + m_xCharset.reset(new CharSetListBox(m_xBuilder->weld_combo_box("charset"))); + m_xCharset->show(); + m_xCharset->connect_changed(LINK(this, OCommonBehaviourTabPage, CharsetSelectHdl)); + } + } + + IMPL_LINK_NOARG(OCommonBehaviourTabPage, CharsetSelectHdl, weld::ComboBox&, void) + { + callModifiedHdl(); + } + + OCommonBehaviourTabPage::~OCommonBehaviourTabPage() + { + m_xCharset.reset(); + } + + void OCommonBehaviourTabPage::fillWindows(std::vector< std::unique_ptr >& _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_clicked(LINK(this, ODbaseDetailsPage, OnButtonClicked)); + } + + 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(ODbaseDetailsPage, OnButtonClicked, weld::Button&, rButton, void) + { + if (m_xIndexes.get() == &rButton) + { + ODbaseIndexDialog aIndexDialog(GetFrameWeld(), m_sDsn); + aIndexDialog.run(); + } + else + { + m_xFT_Message->set_visible(m_xShowDeleted->get_active()); + // it was one of the checkboxes -> 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 && m_xEDDriverClass->get_text().trim().isEmpty() ) + { + m_xEDDriverClass->set_text(m_sDefaultJdbcDriverName); + m_xEDDriverClass->save_value(); + } + } + IMPL_LINK_NOARG(OGeneralSpecialJDBCDetailsPage, OnTestJavaClickHdl, weld::Button&, void) + { + OSL_ENSURE(m_pAdminDialog,"No Admin dialog set! ->GPF"); + OSL_ENSURE(m_bUseClass,"Who called me?"); + + bool bSuccess = false; +#if HAVE_FEATURE_JAVA + try + { + if (!m_xEDDriverClass->get_text().trim().isEmpty()) + { +// TODO change jvmaccess + ::rtl::Reference< jvmaccess::VirtualMachine > xJVM = ::connectivity::getJavaVM( m_pAdminDialog->getORB() ); + m_xEDDriverClass->set_text(m_xEDDriverClass->get_text().trim()); // fdo#68341 + bSuccess = ::connectivity::existsJavaClassByName(xJVM,m_xEDDriverClass->get_text()); + } + } + catch(Exception&) + { + } +#endif + const char* pMessage = bSuccess ? STR_JDBCDRIVER_SUCCESS : STR_JDBCDRIVER_NO_SUCCESS; + const MessageType mt = bSuccess ? MessageType::Info : MessageType::Error; + OSQLMessageBox aMsg(GetFrameWeld(), DBA_RES(pMessage), OUString(), MessBoxStyle::Ok | MessBoxStyle::DefaultOk, mt); + aMsg.run(); + } + + void OGeneralSpecialJDBCDetailsPage::callModifiedHdl(weld::Widget* pControl) + { + if (m_bUseClass && pControl == m_xEDDriverClass.get()) + m_xTestJavaDriver->set_sensitive(!m_xEDDriverClass->get_text().trim().isEmpty()); + + // tell the listener we were modified + OGenericAdministrationPage::callModifiedHdl(); + } + + // MySQLNativePage + MySQLNativePage::MySQLNativePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs) + : OCommonBehaviourTabPage(pPage, pController, "dbaccess/ui/mysqlnativepage.ui", "MysqlNativePage", rCoreAttrs, OCommonBehaviourTabPageFlags::UseCharset) + , m_xMySQLSettingsContainer(m_xBuilder->weld_widget("MySQLSettingsContainer")) + , m_xMySQLSettings(new MySQLNativeSettings(m_xMySQLSettingsContainer.get(), LINK(this,OGenericAdministrationPage,OnControlModified))) + , m_xSeparator1(m_xBuilder->weld_label("connectionheader")) + , m_xSeparator2(m_xBuilder->weld_label("userheader")) + , m_xUserNameLabel(m_xBuilder->weld_label("usernamelabel")) + , m_xUserName(m_xBuilder->weld_entry("username")) + , m_xPasswordRequired(m_xBuilder->weld_check_button("passwordrequired")) + { + m_xUserName->connect_changed(LINK(this,OGenericAdministrationPage,OnControlEntryModifyHdl)); + } + + MySQLNativePage::~MySQLNativePage() + { + m_xMySQLSettings.reset(); + } + + void MySQLNativePage::fillControls(std::vector< std::unique_ptr >& _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::ToggleButton&, 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 000000000..ff82ce06d --- /dev/null +++ b/dbaccess/source/ui/dlg/detailpages.hxx @@ -0,0 +1,255 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_DLG_DETAILPAGES_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_DETAILPAGES_HXX + +#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; + + std::unique_ptr m_xAutoRetrievingEnabled; + std::unique_ptr m_xAutoIncrementLabel; + std::unique_ptr m_xAutoIncrement; + std::unique_ptr m_xAutoRetrievingLabel; + std::unique_ptr m_xAutoRetrieving; + + public: + virtual bool FillItemSet (SfxItemSet* _rCoreAttrs) override; + + OCommonBehaviourTabPage(weld::Container* pPage, weld::DialogController* pController, const OUString& rUIXMLDescription, const OString& rId, const SfxItemSet& _rCoreAttrs, OCommonBehaviourTabPageFlags nControlFlags); + protected: + + virtual ~OCommonBehaviourTabPage() override; + + // subclasses must override this, but it isn't pure virtual + virtual void implInitControls(const SfxItemSet& _rSet, bool _bSaveValue) override; + + // 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); + }; + + // 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; + sal_uInt16 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::ToggleButton&, 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_DETAILPAGES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/directsql.cxx b/dbaccess/source/ui/dlg/directsql.cxx new file mode 100644 index 000000000..8cb2a2e2a --- /dev/null +++ b/dbaccess/source/ui/dlg/directsql.cxx @@ -0,0 +1,504 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +namespace dbaui +{ + SQLEditView::SQLEditView() + { + } + + 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); + } + + bool SQLEditView::KeyInput(const KeyEvent& rKEvt) + { + DoBracketHilight(rKEvt.GetCharCode()); + return WeldEditView::KeyInput(rKEvt); + } + + 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_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_xSQLEd(new weld::CustomWeld(*m_xBuilder, "sql", *m_xSQL)) + , m_aHighlighter(HighlighterLanguage::SQL) + , m_nStatusCount(1) + , m_bInUpdate(false) + , 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); + + m_aUpdateDataTimer.SetTimeout(300); + m_aUpdateDataTimer.SetInvokeHandler(LINK(this, DirectSQLDialog, ImplUpdateDataHdl)); + } + + 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 + { + CHECK_INVARIANTS("DirectSQLDialog::getHistorySize"); + return m_aStatementHistory.size(); + } + + void DirectSQLDialog::implEnsureHistoryLimit() + { + CHECK_INVARIANTS("DirectSQLDialog::implEnsureHistoryLimit"); + + 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) + { + CHECK_INVARIANTS("DirectSQLDialog::implAddToStatementHistory"); + + // 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) + { + CHECK_INVARIANTS("DirectSQLDialog::implExecuteStatement"); + + ::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(); + + 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(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 + { + if (_rStatement.toAsciiUpperCase().startsWith("SELECT")) + { + 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(OUString::number(resultCount) + " rows updated\n"); + } + } + // successful + sStatus = DBA_RES(STR_COMMAND_EXECUTED_SUCCESSFULLY); + + // dispose the statement + ::comphelper::disposeComponent(xStatement); + } + catch(const SQLException& e) + { + sStatus = e.Message; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // add the status text + addStatusText(sStatus); + } + + void DirectSQLDialog::display(const css::uno::Reference< css::sdbc::XResultSet >& xRS) + { + // get a handle for the rows + css::uno::Reference< css::sdbc::XRow > xRow( xRS, css::uno::UNO_QUERY ); + // work through each of the rows + while (xRS->next()) + { + // initialise the output line for each row + OUStringBuffer out; + // work along the columns until that are none left + try + { + int i = 1; + for (;;) + { + // be dumb, treat everything as a string + out.append(xRow->getString(i)).append(","); + i++; + } + } + // trap for when we fall off the end of the row + catch (const SQLException&) + { + } + // report the output + addOutputText(out.makeStringAndClear()); + } + } + + void DirectSQLDialog::addStatusText(const OUString& _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(const OUString& _rMessage) + { + OUString sAppendMessage = _rMessage + "\n"; + + OUString sCompleteMessage = m_xOutput->get_text() + sAppendMessage; + m_xOutput->set_text(sCompleteMessage); + } + + void DirectSQLDialog::executeCurrent() + { + CHECK_INVARIANTS("DirectSQLDialog::executeCurrent"); + + 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) + { + CHECK_INVARIANTS("DirectSQLDialog::switchToHistory"); + + if ((_nHistoryPos >= 0) && (_nHistoryPos < getHistorySize())) + { + // set the text in the statement editor + OUString sStatement = m_aStatementHistory[_nHistoryPos]; + m_xSQL->SetText(sStatement); + UpdateData(); + OnStatementModified(nullptr); + + m_xSQL->GrabFocus(); + } + else + OSL_FAIL("DirectSQLDialog::switchToHistory: invalid position!"); + } + + IMPL_LINK_NOARG( DirectSQLDialog, OnStatementModified, LinkParamNone*, void ) + { + if (m_bInUpdate) + return; + + m_xExecute->set_sensitive(!m_xSQL->GetText().isEmpty()); + m_aUpdateDataTimer.Start(); + } + + 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); + } + + Color DirectSQLDialog::GetColorValue(TokenType aToken) + { + return MultiLineEditSyntaxHighlight::GetSyntaxHighlightColor(m_aColorConfig, m_aHighlighter.GetLanguage(), aToken); + } + + IMPL_LINK_NOARG(DirectSQLDialog, ImplUpdateDataHdl, Timer*, void) + { + UpdateData(); + } + + void DirectSQLDialog::UpdateData() + { + m_bInUpdate = true; + EditEngine& rEditEngine = m_xSQL->GetEditEngine(); + + bool bUndoEnabled = rEditEngine.IsUndoEnabled(); + rEditEngine.EnableUndo(false); + + // syntax highlighting + bool bOrigModified = rEditEngine.IsModified(); + 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)); + } + } + if (!bOrigModified) + rEditEngine.ClearModifyFlag(); + + rEditEngine.EnableUndo(bUndoEnabled); + + m_bInUpdate = false; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dlgattr.cxx b/dbaccess/source/ui/dlg/dlgattr.cxx new file mode 100644 index 000000000..a69f29fe7 --- /dev/null +++ b/dbaccess/source/ui/dlg/dlgattr.cxx @@ -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 . + */ + +#include + +#include + +#include + +#include +#include +#include +#include + +using namespace dbaui; + + +SbaSbAttrDlg::SbaSbAttrDlg(weld::Window* pParent, const SfxItemSet* pCellAttrs, + SvNumberFormatter* pFormatter, bool bHasFormat) + : SfxTabDialogController(pParent, "dbaccess/ui/fielddialog.ui", "FieldDialog", pCellAttrs) +{ + pNumberInfoItem.reset( new SvxNumberInfoItem( pFormatter, 0 ) ); + + if (bHasFormat) + AddTabPage("format", RID_SVXPAGE_NUMBERFORMAT); + else + RemoveTabPage("format"); + AddTabPage("alignment", RID_SVXPAGE_ALIGNMENT); +} + +SbaSbAttrDlg::~SbaSbAttrDlg() +{ +} + +void SbaSbAttrDlg::PageCreated(const OString& rPageId, SfxTabPage& rTabPage) +{ + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + if (rPageId == "format") + { + aSet.Put (SvxNumberInfoItem( pNumberInfoItem->GetNumberFormatter(), static_cast(SID_ATTR_NUMBERFORMAT_INFO))); + rTabPage.PageCreated(aSet); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dlgsave.cxx b/dbaccess/source/ui/dlg/dlgsave.cxx new file mode 100644 index 000000000..ce5d16881 --- /dev/null +++ b/dbaccess/source/ui/dlg/dlgsave.cxx @@ -0,0 +1,351 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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; +namespace dbaui +{ + +class OSaveAsDlgImpl +{ +public: + OUString m_aQryLabel; + OUString m_sTblLabel; + OUString m_aName; + const IObjectNameCheck& m_rObjectNameCheck; + css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xMetaData; + sal_Int32 m_nType; + SADFlags m_nFlags; + + OSQLNameChecker m_aChecker; + + std::unique_ptr 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); + + OSaveAsDlgImpl( weld::Builder* pParent, sal_Int32 _rType, + const css::uno::Reference< css::sdbc::XConnection>& _xConnection, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags); + OSaveAsDlgImpl( weld::Builder* pParent, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags); +}; + +} // dbaui + +IMPL_LINK(OSaveAsDlgImpl, TextFilterHdl, OUString&, rTest, bool) +{ + OUString sCorrected; + if (m_aChecker.checkString(rTest, sCorrected)) + rTest = sCorrected; + return true; +} + +OSaveAsDlgImpl::OSaveAsDlgImpl(weld::Builder* pBuilder, + sal_Int32 _rType, + const Reference< XConnection>& _xConnection, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags) + : m_aQryLabel(DBA_RES(STR_QRY_LABEL)) + , m_sTblLabel(DBA_RES(STR_TBL_LABEL)) + , m_aName(rDefault) + , m_rObjectNameCheck( _rObjectNameCheck ) + , m_nType(_rType) + , m_nFlags(_nFlags) + , m_aChecker(OUString()) + , m_xDescription(pBuilder->weld_label("descriptionft")) + , m_xCatalogLbl(pBuilder->weld_label("catalogft")) + , m_xCatalog(pBuilder->weld_combo_box("catalog")) + , m_xSchemaLbl(pBuilder->weld_label("schemaft")) + , m_xSchema(pBuilder->weld_combo_box("schema")) + , m_xLabel(pBuilder->weld_label("titleft")) + , m_xTitle(pBuilder->weld_entry("title")) + , m_xPB_OK(pBuilder->weld_button("ok")) +{ + if ( _xConnection.is() ) + m_xMetaData = _xConnection->getMetaData(); + + if (m_xMetaData.is()) + { + OUString sExtraNameChars(m_xMetaData->getExtraNameCharacters()); + m_aChecker.setAllowedChars(sExtraNameChars); + } + + m_xTitle->connect_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); + m_xSchema->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); + m_xCatalog->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); +} + +OSaveAsDlgImpl::OSaveAsDlgImpl(weld::Builder* pBuilder, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags) + : m_aQryLabel(DBA_RES(STR_QRY_LABEL)) + , m_sTblLabel(DBA_RES(STR_TBL_LABEL)) + , m_aName(rDefault) + , m_rObjectNameCheck( _rObjectNameCheck ) + , m_nType(CommandType::COMMAND) + , m_nFlags(_nFlags) + , m_aChecker(OUString()) + , m_xDescription(pBuilder->weld_label("descriptionft")) + , m_xCatalogLbl(pBuilder->weld_label("catalogft")) + , m_xCatalog(pBuilder->weld_combo_box("catalog")) + , m_xSchemaLbl(pBuilder->weld_label("schemaft")) + , m_xSchema(pBuilder->weld_combo_box("schema")) + , m_xLabel(pBuilder->weld_label("titleft")) + , m_xTitle(pBuilder->weld_entry("title")) + , m_xPB_OK(pBuilder->weld_button("ok")) +{ + m_xTitle->connect_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); + m_xSchema->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); + m_xCatalog->connect_entry_insert_text(LINK(this, OSaveAsDlgImpl, TextFilterHdl)); +} + +using namespace ::com::sun::star::lang; + +namespace +{ +typedef Reference< XResultSet > (SAL_CALL XDatabaseMetaData::*FGetMetaStrings)(); + +void lcl_fillComboList( weld::ComboBox& _rList, const Reference< XConnection >& _rxConnection, + FGetMetaStrings GetAll, const OUString& _rCurrent ) +{ + try { + Reference< XDatabaseMetaData > xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ); + + Reference< XResultSet > xRes = (xMetaData.get()->*GetAll)(); + Reference< XRow > xRow( xRes, UNO_QUERY_THROW ); + OUString sValue; + while ( xRes->next() ) { + sValue = xRow->getString( 1 ); + if ( !xRow->wasNull() ) + _rList.append_text( sValue ); + } + + int nPos = _rList.find_text( _rCurrent ); + if (nPos != -1) + _rList.set_active( nPos ); + else + _rList.set_active( 0 ); + } catch( const Exception& ) { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} +} + +OSaveAsDlg::OSaveAsDlg( weld::Window * pParent, + sal_Int32 _rType, + const Reference< XComponentContext >& _rxContext, + const Reference< XConnection>& _xConnection, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags) + : GenericDialogController(pParent, "dbaccess/ui/savedialog.ui", "SaveDialog") + , m_xContext( _rxContext ) +{ + m_pImpl.reset( new OSaveAsDlgImpl(m_xBuilder.get(),_rType,_xConnection,rDefault,_rObjectNameCheck,_nFlags) ); + + switch (_rType) { + case CommandType::QUERY: + implInitOnlyTitle(m_pImpl->m_aQryLabel); + break; + + case CommandType::TABLE: + OSL_ENSURE( m_pImpl->m_xMetaData.is(), "OSaveAsDlg::OSaveAsDlg: no meta data for entering table names: this will crash!" ); + { + m_pImpl->m_xLabel->set_label(m_pImpl->m_sTblLabel); + if(m_pImpl->m_xMetaData.is() && !m_pImpl->m_xMetaData->supportsCatalogsInTableDefinitions()) { + m_pImpl->m_xCatalogLbl->hide(); + m_pImpl->m_xCatalog->hide(); + } else { + // now fill the catalogs + lcl_fillComboList( *m_pImpl->m_xCatalog, _xConnection, + &XDatabaseMetaData::getCatalogs, _xConnection->getCatalog() ); + } + + if ( !m_pImpl->m_xMetaData->supportsSchemasInTableDefinitions()) { + m_pImpl->m_xSchemaLbl->hide(); + m_pImpl->m_xSchema->hide(); + } else { + lcl_fillComboList( *m_pImpl->m_xSchema, _xConnection, + &XDatabaseMetaData::getSchemas, m_pImpl->m_xMetaData->getUserName() ); + } + + OSL_ENSURE(m_pImpl->m_xMetaData.is(),"The metadata can not be null!"); + if(m_pImpl->m_aName.indexOf('.') != -1) { + OUString sCatalog,sSchema,sTable; + ::dbtools::qualifiedNameComponents(m_pImpl->m_xMetaData, + m_pImpl->m_aName, + sCatalog, + sSchema, + sTable, + ::dbtools::EComposeRule::InDataManipulation); + + int nPos = m_pImpl->m_xCatalog->find_text(sCatalog); + if (nPos != -1) + m_pImpl->m_xCatalog->set_active(nPos); + + if ( !sSchema.isEmpty() ) { + nPos = m_pImpl->m_xSchema->find_text(sSchema); + if (nPos != -1) + m_pImpl->m_xSchema->set_active(nPos); + } + m_pImpl->m_xTitle->set_text(sTable); + } else + m_pImpl->m_xTitle->set_text(m_pImpl->m_aName); + m_pImpl->m_xTitle->select_region(0, -1); + + sal_Int32 nLength = m_pImpl->m_xMetaData.is() ? m_pImpl->m_xMetaData->getMaxTableNameLength() : 0; + if (nLength) + { + m_pImpl->m_xTitle->set_max_length(nLength); + m_pImpl->m_xSchema->set_entry_max_length(nLength); + m_pImpl->m_xCatalog->set_entry_max_length(nLength); + } + + bool bCheck = _xConnection.is() && isSQL92CheckEnabled(_xConnection); + m_pImpl->m_aChecker.setCheck(bCheck); // enable non valid sql chars as well + } + break; + + default: + OSL_FAIL( "OSaveAsDlg::OSaveAsDlg: Type not supported yet!" ); + } + + implInit(); +} + +OSaveAsDlg::OSaveAsDlg(weld::Window * pParent, + const Reference< XComponentContext >& _rxContext, + const OUString& rDefault, + const OUString& _sLabel, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags) + : GenericDialogController(pParent, "dbaccess/ui/savedialog.ui", "SaveDialog") + , m_xContext( _rxContext ) +{ + m_pImpl.reset( new OSaveAsDlgImpl(m_xBuilder.get(),rDefault,_rObjectNameCheck,_nFlags) ); + implInitOnlyTitle(_sLabel); + implInit(); +} + +OSaveAsDlg::~OSaveAsDlg() +{ +} + +IMPL_LINK_NOARG(OSaveAsDlg, ButtonClickHdl, weld::Button&, void) +{ + m_pImpl->m_aName = m_pImpl->m_xTitle->get_text(); + + OUString sNameToCheck( m_pImpl->m_aName ); + + if ( m_pImpl->m_nType == CommandType::TABLE ) { + sNameToCheck = ::dbtools::composeTableName( + m_pImpl->m_xMetaData, + getCatalog(), + getSchema(), + sNameToCheck, + false, // no quoting + ::dbtools::EComposeRule::InDataManipulation + ); + } + + SQLExceptionInfo aNameError; + if ( m_pImpl->m_rObjectNameCheck.isNameValid( sNameToCheck, aNameError ) ) + m_xDialog->response(RET_OK); + + showError(aNameError, m_xDialog->GetXWindow(), m_xContext); + m_pImpl->m_xTitle->grab_focus(); +} + +IMPL_LINK_NOARG(OSaveAsDlg, EditModifyHdl, weld::Entry&, void) +{ + m_pImpl->m_xPB_OK->set_sensitive(!m_pImpl->m_xTitle->get_text().isEmpty()); +} + +void OSaveAsDlg::implInitOnlyTitle(const OUString& _rLabel) +{ + m_pImpl->m_xLabel->set_label(_rLabel); + m_pImpl->m_xCatalogLbl->hide(); + m_pImpl->m_xCatalog->hide(); + m_pImpl->m_xSchemaLbl->hide(); + m_pImpl->m_xSchema->hide(); + + m_pImpl->m_xTitle->set_text(m_pImpl->m_aName); + m_pImpl->m_aChecker.setCheck(false); // enable non valid sql chars as well +} + +void OSaveAsDlg::implInit() +{ + if ( !( m_pImpl->m_nFlags & SADFlags::AdditionalDescription ) ) { + // hide the description window + m_pImpl->m_xDescription->hide(); + } + + if ( SADFlags::TitlePasteAs == ( m_pImpl->m_nFlags & SADFlags::TitlePasteAs ) ) + m_xDialog->set_title( DBA_RES( STR_TITLE_PASTE_AS ) ); + else if ( SADFlags::TitleRename == ( m_pImpl->m_nFlags & SADFlags::TitleRename ) ) + m_xDialog->set_title( DBA_RES( STR_TITLE_RENAME ) ); + + m_pImpl->m_xPB_OK->connect_clicked(LINK(this,OSaveAsDlg,ButtonClickHdl)); + m_pImpl->m_xTitle->connect_changed(LINK(this,OSaveAsDlg,EditModifyHdl)); + m_pImpl->m_xTitle->grab_focus(); +} + +const OUString& OSaveAsDlg::getName() const +{ + return m_pImpl->m_aName; +} +OUString OSaveAsDlg::getCatalog() const +{ + return m_pImpl->m_xCatalog->get_visible() ? m_pImpl->m_xCatalog->get_active_text() : OUString(); +} +OUString OSaveAsDlg::getSchema() const +{ + return m_pImpl->m_xSchema->get_visible() ? m_pImpl->m_xSchema->get_active_text() : OUString(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dlgsize.cxx b/dbaccess/source/ui/dlg/dlgsize.cxx new file mode 100644 index 000000000..5b9f3a1ae --- /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 ? OString("RowHeightDialog") : OString("ColWidthDialog")) + , m_nPrevValue(nVal) + , m_xMF_VALUE(m_xBuilder->weld_metric_spin_button("value", FieldUnit::CM)) + , m_xCB_STANDARD(m_xBuilder->weld_check_button("automatic")) +{ + sal_Int32 nStandard(bRow ? DEF_ROW_HEIGHT : DEF_COL_WIDTH); + if ( _nAlternativeStandard > 0 ) + nStandard = _nAlternativeStandard; + m_xCB_STANDARD->connect_toggled(LINK(this,DlgSize,CbClickHdl)); + + bool bDefault = -1 == nVal; + m_xCB_STANDARD->set_active(bDefault); + if (bDefault) + { + SetValue(nStandard); + m_nPrevValue = nStandard; + } + CbClickHdl(*m_xCB_STANDARD); +} + +DlgSize::~DlgSize() +{ +} + +void DlgSize::SetValue( sal_Int32 nVal ) +{ + m_xMF_VALUE->set_value(nVal, FieldUnit::CM ); +} + +sal_Int32 DlgSize::GetValue() const +{ + if (m_xCB_STANDARD->get_active()) + return -1; + return static_cast(m_xMF_VALUE->get_value( FieldUnit::CM )); +} + +IMPL_LINK_NOARG(DlgSize, CbClickHdl, weld::ToggleButton&, 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 000000000..41103f8de --- /dev/null +++ b/dbaccess/source/ui/dlg/dsnItem.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_DSNITEM_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_DSNITEM_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_DSNITEM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/dsselect.cxx b/dbaccess/source/ui/dlg/dsselect.cxx new file mode 100644 index 000000000..4c0b9a836 --- /dev/null +++ b/dbaccess/source/ui/dlg/dsselect.cxx @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "dsselect.hxx" + +#include +#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_xOk(m_xBuilder->weld_button("ok")) + , m_xCancel(m_xBuilder->weld_button("cancel")) + , m_xManageDatasources(m_xBuilder->weld_button("organize")) +{ + m_xDatasource->set_size_request(-1, m_xDatasource->get_height_rows(6)); + + fillListBox(_rDatasources); +#ifdef HAVE_ODBC_ADMINISTRATION + // allow ODBC datasource management + m_xManageDatasources->show(); + m_xManageDatasources->set_sensitive(true); + m_xManageDatasources->connect_clicked(LINK(this,ODatasourceSelectDialog,ManageClickHdl)); +#endif + m_xDatasource->connect_row_activated(LINK(this,ODatasourceSelectDialog,ListDblClickHdl)); +} + +ODatasourceSelectDialog::~ODatasourceSelectDialog() +{ +} + +IMPL_LINK(ODatasourceSelectDialog, ListDblClickHdl, weld::TreeView&, rListBox, bool) +{ + if (rListBox.n_children()) + m_xDialog->response(RET_OK); + return true; +} + +short ODatasourceSelectDialog::run() +{ + short nRet = GenericDialogController::run(); +#ifdef HAVE_ODBC_ADMINISTRATION + if (m_xODBCManagement.get()) + m_xODBCManagement->disableCallback(); +#endif + return nRet; +} + +#ifdef HAVE_ODBC_ADMINISTRATION +IMPL_LINK_NOARG(ODatasourceSelectDialog, ManageClickHdl, weld::Button&, void) +{ + if ( !m_xODBCManagement.get() ) + m_xODBCManagement.reset( new OOdbcManagement( LINK( this, ODatasourceSelectDialog, ManageProcessFinished ) ) ); + + if ( !m_xODBCManagement->manageDataSources_async() ) + { + // TODO: error message + m_xDatasource->grab_focus(); + m_xManageDatasources->set_sensitive(false); + return; + } + + m_xDatasource->set_sensitive(false); + m_xOk->set_sensitive(false); + m_xCancel->set_sensitive(false); + m_xManageDatasources->set_sensitive(false); + + SAL_WARN_IF( !m_xODBCManagement->isRunning(), "dbaccess.ui", "ODatasourceSelectDialog::ManageClickHdl: success, but not running - you were *fast*!" ); +} + +IMPL_LINK_NOARG( ODatasourceSelectDialog, ManageProcessFinished, void*, void ) +{ + m_xODBCManagement->receivedCallback(); + + std::set 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 000000000..f365eaf00 --- /dev/null +++ b/dbaccess/source/ui/dlg/dsselect.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_DSSELECT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_DSSELECT_HXX + +#include +#include + +#include +#include + +class SfxItemSet; +namespace dbaui +{ + +// ODatasourceSelector +class ODatasourceSelectDialog final : public weld::GenericDialogController +{ + std::unique_ptr m_xDatasource; + std::unique_ptr m_xOk; + std::unique_ptr m_xCancel; + std::unique_ptr m_xManageDatasources; +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_DSSELECT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/finteraction.cxx b/dbaccess/source/ui/dlg/finteraction.cxx new file mode 100644 index 000000000..611119a0c --- /dev/null +++ b/dbaccess/source/ui/dlg/finteraction.cxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "finteraction.hxx" +#include + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::task; + using namespace ::com::sun::star::ucb; + + // OFilePickerInteractionHandler + OFilePickerInteractionHandler::OFilePickerInteractionHandler( const Reference< XInteractionHandler >& _rxMaster ) + :m_xMaster( _rxMaster ) + ,m_bDoesNotExist(false) + { + assert(m_xMaster.is()); + } + + OFilePickerInteractionHandler::~OFilePickerInteractionHandler( ) + { + } + + void SAL_CALL OFilePickerInteractionHandler::handle( const Reference< XInteractionRequest >& _rxRequest ) + { + InteractiveIOException aIoException; + if ( _rxRequest->getRequest() >>= aIoException ) + { + if ( IOErrorCode_NOT_EXISTING == aIoException.Code ) + { + m_bDoesNotExist = true; + return; + } + } + + if ( m_xMaster.is() ) + m_xMaster->handle( _rxRequest ); + } + +} // namespace svt + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/finteraction.hxx b/dbaccess/source/ui/dlg/finteraction.hxx new file mode 100644 index 000000000..fdc70b7fc --- /dev/null +++ b/dbaccess/source/ui/dlg/finteraction.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_FINTERACTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_FINTERACTION_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_FINTERACTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/generalpage.cxx b/dbaccess/source/ui/dlg/generalpage.cxx new file mode 100644 index 000000000..5361fc2d0 --- /dev/null +++ b/dbaccess/source/ui/dlg/generalpage.cxx @@ -0,0 +1,683 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "generalpage.hxx" +#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( const OUString& _eType, const OUString& _rDisplayName ) : eType( _eType ), sDisplayName( _rDisplayName ) { } + }; + typedef std::vector< DisplayedType > DisplayedTypes; + + struct DisplayedTypeLess + { + bool operator() ( const DisplayedType& _rLHS, const DisplayedType& _rRHS ) + { + return _rLHS.eType < _rRHS.eType; + } + }; + } + + void OGeneralPage::initializeTypeList() + { + if ( !m_bInitTypeList ) + return; + + m_bInitTypeList = false; + m_xDatasourceType->clear(); + + if ( !m_pCollection ) + return; + + DisplayedTypes aDisplayedTypes; + + ::dbaccess::ODsnTypeCollection::TypeIterator aEnd = m_pCollection->end(); + for ( ::dbaccess::ODsnTypeCollection::TypeIterator aTypeLoop = m_pCollection->begin(); + aTypeLoop != aEnd; + ++aTypeLoop + ) + { + const OUString& sURLPrefix = aTypeLoop.getURLPrefix(); + if ( !sURLPrefix.isEmpty() ) + { + // skip mysql connection variations. It is handled in another window. + if(sURLPrefix.startsWith("sdbc:mysql:") && !sURLPrefix.startsWith("sdbc:mysql:jdbc:")) + continue; + + OUString sDisplayName = aTypeLoop.getDisplayName(); + if (m_xDatasourceType->find_text(sDisplayName) == -1 && + approveDatasourceType(sURLPrefix, sDisplayName)) + { + aDisplayedTypes.emplace_back( sURLPrefix, sDisplayName ); + } + } + } + std::sort( aDisplayedTypes.begin(), aDisplayedTypes.end(), DisplayedTypeLess() ); + for ( const auto& rDisplayedType : aDisplayedTypes ) + insertDatasourceTypeEntryData( rDisplayedType.eType, rDisplayedType.sDisplayName ); + } + + void OGeneralPageWizard::initializeEmbeddedDBList() + { + if ( !m_bInitEmbeddedDBList ) + return; + + m_bInitEmbeddedDBList = false; + m_xEmbeddedDBType->clear(); + + if ( !m_pCollection ) + return; + + DisplayedTypes aDisplayedTypes; + + ::dbaccess::ODsnTypeCollection::TypeIterator aEnd = m_pCollection->end(); + + SvtMiscOptions aMiscOptions; + + 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( !aMiscOptions.IsExperimentalMode() && sURLPrefix.startsWith("sdbc:embedded:firebird") ) + continue; + aDisplayedTypes.emplace_back( sURLPrefix, sDisplayName ); + } + } + } + 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(const OUString& _sURLPrefix) + { + SPECIAL_MESSAGE eMessage = smNone; + if ( _sURLPrefix.isEmpty()/*_eType == m_eNotSupportedKnownType*/ ) + { + eMessage = smUnsupportedType; + } + + if ( eMessage != m_eLastMessage ) + { + const char* pResId = nullptr; + 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( const OUString& _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_xFT_HelpText(m_xBuilder->weld_label("helpText")) + , m_xLB_DocumentList(new OpenDocumentListBox(m_xBuilder->weld_combo_box("documentList"), "com.sun.star.sdb.OfficeDatabaseDocument")) + , m_xPB_OpenDatabase(new OpenDocumentButton(m_xBuilder->weld_button("openDatabase"), "com.sun.star.sdb.OfficeDatabaseDocument")) + , m_eOriginalCreationMode(eCreateNew) + , m_bInitEmbeddedDBList(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( "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_clicked( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) ); + m_xRB_ConnectDatabase->connect_clicked( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) ); + m_xRB_OpenExistingDatabase->connect_clicked( LINK( this, OGeneralPageWizard, OnSetupModeSelected ) ); + m_xLB_DocumentList->connect_changed( LINK( this, OGeneralPageWizard, OnDocumentSelected ) ); + m_xPB_OpenDatabase->connect_clicked( LINK( this, OGeneralPageWizard, OnOpenDocument ) ); + + 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)); + + // 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( "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"; + 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_NOARG( OGeneralPageWizard, OnSetupModeSelected, weld::Button&, void ) + { + 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()); + 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->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 000000000..e8af35387 --- /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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_GENERALPAGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_GENERALPAGE_HXX + +#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( const OUString& _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(const OUString& _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_xFT_HelpText; + std::unique_ptr m_xLB_DocumentList; + std::unique_ptr m_xPB_OpenDatabase; + + // 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; + 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::Button&, void ); + DECL_LINK( OnDocumentSelected, weld::ComboBox&, void ); + DECL_LINK( OnOpenDocument, weld::Button&, void ); + }; + +} // namespace dbaui +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_GENERALPAGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/indexdialog.cxx b/dbaccess/source/ui/dlg/indexdialog.cxx new file mode 100644 index 000000000..978fa9f36 --- /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_clicked(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, 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 OString&, rClicked, void) + { + if (rClicked == "ID_INDEX_NEW") + OnNewIndex(); + else if (rClicked == "ID_INDEX_DROP") + OnDropIndex(); + else if (rClicked == "ID_INDEX_RENAME") + OnRenameIndex(); + else if (rClicked == "ID_INDEX_SAVE") + OnSaveIndex(); + else if (rClicked == "ID_INDEX_RESET") + OnResetIndex(); + } + + IMPL_LINK_NOARG(DbaIndexDialog, OnCloseDialog, weld::Button&, void) + { + if (m_bEditingActive) + { + OSL_ENSURE(!m_bEditAgain, "DbaIndexDialog::OnCloseDialog: somebody was faster than hell!"); + // this means somebody entered a new name, which was invalid, which cause us to posted us an event, + // and before the event arrived the user clicked onto "close". VERY fast, this user... + m_xIndexList->end_editing(); + if (m_bEditAgain) + // could not commit the new name (started a new - asynchronous - edit trial) + return; + } + + // the currently selected entry + std::unique_ptr 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) + { + // 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::Button&, 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(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 000000000..8676ff24d --- /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 + +namespace dbaui +{ + +static 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 bool WantMouseEvent() const override { return true; } + 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(long 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(const IndexFields& _rFields) + { + // copy the field descriptions + m_aFields = _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(long _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(long _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(long _nRow, IndexFields::const_iterator& _rPos) + { + _rPos = m_aFields.end(); + if ((_nRow < 0) || (_nRow >= static_cast(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*/, long _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(long _nRow,sal_uInt16 nColId) const + { + IndexFields::const_iterator aRow = m_aFields.end(); + if ( _nRow >= 0 ) + { + aRow = m_aFields.begin() + _nRow; + OSL_ENSURE(aRow <= m_aFields.end(), "IndexFieldsControl::SeekRow: invalid row!"); + } + return GetRowCellText(aRow,nColId); + } + OUString IndexFieldsControl::GetRowCellText(const IndexFields::const_iterator& _rRow,sal_uInt16 nColId) const + { + if (_rRow < m_aFields.end()) + { + switch (nColId) + { + case COLUMN_ID_FIELDNAME: + return _rRow->sFieldName; + case COLUMN_ID_ORDER: + if (_rRow->sFieldName.isEmpty()) + return OUString(); + else + return _rRow->bSortAscending ? m_sAscendingText : m_sDescendingText; + default: + OSL_FAIL("IndexFieldsControl::GetCurrentRowCellText: invalid column id!"); + } + } + return OUString(); + } + bool IndexFieldsControl::IsTabAllowed(bool /*bForward*/) const + { + return false; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/odbcconfig.cxx b/dbaccess/source/ui/dlg/odbcconfig.cxx new file mode 100644 index 000000000..49b120d13 --- /dev/null +++ b/dbaccess/source/ui/dlg/odbcconfig.cxx @@ -0,0 +1,327 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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); + +#define NSQLAllocHandle(a,b,c) (*reinterpret_cast(m_pAllocHandle))(a,b,c) +#define NSQLFreeHandle(a,b) (*reinterpret_cast(m_pFreeHandle))(a,b) +#define NSQLSetEnvAttr(a,b,c,d) (*reinterpret_cast(m_pSetEnvAttr))(a,b,c,d) +#define NSQLDataSources(a,b,c,d,e,f,g,h) (*reinterpret_cast(m_pDataSources))(a,b,c,d,e,f,g,h) +#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 = NSQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_pImpl->hEnvironment); + if (SQL_SUCCESS != nResult) + // can't do anything without environment + return false; + + NSQLSetEnvAttr(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) + NSQLFreeHandle(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 = NSQLDataSources(m_pImpl->hEnvironment, SQL_FETCH_FIRST, szDSN, sizeof(szDSN), &pcbDSN, szDescription, sizeof(szDescription)-1, &pcbDescription); + ; + nResult = NSQLDataSources(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.get() ) + 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.get()) + m_pProcessWait->disableCallback(); +} + +void OOdbcManagement::receivedCallback() +{ + if (m_pProcessWait.get()) + m_pProcessWait->receivedCallback(); +} + +bool OOdbcManagement::isRunning() const +{ + return ( m_pProcessWait.get() && m_pProcessWait->isRunning() ); +} + +#endif // HAVE_ODBC_ADMINISTRATION + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/odbcconfig.hxx b/dbaccess/source/ui/dlg/odbcconfig.hxx new file mode 100644 index 000000000..0b4a78452 --- /dev/null +++ b/dbaccess/source/ui/dlg/odbcconfig.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_ODBCCONFIG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_ODBCCONFIG_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_ODBCCONFIG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/optionalboolitem.cxx b/dbaccess/source/ui/dlg/optionalboolitem.cxx new file mode 100644 index 000000000..5eb4b1272 --- /dev/null +++ b/dbaccess/source/ui/dlg/optionalboolitem.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 "optionalboolitem.hxx" + +namespace dbaui +{ + + // OptionalBoolItem + OptionalBoolItem::OptionalBoolItem( sal_uInt16 _nWhich ) + :SfxPoolItem( _nWhich ) + ,m_aValue() + { + } + + 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 000000000..25aef5cec --- /dev/null +++ b/dbaccess/source/ui/dlg/optionalboolitem.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_OPTIONALBOOLITEM_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_OPTIONALBOOLITEM_HXX + +#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; } + 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_OPTIONALBOOLITEM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/paramdialog.cxx b/dbaccess/source/ui/dlg/paramdialog.cxx new file mode 100644 index 000000000..a7bd8ae15 --- /dev/null +++ b/dbaccess/source/ui/dlg/paramdialog.cxx @@ -0,0 +1,339 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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_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_xOKBtn->set_has_default(false); + m_xTravelNext->set_has_default(true); + } + } + + 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[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_xTravelNext->set_has_default(false); + m_xOKBtn->set_has_default(true); + } + } + + IMPL_LINK(OParameterDialog, OnValueModified, weld::Entry&, rEdit, void) + { + // mark the currently selected entry as dirty + OSL_ENSURE(o3tl::make_unsigned(m_nCurrentlySelected) < m_aVisitedParams.size(), "OParameterDialog::OnValueModified : invalid entry !"); + m_aVisitedParams[m_nCurrentlySelected] |= VisitFlags::Dirty; + rEdit.set_message_type(weld::EntryMessageType::Normal); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/queryfilter.cxx b/dbaccess/source/ui/dlg/queryfilter.cxx new file mode 100644 index 000000000..5eeb86ef0 --- /dev/null +++ b/dbaccess/source/ui/dlg/queryfilter.cxx @@ -0,0 +1,773 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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() +{ +} + +#define LbText(x) ((x).get_active_text()) +#define LbPos(x) ((x).get_active()) + +sal_Int32 DlgFilterCrit::GetOSQLPredicateType( const OUString& _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 + { + OUString sTableName; + _rFilter.Name = _rField.get_active_text(); + Reference< XPropertySet > xColumn = getQueryColumn(_rFilter.Name); + if ( xColumn.is() ) + { + bool bFunction = false; + 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 aCatlog,aSchema,aTable; + ::dbtools::qualifiedNameComponents( m_xMetaData, sTableName, aCatlog, aSchema, aTable, ::dbtools::EComposeRule::InDataManipulation ); + sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation ); + } + } + xColumn->getPropertyValue(PROPERTY_REALNAME) >>= _rFilter.Name; + static const char sAgg[] = "AggregateFunction"; + if ( xInfo->hasPropertyByName(sAgg) ) + xColumn->getPropertyValue(sAgg) >>= bHaving; + static const char sFunction[] = "Function"; + if ( xInfo->hasPropertyByName(sFunction) ) + xColumn->getPropertyValue(sFunction) >>= bFunction; + } + if ( !bFunction ) + { + const OUString aQuote = m_xMetaData.is() ? m_xMetaData->getIdentifierQuoteString() : OUString(); + _rFilter.Name = ::dbtools::quoteName(aQuote,_rFilter.Name); + if ( !sTableName.isEmpty() ) + { + sTableName += "." + _rFilter.Name; + _rFilter.Name = sTableName; + } + } + } + } + catch(const Exception&) + { + } + + _rFilter.Handle = GetOSQLPredicateType( _rComp.get_active_text() ); + if ( SQLFilterOperator::SQLNULL != _rFilter.Handle && _rFilter.Handle != SQLFilterOperator::NOT_SQLNULL ) + { + OUString sPredicateValue; + m_aPredicateInput.getPredicateValue( _rValue.get_text(), getMatchingColumn( _rValue ) ) >>= sPredicateValue; + if ( _rFilter.Handle == SQLFilterOperator::LIKE || + _rFilter.Handle == SQLFilterOperator::NOT_LIKE ) + ::Replace_OS_PlaceHolder( sPredicateValue ); + _rFilter.Value <<= sPredicateValue; + } + return bHaving; +} + +Reference< XPropertySet > DlgFilterCrit::getColumn( const OUString& _rFieldName ) const +{ + Reference< XPropertySet > xColumn; + try + { + if ( m_xColumns.is() && m_xColumns->hasByName( _rFieldName ) ) + m_xColumns->getByName( _rFieldName ) >>= xColumn; + + Reference< XNameAccess> xColumns = Reference< XColumnsSupplier >(m_xQueryComposer,UNO_QUERY_THROW)->getColumns(); + if ( xColumns.is() && !xColumn.is() ) + { + Sequence< OUString> aSeq = xColumns->getElementNames(); + const OUString* pIter = aSeq.getConstArray(); + const OUString* pEnd = pIter + aSeq.getLength(); + for(;pIter != pEnd;++pIter) + { + Reference 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, const OUString& rField) +{ + const sal_Int32 nCnt = rBox.get_count(); + + for( sal_Int32 i=0 ; iset_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( LbPos(*m_xLB_WHEREFIELD2) == 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( LbPos(*m_xLB_WHEREFIELD1) == 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( LbPos(*m_xLB_WHEREFIELD2) == 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( LbPos(*m_xLB_WHEREFIELD3) == 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 && + ((LbPos(*m_xLB_WHERECOMP1) == m_xLB_WHERECOMP1->get_count()-1) || + (LbPos(*m_xLB_WHERECOMP1) == m_xLB_WHERECOMP1->get_count()-2)) ) + m_xET_WHEREVALUE1->set_sensitive(false); + + if(m_xLB_WHERECOMP2->get_count() > 2 && + ((LbPos(*m_xLB_WHERECOMP2) == m_xLB_WHERECOMP2->get_count()-1) || + (LbPos(*m_xLB_WHERECOMP2) == m_xLB_WHERECOMP2->get_count()-2)) ) + m_xET_WHEREVALUE2->set_sensitive(false); + + if(m_xLB_WHERECOMP3->get_count() > 2 && + ((LbPos(*m_xLB_WHERECOMP3) == m_xLB_WHERECOMP3->get_count()-1) || + (LbPos(*m_xLB_WHERECOMP3) == 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 = LbText(*m_xLB_WHEREFIELD1); + pComp = m_xLB_WHERECOMP1.get(); + } + else if(&rListBox == m_xLB_WHEREFIELD2.get()) + { + aName = LbText(*m_xLB_WHEREFIELD2); + pComp = m_xLB_WHERECOMP2.get(); + } + else + { + aName = LbText(*m_xLB_WHEREFIELD3); + 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,aHaving; + aFilter.realloc(1); + aHaving.realloc(1); + + if( LbPos(*m_xLB_WHEREFIELD1) != 0 ) + { + PropertyValue aValue; + if ( getCondition(*m_xLB_WHEREFIELD1,*m_xLB_WHERECOMP1,*m_xET_WHEREVALUE1,aValue) ) + { + aHaving[0].realloc(1); + aHaving[0][0] = aValue; + } + else + { + aFilter[0].realloc(1); + aFilter[0][0] = aValue; + } + } + + if( LbPos(*m_xLB_WHEREFIELD2) != 0 ) + { + PropertyValue aValue; + Sequence >& _rValues = aFilter; + if ( getCondition(*m_xLB_WHEREFIELD2,*m_xLB_WHERECOMP2,*m_xET_WHEREVALUE2,aValue) ) + _rValues = aHaving; + PropertyValue* pPos = nullptr; + if ( m_xLB_WHERECOND2->get_active() ) + { + sal_Int32 nPos = _rValues.getLength(); + _rValues.realloc( nPos + 1); + _rValues[nPos].realloc( 1); + pPos = &_rValues[nPos][0]; + } + else + { + sal_Int32 nPos = _rValues.getLength() - 1; + sal_Int32 nAndPos = _rValues[nPos].getLength(); + _rValues[nPos].realloc( _rValues[nPos].getLength() + 1); + pPos = &_rValues[nPos][nAndPos]; + } + *pPos = aValue; + } + + if( LbPos(*m_xLB_WHEREFIELD3) != 0 ) + { + PropertyValue aValue; + Sequence >& _rValues = aFilter; + if ( getCondition(*m_xLB_WHEREFIELD3,*m_xLB_WHERECOMP3,*m_xET_WHEREVALUE3,aValue) ) + _rValues = aHaving; + PropertyValue* pPos = nullptr; + if (m_xLB_WHERECOND3->get_active()) + { + sal_Int32 nPos = _rValues.getLength(); + _rValues.realloc( nPos + 1); + _rValues[nPos].realloc( 1); + pPos = &_rValues[nPos][0]; + } + else + { + sal_Int32 nPos = _rValues.getLength() - 1; + sal_Int32 nAndPos = _rValues[nPos].getLength(); + _rValues[nPos].realloc( _rValues[nPos].getLength() + 1); + pPos = &_rValues[nPos][nAndPos]; + } + *pPos = 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 000000000..f06935f5e --- /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 + { + const OUString sNameProperty = "Name"; + const OUString sAscendingProperty = "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 000000000..39ba6dc8e --- /dev/null +++ b/dbaccess/source/ui/dlg/sqlmessage.cxx @@ -0,0 +1,607 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +#define RET_MORE RET_RETRY + 1 + +using namespace dbtools; +using namespace com::sun::star::uno; +using namespace com::sun::star::sdb; +using namespace com::sun::star::sdbc; + +namespace dbaui +{ + +namespace +{ + class ImageProvider + { + private: + OUString m_defaultImageID; + + public: + explicit ImageProvider(const OUString& defaultImageID) + : m_defaultImageID(defaultImageID) + { + } + + const OUString& getImage() const + { + return m_defaultImageID; + } + }; + + class LabelProvider + { + private: + OUString m_label; + public: + explicit LabelProvider(const char* 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 ); + const char* 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 empty; + _out_rChain.swap( empty ); + } + + 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, const ExceptionDisplayChain& rExceptions); + +protected: + DECL_LINK(OnExceptionSelected, weld::TreeView&, void); +}; + +} + +OExceptionChainDialog::OExceptionChainDialog(weld::Window* pParent, const 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(rExceptions) +{ + int nListWidth = m_xExceptionText->get_approximate_digit_width() * 28; + int nTextWidth = m_xExceptionText->get_approximate_digit_width() * 42; + int nHeight = m_xExceptionList->get_height_rows(6); + m_xExceptionList->set_size_request(nListWidth, nHeight); + m_xExceptionText->set_size_request(nTextWidth, nHeight); + + m_sStatusLabel = DBA_RES( STR_EXCEPTION_STATUS ); + m_sErrorCodeLabel = DBA_RES( STR_EXCEPTION_ERRORCODE ); + + m_xExceptionList->connect_changed(LINK(this, OExceptionChainDialog, OnExceptionSelected)); + + bool bHave22018 = false; + size_t elementPos = 0; + + for (auto const& elem : m_aExceptions) + { + lcl_insertExceptionEntry(*m_xExceptionList, elementPos, elem); + bHave22018 = elem.sSQLState == "22018"; + ++elementPos; + } + + // if the error has the code 22018, then add an additional explanation + // #i24021# + if ( bHave22018 ) + { + ProviderFactory aProviderFactory; + + ExceptionDisplayInfo aInfo22018; + aInfo22018.sMessage = DBA_RES( STR_EXPLAN_STRINGCONVERSION_ERROR ); + aInfo22018.pLabelProvider = aProviderFactory.getLabelProvider( SQLExceptionInfo::TYPE::SQLContext, false ); + aInfo22018.pImageProvider = aProviderFactory.getImageProvider( SQLExceptionInfo::TYPE::SQLContext ); + m_aExceptions.push_back( aInfo22018 ); + + lcl_insertExceptionEntry(*m_xExceptionList, m_aExceptions.size() - 1, aInfo22018); + } + + if (m_xExceptionList->n_children()) + { + m_xExceptionList->select(0); + OnExceptionSelected(*m_xExceptionList); + } +} + +IMPL_LINK_NOARG(OExceptionChainDialog, OnExceptionSelected, weld::TreeView&, void) +{ + OUString sText; + + OUString sId(m_xExceptionList->get_selected_id()); + if (!sId.isEmpty()) + { + const ExceptionDisplayInfo& aExceptionInfo(m_aExceptions[sId.toUInt32()]); + + if ( !aExceptionInfo.sSQLState.isEmpty() ) + { + sText += m_sStatusLabel + ": " + aExceptionInfo.sSQLState + "\n"; + } + + if ( !aExceptionInfo.sErrorCode.isEmpty() ) + { + sText += m_sErrorCodeLabel + ": " + aExceptionInfo.sErrorCode + "\n"; + } + + if ( !sText.isEmpty() ) + sText += "\n"; + + sText += aExceptionInfo.sMessage; + } + + m_xExceptionText->set_text(sText); +} + +// SQLMessageBox_Impl +struct SQLMessageBox_Impl +{ + ExceptionDisplayChain aDisplayInfo; + + explicit SQLMessageBox_Impl( const SQLExceptionInfo& _rExceptionInfo ) + { + // transform the exception chain to a form more suitable for displaying it here + ProviderFactory aProviderFactory; + lcl_buildExceptionChain( _rExceptionInfo, aProviderFactory, aDisplayInfo ); + } +}; + +namespace +{ + void lcl_addButton(weld::MessageDialog* pDialog, StandardButtonType eType, bool bDefault) + { + sal_uInt16 nButtonID = 0; + switch (eType) + { + case StandardButtonType::Yes: + nButtonID = RET_YES; + pDialog->add_button(GetStandardText(StandardButtonType::Yes), nButtonID); + break; + case StandardButtonType::No: + nButtonID = RET_NO; + pDialog->add_button(GetStandardText(StandardButtonType::No), nButtonID); + break; + case StandardButtonType::OK: + nButtonID = RET_OK; + pDialog->add_button(GetStandardText(StandardButtonType::OK), nButtonID); + break; + case StandardButtonType::Cancel: + nButtonID = RET_CANCEL; + pDialog->add_button(GetStandardText(StandardButtonType::Cancel), nButtonID); + break; + case StandardButtonType::Retry: + nButtonID = RET_RETRY; + pDialog->add_button(GetStandardText(StandardButtonType::Retry), nButtonID); + break; + case StandardButtonType::Help: + nButtonID = RET_HELP; + pDialog->add_button(GetStandardText(StandardButtonType::Help), nButtonID); + break; + default: + OSL_FAIL( "lcl_addButton: invalid button id!" ); + break; + } + if (bDefault) + pDialog->set_default_response(nButtonID); + } +} + +void OSQLMessageBox::impl_fillMessages() +{ + OSL_PRECOND( !m_pImpl->aDisplayInfo.empty(), "OSQLMessageBox::impl_fillMessages: nothing to display at all?" ); + + if ( m_pImpl->aDisplayInfo.empty() ) + return; + const ExceptionDisplayInfo* pSecondInfo = nullptr; + + const ExceptionDisplayInfo& rFirstInfo = *m_pImpl->aDisplayInfo.begin(); + if ( m_pImpl->aDisplayInfo.size() > 1 ) + pSecondInfo = &m_pImpl->aDisplayInfo[1]; + OUString sPrimary, sSecondary; + sPrimary = rFirstInfo.sMessage; + // one or two texts to display? + if ( pSecondInfo ) + { + // we show two elements in the main dialog if and only if one of + // - the first element in the chain is an SQLContext, and the second + // element denotes its sub entry + // - the first and the second element are both independent (i.e. the second + // is no sub entry), and none of them is a context. + bool bFirstElementIsContext = ( rFirstInfo.eType == SQLExceptionInfo::TYPE::SQLContext ); + bool bSecondElementIsContext = ( pSecondInfo->eType == SQLExceptionInfo::TYPE::SQLContext ); + + if ( bFirstElementIsContext && pSecondInfo->bSubEntry ) + sSecondary = pSecondInfo->sMessage; + if ( !bFirstElementIsContext && !bSecondElementIsContext ) + sSecondary = pSecondInfo->sMessage; + } + + // primary text + m_xDialog->set_primary_text(lcl_stripOOoBaseVendor(sPrimary)); + + // secondary text (if applicable) + m_xDialog->set_secondary_text(lcl_stripOOoBaseVendor(sSecondary)); +} + +void OSQLMessageBox::impl_createStandardButtons( MessBoxStyle _nStyle ) +{ + if ( _nStyle & MessBoxStyle::YesNoCancel ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::Yes, bool(_nStyle & MessBoxStyle::DefaultYes)); + lcl_addButton(m_xDialog.get(), StandardButtonType::No, bool(_nStyle & MessBoxStyle::DefaultNo)); + lcl_addButton(m_xDialog.get(), StandardButtonType::Cancel, bool(_nStyle & MessBoxStyle::DefaultCancel)); + } + else if ( _nStyle & MessBoxStyle::OkCancel ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::OK, bool(_nStyle & MessBoxStyle::DefaultOk)); + lcl_addButton(m_xDialog.get(), StandardButtonType::Cancel, bool(_nStyle & MessBoxStyle::DefaultCancel)); + } + else if ( _nStyle & MessBoxStyle::YesNo ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::Yes, bool(_nStyle & MessBoxStyle::DefaultYes)); + lcl_addButton(m_xDialog.get(), StandardButtonType::No, bool(_nStyle & MessBoxStyle::DefaultNo)); + } + else if ( _nStyle & MessBoxStyle::RetryCancel ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::Retry, bool(_nStyle & MessBoxStyle::DefaultRetry)); + lcl_addButton(m_xDialog.get(), StandardButtonType::Cancel, bool(_nStyle & MessBoxStyle::DefaultCancel)); + } + else if ( _nStyle & MessBoxStyle::Ok ) + { + lcl_addButton(m_xDialog.get(), StandardButtonType::OK, true); + } + + if ( m_sHelpURL.isEmpty() ) + return; + + lcl_addButton(m_xDialog.get(), StandardButtonType::Help, false); + + OUString aTmp; + INetURLObject aHID( m_sHelpURL ); + if ( aHID.GetProtocol() == INetProtocol::Hid ) + aTmp = aHID.GetURLPath(); + else + aTmp = m_sHelpURL; + + m_xDialog->set_help_id(OUStringToOString(aTmp, RTL_TEXTENCODING_UTF8)); +} + +void OSQLMessageBox::impl_addDetailsButton() +{ + size_t nFirstPageVisible = m_xDialog->get_secondary_text().isEmpty() ? 1 : 2; + + bool bMoreDetailsAvailable = m_pImpl->aDisplayInfo.size() > nFirstPageVisible; + if ( !bMoreDetailsAvailable ) + { + // even if the text fits into what we can display, we might need to details button + // if there is more non-trivial information in the errors than the mere messages + for (auto const& error : m_pImpl->aDisplayInfo) + { + if ( lcl_hasDetails(error) ) + { + bMoreDetailsAvailable = true; + break; + } + } + } + + if ( bMoreDetailsAvailable ) + { + m_xDialog->add_button(GetStandardText(StandardButtonType::More), RET_MORE); + m_xMoreButton.reset(m_xDialog->weld_widget_for_response(RET_MORE)); + m_xMoreButton->connect_clicked(LINK(this, OSQLMessageBox, ButtonClickHdl)); + } +} + +void OSQLMessageBox::Construct(weld::Window* pParent, MessBoxStyle _nStyle, MessageType _eImage) +{ + // init the image + MessageType eType( _eImage ); + if ( eType == AUTO ) + { + switch ( m_pImpl->aDisplayInfo[0].eType ) + { + case SQLExceptionInfo::TYPE::SQLException: eType = Error; break; + case SQLExceptionInfo::TYPE::SQLWarning: eType = Warning; break; + case SQLExceptionInfo::TYPE::SQLContext: eType = Info; break; + default: OSL_FAIL( "OSQLMessageBox::Construct: invalid type!" ); + } + } + VclMessageType eMessageType; + switch (eType) + { + default: + OSL_FAIL( "OSQLMessageBox::impl_initImage: unsupported image type!" ); + [[fallthrough]]; + case Info: + eMessageType = VclMessageType::Info; + break; + case Warning: + eMessageType = VclMessageType::Warning; + break; + case Error: + eMessageType = VclMessageType::Error; + break; + case Query: + eMessageType = VclMessageType::Question; + break; + } + + m_xDialog.reset(Application::CreateMessageDialog(pParent, eMessageType, VclButtonsType::NONE, "")); + m_xDialog->set_title(utl::ConfigManager::getProductName() + " Base"); + + impl_fillMessages(); + + // create buttons + impl_createStandardButtons( _nStyle ); + impl_addDetailsButton(); +} + +OSQLMessageBox::OSQLMessageBox(weld::Window* pParent, const SQLExceptionInfo& rException, MessBoxStyle nStyle, const OUString& rHelpURL) + : m_pImpl(new SQLMessageBox_Impl(rException)) + , m_sHelpURL(rHelpURL) +{ + Construct(pParent, nStyle, AUTO); +} + +OSQLMessageBox::OSQLMessageBox(weld::Window* pParent, const OUString& rTitle, const OUString& rMessage, MessBoxStyle nStyle, MessageType eType, const ::dbtools::SQLExceptionInfo* pAdditionalErrorInfo ) +{ + SQLContext aError; + aError.Message = rTitle; + aError.Details = rMessage; + if (pAdditionalErrorInfo) + aError.NextException = pAdditionalErrorInfo->get(); + + m_pImpl.reset(new SQLMessageBox_Impl(SQLExceptionInfo(aError))); + + Construct(pParent, nStyle, eType); +} + +OSQLMessageBox::~OSQLMessageBox() +{ +} + +IMPL_LINK_NOARG(OSQLMessageBox, ButtonClickHdl, weld::Button&, void) +{ + OExceptionChainDialog aDlg(m_xDialog.get(), m_pImpl->aDisplayInfo); + aDlg.run(); +} + +// OSQLWarningBox +OSQLWarningBox::OSQLWarningBox(weld::Window* pParent, const OUString& rMessage, MessBoxStyle nStyle, + const ::dbtools::SQLExceptionInfo* pAdditionalErrorInfo ) + : OSQLMessageBox(pParent, DBA_RES(STR_EXCEPTION_WARNING), rMessage, nStyle, MessageType::Warning, pAdditionalErrorInfo) +{ +} + +// OSQLErrorBox +OSQLErrorBox::OSQLErrorBox(weld::Window* pParent, const OUString& rMessage) + : OSQLMessageBox(pParent, DBA_RES(STR_EXCEPTION_ERROR), rMessage, MessBoxStyle::Ok | MessBoxStyle::DefaultOk, + MessageType::Error, nullptr) +{ +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/tablespage.cxx b/dbaccess/source/ui/dlg/tablespage.cxx new file mode 100644 index 000000000..586cf77bf --- /dev/null +++ b/dbaccess/source/ui/dlg/tablespage.cxx @@ -0,0 +1,496 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 TableTreeListBox(m_xBuilder->weld_tree_view("treeview"))) + { + 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.getStr(), 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, 0); + } + 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; + // the current DSN + OUString sURL; + if ( m_pTablesDlg ) + sURL = m_pTablesDlg->getConnectionURL(); + + 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,makeAny(aNewTableFilter)); + + xProp->setPropertyValue( PROPERTY_TABLETYPEFILTER, makeAny( 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, 0); + } + 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_NOARG(OTableSubscriptionPage, OnTreeEntryChecked, const row_col&, void) + { + weld::TreeView& rTreeView = m_xTablesList->GetWidget(); + std::unique_ptr xEntry(rTreeView.make_iterator()); + if (rTreeView.get_cursor(xEntry.get())) + m_xTablesList->checkedButton_noBroadcast(*xEntry); + callModifiedHdl(); + } + + Sequence< OUString > OTableSubscriptionPage::collectDetailedSelection() const + { + Sequence< OUString > aTableFilter; + static const char sWildcard[] = "%"; + + 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, 0) == 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)).append(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)).append("."); + } + + 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[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.realloc(1); + aTableFilter[0] = "%"; + } + 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 000000000..0eb1273d1 --- /dev/null +++ b/dbaccess/source/ui/dlg/tablespage.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_DLG_TABLESPAGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_DLG_TABLESPAGE_HXX + +#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; + + typedef std::pair row_col; + DECL_LINK(OnTreeEntryChecked, const row_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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_DLG_TABLESPAGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/dlg/textconnectionsettings.cxx b/dbaccess/source/ui/dlg/textconnectionsettings.cxx new file mode 100644 index 000000000..5076b3d32 --- /dev/null +++ b/dbaccess/source/ui/dlg/textconnectionsettings.cxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 000000000..bcc0d3052 --- /dev/null +++ b/dbaccess/source/ui/inc/AppElementType.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_APPELEMENTTYPE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_APPELEMENTTYPE_HXX + +#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 PreviewMode + { + E_PREVIEWNONE = 0, + E_DOCUMENT = 1, + E_DOCUMENTINFO = 2 + }; + + enum ElementOpenMode + { + E_OPEN_NORMAL, + E_OPEN_DESIGN, + E_OPEN_FOR_MAIL + }; + +} // namespace dbaui +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_APPELEMENTTYPE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/CollectionView.hxx b/dbaccess/source/ui/inc/CollectionView.hxx new file mode 100644 index 000000000..7d693329f --- /dev/null +++ b/dbaccess/source/ui/inc/CollectionView.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_COLLECTIONVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_COLLECTIONVIEW_HXX + +#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, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + virtual ~OCollectionView() override; + const css::uno::Reference< css::ucb::XContent>& getSelectedFolder() const { return m_xContent;} + OUString getName() const; + }; +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_COLLECTIONVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ColumnControlWindow.hxx b/dbaccess/source/ui/inc/ColumnControlWindow.hxx new file mode 100644 index 000000000..1b6d4a5fd --- /dev/null +++ b/dbaccess/source/ui/inc/ColumnControlWindow.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_COLUMNCONTROLWINDOW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_COLUMNCONTROLWINDOW_HXX + +#include "FieldDescControl.hxx" +#include "TypeInfo.hxx" +#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(long nRow, sal_uInt16 nColId ) override; + + public: + OColumnControlWindow(vcl::Window* 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; + }; +} // namespace dbaui +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_COLUMNCONTROLWINDOW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ConnectionLine.hxx b/dbaccess/source/ui/inc/ConnectionLine.hxx new file mode 100644 index 000000000..89dd1dff2 --- /dev/null +++ b/dbaccess/source/ui/inc/ConnectionLine.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_CONNECTIONLINE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_CONNECTIONLINE_HXX + +#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 const & pLineData ); + OConnectionLine( const OConnectionLine& rLine ); + ~OConnectionLine(); + + OConnectionLine& operator=( const OConnectionLine& rLine ); + + tools::Rectangle GetBoundingRect() const; + bool RecalcLine(); + void Draw( OutputDevice* pOutDev ); + bool CheckHit( const Point& rMousePos ) const; + + bool IsValid() const; + + tools::Rectangle GetSourceTextPos() const; + tools::Rectangle GetDestTextPos() const; + + const OConnectionLineDataRef& GetData() const { return m_pData; } + + Point getMidPoint() const; + }; + +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_CONNECTIONLINE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ConnectionLineAccess.hxx b/dbaccess/source/ui/inc/ConnectionLineAccess.hxx new file mode 100644 index 000000000..4365e7134 --- /dev/null +++ b/dbaccess/source/ui/inc/ConnectionLineAccess.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_CONNECTIONLINEACCESS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_CONNECTIONLINEACCESS_HXX + +#include "TableConnection.hxx" +#include +#include +#include +#include + +namespace dbaui +{ + typedef ::cppu::ImplHelper2< css::accessibility::XAccessibleRelationSet, + css::accessibility::XAccessible + > OConnectionLineAccess_BASE; + class OTableConnection; + /** the class OConnectionLineAccess represents the accessible object for the connection between two table windows + like they are used in the QueryDesign and the RelationDesign + */ + class OConnectionLineAccess : public VCLXAccessibleComponent + , public OConnectionLineAccess_BASE + { + VclPtr m_pLine; // the window which I should give accessibility to + protected: + /** this function is called upon disposing the component + */ + virtual void SAL_CALL disposing() override; + + public: + OConnectionLineAccess(OTableConnection* _pLine); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire( ) throw () override + { // here inline is allowed because we do not use this class outside this dll + VCLXAccessibleComponent::acquire( ); + } + virtual void SAL_CALL release( ) throw () override + { // here inline is allowed because we do not use this class outside this dll + VCLXAccessibleComponent::release( ); + } + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override; + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole( ) override; + virtual OUString SAL_CALL getAccessibleDescription( ) override; + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override; + + // XAccessibleComponent + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + virtual css::awt::Rectangle SAL_CALL getBounds( ) override; + virtual css::awt::Point SAL_CALL getLocation( ) override; + virtual css::awt::Point SAL_CALL getLocationOnScreen( ) override; + virtual css::awt::Size SAL_CALL getSize( ) override; + + // XAccessibleRelationSet + virtual sal_Int32 SAL_CALL getRelationCount( ) override; + virtual css::accessibility::AccessibleRelation SAL_CALL getRelation( sal_Int32 nIndex ) override; + virtual sal_Bool SAL_CALL containsRelation( sal_Int16 aRelationType ) override; + virtual css::accessibility::AccessibleRelation SAL_CALL getRelationByType( sal_Int16 aRelationType ) override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_CONNECTIONLINEACCESS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ConnectionLineData.hxx b/dbaccess/source/ui/inc/ConnectionLineData.hxx new file mode 100644 index 000000000..4a3f16c86 --- /dev/null +++ b/dbaccess/source/ui/inc/ConnectionLineData.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_CONNECTIONLINEDATA_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_CONNECTIONLINEDATA_HXX + +#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( const OUString& rSourceFieldName, const OUString& rDestFieldName ); + OConnectionLineData( const OConnectionLineData& rConnLineData ); + // provide a copy of own instance (this is somehow more acceptable for me compared to a virtual assignment operator + void CopyFrom(const OConnectionLineData& rSource); + + // member access (write) + void SetFieldName(EConnectionSide nWhich, const OUString& strFieldName) + { + if (nWhich==JTCS_FROM) + m_aSourceFieldName = strFieldName; + else + m_aDestFieldName = strFieldName; + } + void SetSourceFieldName( const OUString& rSourceFieldName){ SetFieldName(JTCS_FROM, rSourceFieldName); } + void SetDestFieldName( const OUString& rDestFieldName ){ SetFieldName(JTCS_TO, rDestFieldName); } + + // member access (read) + const OUString& GetFieldName(EConnectionSide nWhich) const { return (nWhich == JTCS_FROM) ? m_aSourceFieldName : m_aDestFieldName; } + OUString const & GetSourceFieldName() const { return GetFieldName(JTCS_FROM); } + OUString const & GetDestFieldName() const { return GetFieldName(JTCS_TO); } + + void Reset(); + OConnectionLineData& operator=( const OConnectionLineData& rConnLineData ); + }; + + typedef ::rtl::Reference< OConnectionLineData > OConnectionLineDataRef; + typedef std::vector< OConnectionLineDataRef > OConnectionLineDataVec; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_CONNECTIONLINEDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/DExport.hxx b/dbaccess/source/ui/inc/DExport.hxx new file mode 100644 index 000000000..fca471a84 --- /dev/null +++ b/dbaccess/source/ui/inc/DExport.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DEXPORT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DEXPORT_HXX + +#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, + const TPositions& _rColumnPositions, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* rList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled, + SvStream& _rInputStream + ); + + void SetColumnTypes(const TColumnVector* rList,const OTypeInfoMap* _pInfoMap); + + void SetTableName(const OUString &_sTableName){ m_sDefaultTableName = _sTableName ; } + + void enableCheckOnly() { m_bCheckOnly = true; } + bool isCheckEnabled() const { return m_bCheckOnly; } + + static css::uno::Reference< css::sdbc::XPreparedStatement > createPreparedStatment( const css::uno::Reference< css::sdbc::XDatabaseMetaData>& _xMetaData + ,const css::uno::Reference< css::beans::XPropertySet>& _xDestTable + ,const TPositions& _rvColumnPositions); + }; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/FieldControls.hxx b/dbaccess/source/ui/inc/FieldControls.hxx new file mode 100644 index 000000000..98c1a7cfc --- /dev/null +++ b/dbaccess/source/ui/inc/FieldControls.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_FIELDCONTROLS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_FIELDCONTROLS_HXX + +#include "SqlNameEdit.hxx" + +namespace dbaui +{ + + class OPropColumnEditCtrl : public OSQLNameEntry + { + short m_nPos; + OUString m_strHelpText; + public: + OPropColumnEditCtrl(std::unique_ptr xEntry, OUString const & _rAllowedChars, const char* 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, const char* 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, const char* 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, const char* 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; } + }; + +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_FIELDCONTROLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/FieldDescControl.hxx b/dbaccess/source/ui/inc/FieldDescControl.hxx new file mode 100644 index 000000000..0de625a64 --- /dev/null +++ b/dbaccess/source/ui/inc/FieldDescControl.hxx @@ -0,0 +1,203 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_FIELDDESCCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_FIELDDESCCONTROL_HXX + +#include +#include +#include +#include +#include "QEnumTypes.hxx" +#include +#include +#include "TypeInfo.hxx" + +// field description columns of a table +#define FIELD_NAME 1 +#define FIELD_TYPE 2 +#define HELP_TEXT 3 +#define COLUMN_DESCRIPTION 4 + +#define FIELD_FIRST_VIRTUAL_COLUMN 5 + +#define FIELD_PROPERTY_REQUIRED 5 +#define FIELD_PROPERTY_NUMTYPE 6 +#define FIELD_PROPERTY_AUTOINC 7 +#define FIELD_PROPERTY_DEFAULT 8 +#define FIELD_PROPERTY_TEXTLEN 9 +#define FIELD_PROPERTY_LENGTH 10 +#define FIELD_PROPERTY_SCALE 11 +#define FIELD_PROPERTY_BOOL_DEFAULT 12 +#define FIELD_PROPERTY_FORMAT 13 +#define FIELD_PROPERTY_COLUMNNAME 14 +#define FIELD_PROPERTY_TYPE 15 +#define FIELD_PROPERTY_AUTOINCREMENT 16 + +class FixedText; +class PushButton; +class ScrollBar; +class Button; +class ListBox; +class Control; + +namespace dbaui +{ + class OTableDesignHelpBar; + class OPropListBoxCtrl; + class OPropEditCtrl; + class OPropNumericEditCtrl; + class OFieldDescription; + class OPropColumnEditCtrl; + + class OFieldDescControl : public TabPage + { + private: + Idle m_aLayoutIdle; + VclPtr m_xVclContentArea; + std::unique_ptr m_xBuilder; + std::unique_ptr m_xContainer; + + VclPtr 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; + + TOTypeInfoSP m_pPreviousType; + short m_nPos; + OUString aYes; + OUString aNo; + + sal_Int32 m_nEditWidth; + + bool m_bAdded; + + OFieldDescription* pActFieldDescr; + + DECL_LINK(FormatClickHdl, weld::Button&, void); + DECL_LINK(ChangeHdl, weld::ComboBox&, void); + DECL_LINK(ImplHandleLayoutTimerHdl, Timer*, void); + + // used by ActivatePropertyField + DECL_LINK( OnControlFocusLost, weld::Widget&, void ); + DECL_LINK( OnControlFocusGot, weld::Widget&, void ); + + void UpdateFormatSample(OFieldDescription const * pFieldDescr); + + bool isTextFormat(const OFieldDescription* _pFieldDescr,sal_uInt32& _nFormatKey) const; + std::unique_ptr CreateNumericControl(const OString& rId, const char* pHelpId, short _nProperty, const OString& _sHelpId); + void InitializeControl(weld::Widget* _pControl,const OString& _sHelpId); + void InitializeControl(OPropListBoxCtrl* _pControl,const OString& _sHelpId,bool _bAddChangeHandler); + + bool IsFocusInEditableWidget() const; + + 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(long 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(const OUString& 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, vcl::Window* pParent, OTableDesignHelpBar* pHelpBar); + virtual ~OFieldDescControl() override; + virtual void dispose() override; + + void DisplayData(OFieldDescription* pFieldDescr ); + + void SaveData( OFieldDescription* pFieldDescr ); + + void SetControlText( sal_uInt16 nControlId, const OUString& rText ); + void SetReadOnly( bool bReadOnly ); + + // when resize is called + bool isCutAllowed() const; + bool isCopyAllowed() const; + bool isPasteAllowed() const; + + void cut(); + void copy(); + void paste(); + + void Init(); + virtual void GetFocus() override; + virtual void LoseFocus() override; + virtual void Resize() override; + + virtual void queue_resize(StateChangedType eReason = StateChangedType::Layout) override; + + 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; + + void setEditWidth(sal_Int32 _nWidth) { m_nEditWidth = _nWidth; } + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/FieldDescriptions.hxx b/dbaccess/source/ui/inc/FieldDescriptions.hxx new file mode 100644 index 000000000..576a4016b --- /dev/null +++ b/dbaccess/source/ui/inc/FieldDescriptions.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_FIELDDESCRIPTIONS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_FIELDDESCRIPTIONS_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_FIELDDESCRIPTIONS_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/GeneralUndo.hxx b/dbaccess/source/ui/inc/GeneralUndo.hxx new file mode 100644 index 000000000..3a7365c1d --- /dev/null +++ b/dbaccess/source/ui/inc/GeneralUndo.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_GENERALUNDO_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_GENERALUNDO_HXX + +#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(const char* pCommentID) { m_strComment = DBA_RES(pCommentID); } + + virtual OUString GetComment() const override { return m_strComment; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_GENERALUNDO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/HtmlReader.hxx b/dbaccess/source/ui/inc/HtmlReader.hxx new file mode 100644 index 000000000..89c142ae2 --- /dev/null +++ b/dbaccess/source/ui/inc/HtmlReader.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_HTMLREADER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_HTMLREADER_HXX + +#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, + const 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 + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/IClipBoardTest.hxx b/dbaccess/source/ui/inc/IClipBoardTest.hxx new file mode 100644 index 000000000..428116704 --- /dev/null +++ b/dbaccess/source/ui/inc/IClipBoardTest.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_ICLIPBOARDTEST_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_ICLIPBOARDTEST_HXX +#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() {} + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_ICLIPBOARDTEST_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/IItemSetHelper.hxx b/dbaccess/source/ui/inc/IItemSetHelper.hxx new file mode 100644 index 000000000..8b0fe5f88 --- /dev/null +++ b/dbaccess/source/ui/inc/IItemSetHelper.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_IITEMSETHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_IITEMSETHELPER_HXX + +#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() {} + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_IITEMSETHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/IUpdateHelper.hxx b/dbaccess/source/ui/inc/IUpdateHelper.hxx new file mode 100644 index 000000000..975eef75c --- /dev/null +++ b/dbaccess/source/ui/inc/IUpdateHelper.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_IUPDATEHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_IUPDATEHELPER_HXX + +#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() {} + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_IUPDATEHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JAccess.hxx b/dbaccess/source/ui/inc/JAccess.hxx new file mode 100644 index 000000000..f5410bef9 --- /dev/null +++ b/dbaccess/source/ui/inc/JAccess.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_JACCESS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_JACCESS_HXX + +#include "JoinTableView.hxx" +#include +#include +#include + +namespace dbaui +{ + class OJoinTableView; + typedef ::cppu::ImplHelper1< css::accessibility::XAccessible + > OJoinDesignViewAccess_BASE; + /** the class OJoinDesignViewAccess represents the accessible object for join views + like the QueryDesign and the RelationDesign + */ + class OJoinDesignViewAccess : public VCLXAccessibleComponent, public OJoinDesignViewAccess_BASE + { + VclPtr m_pTableView; // the window which I should give accessibility to + + public: + /** OJoinDesignViewAccess needs a valid view + */ + OJoinDesignViewAccess( OJoinTableView* _pTableView); + + // XInterface + DECLARE_XINTERFACE( ) + DECLARE_XTYPEPROVIDER( ) + + virtual OUString SAL_CALL getImplementationName() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole( ) override; + + void notifyAccessibleEvent( + const sal_Int16 _nEventId, + const css::uno::Any& _rOldValue, + const css::uno::Any& _rNewValue + ) + { + NotifyAccessibleEvent(_nEventId,_rOldValue,_rNewValue); + } + + void clearTableView(); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_JACCESS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JoinController.hxx b/dbaccess/source/ui/inc/JoinController.hxx new file mode 100644 index 000000000..94638e638 --- /dev/null +++ b/dbaccess/source/ui/inc/JoinController.hxx @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_JOINCONTROLLER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_JOINCONTROLLER_HXX + +#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, long nOffsetX, long nOffsetY ); + + static void SaveTabWinPosSize(OTableWindow const * pTabWin, long nOffsetX, 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_JOINCONTROLLER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JoinDesignView.hxx b/dbaccess/source/ui/inc/JoinDesignView.hxx new file mode 100644 index 000000000..c1153e346 --- /dev/null +++ b/dbaccess/source/ui/inc/JoinDesignView.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_JOINDESIGNVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_JOINDESIGNVIEW_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_JOINDESIGNVIEW_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JoinExchange.hxx b/dbaccess/source/ui/inc/JoinExchange.hxx new file mode 100644 index 000000000..a1a73595a --- /dev/null +++ b/dbaccess/source/ui/inc/JoinExchange.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_JOINEXCHANGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_JOINEXCHANGE_HXX + +#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 TransferableHelper, public OJoinExchObj_Base + { + bool m_bFirstEntry; + + OJoinExchangeData m_jxdSourceDescription; + IDragTransferableListener* m_pDragListener; + + virtual ~OJoinExchObj() override; + + public: + OJoinExchObj(const OJoinExchangeData& jxdSource, bool _bFirstEntry); + + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire( ) throw() override; + virtual void SAL_CALL release( ) throw() override; + + // XUnoTunnel + static css::uno::Sequence< sal_Int8 > getUnoTunnelId(); + virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& _rIdentifier ) override; + + void StartDrag( vcl::Window* pWindow, sal_Int8 nDragSourceActions, IDragTransferableListener* _pListener ); + + 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; + virtual void DragFinished( sal_Int8 nDropAction ) override; + + using TransferableHelper::StartDrag; + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/JoinTableView.hxx b/dbaccess/source/ui/inc/JoinTableView.hxx new file mode 100644 index 000000000..413cccf32 --- /dev/null +++ b/dbaccess/source/ui/inc/JoinTableView.hxx @@ -0,0 +1,327 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_JOINTABLEVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_JOINTABLEVIEW_HXX + +#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_pCornerWindow; + 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 + ScrollBar& GetHScrollBar() { return *m_aHScrollBar; } + ScrollBar& GetVScrollBar() { return *m_aVScrollBar; } + }; + + + class OJoinTableView : public vcl::Window, + public IDragTransferableListener, + public DropTargetHelper + { + friend class OJoinMoveTabWinUndoAct; + + public: + typedef std::map > 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; + OJoinDesignViewAccess* m_pAccessible; + + public: + OJoinTableView( vcl::Window* pParent, OJoinDesignView* pView ); + virtual ~OJoinTableView() override; + virtual void dispose() override; + + // window override + virtual void StateChanged( StateChangedType nStateChange ) override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + virtual void KeyInput( const KeyEvent& rEvt ) override; + // Accessibility + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + + // own methods + ScrollBar& GetHScrollBar() { return static_cast(GetParent())->GetHScrollBar(); } + ScrollBar& GetVScrollBar() { return static_cast(GetParent())->GetVScrollBar(); } + DECL_LINK( ScrollHdl, ScrollBar*, void ); + + void DrawConnections(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect); + void InvalidateConnections(); + + void BeginChildMove( OTableWindow* pTabWin, const Point& rMousePos ); + void BeginChildSizing( OTableWindow* pTabWin, PointerStyle nPointer ); + + void NotifyTitleClicked( OTableWindow* pTabWin, const Point& rMousePos ); + + virtual void AddTabWin(const OUString& _rComposedName, const OUString& rWinName, bool bNewTable = false); + virtual void RemoveTabWin( OTableWindow* pTabWin ); + + // hide all TabWins (does NOT delete them; they are put in an UNDO action) + void HideTabWins(); + + virtual void AddConnection(const OJoinExchangeData& jxdSource, const OJoinExchangeData& jxdDest) = 0; + + /** RemoveConnection allows to remove connections from join table view + + it implies that the same as addConnection + + @param rConnection the connection which should be removed + @param bDelete when true then the connection will be deleted + + @return an iterator to next valid connection, so it can be used in any loop + */ + virtual bool RemoveConnection(VclPtr& 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( long nDelta, bool bHoriz, bool bPaintScrollBars ); + sal_uLong GetTabWinCount() const; + const Point& GetScrollOffset() const { return m_aScrollOffset; } + + OJoinDesignView* getDesignView() const { return m_pView; } + OTableWindow* GetTabWindow( const OUString& rName ); + + VclPtr& 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 _bSupressCrossOrNaturalJoin = 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 supressCrossNaturalJoin(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; + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QEnumTypes.hxx b/dbaccess/source/ui/inc/QEnumTypes.hxx new file mode 100644 index 000000000..d88a7f4d6 --- /dev/null +++ b/dbaccess/source/ui/inc/QEnumTypes.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_QENUMTYPES_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QENUMTYPES_HXX + +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 + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryDesignView.hxx b/dbaccess/source/ui/inc/QueryDesignView.hxx new file mode 100644 index 000000000..4f0571786 --- /dev/null +++ b/dbaccess/source/ui/inc/QueryDesignView.hxx @@ -0,0 +1,156 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYDESIGNVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYDESIGNVIEW_HXX + +#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 setNoneVisbleRow(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(const OUString& 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(const OUString& 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYDESIGNVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryPropertiesDialog.hxx b/dbaccess/source/ui/inc/QueryPropertiesDialog.hxx new file mode 100644 index 000000000..901427c05 --- /dev/null +++ b/dbaccess/source/ui/inc/QueryPropertiesDialog.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYPROPERTIESDIALOG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYPROPERTIESDIALOG_HXX + +#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 + +#endif /// INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYPROPERTIESDIALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryTableView.hxx b/dbaccess/source/ui/inc/QueryTableView.hxx new file mode 100644 index 000000000..e1c442704 --- /dev/null +++ b/dbaccess/source/ui/inc/QueryTableView.hxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYTABLEVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYTABLEVIEW_HXX + +#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 supressCrossNaturalJoin(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; + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryTextView.hxx b/dbaccess/source/ui/inc/QueryTextView.hxx new file mode 100644 index 000000000..c41a7cea7 --- /dev/null +++ b/dbaccess/source/ui/inc/QueryTextView.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYTEXTVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYTEXTVIEW_HXX + +#include "querycontainerwindow.hxx" + +namespace dbaui +{ + class OSqlEdit; + class OQueryTextView : public vcl::Window + { + friend class OQueryViewSwitch; + VclPtr m_pEdit; + public: + OQueryTextView( OQueryContainerWindow* pParent ); + virtual ~OQueryTextView() override; + virtual void dispose() override; + + 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; + // allow access to our edit + OSqlEdit* getSqlEdit() const { return m_pEdit; } + + OQueryContainerWindow* getContainerWindow() { return static_cast< OQueryContainerWindow* >( GetParent() ); } + protected: + virtual void Resize() override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYTEXTVIEW_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/QueryViewSwitch.hxx b/dbaccess/source/ui/inc/QueryViewSwitch.hxx new file mode 100644 index 000000000..879c29b01 --- /dev/null +++ b/dbaccess/source/ui/inc/QueryViewSwitch.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYVIEWSWITCH_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYVIEWSWITCH_HXX + +#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 setNoneVisbleRow(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 ); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYVIEWSWITCH_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RTableConnectionData.hxx b/dbaccess/source/ui/inc/RTableConnectionData.hxx new file mode 100644 index 000000000..bfff5fc9a --- /dev/null +++ b/dbaccess/source/ui/inc/RTableConnectionData.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_RTABLECONNECTIONDATA_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_RTABLECONNECTIONDATA_HXX + +#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(); + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_RTABLECONNECTIONDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelControliFace.hxx b/dbaccess/source/ui/inc/RelControliFace.hxx new file mode 100644 index 000000000..a6bfa0ec9 --- /dev/null +++ b/dbaccess/source/ui/inc/RelControliFace.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_RELCONTROLIFACE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_RELCONTROLIFACE_HXX + +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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_RELCONTROLIFACE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationControl.hxx b/dbaccess/source/ui/inc/RelationControl.hxx new file mode 100644 index 000000000..a2d3a0e35 --- /dev/null +++ b/dbaccess/source/ui/inc/RelationControl.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONCONTROL_HXX + +#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; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONCONTROL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationController.hxx b/dbaccess/source/ui/inc/RelationController.hxx new file mode 100644 index 000000000..d8901f8e9 --- /dev/null +++ b/dbaccess/source/ui/inc/RelationController.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONCONTROLLER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONCONTROLLER_HXX + +#include +#include "JoinController.hxx" +#include + +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(const OUString& _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; + // need by registration + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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 ); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONCONTROLLER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationDesignView.hxx b/dbaccess/source/ui/inc/RelationDesignView.hxx new file mode 100644 index 000000000..bc69359c8 --- /dev/null +++ b/dbaccess/source/ui/inc/RelationDesignView.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONDESIGNVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONDESIGNVIEW_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONDESIGNVIEW_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationDlg.hxx b/dbaccess/source/ui/inc/RelationDlg.hxx new file mode 100644 index 000000000..e3fe49f13 --- /dev/null +++ b/dbaccess/source/ui/inc/RelationDlg.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONDLG_HXX + +#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); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RelationTableView.hxx b/dbaccess/source/ui/inc/RelationTableView.hxx new file mode 100644 index 000000000..0bc8c8627 --- /dev/null +++ b/dbaccess/source/ui/inc/RelationTableView.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONTABLEVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_RELATIONTABLEVIEW_HXX + +#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; + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/RtfReader.hxx b/dbaccess/source/ui/inc/RtfReader.hxx new file mode 100644 index 000000000..c24ca3817 --- /dev/null +++ b/dbaccess/source/ui/inc/RtfReader.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_RTFREADER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_RTFREADER_HXX + +#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, + const 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 + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/ScrollHelper.hxx b/dbaccess/source/ui/inc/ScrollHelper.hxx new file mode 100644 index 000000000..87e50018a --- /dev/null +++ b/dbaccess/source/ui/inc/ScrollHelper.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_SCROLLHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_SCROLLHELPER_HXX + +#include +#include + +namespace dbaui +{ + class OScrollHelper + { + Link m_aUpScroll; + Link m_aDownScroll; + public: + /** default constructor + */ + OScrollHelper(); + + ~OScrollHelper(); + + /** set the memthod which should be called when scrolling up + @param _rUpScroll + the method to set + */ + void setUpScrollMethod( const Link& _rUpScroll ) + { + m_aUpScroll = _rUpScroll; + } + + /** set the memthod which should be called when scrolling down + @param _rDownScroll + the method to set + */ + void setDownScrollMethod( const Link& _rDownScroll ) + { + m_aDownScroll = _rDownScroll; + } + + /** check if a scroll method has to be called + @param _rPoint + the current selection point + @param _rOutputSize + the output size of the window + */ + void scroll(const Point& _rPoint, const Size& _rOutputSize); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_SCROLLHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/SqlNameEdit.hxx b/dbaccess/source/ui/inc/SqlNameEdit.hxx new file mode 100644 index 000000000..7a6e43c15 --- /dev/null +++ b/dbaccess/source/ui/inc/SqlNameEdit.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_SQLNAMEEDIT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_SQLNAMEEDIT_HXX + +#include +#include + +namespace dbaui +{ + class OSQLNameChecker + { + OUString m_sAllowedChars; + bool m_bCheck; // true when we should check for invalid chars + public: + OSQLNameChecker(const OUString& _rAllowedChars) + :m_sAllowedChars(_rAllowedChars) + ,m_bCheck(true) + { + } + + void setAllowedChars(const OUString& _rAllowedChars) + { + m_sAllowedChars = _rAllowedChars; + } + void setCheck(bool _bCheck) + { + m_bCheck = _bCheck; + } + bool checkString(const OUString& _sToCheck,OUString& _rsCorrected); + }; + + class OSQLNameEdit : public Edit + ,public OSQLNameChecker + { + public: + OSQLNameEdit(vcl::Window* _pParent,WinBits nStyle = WB_BORDER, const OUString& _rAllowedChars = OUString()) + : Edit(_pParent,nStyle) + , OSQLNameChecker(_rAllowedChars) + { + } + + // Edit overrides + virtual void Modify() override; + }; + + 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); } + void set_sensitive(bool bSensitive) { m_xEntry->set_sensitive(bSensitive); } + 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(); + } + }; + +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_SQLNAMEEDIT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableConnection.hxx b/dbaccess/source/ui/inc/TableConnection.hxx new file mode 100644 index 000000000..73aa51d50 --- /dev/null +++ b/dbaccess/source/ui/inc/TableConnection.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECONNECTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECONNECTION_HXX + +#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, const TTableConnectionData::value_type& pTabConnData ); + OTableConnection( const OTableConnection& rConn ); + /** destructor + + @attention Normally a pointer to OTableConnectionData is given but + here, however, one has to create an instance (with + OTableConnectionDate::NewInstance) which is never deleted + (same like in other cases). Thus, the caller is + responsible to check and save the data for deleting it + eventually. + */ + virtual ~OTableConnection() override; + virtual void dispose() override; + + OTableConnection& operator=( const OTableConnection& rConn ); + + void Select(); + void Deselect(); + bool IsSelected() const { return m_bSelected; } + bool CheckHit( const Point& rMousePos ) const; + void InvalidateConnection(); + void UpdateLineList(); + + OTableWindow* GetSourceWin() const; + OTableWindow* GetDestWin() const; + + void RecalcLines(); + /** isTableConnection + + @param _pTable the table where we should check if we belong to it + @return true when the source or the destination window are equal + */ + bool isTableConnection(const OTableWindow* _pTable) + { + return (_pTable == GetSourceWin() || _pTable == GetDestWin()); + } + + tools::Rectangle GetBoundingRect() const; + + const TTableConnectionData::value_type& GetData() const { return m_pData; } + const std::vector>& 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; + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableConnectionData.hxx b/dbaccess/source/ui/inc/TableConnectionData.hxx new file mode 100644 index 000000000..c55bce40d --- /dev/null +++ b/dbaccess/source/ui/inc/TableConnectionData.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECONNECTIONDATA_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECONNECTIONDATA_HXX + +#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( const TTableWindowData::value_type& _pReferencingTable, + const TTableWindowData::value_type& _pReferencedTable ); + OTableConnectionData( const OTableConnectionData& rConnData ); + virtual ~OTableConnectionData(); + + /// initialise from a source (more comfortable than a virtual assignment operator) + virtual void CopyFrom(const OTableConnectionData& rSource); + + /** deliver a new instance of my own type + + derived classes have to deliver an instance of their own type + + @note does NOT have to be initialised + */ + virtual std::shared_ptr 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; + +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableController.hxx b/dbaccess/source/ui/inc/TableController.hxx new file mode 100644 index 000000000..6e3192b6c --- /dev/null +++ b/dbaccess/source/ui/inc/TableController.hxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECONTROLLER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECONTROLLER_HXX + +#include "singledoccontroller.hxx" +#include +#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; + // need by registration + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + private: + void startTableListening(); + void stopTableListening(); + virtual void impl_initialize() override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECONTROLLER_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableCopyHelper.hxx b/dbaccess/source/ui/inc/TableCopyHelper.hxx new file mode 100644 index 000000000..670920028 --- /dev/null +++ b/dbaccess/source/ui/inc/TableCopyHelper.hxx @@ -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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECOPYHELPER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECOPYHELPER_HXX + +#include "AppElementType.hxx" +#include "commontypes.hxx" +#include +#include +#include +#include +#include + +class SvTreeListEntry; +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; + SvTreeListEntry* pDroppedAt; + sal_Int8 nAction; + bool bHtml; + bool bError; + + DropDescriptor() + : nType(E_TABLE) + , pDroppedAt(nullptr) + , nAction(DND_ACTION_NONE) + , bHtml(false) + , bError(false) + { } + }; + + OTableCopyHelper(OGenericUnoController* _pControler); + + /** 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 + ,const OUString& _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 + ,const OUString& _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 + ,const OUString& _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, + const OUString& _sDestDataSourceName, + const SharedConnection& _xDestConnection + ); + + /** insert a table into the data source. The source can either be a table or a query + */ + void insertTable( + const OUString& 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, + const OUString& i_rDestDataSource, + const css::uno::Reference< css::sdbc::XConnection>& i_rDestConnection + ); + + }; +} // namespace dbaui +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLECOPYHELPER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableDesignControl.hxx b/dbaccess/source/ui/inc/TableDesignControl.hxx new file mode 100644 index 000000000..9d933b3e6 --- /dev/null +++ b/dbaccess/source/ui/inc/TableDesignControl.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEDESIGNCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEDESIGNCONTROL_HXX + +#include + +#include "IClipBoardTest.hxx" +#include "TypeInfo.hxx" + +namespace dbaui +{ + class OTableDesignView; + + class OTableRowView : public ::svt::EditBrowseBox, public IClipboardTest + { + friend class OTableDesignUndoAct; + + protected: + long m_nDataPos; ///< currently needed row + long m_nCurrentPos; ///< current position of selected column + + private: + sal_uInt16 m_nCurUndoActId; + + public: + OTableRowView(vcl::Window* pParent); + + virtual void SetCellData( long nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) = 0; + virtual void SetCellData( long nRow, sal_uInt16 nColId, const css::uno::Any& _rNewData ) = 0; + virtual css::uno::Any GetCellData( long nRow, sal_uInt16 nColId ) = 0; + virtual void SetControlText( long 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( long nRow ); + + virtual void CopyRows() = 0; + virtual void DeleteRows() = 0; + virtual void InsertRows( long nRow ) = 0; + virtual void InsertNewRows( long nRow ) = 0; + + virtual bool IsPrimaryKeyAllowed() = 0; + virtual bool IsInsertNewAllowed( long nRow ) = 0; + virtual bool IsDeleteAllowed() = 0; + + virtual RowStatus GetRowStatus(long nRow) const override; + virtual void KeyInput(const KeyEvent& rEvt) override; + virtual void Command( const CommandEvent& rEvt ) override; + + virtual void Init() override; + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableDesignHelpBar.hxx b/dbaccess/source/ui/inc/TableDesignHelpBar.hxx new file mode 100644 index 000000000..871183625 --- /dev/null +++ b/dbaccess/source/ui/inc/TableDesignHelpBar.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEDESIGNHELPBAR_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEDESIGNHELPBAR_HXX + +#include +#include "IClipBoardTest.hxx" + +class VclMultiLineEdit; + +namespace dbaui +{ + // Deriving from TabPage is a trick to notice changes + // of the system colors + class OTableDesignHelpBar : public TabPage, public IClipboardTest + { + private: + VclPtr m_pTextWin; + + protected: + virtual void Resize() override; + + public: + OTableDesignHelpBar( vcl::Window* pParent ); + virtual ~OTableDesignHelpBar() override; + virtual void dispose() override; + + void SetHelpText( const OUString& rText ); + + virtual bool PreNotify( NotifyEvent& rNEvt ) 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; + }; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableDesignView.hxx b/dbaccess/source/ui/inc/TableDesignView.hxx new file mode 100644 index 000000000..262e04933 --- /dev/null +++ b/dbaccess/source/ui/inc/TableDesignView.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEDESIGNVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEDESIGNVIEW_HXX + +#include +#include +#include +#include "IClipBoardTest.hxx" + +namespace dbaui +{ + class OTableController; + class OTableFieldDescWin; + class OTableEditorCtrl; + class OTableBorderWindow : public vcl::Window + { + VclPtr m_aHorzSplitter; + VclPtr m_pFieldDescWin; + VclPtr m_pEditorCtrl; + + void ImplInitSettings(); + DECL_LINK( SplitHdl, Splitter*, void ); + protected: + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + public: + OTableBorderWindow(vcl::Window* pParent); + virtual ~OTableBorderWindow() override; + // Window overrides + virtual void dispose() override; + virtual void Resize() override; + virtual void GetFocus() override; + + OTableEditorCtrl* GetEditorCtrl() const { return m_pEditorCtrl; } + OTableFieldDescWin* GetDescWin() const { return m_pFieldDescWin; } + }; + 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; + 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 + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEDESIGNVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableFieldDescription.hxx b/dbaccess/source/ui/inc/TableFieldDescription.hxx new file mode 100644 index 000000000..1834f409f --- /dev/null +++ b/dbaccess/source/ui/inc/TableFieldDescription.hxx @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEFIELDDESCRIPTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEFIELDDESCRIPTION_HXX + +#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; +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableGrantCtrl.hxx b/dbaccess/source/ui/inc/TableGrantCtrl.hxx new file mode 100644 index 000000000..7f7062f52 --- /dev/null +++ b/dbaccess/source/ui/inc/TableGrantCtrl.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEGRANTCTRL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEGRANTCTRL_HXX + +#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 m_pEdit; + 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, long nRow, sal_uInt16 nCol ) override; + virtual ::svt::CellController* GetController( long nRow, sal_uInt16 nCol ) override; + virtual void PaintCell( OutputDevice& rDev, const tools::Rectangle& rRect, sal_uInt16 nColId ) const override; + virtual bool SeekRow( long nRow ) override; + virtual bool SaveModified() override; + virtual OUString GetCellText( long 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; +}; + +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEGRANTCTRL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableRow.hxx b/dbaccess/source/ui/inc/TableRow.hxx new file mode 100644 index 000000000..c7bf3a783 --- /dev/null +++ b/dbaccess/source/ui/inc/TableRow.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEROW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEROW_HXX + +#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 css::uno::Reference< css::beans::XPropertySet >& xAffectedCol); + OTableRow( const OTableRow& rRow, 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 ); + }; + +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEROW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableRowExchange.hxx b/dbaccess/source/ui/inc/TableRowExchange.hxx new file mode 100644 index 000000000..6d3668f6d --- /dev/null +++ b/dbaccess/source/ui/inc/TableRowExchange.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEROWEXCHANGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEROWEXCHANGE_HXX + +#include +#include + +namespace dbaui +{ + class OTableRow; + class OTableRowExchange : public TransferableHelper + { + std::vector< std::shared_ptr > m_vTableRow; + public: + OTableRowExchange(const 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEROWEXCHANGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindow.hxx b/dbaccess/source/ui/inc/TableWindow.hxx new file mode 100644 index 000000000..e356a5a26 --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindow.hxx @@ -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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOW_HXX + +#include +#include +#include "TableWindowTitle.hxx" +#include +#include "TableWindowData.hxx" +#include "TableWindowListBox.hxx" +#include +#include + +#include +#include +#include + +class SvTreeListEntry; + +// 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_aTypeImage; + 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(SvTreeListEntry* /*pEntry*/) { } + // called from the DoubleClickHdl of the ListBox + + /** HandleKeyInput tries to handle the KeyEvent. Movement or deletion + @param rEvt + The KeyEvent + @return + when the table could handle the KeyEvent. + */ + bool HandleKeyInput( const KeyEvent& rEvt ); + + /** 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 m_aTypeImage + */ + void impl_updateImage(); + + OTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData ); + + public: + virtual ~OTableWindow() override; + virtual void dispose() override; + + // late Constructor, see also CreateListbox and FillListbox + virtual bool Init(); + + OJoinTableView* getTableView(); + const OJoinTableView* getTableView() const; + OJoinDesignView* getDesignView(); + void SetPosPixel( const Point& rNewPos ) override; + void SetSizePixel( const Size& rNewSize ) override; + void SetPosSizePixel( const Point& rNewPos, const Size& rNewSize ) override; + + OUString getTitle() const; + void SetBoldTitle( bool bBold ); + void setActive(bool _bActive = true); + + void Remove(); + + OUString const & GetTableName() const { return m_pData->GetTableName(); } + OUString const & GetWinName() const { return m_pData->GetWinName(); } + OUString const & GetComposedName() const { return m_pData->GetComposedName(); } + const VclPtr& 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(); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindowAccess.hxx b/dbaccess/source/ui/inc/TableWindowAccess.hxx new file mode 100644 index 000000000..4ee3539a2 --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindowAccess.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWACCESS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWACCESS_HXX + +#include "TableWindow.hxx" +#include +#include +#include +#include + +namespace dbaui +{ + typedef ::cppu::ImplHelper2< css::accessibility::XAccessibleRelationSet, + css::accessibility::XAccessible + > OTableWindowAccess_BASE; + class OTableWindow; + /** the class OTableWindowAccess represents the accessible object for table windows + like they are used in the QueryDesign and the RelationDesign + */ + class OTableWindowAccess : public VCLXAccessibleComponent + , public OTableWindowAccess_BASE + { + VclPtr m_pTable; // the window which I should give accessibility to + + css::uno::Reference< css::accessibility::XAccessible > getParentChild(sal_Int32 _nIndex); + protected: + /** this function is called upon disposing the component + */ + virtual void SAL_CALL disposing() override; + + virtual void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) override; + public: + OTableWindowAccess( OTableWindow* _pTable); + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire( ) throw () override + { // here inline is allowed because we do not use this class outside this dll + VCLXAccessibleComponent::acquire( ); + } + virtual void SAL_CALL release( ) throw () override + { // here inline is allowed because we do not use this class outside this dll + VCLXAccessibleComponent::release( ); + } + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int32 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 i ) override; + virtual sal_Int32 SAL_CALL getAccessibleIndexInParent( ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole( ) override; + virtual OUString SAL_CALL getAccessibleName( ) override; + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override; + + // XAccessibleComponent + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + + // XAccessibleExtendedComponent + virtual OUString SAL_CALL getTitledBorderText( ) override; + + // XAccessibleRelationSet + virtual sal_Int32 SAL_CALL getRelationCount( ) override; + virtual css::accessibility::AccessibleRelation SAL_CALL getRelation( sal_Int32 nIndex ) override; + virtual sal_Bool SAL_CALL containsRelation( sal_Int16 aRelationType ) override; + virtual css::accessibility::AccessibleRelation SAL_CALL getRelationByType( sal_Int16 aRelationType ) override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWACCESS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindowData.hxx b/dbaccess/source/ui/inc/TableWindowData.hxx new file mode 100644 index 000000000..863d4ab45 --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindowData.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWDATA_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWDATA_HXX + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dbaui +{ + class OTableWindowData : public ::utl::OEventListenerAdapter + { + mutable ::osl::Mutex m_aMutex; + + void listen(); + protected: + // the columns of the table + css::uno::Reference< css::beans::XPropertySet > m_xTable; // can either be a table or a query + css::uno::Reference< css::container::XIndexAccess> m_xKeys; + css::uno::Reference< css::container::XNameAccess > m_xColumns; + + OUString m_aTableName; + OUString m_aWinName; + OUString m_sComposedName; + Point m_aPosition; + Size m_aSize; + bool m_bShowAll; + bool m_bIsQuery; + bool m_bIsValid; + + public: + explicit OTableWindowData( const css::uno::Reference< css::beans::XPropertySet>& _xTable + ,const OUString& _rComposedName + ,const OUString& strTableName + ,const OUString& rWinName ); + virtual ~OTableWindowData() override; + + /** late constructor + * + * \param _xConnection + * \param _bAllowQueries when true, queries are allowed + * \return false if the table was unaccessible otherwise true + */ + bool init(const css::uno::Reference< css::sdbc::XConnection >& _xConnection + ,bool _bAllowQueries); + + const OUString& GetComposedName() const { return m_sComposedName; } + const OUString& GetTableName() const { return m_aTableName; } + const OUString& GetWinName() const { return m_aWinName; } + const Point& GetPosition() const { return m_aPosition; } + const Size& GetSize() const { return m_aSize; } + bool IsShowAll() const { return m_bShowAll; } + bool isQuery() const { return m_bIsQuery; } + bool isValid() const { return m_bIsValid; } // it is either a table or query but it is known + bool HasPosition() const; + bool HasSize() const; + + void SetWinName( const OUString& rWinName ) { m_aWinName = rWinName; } + void SetPosition( const Point& rPos ) { m_aPosition=rPos; } + void SetSize( const Size& rSize ) { m_aSize = rSize; } + void ShowAll( bool bAll ) { m_bShowAll = bAll; } + + css::uno::Reference< css::beans::XPropertySet> getTable() const { ::osl::MutexGuard aGuard( m_aMutex ); return m_xTable; } + css::uno::Reference< css::container::XIndexAccess> getKeys() const { ::osl::MutexGuard aGuard( m_aMutex ); return m_xKeys; } + css::uno::Reference< css::container::XNameAccess > getColumns() const { ::osl::MutexGuard aGuard( m_aMutex ); return m_xColumns; } + + // OEventListenerAdapter + virtual void _disposing( const css::lang::EventObject& _rSource ) override; + }; + + typedef std::vector< std::shared_ptr > TTableWindowData; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindowListBox.hxx b/dbaccess/source/ui/inc/TableWindowListBox.hxx new file mode 100644 index 000000000..1e0f8bd61 --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindowListBox.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWLISTBOX_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWLISTBOX_HXX + +#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) + SvTreeListEntry* pEntry; // the entry, which was dragged or to which was dropped on + + OJoinExchangeData(OTableWindowListBox* pBox); + OJoinExchangeData() : pListBox(nullptr), pEntry(nullptr) { } + }; + struct OJoinDropData + { + OJoinExchangeData aSource; + OJoinExchangeData aDest; + }; + + class OTableWindow; + class OTableWindowListBox + :public SvTreeListBox + ,public IDragTransferableListener + { + DECL_LINK( OnDoubleClick, SvTreeListBox*, bool ); + DECL_LINK( ScrollUpHdl, Timer*, void ); + DECL_LINK( ScrollDownHdl, Timer*, void ); + DECL_LINK( DropHdl, void*, void ); + DECL_LINK( LookForUiHdl, void*, void ); + + Timer m_aScrollTimer; + Point m_aMousePos; + + VclPtr m_pTabWin; + ImplSVEvent * m_nDropEvent; + ImplSVEvent * m_nUiEvent; + OJoinDropData m_aDropInfo; + + bool m_bReallyScrolled : 1; + + protected: + virtual void LoseFocus() override; + virtual void GetFocus() override; + virtual void NotifyScrolled() override; + virtual void NotifyEndScroll() override; + + virtual bool PreNotify(NotifyEvent& rNEvt) override; + + virtual void dragFinished( ) override; + + + public: + OTableWindowListBox(OTableWindow* pParent); + virtual ~OTableWindowListBox() override; + virtual void dispose() override; + + // DnD stuff + virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override; + virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override; + virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override; + + // window + virtual void Command(const CommandEvent& rEvt) override; + + OTableWindow* GetTabWin(){ return m_pTabWin; } + SvTreeListEntry* GetEntryFromText( const OUString& rEntryText ); + + private: + using SvTreeListBox::ExecuteDrop; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWLISTBOX_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TableWindowTitle.hxx b/dbaccess/source/ui/inc/TableWindowTitle.hxx new file mode 100644 index 000000000..50f5dda8a --- /dev/null +++ b/dbaccess/source/ui/inc/TableWindowTitle.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWTITLE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWTITLE_HXX + +#include + +namespace dbaui +{ + class OTableWindow; + class OTableWindowTitle : public FixedText + { + VclPtr m_pTabWin; + + protected: + virtual void Command(const CommandEvent& rEvt) override; + // virtual void Paint( const Rectangle& rRect ); + virtual void MouseButtonDown( const MouseEvent& rEvt ) override; + virtual void KeyInput( const KeyEvent& rEvt ) override; + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + + public: + OTableWindowTitle( OTableWindow* pParent ); + virtual ~OTableWindowTitle() override; + virtual void dispose() override; + virtual void LoseFocus() override; + virtual void GetFocus() override; + virtual void RequestHelp( const HelpEvent& rHEvt ) override; + // window override + virtual void StateChanged( StateChangedType nStateChange ) override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLEWINDOWTITLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TablesSingleDlg.hxx b/dbaccess/source/ui/inc/TablesSingleDlg.hxx new file mode 100644 index 000000000..2cb947a9f --- /dev/null +++ b/dbaccess/source/ui/inc/TablesSingleDlg.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLESSINGLEDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLESSINGLEDLG_HXX + +#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(); + OUString getConnectionURL() const; + 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLESSINGLEDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TokenWriter.hxx b/dbaccess/source/ui/inc/TokenWriter.hxx new file mode 100644 index 000000000..ecf8f9442 --- /dev/null +++ b/dbaccess/source/ui/inc/TokenWriter.hxx @@ -0,0 +1,212 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_TOKENWRITER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TOKENWRITER_HXX + +#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( const SharedConnection& _rxConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rM); + + virtual ~ODatabaseImportExport() override; + + virtual void initialize(); + public: + void setStream(SvStream* _pStream){ m_pStream = _pStream; } + + //for set the tablename + void setSTableName(const OUString &_sTableName){ m_sDefaultTableName = _sTableName; } + + virtual bool Write(); // Export + virtual bool Read(); // Import + + void initialize(const svx::ODataAccessDescriptor& _aDataDescriptor); + void dispose(); + + void enableCheckOnly() { m_bCheckOnly = true; } + bool isCheckEnabled() const { return m_bCheckOnly; } + + private: + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + void impl_initFromDescriptor( const svx::ODataAccessDescriptor& _aDataDescriptor, bool _bPlusDefaultInit ); + }; + + // RTF Import and Export + + class ORTFImportExport : public ODatabaseImportExport + { + void appendRow(OString const * pHorzChar,sal_Int32 _nColumnCount,sal_Int32& k,sal_Int32& kk); + public: + // export data + ORTFImportExport( const svx::ODataAccessDescriptor& _aDataDescriptor, + const css::uno::Reference< css::uno::XComponentContext >& _rM, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF) + : ODatabaseImportExport(_aDataDescriptor,_rM,_rxNumberF) {}; + + // import data + ORTFImportExport( const SharedConnection& _rxConnection, + const css::uno::Reference< css::util::XNumberFormatter >& _rxNumberF, + const css::uno::Reference< css::uno::XComponentContext >& _rM) + : ODatabaseImportExport(_rxConnection,_rxNumberF,_rM) + {} + + virtual bool Write() override; + virtual bool Read() override; + }; + // HTML Import and Export + #define SBA_HTML_FONTSIZES 7 + const sal_Int16 nIndentMax = 23; + class OHTMLImportExport : public ODatabaseImportExport + { + // default HtmlFontSz[1-7] + static const sal_Int16 nDefaultFontSize[SBA_HTML_FONTSIZES]; + // HtmlFontSz[1-7] in s*3.ini [user] + static sal_Int16 nFontSize[SBA_HTML_FONTSIZES]; + 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; + }; + +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TOKENWRITER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/TypeInfo.hxx b/dbaccess/source/ui/inc/TypeInfo.hxx new file mode 100644 index 000000000..36cf41e92 --- /dev/null +++ b/dbaccess/source/ui/inc/TypeInfo.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TYPEINFO_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TYPEINFO_HXX + +#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); +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TYPEINFO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/UITools.hxx b/dbaccess/source/ui/inc/UITools.hxx new file mode 100644 index 000000000..0ea5b03c9 --- /dev/null +++ b/dbaccess/source/ui/inc/UITools.hxx @@ -0,0 +1,393 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_UITOOLS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_UITOOLS_HXX + +#include +#include +#include "TypeInfo.hxx" +#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 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, + const OUString& _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 mapTextAllign(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, + const vcl::Window* _pParent); + + /** second variant of the function before + */ + bool callColumnFormatDialog(const vcl::Window* _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, const char* pTitle, const char* pText, bool bAll, const OUString& 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 insertHierachyElement( + 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 ); + +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_UITOOLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/UserAdminDlg.hxx b/dbaccess/source/ui/inc/UserAdminDlg.hxx new file mode 100644 index 000000000..b30f2cd95 --- /dev/null +++ b/dbaccess/source/ui/inc/UserAdminDlg.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_USERADMINDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_USERADMINDLG_HXX + +#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 OString& rId, SfxTabPage& _rPage) override; + public: + OUserAdminDlg(weld::Window* pParent, SfxItemSet* pItems, + const css::uno::Reference< css::uno::XComponentContext >& rxORB, + const css::uno::Any& rDataSourceName, + const css::uno::Reference< css::sdbc::XConnection>& rConnection); + + virtual ~OUserAdminDlg() override; + + virtual const SfxItemSet* getOutputSet() const override; + virtual SfxItemSet* getWriteOutputSet() override; + + virtual short run() override; + + // forwards to ODbDataSourceAdministrationHelper + virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override; + virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override; + virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override; + virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override; + virtual void clearPassword() override; + virtual void saveDatasource() override; + virtual void setTitle(const OUString& _sTitle) override; + virtual void enableConfirmSettings( bool _bEnable ) override; + }; +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_USERADMINDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/VertSplitView.hxx b/dbaccess/source/ui/inc/VertSplitView.hxx new file mode 100644 index 000000000..25a0a6442 --- /dev/null +++ b/dbaccess/source/ui/inc/VertSplitView.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_VERTSPLITVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_VERTSPLITVIEW_HXX + +#include + +class Splitter; + +namespace dbaui +{ + class OSplitterView : public vcl::Window + { + VclPtr m_pSplitter; + VclPtr m_pLeft; + VclPtr m_pRight; + ImplSVEvent *m_pResizeId; + + void ImplInitSettings(); + DECL_LINK(SplitHdl, Splitter*, void); + DECL_LINK(ResizeHdl, void*, void); + protected: + virtual void DataChanged(const DataChangedEvent& rDCEvt) override; + public: + OSplitterView(vcl::Window* _pParent); + virtual ~OSplitterView() override; + // Window overrides + virtual void dispose() override; + virtual void GetFocus() override; + + void setSplitter(Splitter* _pSplitter); + void set(vcl::Window* _pRight,Window* _pLeft = nullptr); + virtual void Resize() override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_VERTSPLITVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WCPage.hxx b/dbaccess/source/ui/inc/WCPage.hxx new file mode 100644 index 000000000..617f723c7 --- /dev/null +++ b/dbaccess/source/ui/inc/WCPage.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_WCPAGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_WCPAGE_HXX + +#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( AppendDataClickHdl, weld::Button&, void ); + DECL_LINK( RadioChangeHdl, weld::Button&, void ); + DECL_LINK( KeyClickHdl, weld::Button&, 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 ); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_WCPAGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WColumnSelect.hxx b/dbaccess/source/ui/inc/WColumnSelect.hxx new file mode 100644 index 000000000..59ebc0ae8 --- /dev/null +++ b/dbaccess/source/ui/inc/WColumnSelect.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_WCOLUMNSELECT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_WCOLUMNSELECT_HXX + +#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, + const OUString& _sExtraChars, + sal_Int32 _nMaxNameLen, + const ::comphelper::UStringMixEqual& _aCase); + + void moveColumn( weld::TreeView* _pRight, + weld::TreeView const * _pLeft, + std::vector< OUString>& _rRightColumns, + const OUString& _sColumnName, + const OUString& _sExtraChars, + sal_Int32 _nMaxNameLen, + const ::comphelper::UStringMixEqual& _aCase); + + void enableButtons(); + + sal_Int32 adjustColumnPosition(weld::TreeView const * _pLeft, + const OUString& _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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_WCOLUMNSELECT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WCopyTable.hxx b/dbaccess/source/ui/inc/WCopyTable.hxx new file mode 100644 index 000000000..056323245 --- /dev/null +++ b/dbaccess/source/ui/inc/WCopyTable.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_WCOPYTABLE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_WCOPYTABLE_HXX + +#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, + const OUString& _rTableName + ); + + // ICopyTableSourceObject overridables + virtual OUString getQualifiedObjectName() const override; + virtual bool isView() const override; + virtual void copyUISettingsTo( const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual void copyFilterAndSortingTo(const css::uno::Reference< css::sdbc::XConnection >& _xConnection,const css::uno::Reference< css::beans::XPropertySet >& _rxObject ) const override; + virtual css::uno::Sequence< OUString > + getColumnNames() const override; + virtual css::uno::Sequence< OUString > + getPrimaryKeyColumnNames() const override; + virtual OFieldDescription* createFieldDescription( const OUString& _rColumnName ) const override; + virtual OUString getSelectStatement() const override; + virtual ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement > + getPreparedSelectStatement() const override; + + private: + void impl_ensureColumnInfo_throw(); + ::utl::SharedUNOComponent< css::sdbc::XPreparedStatement > const & + impl_ensureStatement_throw(); + }; + + // Wizard Dialog + class OCopyTableWizard : public vcl::RoadmapWizardMachine + { + friend class OWizColumnSelect; + friend class OWizTypeSelect; + friend class OWizTypeSelectControl; + friend class OCopyTable; + friend class OWizNameMatching; + + public: + typedef std::map 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, + const OUString& _rDefaultName, + sal_Int16 _nOperation, + const 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(); + 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, + const OUString& _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(const OUString& _rColumnName); + + void removeColumnNameFromNameMap(const OUString& _sName); + void showError(const OUString& _sErrorMessage); + void showError(const css::uno::Any& _aError); + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_WCOPYTABLE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WExtendPages.hxx b/dbaccess/source/ui/inc/WExtendPages.hxx new file mode 100644 index 000000000..05a251c0e --- /dev/null +++ b/dbaccess/source/ui/inc/WExtendPages.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_WEXTENDPAGES_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_WEXTENDPAGES_HXX + +#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); + } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_WEXTENDPAGES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WNameMatch.hxx b/dbaccess/source/ui/inc/WNameMatch.hxx new file mode 100644 index 000000000..0b4b45617 --- /dev/null +++ b/dbaccess/source/ui/inc/WNameMatch.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_WNAMEMATCH_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_WNAMEMATCH_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_WNAMEMATCH_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WTabPage.hxx b/dbaccess/source/ui/inc/WTabPage.hxx new file mode 100644 index 000000000..0bcd04082 --- /dev/null +++ b/dbaccess/source/ui/inc/WTabPage.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_WTABPAGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_WTABPAGE_HXX + +#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 OString& rID); + + public: + virtual ~OWizardPage() override; + virtual void Reset ( ) = 0; + virtual bool LeavePage() = 0; + virtual OUString GetTitle() const = 0; + + bool IsFirstTime() const { return m_bFirstTime; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_WTABPAGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/WTypeSelect.hxx b/dbaccess/source/ui/inc/WTypeSelect.hxx new file mode 100644 index 000000000..4a0f240a7 --- /dev/null +++ b/dbaccess/source/ui/inc/WTypeSelect.hxx @@ -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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_WTYPESELECT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_WTYPESELECT_HXX + +#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(long 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 show() { m_xControl->show(); } + 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_xColumns; + std::unique_ptr m_xControlContainer; + VclPtr 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&); +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_WTYPESELECT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/adtabdlg.hxx b/dbaccess/source/ui/inc/adtabdlg.hxx new file mode 100644 index 000000000..bad72a5f6 --- /dev/null +++ b/dbaccess/source/ui/inc/adtabdlg.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_ADTABDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_ADTABDLG_HXX + +#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::Button&, 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 ); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_ADTABDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/advancedsettingsdlg.hxx b/dbaccess/source/ui/inc/advancedsettingsdlg.hxx new file mode 100644 index 000000000..f2d6e68cd --- /dev/null +++ b/dbaccess/source/ui/inc/advancedsettingsdlg.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_ADVANCEDSETTINGSDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_ADVANCEDSETTINGSDLG_HXX + +#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 OString& rId, SfxTabPage& _rPage) override; + virtual short Ok() override; + + public: + AdvancedSettingsDialog(weld::Window* pParent, + SfxItemSet* _pItems, + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + const css::uno::Any& _aDataSourceName); + + virtual ~AdvancedSettingsDialog() override; + + /// determines whether or not the given data source type has any advanced setting + static bool doesHaveAnyAdvancedSettings( const OUString& _sURL ); + + virtual const SfxItemSet* getOutputSet() const override; + virtual SfxItemSet* getWriteOutputSet() override; + + // forwards to ODbDataSourceAdministrationHelper + virtual css::uno::Reference< css::uno::XComponentContext > getORB() const override; + virtual std::pair< css::uno::Reference< css::sdbc::XConnection >,bool> createConnection() override; + virtual css::uno::Reference< css::sdbc::XDriver > getDriver() override; + virtual OUString getDatasourceType(const SfxItemSet& _rSet) const override; + virtual void clearPassword() override; + virtual void saveDatasource() override; + virtual void setTitle(const OUString& _sTitle) override; + virtual void enableConfirmSettings( bool _bEnable ) override; + }; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_ADVANCEDSETTINGSDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/asyncmodaldialog.hxx b/dbaccess/source/ui/inc/asyncmodaldialog.hxx new file mode 100644 index 000000000..3b6d2517a --- /dev/null +++ b/dbaccess/source/ui/inc/asyncmodaldialog.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_ASYNCMODALDIALOG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_ASYNCMODALDIALOG_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_ASYNCMODALDIALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/browserids.hxx b/dbaccess/source/ui/inc/browserids.hxx new file mode 100644 index 000000000..44e96431f --- /dev/null +++ b/dbaccess/source/ui/inc/browserids.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_BROWSERIDS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_BROWSERIDS_HXX + +#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_COLUMNINFO 10024 // copies the column description to insert it into the table design +#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 + + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_BROWSERIDS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/brwctrlr.hxx b/dbaccess/source/ui/inc/brwctrlr.hxx new file mode 100644 index 000000000..58a13cf17 --- /dev/null +++ b/dbaccess/source/ui/inc/brwctrlr.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_BRWCTRLR_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_BRWCTRLR_HXX + +#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 + css::uno::Reference< css::uno::XAggregation > m_xFormControllerImpl; + 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 + FormControllerImpl* m_pFormControllerImpl; // 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 ); + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_BRWCTRLR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/brwview.hxx b/dbaccess/source/ui/inc/brwview.hxx new file mode 100644 index 000000000..82a7129f6 --- /dev/null +++ b/dbaccess/source/ui/inc/brwview.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_BRWVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_BRWVIEW_HXX + +#include + +#include +#include + +namespace com::sun::star::awt { + class XControl; + class XControlContainer; + class XControlModel; +} + +class Splitter; + +namespace dbaui +{ + class DBTreeView; + 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 + VclPtr m_pStatus; + + 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(DBTreeView* _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( ); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_BRWVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/callbacks.hxx b/dbaccess/source/ui/inc/callbacks.hxx new file mode 100644 index 000000000..8a607db34 --- /dev/null +++ b/dbaccess/source/ui/inc/callbacks.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_CALLBACKS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_CALLBACKS_HXX + +#include + +class SvTreeListEntry; +class Point; +class PopupMenu; +class Control; +struct AcceptDropEvent; +struct ExecuteDropEvent; + +namespace comphelper { class OInterfaceContainerHelper2; } + +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 SvTreeListEntry* _pEntry, OUString& _rText ) const = 0; + + /** handler for StartDrag requests + @return if a drag operation was started + */ + virtual bool requestDrag( const Point& _rPosPixel ) = 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( Control& _rControl ) 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( Control& _rControl ) 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_CALLBACKS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/charsetlistbox.hxx b/dbaccess/source/ui/inc/charsetlistbox.hxx new file mode 100644 index 000000000..d58c1ca65 --- /dev/null +++ b/dbaccess/source/ui/inc/charsetlistbox.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_CHARSETLISTBOX_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_CHARSETLISTBOX_HXX + +#include +#include "charsets.hxx" + +class SfxItemSet; + +namespace dbaui +{ + // CharSetListBox + class CharSetListBox + { + public: + CharSetListBox(std::unique_ptr xControl); + + void SelectEntryByIanaName( const OUString& _rIanaName ); + bool StoreSelectedCharSet( SfxItemSet& _rSet, const sal_uInt16 _nItemId ); + + weld::ComboBox* get_widget() { return m_xControl.get(); } + void connect_changed(const Link& rLink) { m_xControl->connect_changed(rLink); } + void show() { m_xControl->show(); } + + private: + OCharsetDisplay m_aCharSets; + std::unique_ptr m_xControl; + }; +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_CHARSETLISTBOX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/charsets.hxx b/dbaccess/source/ui/inc/charsets.hxx new file mode 100644 index 000000000..b48e14f6e --- /dev/null +++ b/dbaccess/source/ui/inc/charsets.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_CHARSETS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_CHARSETS_HXX + +#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(const OUString& _rIanaName) const; + const_iterator findDisplayName(const OUString& _rDisplayName) const; + + /// get access to the first element of the charset collection + const_iterator begin() const; + /// get access to the (last + 1st) element of the charset collection + const_iterator end() const; + + private: + virtual bool approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const override; + + using OCharsetDisplay_Base::find; + }; + + //- CharsetDisplayDerefHelper + typedef ::dbtools::CharsetIteratorDerefHelper CharsetDisplayDerefHelper_Base; + class CharsetDisplayDerefHelper final : protected CharsetDisplayDerefHelper_Base + { + friend class OCharsetDisplay::ExtendedCharsetIterator; + + OUString m_sDisplayName; + + public: + CharsetDisplayDerefHelper(const CharsetDisplayDerefHelper& _rSource); + + OUString const & getIanaName() const { return CharsetDisplayDerefHelper_Base::getIanaName(); } + const OUString& getDisplayName() const { return m_sDisplayName; } + + private: + CharsetDisplayDerefHelper(const ::dbtools::CharsetIteratorDerefHelper& _rBase, const OUString& _rDisplayName); + }; + + //- OCharsetDisplay::ExtendedCharsetIterator + class OCharsetDisplay::ExtendedCharsetIterator + { + friend class OCharsetDisplay; + + friend bool operator==(const ExtendedCharsetIterator& lhs, const ExtendedCharsetIterator& rhs); + friend bool operator!=(const ExtendedCharsetIterator& lhs, const ExtendedCharsetIterator& rhs) { return !(lhs == rhs); } + + typedef ::dbtools::OCharsetMap container; + typedef container::CharsetIterator base_iterator; + + protected: + const OCharsetDisplay* m_pContainer; + base_iterator m_aPosition; + + public: + CharsetDisplayDerefHelper operator*() const; + + /// prefix increment + const ExtendedCharsetIterator& operator++(); + + protected: + ExtendedCharsetIterator( const OCharsetDisplay* _pContainer, const base_iterator& _rPosition ); + }; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_CHARSETS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/commontypes.hxx b/dbaccess/source/ui/inc/commontypes.hxx new file mode 100644 index 000000000..6562555e6 --- /dev/null +++ b/dbaccess/source/ui/inc/commontypes.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_COMMONTYPES_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_COMMONTYPES_HXX + +#include + +#include + +namespace com::sun::star { + namespace sdbc { + class XConnection; + } +} + +namespace dbaui +{ + + typedef ::utl::SharedUNOComponent< css::sdbc::XConnection > SharedConnection; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_COMMONTYPES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/curledit.hxx b/dbaccess/source/ui/inc/curledit.hxx new file mode 100644 index 000000000..1b53358c4 --- /dev/null +++ b/dbaccess/source/ui/inc/curledit.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_CURLEDIT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_CURLEDIT_HXX + +#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 OString& rName) { m_xEntry->set_help_id(rName); } + void hide() + { + m_xEntry->hide(); + if (m_bShowPrefix) + m_xForcedPrefix->hide(); + } + void show() + { + m_xEntry->show(); + if (m_bShowPrefix) + m_xForcedPrefix->show(); + } + void save_value() { m_sSavedValue = GetText(); } + bool get_value_changed_from_saved() const { return m_sSavedValue != GetText(); } + void grab_focus() + { + m_xEntry->grab_focus(); + } + void set_sensitive(bool bSensitive) + { + m_xEntry->set_sensitive(bSensitive); + if (m_bShowPrefix) + m_xForcedPrefix->set_sensitive(bSensitive); + } + void connect_focus_in(const Link& 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_CURLEDIT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/databaseobjectview.hxx b/dbaccess/source/ui/inc/databaseobjectview.hxx new file mode 100644 index 000000000..9fa293c0e --- /dev/null +++ b/dbaccess/source/ui/inc/databaseobjectview.hxx @@ -0,0 +1,233 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DATABASEOBJECTVIEW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DATABASEOBJECTVIEW_HXX + +#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, + const OUString& _rComponentURL + ); + virtual ~DatabaseObjectView(){} + + /** sets the target frame into which the view should be loaded. + + By default, the view is loaded into a top-level frame not being part of the + Desktop. + */ + void setTargetFrame( const css::uno::Reference< css::frame::XFrame >& _rxFrame ) + { + m_xFrameLoader.set( _rxFrame, css::uno::UNO_QUERY ); + } + + /** opens a view for a to-be-created object + + @param _xDataSource + the data source for which a new object is to be created + @return + the controller of the newly created document + */ + css::uno::Reference< css::lang::XComponent > + createNew( + const css::uno::Reference< css::sdbc::XDataSource >& _xDataSource, + const ::comphelper::NamedValueCollection& i_rDispatchArgs = ::comphelper::NamedValueCollection() + ); + + /** opens a view for an existent object + + @param _xDataSource + the data source for which a new object is to be created + @param _rObjectName + the name of the object to be edited + @param _rArgs + Additional settings which should be forwarded to the frame + @return + the frame into which the view has been loaded + */ + css::uno::Reference< css::lang::XComponent > + openExisting( + const css::uno::Any& _aDataSource, + const OUString& _rName, + const ::comphelper::NamedValueCollection& i_rDispatchArgs + ); + }; + + // QueryDesigner + class QueryDesigner final : public DatabaseObjectView + { + sal_Int32 m_nCommandType; + + virtual void fillDispatchArgs( + ::comphelper::NamedValueCollection& i_rDispatchArgs, + const css::uno::Any& _aDataSource, + const OUString& _rObjectName + ) override; + + public: + QueryDesigner( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication, + const css::uno::Reference< css::frame::XFrame >& _rxParentFrame, + bool _bCreateView + ); + }; + + // TableDesigner + class TableDesigner : public DatabaseObjectView + { + protected: + virtual void fillDispatchArgs( + ::comphelper::NamedValueCollection& i_rDispatchArgs, + const css::uno::Any& _aDataSource, + const OUString& _rObjectName + ) override; + + virtual css::uno::Reference< css::lang::XComponent > doCreateView( + const css::uno::Any& _rDataSource, + const OUString& _rObjectName, + const ::comphelper::NamedValueCollection& i_rCreationArgs + ) override; + + public: + TableDesigner( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& _rxApplication, + const css::uno::Reference< css::frame::XFrame >& _rxParentFrame + ); + + private: + /** retrieves the table designer component as provided by the connection, if any + @param _rTableName + the name of the table for which a designer is to be obtained + @return + the designer component, as provided by the connection, or , 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DATABASEOBJECTVIEW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/datasourceconnector.hxx b/dbaccess/source/ui/inc/datasourceconnector.hxx new file mode 100644 index 000000000..30cc3cdfe --- /dev/null +++ b/dbaccess/source/ui/inc/datasourceconnector.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DATASOURCECONNECTOR_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DATASOURCECONNECTOR_HXX + +#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, + const OUString& _rContextInformation + ); + + /// 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DATASOURCECONNECTOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbadmin.hxx b/dbaccess/source/ui/inc/dbadmin.hxx new file mode 100644 index 000000000..f0c6ed6c7 --- /dev/null +++ b/dbaccess/source/ui/inc/dbadmin.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DBADMIN_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DBADMIN_HXX + +#include +#include +#include "IItemSetHelper.hxx" +#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; + + OString 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, SfxItemPool*& _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, SfxItemPool*& _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 OString& rPageId, const char* pTextId, CreateTabPage pCreateFunc); + + virtual void PageCreated(const OString& rId, SfxTabPage& _rPage) override; + virtual short Ok() override; + + /// select a datasource with a given name, adjust the item set accordingly, and everything like that .. + void impl_selectDataSource(const css::uno::Any& _aDataSourceName); + /// reset the tag pages according to m_sCurrentDatasource and _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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DBADMIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbexchange.hxx b/dbaccess/source/ui/inc/dbexchange.hxx new file mode 100644 index 000000000..7ee0f5ca2 --- /dev/null +++ b/dbaccess/source/ui/inc/dbexchange.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DBEXCHANGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DBEXCHANGE_HXX + +#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( + 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 + ); + + ODataClipboard( + 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 + ); + + 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 + ); + + // 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; + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DBEXCHANGE_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbtreelistbox.hxx b/dbaccess/source/ui/inc/dbtreelistbox.hxx new file mode 100644 index 000000000..c1678108f --- /dev/null +++ b/dbaccess/source/ui/inc/dbtreelistbox.hxx @@ -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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DBTREELISTBOX_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DBTREELISTBOX_HXX + +#include "ScrollHelper.hxx" + +#include + +#include +#include + +#include +#include + +namespace dbaui +{ + struct DBTreeEditedEntry + { + OUString aNewText; + }; + + class IEntryFilter + { + public: + virtual bool includeEntry(const void* pUserData) const = 0; + + protected: + ~IEntryFilter() {} + }; + + class IControlActionListener; + class IContextMenuProvider; + class DBTreeListBox :public SvTreeListBox + { + OScrollHelper m_aScrollHelper; + Timer m_aTimer; // is needed for table updates + Point m_aMousePos; + std::set m_aSelectedEntries; + SvTreeListEntry* m_pDragedEntry; + IControlActionListener* m_pActionListener; + IContextMenuProvider* m_pContextMenuProvider; + ImplSVEvent* m_pResetEvent; + css::uno::Reference m_xMenuController; + + Link m_aPreExpandHandler; // handler to be called before a node is expanded + 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 + Link m_aEnterKeyHdl; + + private: + void init(); + DECL_LINK( OnTimeOut, Timer*, void ); + DECL_LINK( OnResetEntryHdl, void*, void ); + DECL_LINK( ScrollUpHdl, LinkParamNone*, void ); + DECL_LINK( ScrollDownHdl, LinkParamNone*, void ); + DECL_LINK( MenuEventListener, VclMenuEvent&, void ); + + public: + DBTreeListBox( vcl::Window* pParent, WinBits nWinStyle); + virtual ~DBTreeListBox() override; + virtual void dispose() override; + + void setControlActionListener( IControlActionListener* _pListener ) { m_pActionListener = _pListener; } + void setContextMenuProvider( IContextMenuProvider* _pContextMenuProvider ) { m_pContextMenuProvider = _pContextMenuProvider; } + + void SetPreExpandHandler(const Link& _rHdl) { m_aPreExpandHandler = _rHdl; } + 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; } + + // modified the given entry so that the expand handler is called whenever the entry is expanded + // (normally, the expand handler is called only once) + void EnableExpandHandler(SvTreeListEntry* _pEntry); + + SvTreeListEntry* GetEntryPosByName( const OUString& aName, SvTreeListEntry* pStart = nullptr, const IEntryFilter* _pFilter = nullptr ) const; + virtual void RequestingChildren( SvTreeListEntry* pParent ) override; + virtual void SelectHdl() override; + virtual void DeselectHdl() override; + // Window + virtual void KeyInput( const KeyEvent& rKEvt ) override; + + virtual void StateChanged( StateChangedType nStateChange ) override; + virtual void InitEntry(SvTreeListEntry* pEntry, const OUString& aStr, const Image& aCollEntryBmp, const Image& aExpEntryBmp) override; + + // enable editing for tables/views and queries + virtual bool EditingEntry( SvTreeListEntry* pEntry, Selection& ) override; + virtual bool EditedEntry( SvTreeListEntry* pEntry, const OUString& rNewText ) override; + + virtual bool DoubleClickHdl() override; + + virtual VclPtr CreateContextMenu() override; + virtual void ExecuteContextMenuAction( sal_uInt16 nSelectedPopupEntry ) override; + + void SetEnterKeyHdl(const Link& rNewHdl) {m_aEnterKeyHdl = rNewHdl;} + + void clearCurrentSelection() { m_aSelectedEntries.clear(); } + + protected: + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void RequestHelp( const HelpEvent& rHEvt ) override; + + // DragSourceHelper overridables + virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override; + // DropTargetHelper overridables + virtual sal_Int8 AcceptDrop( const AcceptDropEvent& _rEvt ) override; + virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& _rEvt ) override; + + virtual void ModelHasRemoved( SvTreeListEntry* pEntry ) override; + virtual void ModelHasEntryInvalidated( SvTreeListEntry* pEntry ) override; + + void implStopSelectionTimer(); + void implStartSelectionTimer(); + + protected: + using SvTreeListBox::ExecuteDrop; + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DBTREELISTBOX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbu_dlg.hxx b/dbaccess/source/ui/inc/dbu_dlg.hxx new file mode 100644 index 000000000..02e7034b2 --- /dev/null +++ b/dbaccess/source/ui/inc/dbu_dlg.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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_DBU_DLG_HRC +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DBU_DLG_HRC + +#define WIZARD_PAGE_X 56 +#define WIZARD_PAGE_Y 30 + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbwiz.hxx b/dbaccess/source/ui/inc/dbwiz.hxx new file mode 100644 index 000000000..776d19b52 --- /dev/null +++ b/dbaccess/source/ui/inc/dbwiz.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DBWIZ_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DBWIZ_HXX + +#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; +using vcl::WizardTypes::CommitPageReason; + +namespace dbaccess +{ + class ODsnTypeCollection; +} +namespace dbaui +{ + +// ODbTypeWizDialog +class OGeneralPage; +class ODbDataSourceAdministrationHelper; +/** tab dialog for administrating the office wide registered data sources +*/ +class ODbTypeWizDialog : public vcl::WizardMachine , public IItemSetHelper, public IDatabaseSettingsDialog +{ +private: + std::unique_ptr 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DBWIZ_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dbwizsetup.hxx b/dbaccess/source/ui/inc/dbwizsetup.hxx new file mode 100644 index 000000000..e204dc1f4 --- /dev/null +++ b/dbaccess/source/ui/inc/dbwizsetup.hxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_DBWIZSETUP_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DBWIZSETUP_HXX + +#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::WizardTypes::CommitPageReason; +using vcl::RoadmapWizardTypes::PathId; + +namespace dbaui +{ + +class OGenericAdministrationPage; + +// ODbTypeWizDialogSetup +class OGeneralPage; +class OGeneralPageWizard; +class ODbDataSourceAdministrationHelper; +/** tab dialog for administrating the office wide registered data sources +*/ +class OMySQLIntroPageSetup; +class OFinalDBPageSetup; + +class ODbTypeWizDialogSetup final : public vcl::RoadmapWizardMachine, public IItemSetHelper, public IDatabaseSettingsDialog +{ +private: + std::unique_ptr 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_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(const OUString& 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DBWIZSETUP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/defaultobjectnamecheck.hxx b/dbaccess/source/ui/inc/defaultobjectnamecheck.hxx new file mode 100644 index 000000000..e86f2575c --- /dev/null +++ b/dbaccess/source/ui/inc/defaultobjectnamecheck.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DEFAULTOBJECTNAMECHECK_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DEFAULTOBJECTNAMECHECK_HXX + +#include "objectnamecheck.hxx" + +#include +#include + +#include + +namespace dbaui +{ + + // HierarchicalNameCheck + struct HierarchicalNameCheck_Impl; + /** class implementing the IObjectNameCheck interface, and checking given object names + against a hierarchical name container + */ + class HierarchicalNameCheck :public IObjectNameCheck + { + private: + std::unique_ptr< HierarchicalNameCheck_Impl > m_pImpl; + + public: + /** constructs a HierarchicalNameCheck instance + @param _rxNames + the hierarchical container of named objects, against which given names should be + checked + @param _rRelativeRoot + the root in the hierarchy against which given names should be checked + @throws css::lang::IllegalArgumentException + if the given container is + */ + HierarchicalNameCheck( + const css::uno::Reference< css::container::XHierarchicalNameAccess >& _rxNames, + const OUString& _rRelativeRoot + ); + + virtual ~HierarchicalNameCheck() override; + + HierarchicalNameCheck(const HierarchicalNameCheck&) = delete; + const HierarchicalNameCheck& operator=(const HierarchicalNameCheck&) = delete; + + // IObjectNameCheck overridables + virtual bool isNameValid( + const OUString& _rObjectName, + ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay + ) const override; + }; + + // DynamicTableOrQueryNameCheck + struct DynamicTableOrQueryNameCheck_Impl; + /** class implementing the IObjectNameCheck interface, and checking a given name + for being valid as either a query or a table name. + + The class can be parametrized to act as either table name or query name validator. + + For databases which support queries in queries, the name check is implicitly extended + to both queries and tables, no matter which category is checked. This prevents, for + such databases, that users can create a query with the name of an existing table, + or vice versa. + + @seealso dbtools::DatabaseMetaData::supportsSubqueriesInFrom + @seealso css::sdb::tools::XObjectNames::checkNameForCreate + */ + class DynamicTableOrQueryNameCheck :public IObjectNameCheck + { + private: + std::unique_ptr< DynamicTableOrQueryNameCheck_Impl > m_pImpl; + + public: + /** constructs a DynamicTableOrQueryNameCheck instance + @param _rxSdbLevelConnection + a connection supporting the css.sdb.Connection service, in other word, it + does expose the XTablesSupplier and XQueriesSupplier interfaces. + @param _nCommandType + specifies whether table names or query names should be checked. Only valid values + are CommandType::TABLE and CommandType::QUERY. + @throws css::lang::IllegalArgumentException + if the given connection is , 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DEFAULTOBJECTNAMECHECK_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/directsql.hxx b/dbaccess/source/ui/inc/directsql.hxx new file mode 100644 index 000000000..a58cfde78 --- /dev/null +++ b/dbaccess/source/ui/inc/directsql.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DIRECTSQL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DIRECTSQL_HXX + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +struct ImplSVEvent; + +namespace dbaui +{ + class SQLEditView : public WeldEditView + { + private: + void DoBracketHilight(sal_uInt16 nKey); + public: + SQLEditView(); + virtual bool KeyInput(const KeyEvent& rKEvt) override; + }; + + // 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_xShowOutput; + std::unique_ptr m_xOutput; + std::unique_ptr m_xClose; + std::unique_ptr m_xSQL; + std::unique_ptr m_xSQLEd; + + Timer m_aUpdateDataTimer; + const SyntaxHighlighter m_aHighlighter; + const svtools::ColorConfig m_aColorConfig; + + 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; + bool m_bInUpdate; + + 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); + + Color GetColorValue(TokenType aToken); + + void UpdateData(); + + // 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 ); + DECL_LINK( ImplUpdateDataHdl, Timer*, 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(const OUString& _rMessage); + + /// adds a status text to the output list + void addOutputText(const OUString& _rMessage); + + /// displays resultset + void display(const css::uno::Reference< css::sdbc::XResultSet >& xRS); + +#ifdef DBG_UTIL + const char* impl_CheckInvariants() const; +#endif + }; + +#ifdef DBG_UTIL +#define CHECK_INVARIANTS(methodname) \ + { \ + const char* pError = impl_CheckInvariants(); \ + if (pError) \ + SAL_WARN("dbaccess.ui", methodname ": " << pError); \ + } +#else +#define CHECK_INVARIANTS(methodname) +#endif + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DIRECTSQL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dlgattr.hxx b/dbaccess/source/ui/inc/dlgattr.hxx new file mode 100644 index 000000000..6be420776 --- /dev/null +++ b/dbaccess/source/ui/inc/dlgattr.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DLGATTR_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DLGATTR_HXX + +#include + +class SvxNumberInfoItem; +class SfxItemSet; +class SvNumberFormatter; +namespace dbaui +{ + + class SbaSbAttrDlg : public SfxTabDialogController + { + std::unique_ptr pNumberInfoItem; + + public: + SbaSbAttrDlg(weld::Window * pParent, const SfxItemSet*, SvNumberFormatter*, bool bHasFormat); + virtual ~SbaSbAttrDlg() override; + + virtual void PageCreated(const OString& rPageId, SfxTabPage& rTabPage) override; + }; +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DLGATTR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dlgsave.hxx b/dbaccess/source/ui/inc/dlgsave.hxx new file mode 100644 index 000000000..598cbfb7c --- /dev/null +++ b/dbaccess/source/ui/inc/dlgsave.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DLGSAVE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DLGSAVE_HXX + +#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 OSaveAsDlgImpl; + class IObjectNameCheck; + class OSaveAsDlg : public weld::GenericDialogController + { + private: + std::unique_ptr m_pImpl; + css::uno::Reference< css::uno::XComponentContext > m_xContext; + public: + OSaveAsDlg( weld::Window * pParent, sal_Int32 _rType, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const css::uno::Reference< css::sdbc::XConnection>& _xConnection, + const OUString& rDefault, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags); + + OSaveAsDlg( weld::Window* _pParent, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const OUString& _rDefault, + const OUString& _sLabel, + const IObjectNameCheck& _rObjectNameCheck, + SADFlags _nFlags); + virtual ~OSaveAsDlg() override; + + const OUString& getName() const; + OUString getCatalog() const; + OUString getSchema() const; + private: + DECL_LINK(ButtonClickHdl, weld::Button&, void); + DECL_LINK(EditModifyHdl, weld::Entry&, void); + + void implInitOnlyTitle(const OUString& _rLabel); + void implInit(); + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DLGSAVE_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dlgsize.hxx b/dbaccess/source/ui/inc/dlgsize.hxx new file mode 100644 index 000000000..0d27ba543 --- /dev/null +++ b/dbaccess/source/ui/inc/dlgsize.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DLGSIZE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DLGSIZE_HXX + +#include + +namespace dbaui +{ + + class DlgSize final : public weld::GenericDialogController + { + private: + sal_Int32 m_nPrevValue; + void SetValue( sal_Int32 nVal ); + + DECL_LINK(CbClickHdl, weld::ToggleButton&, 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DLGSIZE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dsitems.hxx b/dbaccess/source/ui/inc/dsitems.hxx new file mode 100644 index 000000000..9d05d0adf --- /dev/null +++ b/dbaccess/source/ui/inc/dsitems.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DSITEMS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DSITEMS_HXX + +#include + +typedef sal_Int32 ItemID; + +// item ids for the data source administration dialog + +#define DSID_NAME 1 // name of a data source, SfxStringItem +#define DSID_ORIGINALNAME 2 // original name, internal, SfxStringItem +#define DSID_CONNECTURL 3 // connection URL, SfxStringItem +#define DSID_TABLEFILTER 4 // table filter, OStringListItem +#define DSID_TYPECOLLECTION 5 // collection of data source types, ODsnTypeCollection +#define DSID_INVALID_SELECTION 6 // is the selection (thus the set data) invalid?, SfxBoolItem +#define DSID_READONLY 7 // is the selection (thus the set data) readonly?, SfxBoolItem +#define DSID_USER 8 // the user name used for logon, SfxStringItem +#define DSID_PASSWORD 9 // the password used for logon, SfxStringItem +#define DSID_ADDITIONALOPTIONS 10 // additional options used for connecting, SfxStringItem +#define DSID_CHARSET 11 // character set to use, SfxStringItem by now +#define DSID_PASSWORDREQUIRED 12 // is the password required to connect?, SfxBoolItem +#define DSID_SHOWDELETEDROWS 13 // show deleted rows?, SfxBoolItem +#define DSID_ALLOWLONGTABLENAMES 14 // allow tables names longer than 8.3?, SfxBoolItem +#define DSID_JDBCDRIVERCLASS 15 // JDBC driver class, SfxStringItem +#define DSID_FIELDDELIMITER 16 // field delimiter, SfxUInt16Item +#define DSID_TEXTDELIMITER 17 // text delimiter, SfxUInt16Item +#define DSID_DECIMALDELIMITER 18 // decimal delimiter, SfxUInt16Item +#define DSID_THOUSANDSDELIMITER 19 // thousands delimiter, SfxUInt16Item +#define DSID_TEXTFILEEXTENSION 20 // extension for text files, SfxStringItem +#define DSID_TEXTFILEHEADER 21 // the text file contains a header?, SfxBoolItem +#define DSID_PARAMETERNAMESUBST 22 +#define DSID_CONN_PORTNUMBER 23 +#define DSID_SUPPRESSVERSIONCL 24 // meta data: sal_True if the data source described by the set is to-be-deleted +#define DSID_CONN_SHUTSERVICE 25 +#define DSID_CONN_DATAINC 26 +#define DSID_CONN_CACHESIZE 27 +#define DSID_CONN_CTRLUSER 28 +#define DSID_CONN_CTRLPWD 29 +#define DSID_USECATALOG 30 // should the driver use the catalog name when the database is filebased +#define DSID_CONN_HOSTNAME 31 +#define DSID_CONN_LDAP_BASEDN 32 +#define DSID_CONN_LDAP_PORTNUMBER 33 +#define DSID_CONN_LDAP_ROWCOUNT 34 +#define DSID_SQL92CHECK 35 +#define DSID_AUTOINCREMENTVALUE 36 +#define DSID_AUTORETRIEVEVALUE 37 +#define DSID_AUTORETRIEVEENABLED 38 +#define DSID_APPEND_TABLE_ALIAS 39 +#define DSID_MYSQL_PORTNUMBER 40 +#define DSID_IGNOREDRIVER_PRIV 41 +#define DSID_BOOLEANCOMPARISON 42 +#define DSID_ORACLE_PORTNUMBER 43 +#define DSID_ENABLEOUTERJOIN 44 +#define DSID_CATALOG 45 +#define DSID_SCHEMA 46 +#define DSID_INDEXAPPENDIX 47 +#define DSID_CONN_LDAP_USESSL 48 +#define DSID_DOCUMENT_URL 49 +#define DSID_DOSLINEENDS 50 +#define DSID_DATABASENAME 51 +#define DSID_AS_BEFORE_CORRNAME 52 +#define DSID_CHECK_REQUIRED_FIELDS 53 +#define DSID_IGNORECURRENCY 54 +#define DSID_CONN_SOCKET 55 +#define DSID_ESCAPE_DATETIME 56 +#define DSID_NAMED_PIPE 57 +#define DSID_PRIMARY_KEY_SUPPORT 58 +#define DSID_MAX_ROW_SCAN 59 +#define DSID_RESPECTRESULTSETTYPE 60 + // don't forget to adjust DSID_LAST_ITEM_ID below! + +// item range. Adjust this if you introduce new items above + +#define DSID_FIRST_ITEM_ID DSID_NAME +#define DSID_LAST_ITEM_ID DSID_RESPECTRESULTSETTYPE + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DSITEMS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/dsmeta.hxx b/dbaccess/source/ui/inc/dsmeta.hxx new file mode 100644 index 000000000..b6b7ab997 --- /dev/null +++ b/dbaccess/source/ui/inc/dsmeta.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_DSMETA_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_DSMETA_HXX + +#include + +#include + +#include "dsitems.hxx" + +#include + +#include + +namespace dbaui +{ + + // AuthenticationMode + enum AuthenticationMode + { + AuthNone, + AuthUserPwd, + AuthPwd + }; + + // DataSourceMetaData + class FeatureSet; + class DataSourceMetaData_Impl; + /** encapsulates meta data for a data source + + On the long run, this class should a) encapsulate *all* meta data which + currently is hard coded somewhere in the program logic and b) be initialized + from the configuration. + + At the moment, the data a) is still hard coded in the, well, code and b) + contains meta data about the advanced settings only. + */ + class DataSourceMetaData + { + public: + DataSourceMetaData( const OUString& _sURL ); + ~DataSourceMetaData(); + + /// returns a struct describing this data source type's support for our known advanced settings + const FeatureSet& getFeatureSet() const; + + /// determines whether or not the data source requires authentication + static AuthenticationMode getAuthentication( const OUString& _sURL ); + + private: + std::shared_ptr< DataSourceMetaData_Impl > m_pImpl; + }; + + // FeatureSet + /** can be used to ask for (UI) support for certain advanced features + */ + class FeatureSet + { + public: + typedef std::set< ItemID >::const_iterator const_iterator; + + public: + FeatureSet() { } + + void put( const ItemID _id ) { m_aContent.insert( _id ); } + bool has( const ItemID _id ) const { return m_aContent.find( _id ) != m_aContent.end(); } + + inline bool supportsAnySpecialSetting() const; + inline bool supportsGeneratedValues() const; + + const_iterator begin() const { return m_aContent.begin(); } + const_iterator end() const { return m_aContent.end(); } + + private: + std::set< ItemID > m_aContent; + }; + + inline bool FeatureSet::supportsGeneratedValues() const + { + return has( DSID_AUTORETRIEVEENABLED ); + } + + inline bool FeatureSet::supportsAnySpecialSetting() const + { + return has( DSID_SQL92CHECK ) + || has( DSID_APPEND_TABLE_ALIAS ) + || has( DSID_AS_BEFORE_CORRNAME ) + || has( DSID_ENABLEOUTERJOIN ) + || has( DSID_IGNOREDRIVER_PRIV ) + || has( DSID_PARAMETERNAMESUBST ) + || has( DSID_SUPPRESSVERSIONCL ) + || has( DSID_CATALOG ) + || has( DSID_SCHEMA ) + || has( DSID_INDEXAPPENDIX ) + || has( DSID_DOSLINEENDS ) + || has( DSID_BOOLEANCOMPARISON ) + || has( DSID_CHECK_REQUIRED_FIELDS ) + || has( DSID_IGNORECURRENCY ) + || has( DSID_ESCAPE_DATETIME ) + || has( DSID_PRIMARY_KEY_SUPPORT ) + || has( DSID_MAX_ROW_SCAN ) + || has( DSID_RESPECTRESULTSETTYPE ) + ; + } + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_DSMETA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/exsrcbrw.hxx b/dbaccess/source/ui/inc/exsrcbrw.hxx new file mode 100644 index 000000000..12333d3ef --- /dev/null +++ b/dbaccess/source/ui/inc/exsrcbrw.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_EXSRCBRW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_EXSRCBRW_HXX + +#include "brwctrlr.hxx" + +#include + +// SbaExternalSourceBrowser + +namespace dbaui +{ + class SbaXFormAdapter; + class SbaExternalSourceBrowser final + :public SbaXDataBrowserController + ,public css::util::XModifyBroadcaster + { + ::comphelper::OInterfaceContainerHelper2 m_aModifyListeners; + // for multiplexing the modify events + SbaXFormAdapter* m_pDataSourceImpl; + bool m_bInQueryDispatch; + // our queryDispatch will ask our frame, which first will ask our queryDispatch, so we need to protect against + // recursion + + public: + SbaExternalSourceBrowser(const css::uno::Reference< css::uno::XComponentContext >& _rM); + + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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(); + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_EXSRCBRW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/formadapter.hxx b/dbaccess/source/ui/inc/formadapter.hxx new file mode 100644 index 000000000..3394aa2fe --- /dev/null +++ b/dbaccess/source/ui/inc/formadapter.hxx @@ -0,0 +1,437 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_FORMADAPTER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_FORMADAPTER_HXX + +#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 + +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::OInterfaceContainerHelper2 m_aDisposeListeners; + ::comphelper::OInterfaceContainerHelper2 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(); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_FORMADAPTER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/imageprovider.hxx b/dbaccess/source/ui/inc/imageprovider.hxx new file mode 100644 index 000000000..1f267818a --- /dev/null +++ b/dbaccess/source/ui/inc/imageprovider.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_IMAGEPROVIDER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_IMAGEPROVIDER_HXX + +#include + +#include +#include + +#include + +namespace dbaui +{ + // ImageProvider + struct ImageProvider_Data; + /** provides images for database objects such as tables, queries, forms, reports ... + + At the moment, this class cares for small icons only, that is, icons which can be used + in a tree control. On the medium term, we should extend it with support for different-sized + icons. + */ + class ImageProvider + { + private: + std::shared_ptr< ImageProvider_Data > m_pData; + + public: + /** creates a semi-functional ImageProvider instance + + The resulting instance is not able to provide any concrete object images, + but only default images. + */ + ImageProvider(); + + /** creates an ImageProvider instance + + @param _rxConnection + denotes the connection to work for. Must not be . + */ + 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 + @param _out_rImage + the normal image to use for the object + @return + the image to be used for the object. + */ + void getImages( + const OUString& _rName, + const sal_Int32 _nDatabaseObjectType, + Image& _out_rImage + ); + + 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 default image to be used for a database object + + In opposite to getImages, 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 image to be used for the object type. + */ + static Image getDefaultImage( + sal_Int32 _nDatabaseObjectType + ); + + /** returns the resource ID for the default image to be used for a database object + + In opposite to getImages, 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); + + /** retrieves the image to be used for folders of database objects + @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 image to be used for folders of the given type + */ + static Image getFolderImage( + 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 Image getDatabaseImage(); + }; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_IMAGEPROVIDER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/indexcollection.hxx b/dbaccess/source/ui/inc/indexcollection.hxx new file mode 100644 index 000000000..d58a4c180 --- /dev/null +++ b/dbaccess/source/ui/inc/indexcollection.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXCOLLECTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXCOLLECTION_HXX + +#include +#include +#include "indexes.hxx" + +namespace dbaui +{ + + // OIndexCollection + class OIndexCollection + { + protected: + css::uno::Reference< css::container::XNameAccess > + m_xIndexes; + + // cached information + Indexes m_aIndexes; + + public: + // construction + OIndexCollection(); + OIndexCollection(const OIndexCollection& _rSource); + // OIndexCollection(const css::uno::Reference< css::container::XNameAccess >& _rxIndexes); + + OIndexCollection& operator=(const OIndexCollection& _rSource); + + // iterating through the collection + typedef OIndex* iterator; + typedef OIndex const* const_iterator; + + /// get access to the first element of the index collection + Indexes::const_iterator begin() const { return m_aIndexes.begin(); } + /// get access to the first element of the index collection + Indexes::iterator begin() { return m_aIndexes.begin(); } + /// get access to the (last + 1st) element of the index collection + Indexes::const_iterator end() const { return m_aIndexes.end(); } + /// get access to the (last + 1st) element of the index collection + Indexes::iterator end() { return m_aIndexes.end(); } + + // searching + Indexes::const_iterator find(const OUString& _rName) const; + Indexes::iterator find(const OUString& _rName); + Indexes::const_iterator findOriginal(const OUString& _rName) const; + Indexes::iterator findOriginal(const OUString& _rName); + + // inserting without committing + // the OriginalName of the newly inserted index will be empty, thus indicating that it's new + Indexes::iterator insert(const OUString& _rName); + // commit a new index, which is already part if the collection, but does not have an equivalent in the + // data source, yet + void commitNewIndex(const Indexes::iterator& _rPos); + + // reset the data for the given index + void resetIndex(const Indexes::iterator& _rPos); + + // attach to a new key container + void attach(const css::uno::Reference< css::container::XNameAccess >& _rxIndexes); + // detach from the container + void detach(); + + /// drop an index, and remove it from the collection + bool drop(const Indexes::iterator& _rPos); + /// simply drop the index described by the name, but don't remove the descriptor from the collection + bool dropNoRemove(const Indexes::iterator& _rPos); + + protected: + void implConstructFrom(const css::uno::Reference< css::container::XNameAccess >& _rxIndexes); + static void implFillIndexInfo(OIndex& _rIndex, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor); + void implFillIndexInfo(OIndex& _rIndex); + }; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXCOLLECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/indexdialog.hxx b/dbaccess/source/ui/inc/indexdialog.hxx new file mode 100644 index 000000000..00357f903 --- /dev/null +++ b/dbaccess/source/ui/inc/indexdialog.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXDIALOG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXDIALOG_HXX + +#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 OString&, void ); + DECL_LINK( OnEntryEditing, const weld::TreeIter&, bool ); + DECL_LINK( OnEntryEdited, const IterString&, bool ); + DECL_LINK( OnModifiedClick, weld::Button&, 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXDIALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/indexes.hxx b/dbaccess/source/ui/inc/indexes.hxx new file mode 100644 index 000000000..0a54aff7e --- /dev/null +++ b/dbaccess/source/ui/inc/indexes.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXES_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXES_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXES_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/indexfieldscontrol.hxx b/dbaccess/source/ui/inc/indexfieldscontrol.hxx new file mode 100644 index 000000000..b09723d57 --- /dev/null +++ b/dbaccess/source/ui/inc/indexfieldscontrol.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXFIELDSCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXFIELDSCONTROL_HXX + +#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(const 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(long _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(long nRow) override; + virtual sal_uInt32 GetTotalCellWidth(long nRow, sal_uInt16 nColId) override; + virtual bool IsTabAllowed(bool bForward) const override; + + ::svt::CellController* GetController(long _nRow, sal_uInt16 _nColumnId) override; + void InitController(::svt::CellControllerRef&, long _nRow, sal_uInt16 _nColumnId) override; + + OUString GetRowCellText(const IndexFields::const_iterator& _rRow,sal_uInt16 nColId) const; + bool implGetFieldDesc(long _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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_INDEXFIELDSCONTROL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/linkeddocuments.hxx b/dbaccess/source/ui/inc/linkeddocuments.hxx new file mode 100644 index 000000000..0a18bdcd2 --- /dev/null +++ b/dbaccess/source/ui/inc/linkeddocuments.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_LINKEDDOCUMENTS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_LINKEDDOCUMENTS_HXX + +#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, + const OUString& _sDataSourceName + ); + ~OLinkedDocumentsAccess(); + + bool isConnected() const { return m_xConnection.is(); } + + css::uno::Reference< css::lang::XComponent> + open( + const OUString& _rLinkName, + css::uno::Reference< css::lang::XComponent>& _xDefinition, + ElementOpenMode _eOpenMode, + const ::comphelper::NamedValueCollection& _rAdditionalArgs + ); + + css::uno::Reference< css::lang::XComponent > + newDocument( + sal_Int32 i_nActionID, + const ::comphelper::NamedValueCollection& i_rCreationArgs, + css::uno::Reference< css::lang::XComponent >& o_rDefinition + ); + + void newFormWithPilot( + const sal_Int32 _nCommandType, + const OUString& _rObjectName + ); + void newReportWithPilot( + const sal_Int32 _nCommandType, + const OUString& _rObjectName + ); + void newQueryWithPilot(); + void newTableWithPilot(); + + private: + css::uno::Reference< css::lang::XComponent > + impl_open( + const OUString& _rLinkName, + css::uno::Reference< css::lang::XComponent >& _xDefinition, + ElementOpenMode _eOpenMode, + const ::comphelper::NamedValueCollection& _rAdditionalArgs + ); + + void + impl_newWithPilot( + const char* _pWizardService, + const sal_Int32 _nCommandType, + const OUString& _rObjectName + ); + + }; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_LINKEDDOCUMENTS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/listviewitems.hxx b/dbaccess/source/ui/inc/listviewitems.hxx new file mode 100644 index 000000000..47b231272 --- /dev/null +++ b/dbaccess/source/ui/inc/listviewitems.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_LISTVIEWITEMS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_LISTVIEWITEMS_HXX + +#include + +namespace dbaui +{ + + // OBoldListboxString + class OBoldListboxString : public SvLBoxString + { + bool m_bEmphasized; + + public: + OBoldListboxString(const OUString& _rStr) + :SvLBoxString(_rStr) + ,m_bEmphasized(false) + { + } + + virtual SvLBoxItemType GetType() const override; + + virtual void Paint(const Point& rPos, SvTreeListBox& rOutDev, vcl::RenderContext& rRenderContext, + const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) override; + virtual void InitViewData( SvTreeListBox* pView,SvTreeListEntry* pEntry, SvViewDataItem* _pViewData = nullptr) override; + + bool isEmphasized() const { return m_bEmphasized; } + void emphasize(bool _bEmphasize) { m_bEmphasized = _bEmphasize; } + }; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_LISTVIEWITEMS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/marktree.hxx b/dbaccess/source/ui/inc/marktree.hxx new file mode 100644 index 000000000..5eeece39d --- /dev/null +++ b/dbaccess/source/ui/inc/marktree.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_MARKTREE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_MARKTREE_HXX + +#include "dbtreelistbox.hxx" + +#include + +namespace dbaui +{ + +// OMarkableTreeListBox +/** a tree list box where all entries can be marked (with a checkbox) and + unmarked. In addition, inner nodes know a third state which applies + if some, but not all of their descendants are marked. +*/ +class OMarkableTreeListBox : public DBTreeListBox +{ + std::unique_ptr m_pCheckButton; + +public: + OMarkableTreeListBox( vcl::Window* pParent, WinBits nWinStyle ); + virtual ~OMarkableTreeListBox() override; + virtual void dispose() override; + + virtual void KeyInput( const KeyEvent& rKEvt ) override; + virtual void CheckButtonHdl() override; + void CheckButtons(); // make the button states consistent (bottom-up) + +protected: + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& _rRect) override; + virtual void checkedButton_noBroadcast(SvTreeListEntry* _pEntry); + + SvButtonState implDetermineState(SvTreeListEntry* _pEntry); + // determines the check state of the given entry, by analyzing the states of all descendants + +private: + void InitButtonData(); +}; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_MARKTREE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/objectnamecheck.hxx b/dbaccess/source/ui/inc/objectnamecheck.hxx new file mode 100644 index 000000000..602b822c4 --- /dev/null +++ b/dbaccess/source/ui/inc/objectnamecheck.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_OBJECTNAMECHECK_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_OBJECTNAMECHECK_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_OBJECTNAMECHECK_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/opendoccontrols.hxx b/dbaccess/source/ui/inc/opendoccontrols.hxx new file mode 100644 index 000000000..9ab29b624 --- /dev/null +++ b/dbaccess/source/ui/inc/opendoccontrols.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_OPENDOCCONTROLS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_OPENDOCCONTROLS_HXX + +#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); } + bool get_sensitive() const { return m_xControl->get_sensitive(); } + 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); } + bool get_sensitive() const { return m_xControl->get_sensitive(); } + void grab_focus() { m_xControl->grab_focus(); } + 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: + StringPair impl_getDocumentAtIndex( sal_uInt16 _nListIndex ) const; + + void impl_init( const char* _pAsciiModuleName ); + }; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_OPENDOCCONTROLS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/paramdialog.hxx b/dbaccess/source/ui/inc/paramdialog.hxx new file mode 100644 index 000000000..201aabe29 --- /dev/null +++ b/dbaccess/source/ui/inc/paramdialog.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_PARAMDIALOG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_PARAMDIALOG_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_PARAMDIALOG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/propertystorage.hxx b/dbaccess/source/ui/inc/propertystorage.hxx new file mode 100644 index 000000000..51732053a --- /dev/null +++ b/dbaccess/source/ui/inc/propertystorage.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_PROPERTYSTORAGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_PROPERTYSTORAGE_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_PROPERTYSTORAGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/querycontainerwindow.hxx b/dbaccess/source/ui/inc/querycontainerwindow.hxx new file mode 100644 index 000000000..607a38c82 --- /dev/null +++ b/dbaccess/source/ui/inc/querycontainerwindow.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYCONTAINERWINDOW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYCONTAINERWINDOW_HXX + +#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 setNoneVisbleRow(sal_Int32 _nRows) { m_pViewSwitch->setNoneVisbleRow( _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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYCONTAINERWINDOW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/querycontroller.hxx b/dbaccess/source/ui/inc/querycontroller.hxx new file mode 100644 index 000000000..c3988baac --- /dev/null +++ b/dbaccess/source/ui/inc/querycontroller.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYCONTROLLER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYCONTROLLER_HXX + +#include "JoinController.hxx" +#include "querycontainerwindow.hxx" +#include +#include "TableFieldDescription.hxx" + +#include +#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; + // need by registration + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYCONTROLLER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/queryfilter.hxx b/dbaccess/source/ui/inc/queryfilter.hxx new file mode 100644 index 000000000..b7917fdeb --- /dev/null +++ b/dbaccess/source/ui/inc/queryfilter.hxx @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYFILTER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYFILTER_HXX + +#include +#include + +#include +#include + +namespace com +{ + namespace sun + { + namespace 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, const OUString& 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( const OUString& _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); + }; + +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYFILTER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/queryorder.hxx b/dbaccess/source/ui/inc/queryorder.hxx new file mode 100644 index 000000000..2207be16a --- /dev/null +++ b/dbaccess/source/ui/inc/queryorder.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYORDER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYORDER_HXX + +#include + +#define DOG_ROWS 3 + +namespace com +{ + namespace sun + { + namespace 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(); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_QUERYORDER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sbagrid.hrc b/dbaccess/source/ui/inc/sbagrid.hrc new file mode 100644 index 000000000..c84dbccea --- /dev/null +++ b/dbaccess/source/ui/inc/sbagrid.hrc @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef DBACCESS_SBA_GRID_HRC +#define DBACCESS_SBA_GRID_HRC + +//----------------Menueitems------------------------------------------------- +// Table +#define SBA_WHICHID_START 100 + +// Columns +// Formatting +#define SBA_DEF_RANGEFORMAT (SBA_WHICHID_START+143) // RangeItem +#define SBA_DEF_FMTVALUE (SBA_WHICHID_START+144) // SfxULONG, Format + +// Justification +#define SBA_ATTR_ALIGN_HOR_JUSTIFY (SBA_WHICHID_START + 145) // SvxHorJustifyItem + +#endif // DBACCESS_SBA_GRID_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sbagrid.hxx b/dbaccess/source/ui/inc/sbagrid.hxx new file mode 100644 index 000000000..30fb9fa73 --- /dev/null +++ b/dbaccess/source/ui/inc/sbagrid.hxx @@ -0,0 +1,299 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_SBAGRID_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_SBAGRID_HXX + +#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_DEFAULTS(SbaXGridControl, FmXGridControl) + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override; + + // css::lang::XServiceInfo + OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + // need by registration + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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 FmXGridPeer* imp_CreatePeer(vcl::Window* pParent) override; + }; + + // SbaXGridPeer + + class SbaXGridPeer final + :public FmXGridPeer + ,public css::frame::XDispatch + { + cppu::OMultiTypeInterfaceContainerHelperVar< + css::util::URL, void, SbaURLCompare> m_aStatusListeners; + + public: + SbaXGridPeer(const css::uno::Reference< css::uno::XComponentContext >&); + virtual ~SbaXGridPeer() override; + + // UNO + virtual void SAL_CALL acquire() throw() override { FmXGridPeer::acquire(); } + virtual void SAL_CALL release() throw() override { FmXGridPeer::release(); } + virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override; + + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + + UNO3_GETIMPLEMENTATION_DECL(SbaXGridPeer) + + // css::frame::XDispatch + virtual void SAL_CALL dispatch(const css::util::URL& aURL, const css::uno::Sequence< css::beans::PropertyValue >& aArgs) override; + virtual void SAL_CALL addStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override; + virtual void SAL_CALL removeStatusListener(const css::uno::Reference< css::frame::XStatusListener > & xControl, const css::util::URL& aURL) override; + + // css::frame::XDispatchProvider + virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch(const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags) override; + + // css::lang::XComponent + virtual void SAL_CALL dispose() override; + + private: + virtual VclPtr 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, PopupMenu& rMenu) override; + virtual void PostExecuteColumnContextMenu(sal_uInt16 nColId, const PopupMenu& rMenu, sal_uInt16 nExecutionResult) 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(long 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( ::vcl::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(long nRow, sal_uInt16 nCol) override; + + // DbGridControl overridables + virtual void PreExecuteRowContextMenu(sal_uInt16 nRow, PopupMenu& rMenu) override; + virtual void PostExecuteRowContextMenu(sal_uInt16 nRow, const PopupMenu& rMenu, sal_uInt16 nExecutionResult) 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_SBAGRID_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sbamultiplex.hxx b/dbaccess/source/ui/inc/sbamultiplex.hxx new file mode 100644 index 000000000..c71c9cbbe --- /dev/null +++ b/dbaccess/source/ui/inc/sbamultiplex.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_SBAMULTIPLEX_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_SBAMULTIPLEX_HXX + +#include +#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() throw() override { m_rParent.acquire(); } + virtual void SAL_CALL release() throw() override { m_rParent.release(); } + }; + + // declaration of a listener multiplexer class + #define BEGIN_DECLARE_LISTENER_MULTIPLEXER(classname, listenerclass) \ + class classname \ + :public OSbaWeakSubObject \ + ,public listenerclass \ + ,public ::comphelper::OInterfaceContainerHelper2 \ + { \ + public: \ + classname( ::cppu::OWeakObject& rSource, \ + ::osl::Mutex& rMutex); \ + DECLARE_UNO3_DEFAULTS(classname, 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; \ + + #define DECLARE_MULTIPLEXER_VOID_METHOD(methodname, eventtype) \ + virtual void SAL_CALL methodname(const eventtype& e) override; \ + + #define DECLARE_MULTIPLEXER_BOOL_METHOD(methodname, eventtype) \ + virtual sal_Bool SAL_CALL methodname(const eventtype& e) override; \ + + #define END_DECLARE_LISTENER_MULTIPLEXER() \ + /* resolve ambiguity : both OWeakObject and OInterfaceContainerHelper2 have these memory operators */ \ + using OSbaWeakSubObject::operator new; \ + using OSbaWeakSubObject::operator delete; \ + }; \ + + // implementation of a listener multiplexer class + + #define IMPLEMENT_LISTENER_MULTIPLEXER_CORE(classname, listenerclass) \ + \ + classname::classname(::cppu::OWeakObject& rSource, ::osl::Mutex& _rMutex) \ + :OSbaWeakSubObject(rSource) \ + ,OInterfaceContainerHelper2(_rMutex) \ + { \ + } \ + \ + css::uno::Any SAL_CALL classname::queryInterface( \ + const css::uno::Type& _rType) \ + { \ + css::uno::Any aReturn = \ + OSbaWeakSubObject::queryInterface(_rType); \ + if (!aReturn.hasValue()) \ + aReturn = ::cppu::queryInterface(_rType, \ + static_cast< listenerclass* >(this), \ + static_cast< css::lang::XEventListener* >(static_cast< listenerclass* >(this)) \ + ); \ + \ + return aReturn; \ + } \ + void SAL_CALL classname::disposing(const css::lang::EventObject& )\ + { \ + } \ + + #define IMPLEMENT_LISTENER_MULTIPLEXER_VOID_METHOD(classname, listenerclass, methodname, eventtype) \ + void SAL_CALL classname::methodname(const eventtype& e) \ + { \ + eventtype aMulti(e); \ + aMulti.Source = &m_rParent; \ + ::comphelper::OInterfaceIteratorHelper2 aIt(*this); \ + while (aIt.hasMoreElements()) \ + static_cast< listenerclass*>(aIt.next())->methodname(aMulti); \ + } \ + + #define IMPLEMENT_LISTENER_MULTIPLEXER_BOOL_METHOD(classname, listenerclass, methodname, eventtype) \ + sal_Bool SAL_CALL classname::methodname(const eventtype& e) \ + { \ + eventtype aMulti(e); \ + aMulti.Source = &m_rParent; \ + ::comphelper::OInterfaceIteratorHelper2 aIt(*this); \ + bool bResult = true; \ + while (bResult && aIt.hasMoreElements()) \ + bResult = static_cast< listenerclass*>(aIt.next())->methodname(aMulti); \ + return bResult; \ + } \ + + // helper for classes which do event multiplexing + #define IMPLEMENT_LISTENER_ADMINISTRATION(classname, listenernamespace, listenerdesc, multiplexer, broadcasterclass, broadcaster) \ + void SAL_CALL classname::add##listenerdesc(const css::uno::Reference< css::listenernamespace::X##listenerdesc >& l)\ + { \ + multiplexer.addInterface(l); \ + if (multiplexer.getLength() == 1) \ + { \ + css::uno::Reference< broadcasterclass > xBroadcaster(broadcaster, css::uno::UNO_QUERY); \ + if (xBroadcaster.is()) \ + xBroadcaster->add##listenerdesc(&multiplexer); \ + } \ + } \ + void SAL_CALL classname::remove##listenerdesc(const css::uno::Reference< css::listenernamespace::X##listenerdesc >& l)\ + { \ + if (multiplexer.getLength() == 1) \ + { \ + css::uno::Reference< broadcasterclass > xBroadcaster(broadcaster, css::uno::UNO_QUERY); \ + if (xBroadcaster.is()) \ + xBroadcaster->remove##listenerdesc(&multiplexer); \ + } \ + multiplexer.removeInterface(l); \ + } \ + + #define STOP_MULTIPLEXER_LISTENING(listenerdesc, multiplexer, broadcasterclass, broadcaster) \ + if (multiplexer.getLength()) \ + { \ + css::uno::Reference< broadcasterclass > xBroadcaster(broadcaster, css::uno::UNO_QUERY); \ + if (xBroadcaster.is()) \ + xBroadcaster->remove##listenerdesc(&multiplexer); \ + } \ + + #define START_MULTIPLEXER_LISTENING(listenerdesc, multiplexer, broadcasterclass, broadcaster) \ + if (multiplexer.getLength()) \ + { \ + css::uno::Reference< broadcasterclass > xBroadcaster(broadcaster, css::uno::UNO_QUERY); \ + if (xBroadcaster.is()) \ + xBroadcaster->add##listenerdesc(&multiplexer); \ + } \ + + // declaration of property listener multiplexers + // (with support for specialized and unspecialized property listeners) + + #define DECLARE_PROPERTY_MULTIPLEXER(classname, listenerclass, methodname, eventtype) \ + class classname final \ + :public OSbaWeakSubObject \ + ,public listenerclass \ + { \ + typedef ::cppu::OMultiTypeInterfaceContainerHelperVar< \ + OUString > ListenerContainerMap; \ + ListenerContainerMap m_aListeners; \ + \ + public: \ + classname( ::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex ); \ + DECLARE_UNO3_DEFAULTS(classname, 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 methodname(const eventtype& e) override; \ + \ + void addInterface(const OUString& rName, const css::uno::Reference< css::uno::XInterface >& rListener); \ + void removeInterface(const OUString& rName, const css::uno::Reference< css::uno::XInterface >& rListener); \ + \ + void disposeAndClear(); \ + \ + sal_Int32 getOverallLen() const; \ + \ + ::cppu::OInterfaceContainerHelper* getContainer(const OUString& rName) \ + { return m_aListeners.getContainer(rName); } \ + \ + private: \ + void Notify(::cppu::OInterfaceContainerHelper& rListeners, const eventtype& e); \ + }; \ + + // implementation of property listener multiplexers + #define IMPLEMENT_PROPERTY_MULTIPLEXER(classname, listenerclass, methodname, eventtype) \ + classname::classname(::cppu::OWeakObject& rSource, ::osl::Mutex& rMutex) \ + :OSbaWeakSubObject(rSource) \ + ,m_aListeners(rMutex) \ + { \ + } \ + \ + css::uno::Any SAL_CALL classname::queryInterface( \ + const css::uno::Type& _rType) \ + { \ + css::uno::Any aReturn = \ + OSbaWeakSubObject::queryInterface(_rType); \ + if (!aReturn.hasValue()) \ + aReturn = ::cppu::queryInterface(_rType, \ + static_cast< listenerclass* >(this), \ + static_cast< css::lang::XEventListener* >(static_cast< listenerclass* >(this)) \ + ); \ + \ + return aReturn; \ + } \ + void SAL_CALL classname::disposing(const css::lang::EventObject& )\ + { \ + } \ + \ + void SAL_CALL classname::methodname(const eventtype& e) \ + { \ + ::cppu::OInterfaceContainerHelper* 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 classname::addInterface(const OUString& rName, \ + const css::uno::Reference< css::uno::XInterface > & rListener) \ + { \ + m_aListeners.addInterface(rName, rListener); \ + } \ + \ + void classname::removeInterface(const OUString& rName, \ + const css::uno::Reference< css::uno::XInterface > & rListener) \ + { \ + m_aListeners.removeInterface(rName, rListener); \ + } \ + \ + void classname::disposeAndClear() \ + { \ + css::lang::EventObject aEvt(m_rParent); \ + m_aListeners.disposeAndClear(aEvt); \ + } \ + \ + sal_Int32 classname::getOverallLen() const \ + { \ + sal_Int32 nLen = 0; \ + const css::uno::Sequence< OUString > aContained = m_aListeners.getContainedTypes(); \ + for ( OUString const & s : aContained) \ + { \ + ::cppu::OInterfaceContainerHelper* pListeners = m_aListeners.getContainer(s); \ + if (!pListeners) \ + continue; \ + nLen += pListeners->getLength(); \ + } \ + return nLen; \ + } \ + \ + void classname::Notify(::cppu::OInterfaceContainerHelper& rListeners, const eventtype& e) \ + { \ + eventtype aMulti(e); \ + aMulti.Source = &m_rParent; \ + ::cppu::OInterfaceIteratorHelper aIt(rListeners); \ + while (aIt.hasMoreElements()) \ + static_cast< listenerclass*>(aIt.next())->methodname(aMulti); \ + } \ + + // helper for classes which do property event multiplexing + #define IMPLEMENT_PROPERTY_LISTENER_ADMINISTRATION(classname, listenerdesc, multiplexer, broadcasterclass, broadcaster) \ + void SAL_CALL classname::add##listenerdesc(const OUString& rName, const css::uno::Reference< css::beans::X##listenerdesc >& l )\ + { \ + multiplexer.addInterface(rName, l); \ + if (multiplexer.getOverallLen() == 1) \ + { \ + css::uno::Reference< broadcasterclass > xBroadcaster(broadcaster, css::uno::UNO_QUERY); \ + if (xBroadcaster.is()) \ + xBroadcaster->add##listenerdesc(OUString(), &multiplexer); \ + } \ + } \ + void SAL_CALL classname::remove##listenerdesc(const OUString& rName, const css::uno::Reference< css::beans::X##listenerdesc >& l )\ + { \ + if (multiplexer.getOverallLen() == 1) \ + { \ + css::uno::Reference< broadcasterclass > xBroadcaster(broadcaster, css::uno::UNO_QUERY); \ + if (xBroadcaster.is()) \ + xBroadcaster->remove##listenerdesc(OUString(), &multiplexer); \ + } \ + multiplexer.removeInterface(rName, l); \ + } \ + + #define STOP_PROPERTY_MULTIPLEXER_LISTENING(listenerdesc, multiplexer, broadcasterclass, broadcaster) \ + if (multiplexer.getOverallLen()) \ + { \ + css::uno::Reference< broadcasterclass > xBroadcaster(broadcaster, css::uno::UNO_QUERY); \ + if (xBroadcaster.is()) \ + xBroadcaster->remove##listenerdesc(OUString(), &multiplexer); \ + } \ + + #define START_PROPERTY_MULTIPLEXER_LISTENING(listenerdesc, multiplexer, broadcasterclass, broadcaster) \ + if (multiplexer.getOverallLen()) \ + { \ + css::uno::Reference< broadcasterclass > xBroadcaster(broadcaster, css::uno::UNO_QUERY); \ + if (xBroadcaster.is()) \ + xBroadcaster->add##listenerdesc(OUString(), &multiplexer); \ + } \ + + // some listener multiplexers + // css::frame::XStatusListener + BEGIN_DECLARE_LISTENER_MULTIPLEXER(SbaXStatusMultiplexer, css::frame::XStatusListener) + DECLARE_MULTIPLEXER_VOID_METHOD(statusChanged, css::frame::FeatureStateEvent) + + private: + css::frame::FeatureStateEvent m_aLastKnownStatus; + public: \ + const css::frame::FeatureStateEvent& getLastEvent( ) const { return m_aLastKnownStatus; } + END_DECLARE_LISTENER_MULTIPLEXER() + + // css::form::XLoadListener + BEGIN_DECLARE_LISTENER_MULTIPLEXER(SbaXLoadMultiplexer, css::form::XLoadListener) + DECLARE_MULTIPLEXER_VOID_METHOD(loaded, css::lang::EventObject) + DECLARE_MULTIPLEXER_VOID_METHOD(unloaded, css::lang::EventObject) + DECLARE_MULTIPLEXER_VOID_METHOD(unloading, css::lang::EventObject) + DECLARE_MULTIPLEXER_VOID_METHOD(reloading, css::lang::EventObject) + DECLARE_MULTIPLEXER_VOID_METHOD(reloaded, css::lang::EventObject) + END_DECLARE_LISTENER_MULTIPLEXER() + + // css::form::XDatabaseParameterListener + BEGIN_DECLARE_LISTENER_MULTIPLEXER(SbaXParameterMultiplexer, css::form::XDatabaseParameterListener) + DECLARE_MULTIPLEXER_BOOL_METHOD(approveParameter, css::form::DatabaseParameterEvent) + END_DECLARE_LISTENER_MULTIPLEXER() + + // css::form::XSubmitListener + BEGIN_DECLARE_LISTENER_MULTIPLEXER(SbaXSubmitMultiplexer, css::form::XSubmitListener) + DECLARE_MULTIPLEXER_BOOL_METHOD(approveSubmit, css::lang::EventObject) + END_DECLARE_LISTENER_MULTIPLEXER() + + // css::form::XResetListener + BEGIN_DECLARE_LISTENER_MULTIPLEXER(SbaXResetMultiplexer, css::form::XResetListener) + DECLARE_MULTIPLEXER_BOOL_METHOD(approveReset, css::lang::EventObject) + DECLARE_MULTIPLEXER_VOID_METHOD(resetted, css::lang::EventObject) + END_DECLARE_LISTENER_MULTIPLEXER() + + // css::sdbc::XRowSetListener + BEGIN_DECLARE_LISTENER_MULTIPLEXER(SbaXRowSetMultiplexer, css::sdbc::XRowSetListener) + DECLARE_MULTIPLEXER_VOID_METHOD(cursorMoved, css::lang::EventObject) + DECLARE_MULTIPLEXER_VOID_METHOD(rowChanged, css::lang::EventObject) + DECLARE_MULTIPLEXER_VOID_METHOD(rowSetChanged, css::lang::EventObject) + END_DECLARE_LISTENER_MULTIPLEXER() + + // css::sdb::XRowSetApproveListener + BEGIN_DECLARE_LISTENER_MULTIPLEXER(SbaXRowSetApproveMultiplexer, css::sdb::XRowSetApproveListener) + DECLARE_MULTIPLEXER_BOOL_METHOD(approveCursorMove, css::lang::EventObject) + DECLARE_MULTIPLEXER_BOOL_METHOD(approveRowChange, css::sdb::RowChangeEvent) + DECLARE_MULTIPLEXER_BOOL_METHOD(approveRowSetChange, css::lang::EventObject) + END_DECLARE_LISTENER_MULTIPLEXER() + + // css::sdb::XSQLErrorListener + BEGIN_DECLARE_LISTENER_MULTIPLEXER(SbaXSQLErrorMultiplexer, css::sdb::XSQLErrorListener) + DECLARE_MULTIPLEXER_VOID_METHOD(errorOccured, css::sdb::SQLErrorEvent) + END_DECLARE_LISTENER_MULTIPLEXER() + + // css::beans::XPropertyChangeListener + DECLARE_PROPERTY_MULTIPLEXER(SbaXPropertyChangeMultiplexer, css::beans::XPropertyChangeListener, propertyChange, css::beans::PropertyChangeEvent) + + // css::beans::XVetoableChangeListener + DECLARE_PROPERTY_MULTIPLEXER(SbaXVetoableChangeMultiplexer, css::beans::XVetoableChangeListener, vetoableChange, css::beans::PropertyChangeEvent) + + // css::beans::XPropertiesChangeListener + BEGIN_DECLARE_LISTENER_MULTIPLEXER(SbaXPropertiesChangeMultiplexer, css::beans::XPropertiesChangeListener) + DECLARE_MULTIPLEXER_VOID_METHOD(propertiesChange, css::uno::Sequence< css::beans::PropertyChangeEvent >) + END_DECLARE_LISTENER_MULTIPLEXER() + // the SbaXPropertiesChangeMultiplexer doesn't care about the property names a listener logs on for, it simply + // forwards _all_ changes to _all_ listeners +} + +#endif // _SBA_MULTIPLEXER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/singledoccontroller.hxx b/dbaccess/source/ui/inc/singledoccontroller.hxx new file mode 100644 index 000000000..37cc67400 --- /dev/null +++ b/dbaccess/source/ui/inc/singledoccontroller.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_SINGLEDOCCONTROLLER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_SINGLEDOCCONTROLLER_HXX + +#include +#include + +#include + +#include + +class SfxUndoAction; +class SfxUndoManager; + +namespace dbaui +{ + + // OSingleDocumentController + struct OSingleDocumentController_Data; + typedef ::cppu::ImplInheritanceHelper< DBSubComponentController + , css::document::XUndoManagerSupplier + > OSingleDocumentController_Base; + class OSingleDocumentController : public OSingleDocumentController_Base + { + protected: + OSingleDocumentController( const css::uno::Reference< css::uno::XComponentContext>& _rxORB ); + virtual ~OSingleDocumentController() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + public: + /// need for undo's and redo's + SfxUndoManager& GetUndoManager() const; + + /// complete clears the Undo/Redo stacks + void ClearUndoManager(); + + /** addUndoActionAndInvalidate adds an undo action to the undoManager, + additionally invalidates the UNDO and REDO slot + @param pAction the undo action to add + */ + void addUndoActionAndInvalidate( std::unique_ptr pAction ); + + // OGenericUnoController + virtual FeatureState GetState( sal_uInt16 nId ) const override; + virtual void Execute( sal_uInt16 nId, const css::uno::Sequence< css::beans::PropertyValue>& aArgs ) override; + + // XUndoManagerSupplier + virtual css::uno::Reference< css::document::XUndoManager > SAL_CALL getUndoManager( ) override; + + // XEventListener + using OSingleDocumentController_Base::disposing; + + private: + std::unique_ptr< OSingleDocumentController_Data > m_pData; + }; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_SINGLEDOCCONTROLLER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sqledit.hxx b/dbaccess/source/ui/inc/sqledit.hxx new file mode 100644 index 000000000..8337ae398 --- /dev/null +++ b/dbaccess/source/ui/inc/sqledit.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_SQLEDIT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_SQLEDIT_HXX + +#include + +#include +#include +#include + +namespace com::sun::star::beans { class XMultiPropertySet; } + +namespace dbaui +{ + class OQueryTextView; + class OSqlEdit final : public MultiLineEditSyntaxHighlight, public utl::ConfigurationListener + { + private: + class ChangesListener; + friend class ChangesListener; + + Timer m_timerInvalidate; + Timer m_timerUndoActionCreation; + OUString m_strOrigText; // is restored on undo + VclPtr m_pView; + bool m_bAccelAction; // is set on cut, copy, paste + bool m_bStopTimer; + svtools::ColorConfig m_ColorConfig; + + rtl::Reference< ChangesListener > m_listener; + osl::Mutex m_mutex; + css::uno::Reference< css::beans::XMultiPropertySet > m_notifier; + + DECL_LINK(OnUndoActionTimer, Timer*, void); + DECL_LINK(OnInvalidateTimer, Timer*, void); + + void ImplSetFont(); + + virtual void KeyInput( const KeyEvent& rKEvt ) override; + virtual void GetFocus() override; + + DECL_LINK(ModifyHdl, Edit&, void); + + public: + OSqlEdit( OQueryTextView* pParent); + virtual ~OSqlEdit() override; + virtual void dispose() override; + + // Edit overridables + virtual void SetText(const OUString& rNewText) override; + using MultiLineEditSyntaxHighlight::SetText; + + // own functionality + // Cut, Copy, Paste by Accel. runs the action in the Edit but also the + // corresponding slot in the View. Therefore, the action occurs twice. + // To prevent this, SlotExec in View can call this function. + bool IsInAccelAct() const { return m_bAccelAction; } + + void stopTimer(); + void startTimer(); + + virtual void ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints ) override; + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_SQLEDIT_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/sqlmessage.hxx b/dbaccess/source/ui/inc/sqlmessage.hxx new file mode 100644 index 000000000..ff80b962f --- /dev/null +++ b/dbaccess/source/ui/inc/sqlmessage.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_SQLMESSAGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_SQLMESSAGE_HXX + +#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, + const OUString& _rHelpURL = OUString() + ); + + /** display a database related error message + + @param rTitle the title to display + @param rMessage the detailed message to display + @param _eType determines the image to use. AUTO is disallowed in this constructor version + */ + OSQLMessageBox(weld::Window* pParent, + const OUString& rTitle, + const OUString& rMessage, + MessBoxStyle nStyle = MessBoxStyle::Ok | MessBoxStyle::DefaultOk, + MessageType _eType = Info, + const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo = nullptr ); + + void set_title(const OUString& rTitle) { m_xDialog->set_title(rTitle); } + void add_button(const OUString& rText, int nResponse, const OString& rHelpId = OString()) { m_xDialog->add_button(rText, nResponse, rHelpId); } + void set_default_response(int nResponse) { m_xDialog->set_default_response(nResponse); } + + virtual ~OSQLMessageBox() override; + +private: + void Construct(weld::Window* pParent, MessBoxStyle nStyle, MessageType eImage); + + DECL_LINK(ButtonClickHdl, weld::Button&, void); + +private: + void impl_fillMessages(); + void impl_createStandardButtons( MessBoxStyle _nStyle ); + void impl_addDetailsButton(); +}; + +// OSQLWarningBox +class OSQLWarningBox : public OSQLMessageBox +{ +public: + OSQLWarningBox( weld::Window* pParent, + const OUString& _rMessage, + MessBoxStyle _nStyle = MessBoxStyle::Ok | MessBoxStyle::DefaultOk, + const ::dbtools::SQLExceptionInfo* _pAdditionalErrorInfo = nullptr ); +}; + +// OSQLErrorBox +class OSQLErrorBox : public OSQLMessageBox +{ +public: + OSQLErrorBox( weld::Window* pParent, + const OUString& _rMessage ); +}; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_SQLMESSAGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/stringlistitem.hxx b/dbaccess/source/ui/inc/stringlistitem.hxx new file mode 100644 index 000000000..7601f3030 --- /dev/null +++ b/dbaccess/source/ui/inc/stringlistitem.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_STRINGLISTITEM_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_STRINGLISTITEM_HXX + +#include + +#include +#include + +namespace dbaui +{ + +// OStringListItem +/** SfxPoolItem which transports a sequence of OUString's +*/ +class OStringListItem : public SfxPoolItem +{ + css::uno::Sequence< OUString > m_aList; + +public: + OStringListItem(sal_Int16 nWhich, const css::uno::Sequence< OUString >& _rList); + OStringListItem(const OStringListItem& _rSource); + + virtual bool operator==(const SfxPoolItem& _rItem) const override; + virtual OStringListItem* Clone(SfxItemPool* _pPool = nullptr) const override; + + const css::uno::Sequence< OUString >& getList() const { return m_aList; } +}; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_STRINGLISTITEM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/tabletree.hxx b/dbaccess/source/ui/inc/tabletree.hxx new file mode 100644 index 000000000..9be6310cd --- /dev/null +++ b/dbaccess/source/ui/inc/tabletree.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TABLETREE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TABLETREE_HXX + +#include "imageprovider.hxx" +#include "marktree.hxx" + +#include +#include +#include +#include +#include + +namespace dbaui +{ + +// OTableTreeListBox +class OTableTreeListBox final : public OMarkableTreeListBox +{ + 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 + +public: + OTableTreeListBox(vcl::Window* pParent, WinBits nWinStyle); + + typedef std::pair< OUString, bool > TTableViewName; + typedef std::vector< TTableViewName > TNames; + + /** call when HiContrast change. + */ + void notifyHiContrastChanged(); + + /** determines whether the given entry denotes a tables folder + */ + static bool isFolderEntry( const SvTreeListEntry* _pEntry ); + + /** 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 + ); + + /** returns a NamedDatabaseObject record which describes the given entry + */ + css::sdb::application::NamedDatabaseObject + describeObject( SvTreeListEntry* _pEntry ); + + /** to be used if a foreign instance added a table + */ + SvTreeListEntry* addedTable( const OUString& _rName ); + + /** to be used if a foreign instance removed a table + */ + void removedTable( const OUString& _rName ); + + /** 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( SvTreeListEntry* _pEntry ) const; + + SvTreeListEntry* getEntryByQualifiedName( const OUString& _rName ); + +private: + virtual void InitEntry(SvTreeListEntry* _pEntry, const OUString& _rString, const Image& _rCollapsedBitmap, const Image& _rExpandedBitmap) override; + + virtual void checkedButton_noBroadcast(SvTreeListEntry* _pEntry) override; + + void implEmphasize(SvTreeListEntry* _pEntry, 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. + */ + SvTreeListEntry* implAddEntry( + const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxMeta, + const OUString& _rTableName, + bool _bCheckName = true + ); + + void implSetDefaultImages(); + + void implOnNewConnection( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection ); + + bool impl_getAndAssertMetaData( css::uno::Reference< css::sdbc::XDatabaseMetaData >& _out_rMetaData ) const; + + /** 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 + ); + +}; + +class TableTreeListBox +{ + 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 + int m_nTextColumn; // column text is in, depends on if toggles are shown + std::unique_ptr m_xTreeView; + +public: + TableTreeListBox(std::unique_ptr xTreeView); + + weld::TreeView& GetWidget() { return *m_xTreeView; } + + void init() { m_bVirtualRoot = true; } + + typedef std::pair< OUString, bool > TTableViewName; + typedef std::vector< TTableViewName > TNames; + + void SuppressEmptyFolders() { m_bNoEmptyFolders = true; } + void DisableCheckButtons(); + + /** 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 + ); + + 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(weld::TreeIter& rEntry); + + /** determine if the given entry is 'wildcard checked' + @see checkWildcard + */ + bool isWildcardChecked(const weld::TreeIter& rEntry); + + std::unique_ptr GetEntryPosByName(const OUString& aName, const weld::TreeIter* pStart = nullptr, const IEntryFilter* _pFilter = nullptr) const; + + void CheckButtons(); // make the button states consistent (bottom-up) + + void checkedButton_noBroadcast(weld::TreeIter& rEntry); +private: + TriState implDetermineState(weld::TreeIter& rEntry); + + void implEmphasize(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. + */ + void implAddEntry( + const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxMeta, + const OUString& _rTableName + ); + + void implOnNewConnection( const css::uno::Reference< css::sdbc::XConnection >& _rxConnection ); + + bool haveVirtualRoot() const { return m_bVirtualRoot; } + + /** 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 + ); +}; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TABLETREE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/textconnectionsettings.hxx b/dbaccess/source/ui/inc/textconnectionsettings.hxx new file mode 100644 index 000000000..4f2a86620 --- /dev/null +++ b/dbaccess/source/ui/inc/textconnectionsettings.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_TEXTCONNECTIONSETTINGS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_TEXTCONNECTIONSETTINGS_HXX + +#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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_TEXTCONNECTIONSETTINGS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/uiservices.hxx b/dbaccess/source/ui/inc/uiservices.hxx new file mode 100644 index 000000000..da225602a --- /dev/null +++ b/dbaccess/source/ui/inc/uiservices.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_UISERVICES_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_UISERVICES_HXX + +#include + +extern "C" { + +void createRegistryInfo_ComposerDialogs(); +void createRegistryInfo_CopyTableWizard(); +void createRegistryInfo_DBContentLoader(); +void createRegistryInfo_LimitBoxController(); +void createRegistryInfo_OAdvancedSettingsDialog(); +void createRegistryInfo_OBrowser(); +void createRegistryInfo_OColumnControl(); +void createRegistryInfo_OColumnControlModel(); +void createRegistryInfo_ODBApplication(); +void createRegistryInfo_ODBTypeWizDialog(); +void createRegistryInfo_ODBTypeWizDialogSetup(); +void createRegistryInfo_ODataSourcePropertyDialog(); +void createRegistryInfo_ODirectSQLDialog(); +void createRegistryInfo_OFormGridView(); +void createRegistryInfo_OInteractionHandler(); +void createRegistryInfo_OQueryControl(); +void createRegistryInfo_ORelationControl(); +void createRegistryInfo_OSQLMessageDialog(); +void createRegistryInfo_OTableControl(); +void createRegistryInfo_OTableFilterDialog(); +void createRegistryInfo_OTextConnectionSettingsDialog(); +void createRegistryInfo_OUserSettingsDialog(); +void createRegistryInfo_OViewControl(); +void createRegistryInfo_SbaXGridControl(); +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/undosqledit.hxx b/dbaccess/source/ui/inc/undosqledit.hxx new file mode 100644 index 000000000..8d7f1d9ba --- /dev/null +++ b/dbaccess/source/ui/inc/undosqledit.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_UNDOSQLEDIT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_UNDOSQLEDIT_HXX + +#include "GeneralUndo.hxx" +#include "sqledit.hxx" +#include +#include + +namespace dbaui +{ + class OSqlEdit; + // OSqlEditUndoAct - Undo-class for changing sql text + class OSqlEditUndoAct final : public OCommentUndoAction + { + VclPtr m_pOwner; + OUString m_strNextText; + + virtual void Undo() override { ToggleText(); } + virtual void Redo() override { ToggleText(); } + + void ToggleText(); + public: + OSqlEditUndoAct(OSqlEdit* pEdit) : OCommentUndoAction(STR_QUERY_UNDO_MODIFYSQLEDIT), m_pOwner(pEdit) { } + + void SetOriginalText(const OUString& strText) { m_strNextText =strText; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_UNDOSQLEDIT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/unoadmin.hxx b/dbaccess/source/ui/inc/unoadmin.hxx new file mode 100644 index 000000000..8f9013d4d --- /dev/null +++ b/dbaccess/source/ui/inc/unoadmin.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_UNOADMIN_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_UNOADMIN_HXX + +#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 + SfxItemPool* 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_UNOADMIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/unodatbr.hxx b/dbaccess/source/ui/inc/unodatbr.hxx new file mode 100644 index 000000000..6ea21d08b --- /dev/null +++ b/dbaccess/source/ui/inc/unodatbr.hxx @@ -0,0 +1,464 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_INC_UNODATBR_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_UNODATBR_HXX + +#include +#include "brwctrlr.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "callbacks.hxx" +#include +#include +#include "TableCopyHelper.hxx" +#include "commontypes.hxx" + +class SvTreeListEntry; +class Splitter; +struct SvSortData; + +namespace com::sun::star::container { class XNameContainer; } + +class SvTreeList; +namespace dbaui +{ + + class DBTreeView; + struct DBTreeEditedEntry; + class ImageProvider; + + typedef ::cppu::ImplHelper5 < css::frame::XStatusListener + , css::view::XSelectionSupplier + , css::document::XScriptInvocationContext + , css::ui::XContextMenuInterception + , css::sdb::XDatabaseRegistrationsListener + > SbaTableQueryBrowser_Base; + class SbaTableQueryBrowser final + :public SbaXDataBrowserController + ,public SbaTableQueryBrowser_Base + ,public IControlActionListener + ,public IContextMenuProvider + { + css::uno::Reference< css::i18n::XCollator > m_xCollator; + css::uno::Reference< css::frame::XFrame > m_xCurrentFrameParent; + css::uno::Reference< css::awt::XWindow > m_xMainToolbar; + + struct ExternalFeature + { + css::util::URL aURL; + css::uno::Reference< css::frame::XDispatch > + xDispatcher; + bool bEnabled; + + ExternalFeature() : bEnabled( false ) { } + ExternalFeature( const css::util::URL& _rURL ) : aURL( _rURL ), bEnabled( false ) { } + }; + + typedef std::map< sal_uInt16, ExternalFeature > ExternalFeaturesMap; + ExternalFeaturesMap m_aExternalFeatures; + + svx::ODataAccessDescriptor m_aDocumentDataSource; + // if we're part of a document, this is the state of the DocumentDataSource slot + + ::comphelper::OInterfaceContainerHelper2 m_aSelectionListeners; + ::comphelper::OInterfaceContainerHelper2 m_aContextMenuInterceptors; + + OTableCopyHelper::DropDescriptor m_aAsyncDrop; + OTableCopyHelper m_aTableCopyHelper; + + OUString m_sQueryCommand; // the command of the query currently loaded (if any) + //OUString m_sToBeLoaded; // contains the element name which should be loaded if any + + VclPtr m_pTreeView; // contains the datasources of the registry + VclPtr m_pSplitter; + SvTreeListEntry* m_pCurrentlyDisplayed; + 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 ); + + // need by registration + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + 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; + + //IController + virtual void notifyHiContrastChanged() 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 SvTreeListEntry* _pEntry, OUString& _rText ) const override; + virtual bool requestDrag( const Point& _rPosPixel ) override; + virtual sal_Int8 queryDrop( const AcceptDropEvent& _rEvt, const DataFlavorExVector& _rFlavors ) override; + virtual sal_Int8 executeDrop( const ExecuteDropEvent& _rEvt ) override; + + // IContextMenuProvider + virtual OUString getContextMenuResourceName( Control& _rControl ) const override; + virtual IController& getCommandController() override; + virtual ::comphelper::OInterfaceContainerHelper2* + getContextMenuInterceptors() override; + virtual css::uno::Any getCurrentSelection( Control& _rControl ) 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) + static bool isSelected(SvTreeListEntry* _pEntry); + // select the entry (and only the entry, not the whole path) + void select(SvTreeListEntry* _pEntry, bool _bSelect); + // select the path of the entry (which must be an entry without children) + void selectPath(SvTreeListEntry* _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, Image& _rDbImage, + OUString& _rQueryName, Image& _rQueryImage, + OUString& _rTableName, Image& _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( const OUString& _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( SvTreeListEntry* _pDSEntry ); + + /// 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(SvTreeListEntry* _pEntry, bool _bDisposeConnection = true); + + void populateTree(const css::uno::Reference< css::container::XNameAccess>& _xNameAccess, SvTreeListEntry* _pParent, EntryType _eEntryType); + void initializeTreeModel(); + + /** search in the tree for query- or tablecontainer equal to this interface and return + this container entry + */ + SvTreeListEntry* getEntryFromContainer(const css::uno::Reference< css::container::XNameAccess>& _rxNameAccess); + // return true when there is connection available + bool ensureConnection(SvTreeListEntry* _pDSEntry, void * pDSData, SharedConnection& _rConnection ); + bool ensureConnection(SvTreeListEntry* _pAnyEntry, SharedConnection& _rConnection ); + + bool getExistentConnectionFor( SvTreeListEntry* _pDSEntry, SharedConnection& _rConnection ); + /** returns an image provider which works with the connection belonging to the given entry + */ + std::unique_ptr< ImageProvider > + getImageProviderFor( SvTreeListEntry* _pAnyEntry ); + + void implAdministrate( SvTreeListEntry* _pApplyTo ); + + TransferableHelper* + implCopyObject( SvTreeListEntry* _pApplyTo, sal_Int32 _nCommandType ); + + EntryType getEntryType( const SvTreeListEntry* _pEntry ) const; + EntryType getChildType( SvTreeListEntry const * _pEntry ) const; + static bool isObject( EntryType _eType ) { return ( etTableOrView== _eType ) || ( etQuery == _eType ); } + static bool isContainer( EntryType _eType ) { return (etTableContainer == _eType) || (etQueryContainer == _eType); } + bool isContainer( const SvTreeListEntry* _pEntry ) const { return isContainer( getEntryType( _pEntry ) ); } + + // ensure that the xObject for the given entry is set on the user data + bool ensureEntryObject( SvTreeListEntry* _pEntry ); + + // get the display text of the entry given + OUString GetEntryText( SvTreeListEntry* _pEntry ) const; + + // is called when a table or a query was selected + DECL_LINK( OnSelectionChange, LinkParamNone*, void ); + DECL_LINK( OnExpandEntry, SvTreeListEntry*, bool ); + + DECL_LINK( OnCopyEntry, LinkParamNone*, void ); + + DECL_LINK( OnTreeEntryCompare, const SvSortData&, sal_Int32 ); + + DECL_LINK( OnAsyncDrop, void*, void ); + + void implRemoveStatusListeners(); + + bool implSelect(const svx::ODataAccessDescriptor& _rDescriptor, bool _bSelectDirect = false); + bool implSelect( SvTreeListEntry* _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 + ); + + SvTreeListEntry* implGetConnectionEntry(SvTreeListEntry* _pEntry) const; + /// inserts an entry into the tree + SvTreeListEntry* implAppendEntry( + SvTreeListEntry* _pParent, + const OUString& _rName, + void* _pUserData, + EntryType _eEntryType + ); + + /// 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 + */ + SvTreeListEntry* getObjectEntry(const svx::ODataAccessDescriptor& _rDescriptor, + SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _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 + */ + SvTreeListEntry* getObjectEntry( + const OUString& _rDataSource, const OUString& _rCommand, sal_Int32 _nCommandType, + SvTreeListEntry** _ppDataSourceEntry, SvTreeListEntry** _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( SvTreeListEntry* _pEntry ) const; + + /// retrieves the data source URL/name for the given entry representing a data source + OUString getDataSourceAccessor( SvTreeListEntry* _pDataSourceEntry ) 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(SvTreeListEntry const * _pEntry) const; + + void copyEntry(SvTreeListEntry* _pEntry); + + // 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 _sName + Name of the changed entry + @param _pContainer + The container of the displayed entry + @return + if it is the currently displayed otherwise + */ + bool isCurrentlyDisplayedChanged(const OUString& _sName, SvTreeListEntry const * _pContainer); + + /** 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_UNODATBR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/inc/unosqlmessage.hxx b/dbaccess/source/ui/inc/unosqlmessage.hxx new file mode 100644 index 000000000..b4d9fd279 --- /dev/null +++ b/dbaccess/source/ui/inc/unosqlmessage.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_INC_UNOSQLMESSAGE_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_INC_UNOSQLMESSAGE_HXX + +#include +#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; + // + + OSQLMessageDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + +public: + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_INC_UNOSQLMESSAGE_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/DExport.cxx b/dbaccess/source/ui/misc/DExport.cxx new file mode 100644 index 000000000..cc24fe114 --- /dev/null +++ b/dbaccess/source/ui/misc/DExport.cxx @@ -0,0 +1,842 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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, + const TPositions &_rColumnPositions, + const Reference< XNumberFormatter >& _rxNumberF, + const Reference< css::uno::XComponentContext >& _rxContext, + const TColumnVector* pList, + const OTypeInfoMap* _pInfoMap, + bool _bAutoIncrementEnabled, + SvStream& _rInputStream) + :m_vColumnPositions(_rColumnPositions) + ,m_aDestColumns(true) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rxContext) + ,m_pFormatter(nullptr) + ,m_rInputStream( _rInputStream ) + ,m_pTypeInfo() + ,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_pTypeInfo() + ,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; + ++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; + ++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; + ++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; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->bNullable = static_cast(aValue) == 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; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bUnsigned + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->bCurrency = aValue; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->bAutoIncrement = aValue; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->aLocalTypeName = aValue; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nMinimumScale = aValue; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + m_pTypeInfo->nMaximumScale = aValue; + nPos = 18; + aValue.fill(nPos,aTypes[nPos],xRow); + m_pTypeInfo->nNumPrecRadix = aValue; + + // 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(createPreparedStatment(m_xConnection->getMetaData(),m_xTable,m_vColumnPositions)); +} + +bool ODatabaseExport::executeWizard(const OUString& _rTableName, const Any& _aTextColor, const FontDescriptor& _rFont) +{ + bool bHaveDefaultTable = !m_sDefaultTableName.isEmpty(); + OUString sTableName( bHaveDefaultTable ? m_sDefaultTableName : _rTableName ); + OCopyTableWizard aWizard( + nullptr, + sTableName, + bHaveDefaultTable ? CopyTableOperation::AppendData : CopyTableOperation::CopyDefinitionAndData, + 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,makeAny(_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::getUnoTunnelImplementation(xSupplier); + m_pFormatter = pSupplierImpl ? pSupplierImpl->GetNumberFormatter() : nullptr; + Reference xNumberFormatSettings = xSupplier->getNumberFormatSettings(); + xNumberFormatSettings->getPropertyValue("NullDate") >>= m_aNullDate; + } +} + +Reference< XPreparedStatement > ODatabaseExport::createPreparedStatment( 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); + aSql.append(","); + aValues.append("?,"); + } + } + + aSql[aSql.getLength()-1] = ')'; + aValues[aValues.getLength()-1] = ')'; + + aSql.append(aValues); + // now create,fill and execute the prepared statement + return _xMetaData->getConnection()->prepareStatement(aSql.makeStringAndClear()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/HtmlReader.cxx b/dbaccess/source/ui/misc/HtmlReader.cxx new file mode 100644 index 000000000..6e3d329e3 --- /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, + const 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, _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 + OUString aFName = rFace.getToken( 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,makeAny(nTextColor),aFont) && m_xTable.is(); +} + +void OHTMLReader::setTextEncoding() +{ + ParseMetaOptions(nullptr, nullptr); +} + +TypeSelectionPageFactory OHTMLReader::getTypeSelectionPageFactory() +{ + return &OWizHTMLExtend::Create; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/RowSetDrop.cxx b/dbaccess/source/ui/misc/RowSetDrop.cxx new file mode 100644 index 000000000..065fee9ce --- /dev/null +++ b/dbaccess/source/ui/misc/RowSetDrop.cxx @@ -0,0 +1,247 @@ + +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 000000000..1a247ca88 --- /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, + const 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, _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 000000000..596aa7335 --- /dev/null +++ b/dbaccess/source/ui/misc/TableCopyHelper.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 +#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* _pControler) + :m_pController(_pControler) +{ +} + +void OTableCopyHelper::insertTable( const OUString& 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, + const OUString& 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, makeAny( i_nCommandType ) ); + xSource->setPropertyValue( PROPERTY_COMMAND, makeAny( i_rCommand ) ); + xSource->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( xSrcConnection ) ); + xSource->setPropertyValue( PROPERTY_RESULT_SET, makeAny( i_rSourceRows ) ); + xSource->setPropertyValue( PROPERTY_SELECTION, makeAny( i_rSelection ) ); + xSource->setPropertyValue( PROPERTY_BOOKMARK_SELECTION, makeAny( i_bBookmarkSelection ) ); + + Reference< XPropertySet > xDest( xFactory->createDataAccessDescriptor(), UNO_SET_THROW ); + xDest->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, makeAny( 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, const OUString& 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 + ,const OUString& 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 = const_cast(_rTransData).GetSotStorageStream(SotClipboardFormatId::HTML ,aTrans.aHtmlRtfStorage); + else + bOk = const_cast(_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 + ,const OUString& 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) +{ + Reference xEvt; + ODatabaseImportExport* pImport = nullptr; + 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()); + + xEvt = pImport; + 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 = const_cast(_aDroppedData).GetSotStorageStream(SotClipboardFormatId::HTML ,_rAsyncDrop.aHtmlRtfStorage); + else + bOk = const_cast(_aDroppedData).GetSotStorageStream(SotClipboardFormatId::RTF,_rAsyncDrop.aHtmlRtfStorage); + + _rAsyncDrop.bHtml = bHtml; + _rAsyncDrop.bError = !copyTagTable(_rAsyncDrop,true,_xConnection); + + bRet = ( !_rAsyncDrop.bError && bOk && _rAsyncDrop.aHtmlRtfStorage.is() ); + if ( bRet ) + { + // now we need to copy the stream + ::utl::TempFile aTmp; + _rAsyncDrop.aUrl = aTmp.GetURL(); + ::tools::SvRef aNew = new SotStorageStream( aTmp.GetFileName() ); + _rAsyncDrop.aHtmlRtfStorage->Seek(STREAM_SEEK_TO_BEGIN); + _rAsyncDrop.aHtmlRtfStorage->CopyTo( aNew.get() ); + aNew->Commit(); + _rAsyncDrop.aHtmlRtfStorage = aNew; + } + else + _rAsyncDrop.aHtmlRtfStorage = nullptr; + } + return bRet; +} + +void OTableCopyHelper::asyncCopyTagTable( DropDescriptor& _rDesc + ,const OUString& i_rDestDataSource + ,const SharedConnection& _xConnection) +{ + if ( _rDesc.aHtmlRtfStorage.is() ) + { + copyTagTable(_rDesc,false,_xConnection); + _rDesc.aHtmlRtfStorage = nullptr; + // we now have to delete the temp file created in executeDrop + INetURLObject aURL; + aURL.SetURL(_rDesc.aUrl); + ::utl::UCBContentHelper::Kill(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE)); + } + else if ( !_rDesc.bError ) + pasteTable(_rDesc.aDroppedData,i_rDestDataSource,_xConnection); + else + m_pController->showError(SQLException(DBA_RES(STR_NO_TABLE_FORMAT_INSIDE), *m_pController, "S1000", 0, Any())); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/TokenWriter.cxx b/dbaccess/source/ui/misc/TokenWriter.cxx new file mode 100644 index 000000000..3d73e9427 --- /dev/null +++ b/dbaccess/source/ui/misc/TokenWriter.cxx @@ -0,0 +1,973 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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_xFormatter(_rxNumberF) + ,m_xContext(_rM) + ,m_nCommandType(CommandType::TABLE) + ,m_bNeedToReInitialize(false) + ,m_bInInitialize(false) + ,m_bCheckOnly(false) +{ + m_eDestEnc = osl_getThreadTextEncoding(); + + osl_atomic_increment( &m_refCount ); + impl_initFromDescriptor( _aDataDescriptor, false ); + osl_atomic_decrement( &m_refCount ); +} + +// import data +ODatabaseImportExport::ODatabaseImportExport( const ::dbtools::SharedConnection& _rxConnection, + const Reference< XNumberFormatter >& _rxNumberF, const Reference< XComponentContext >& _rM ) + :m_bBookmarkSelection( false ) + ,m_pStream(nullptr) + ,m_xConnection(_rxConnection) + ,m_xFormatter(_rxNumberF) + ,m_xContext(_rM) + ,m_nCommandType(css::sdb::CommandType::TABLE) + ,m_bNeedToReInitialize(false) + ,m_bInInitialize(false) + ,m_bCheckOnly(false) +{ + m_eDestEnc = osl_getThreadTextEncoding(); +} + +ODatabaseImportExport::~ODatabaseImportExport() +{ + acquire(); + dispose(); +} + +void ODatabaseImportExport::dispose() +{ + // remove me as listener + Reference< XComponent > xComponent(m_xConnection, UNO_QUERY); + if (xComponent.is()) + { + Reference< XEventListener> xEvt(static_cast(this),UNO_QUERY); + xComponent->removeEventListener(xEvt); + } + m_xConnection.clear(); + + ::comphelper::disposeComponent(m_xRow); + + m_xObject.clear(); + m_xResultSetMetaData.clear(); + m_xResultSet.clear(); + m_xRow.clear(); + m_xRowLocate.clear(); + m_xFormatter.clear(); +} + +void SAL_CALL ODatabaseImportExport::disposing( const EventObject& Source ) +{ + Reference 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(static_cast(this),UNO_QUERY); + 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(static_cast(this),UNO_QUERY); + + 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, makeAny( m_xConnection.getTyped() ) ); + xProp->setPropertyValue( PROPERTY_COMMAND_TYPE, makeAny( m_nCommandType ) ); + xProp->setPropertyValue( PROPERTY_COMMAND, makeAny( 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( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RTF ); + m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSI); + if (sal_uInt32 nCpg = rtl_getWindowsCodePageFromTextEncoding(m_eDestEnc); nCpg && nCpg != 65001) + { + m_pStream->WriteCharPtr(OOO_STRING_SVTOOLS_RTF_ANSICPG).WriteUInt32AsString(nCpg); + } + m_pStream->WriteCharPtr(SAL_NEWLINE_STRING); + + bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight ); + bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant ); + bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline ); + bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout ); + + sal_Int32 nColor = 0; + if(m_xObject.is()) + m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= nColor; + ::Color aColor(nColor); + + OString aFonts(OUStringToOString(m_aFont.Name, RTL_TEXTENCODING_MS_1252)); + if (aFonts.isEmpty()) + { + OUString aName = Application::GetSettings().GetStyleSettings().GetAppFont().GetFamilyName(); + aFonts = OUStringToOString(aName, RTL_TEXTENCODING_MS_1252); + } + + m_pStream->WriteCharPtr( "{\\fonttbl" ); + if (!aFonts.isEmpty()) + { + sal_Int32 nIdx{0}; + sal_Int32 nTok{-1}; // to compensate pre-increment + do { + m_pStream->WriteCharPtr( "\\f" ); + m_pStream->WriteInt32AsString(++nTok); + m_pStream->WriteCharPtr( "\\fcharset0\\fnil " ); + m_pStream->WriteOString( aFonts.getToken(0, ';', nIdx) ); + m_pStream->WriteChar( ';' ); + } while (nIdx>=0); + } + m_pStream->WriteChar( '}' ) ; + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + // write the rtf color table + m_pStream->WriteChar( '{' ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_COLORTBL ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_RED ); + m_pStream->WriteUInt32AsString(aColor.GetRed()); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_GREEN ); + m_pStream->WriteUInt32AsString(aColor.GetGreen()); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_BLUE ); + m_pStream->WriteUInt32AsString(aColor.GetBlue()); + + m_pStream->WriteCharPtr( ";\\red255\\green255\\blue255;\\red192\\green192\\blue192;}" ) + .WriteCharPtr( SAL_NEWLINE_STRING ); + + static char const aCell1[] = "\\clbrdrl\\brdrs\\brdrcf0\\clbrdrt\\brdrs\\brdrcf0\\clbrdrb\\brdrs\\brdrcf0\\clbrdrr\\brdrs\\brdrcf0\\clshdng10000\\clcfpat2\\cellx"; + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH ); + m_pStream->WriteInt32AsString(40); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + + if(m_xObject.is()) + { + Reference 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->WriteCharPtr( aCell1 ); + m_pStream->WriteInt32AsString(i*CELL_X); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + } + + // column description + m_pStream->WriteChar( '{' ).WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" ); + + std::unique_ptr 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->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '{' ); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_QC ); // column header always centered + + if ( bBold ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B ); + if ( bItalic ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I ); + if ( bUnderline ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL ); + if ( bStrikeout ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE ); + + m_pStream->WriteCharPtr( "\\fs20\\f0\\cf0\\cb2" ); + m_pStream->WriteChar( ' ' ); + RTFOutFuncs::Out_String(*m_pStream, sColumnName, m_eDestEnc); + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL ); + m_pStream->WriteChar( '}' ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL ); + } + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ).WriteChar( '}' ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + + sal_Int32 k=1; + sal_Int32 kk=0; + if ( m_aSelection.hasElements() ) + { + const Any* pSelIter = m_aSelection.getConstArray(); + const Any* pEnd = pSelIter + m_aSelection.getLength(); + + bool bContinue = true; + for( ; pSelIter != pEnd && bContinue; ++pSelIter ) + { + if ( m_bBookmarkSelection ) + { + bContinue = m_xRowLocate->moveToBookmark( *pSelIter ); + } + else + { + sal_Int32 nPos = -1; + OSL_VERIFY( *pSelIter >>= nPos ); + bContinue = ( m_xResultSet->absolute( nPos ) ); + } + + if ( bContinue ) + appendRow( pHorzChar.get(), nCount, k, kk ); + } + } + else + { + m_xResultSet->beforeFirst(); // set back before the first row + while(m_xResultSet->next()) + { + appendRow(pHorzChar.get(),nCount,k,kk); + } + } + } + + m_pStream->WriteChar( '}' ).WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteUChar( 0 ); + return ((*m_pStream).GetError() == ERRCODE_NONE); +} + +void ORTFImportExport::appendRow(OString const * pHorzChar,sal_Int32 _nColumnCount,sal_Int32& k,sal_Int32& kk) +{ + ++kk; + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TROWD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_TRGAPH ); + m_pStream->WriteInt32AsString(40); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + + static char const aCell2[] = "\\clbrdrl\\brdrs\\brdrcf2\\clbrdrt\\brdrs\\brdrcf2\\clbrdrb\\brdrs\\brdrcf2\\clbrdrr\\brdrs\\brdrcf2\\clshdng10000\\clcfpat1\\cellx"; + + for ( sal_Int32 i=1; i<=_nColumnCount; ++i ) + { + m_pStream->WriteCharPtr( aCell2 ); + m_pStream->WriteInt32AsString(i*CELL_X); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + } + + const bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight ); + const bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant ); + const bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline ); + const bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout ); + Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY); + + m_pStream->WriteChar( '{' ); + m_pStream->WriteCharPtr( "\\trrh-270\\pard\\intbl" ); + for ( sal_Int32 i=1; i <= _nColumnCount; ++i ) + { + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '{' ); + m_pStream->WriteOString( pHorzChar[i-1] ); + + if ( bBold ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_B ); + if ( bItalic ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_I ); + if ( bUnderline ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_UL ); + if ( bStrikeout ) m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_STRIKE ); + + m_pStream->WriteCharPtr( "\\fs20\\f1\\cf0\\cb1 " ); + + try + { + Reference xColumn(m_xRowSetColumns->getByIndex(i-1),UNO_QUERY_THROW); + dbtools::FormattedColumnValue aFormatedValue(m_xContext,xRowSet,xColumn); + OUString sValue = aFormatedValue.getFormattedValue(); + if ( !sValue.isEmpty() ) + RTFOutFuncs::Out_String(*m_pStream,sValue,m_eDestEnc); + } + catch (Exception&) + { + SAL_WARN("dbaccess.ui","RTF WRITE!"); + } + + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_CELL ); + m_pStream->WriteChar( '}' ); + m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_PARD ).WriteCharPtr( OOO_STRING_SVTOOLS_RTF_INTBL ); + } + m_pStream->WriteCharPtr( OOO_STRING_SVTOOLS_RTF_ROW ).WriteCharPtr( SAL_NEWLINE_STRING ); + m_pStream->WriteChar( '}' ); + ++k; +} + +bool ORTFImportExport::Read() +{ + ODatabaseImportExport::Read(); + SvParserState eState = SvParserState::Error; + if ( m_pStream ) + { + tools::SvRef 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::nDefaultFontSize[SBA_HTML_FONTSIZES] = +{ + HTMLFONTSZ1_DFLT, HTMLFONTSZ2_DFLT, HTMLFONTSZ3_DFLT, HTMLFONTSZ4_DFLT, + HTMLFONTSZ5_DFLT, HTMLFONTSZ6_DFLT, HTMLFONTSZ7_DFLT +}; + +sal_Int16 OHTMLImportExport::nFontSize[SBA_HTML_FONTSIZES] = { 0 }; + +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"; + +// Macros for HTML-Export +#define TAG_ON( tag ) HTMLOutFuncs::Out_AsciiTag( (*m_pStream), tag ) +#define TAG_OFF( tag ) HTMLOutFuncs::Out_AsciiTag( (*m_pStream), tag, false ) +#define OUT_LF() m_pStream->WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() ) +#define TAG_ON_LF( tag ) (TAG_ON( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() )) +#define TAG_OFF_LF( tag ) (TAG_OFF( tag ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( GetIndentStr() )) + +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 + SvxHtmlOptions& rHtmlOptions = SvxHtmlOptions::Get(); + m_eDestEnc = rHtmlOptions.GetTextEncoding(); + strncpy( sIndent, sIndentSource ,std::min(sizeof(sIndent),sizeof(sIndentSource))); + sIndent[0] = 0; +} + +bool OHTMLImportExport::Write() +{ + ODatabaseImportExport::Write(); + if(m_xObject.is()) + { + m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_doctype40 ).WriteChar( '>' ).WriteCharPtr( SAL_NEWLINE_STRING ).WriteCharPtr( SAL_NEWLINE_STRING ); + TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_html ); + WriteHeader(); + OUT_LF(); + WriteBody(); + OUT_LF(); + TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_html ); + + 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); TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_head ); + + SfxFrameHTMLWriter::Out_DocInfo( (*m_pStream), OUString(), + xDocProps, sIndent, osl_getThreadTextEncoding() ); + OUT_LF(); + IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_head ); +} + +void OHTMLImportExport::WriteBody() +{ + IncIndent(1); + m_pStream->WriteCharPtr( "<" ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_style ).WriteCharPtr( " " ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_type ).WriteCharPtr( "=\"text/css\">" ); + + m_pStream->WriteCharPtr( "" ); + IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_style ); + OUT_LF(); + + // default Textcolour black + m_pStream->WriteChar( '<' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_body ).WriteChar( ' ' ).WriteCharPtr( OOO_STRING_SVTOOLS_HTML_O_text ).WriteChar( '=' ); + sal_Int32 nColor = 0; + if(m_xObject.is()) + m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= nColor; + ::Color aColor(nColor); + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + + m_pStream->WriteCharPtr( " " OOO_STRING_SVTOOLS_HTML_O_bgcolor "=" ); + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + + m_pStream->WriteChar( '>' ); OUT_LF(); + + WriteTables(); + + TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_body ); +} + +void OHTMLImportExport::WriteTables() +{ + OString aStrOut = OOO_STRING_SVTOOLS_HTML_table + " " + OOO_STRING_SVTOOLS_HTML_frame + "=" + OOO_STRING_SVTOOLS_HTML_TF_void; + + Sequence< OUString> aNames; + Reference 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); + for (sal_Int32 i= 0; i < nCount; ++i) + aNames[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); + TAG_ON( aStrOut.getStr() ); + + FontOn(); + + TAG_ON( OOO_STRING_SVTOOLS_HTML_caption ); + TAG_ON( OOO_STRING_SVTOOLS_HTML_bold ); + + m_pStream->WriteOString( OUStringToOString(m_sName, osl_getThreadTextEncoding()) ); + // TODO : think about the encoding of the name + TAG_OFF( OOO_STRING_SVTOOLS_HTML_bold ); + TAG_OFF( OOO_STRING_SVTOOLS_HTML_caption ); + + FontOff(); + OUT_LF(); + // + + IncIndent(1); + TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_thead ); + + IncIndent(1); + TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tablerow ); + + 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); + TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tablerow ); + TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_thead ); + + IncIndent(1); + TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tbody ); + + // 2. and now the data + Reference< XRowSet > xRowSet(m_xRow,UNO_QUERY); + sal_Int32 kk=0; + m_xResultSet->beforeFirst(); // set back before the first row + while(m_xResultSet->next()) + { + IncIndent(1); + TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tablerow ); + + ++kk; + 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); + } + TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tablerow ); + } + } + else + { + IncIndent(-1); + TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tablerow ); + TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_thead ); + + IncIndent(1); + TAG_ON_LF( OOO_STRING_SVTOOLS_HTML_tbody ); + } + + IncIndent(-1); OUT_LF(); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_tbody ); + IncIndent(-1); TAG_OFF_LF( OOO_STRING_SVTOOLS_HTML_table ); +} + +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::getUnoTunnelImplementation(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); + } + } + + TAG_ON( aStrTD.getStr() ); + + FontOn(); + + bool bBold = ( css::awt::FontWeight::BOLD == m_aFont.Weight ); + bool bItalic = ( css::awt::FontSlant_ITALIC == m_aFont.Slant ); + bool bUnderline = ( css::awt::FontUnderline::NONE != m_aFont.Underline ); + bool bStrikeout = ( css::awt::FontStrikeout::NONE != m_aFont.Strikeout ); + + if ( bBold ) TAG_ON( OOO_STRING_SVTOOLS_HTML_bold ); + if ( bItalic ) TAG_ON( OOO_STRING_SVTOOLS_HTML_italic ); + if ( bUnderline ) TAG_ON( OOO_STRING_SVTOOLS_HTML_underline ); + if ( bStrikeout ) TAG_ON( OOO_STRING_SVTOOLS_HTML_strike ); + + if ( rValue.isEmpty() ) + TAG_ON( OOO_STRING_SVTOOLS_HTML_linebreak ); // no completely empty cell + else + HTMLOutFuncs::Out_String( (*m_pStream), rValue ,m_eDestEnc); + + if ( bStrikeout ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_strike ); + if ( bUnderline ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_underline ); + if ( bItalic ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_italic ); + if ( bBold ) TAG_OFF( OOO_STRING_SVTOOLS_HTML_bold ); + + FontOff(); + + TAG_OFF_LF( pHtmlTag ); +} + +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 ); + + sal_Int32 nColor = 0; + if(m_xObject.is()) + m_xObject->getPropertyValue(PROPERTY_TEXTCOLOR) >>= nColor; + ::Color aColor(nColor); + + HTMLOutFuncs::Out_Color( (*m_pStream), aColor ); + m_pStream->WriteCharPtr( ">" ); +} + +inline void OHTMLImportExport::FontOff() +{ +#if OSL_DEBUG_LEVEL > 0 + OSL_ENSURE(m_bCheckFont,"No FontOn() called"); +#endif + TAG_OFF( OOO_STRING_SVTOOLS_HTML_font ); +#if OSL_DEBUG_LEVEL > 0 + m_bCheckFont = false; +#endif +} + +void OHTMLImportExport::IncIndent( sal_Int16 nVal ) +{ + sIndent[m_nIndent] = '\t'; + m_nIndent = m_nIndent + nVal; + if ( m_nIndent < 0 ) + m_nIndent = 0; + else if ( m_nIndent > nIndentMax ) + m_nIndent = nIndentMax; + sIndent[m_nIndent] = 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/UITools.cxx b/dbaccess/source/ui/misc/UITools.cxx new file mode 100644 index 000000000..865a580b3 --- /dev/null +++ b/dbaccess/source/ui/misc/UITools.cxx @@ -0,0 +1,1374 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +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; + Any aError; + 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 ); + if ( !aSQLError.isValid() ) + aError = 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, + const OUString& _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; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nType = aValue; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nPrecision = aValue; + ++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; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->bNullable = static_cast(aValue) == ColumnValue::NULLABLE; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bCaseSensitive + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nSearchType = aValue; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + // bUnsigned + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->bCurrency = static_cast(aValue); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->bAutoIncrement = static_cast(aValue); + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->aLocalTypeName = aValue; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nMinimumScale = aValue; + ++nPos; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nMaximumScale = aValue; + assert(nPos == 15); + // 16 and 17 are unused + nPos = 18; + aValue.fill(nPos,aTypes[nPos],aNullable[nPos],xRow); + pInfo->nNumPrecRadix = aValue; + + // 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; + + OUString aName; + switch(pInfo->nType) + { + case DataType::CHAR: + aName = _rsTypeNames.getToken(TYPE_CHAR, ';'); + break; + case DataType::VARCHAR: + aName = _rsTypeNames.getToken(TYPE_TEXT, ';'); + break; + case DataType::DECIMAL: + aName = _rsTypeNames.getToken(TYPE_DECIMAL, ';'); + break; + case DataType::NUMERIC: + aName = _rsTypeNames.getToken(TYPE_NUMERIC, ';'); + break; + case DataType::BIGINT: + aName = _rsTypeNames.getToken(TYPE_BIGINT, ';'); + break; + case DataType::FLOAT: + aName = _rsTypeNames.getToken(TYPE_FLOAT, ';'); + break; + case DataType::DOUBLE: + aName = _rsTypeNames.getToken(TYPE_DOUBLE, ';'); + break; + case DataType::LONGVARCHAR: + aName = _rsTypeNames.getToken(TYPE_MEMO, ';'); + break; + case DataType::LONGVARBINARY: + aName = _rsTypeNames.getToken(TYPE_IMAGE, ';'); + break; + case DataType::DATE: + aName = _rsTypeNames.getToken(TYPE_DATE, ';'); + break; + case DataType::TIME: + aName = _rsTypeNames.getToken(TYPE_TIME, ';'); + break; + case DataType::TIMESTAMP: + aName = _rsTypeNames.getToken(TYPE_DATETIME, ';'); + break; + case DataType::BIT: + if ( !pInfo->aCreateParams.isEmpty() ) + { + aName = _rsTypeNames.getToken(TYPE_BIT, ';'); + break; + } + [[fallthrough]]; + case DataType::BOOLEAN: + aName = _rsTypeNames.getToken(TYPE_BOOL, ';'); + break; + case DataType::TINYINT: + aName = _rsTypeNames.getToken(TYPE_TINYINT, ';'); + break; + case DataType::SMALLINT: + aName = _rsTypeNames.getToken(TYPE_SMALLINT, ';'); + break; + case DataType::INTEGER: + aName = _rsTypeNames.getToken(TYPE_INTEGER, ';'); + break; + case DataType::REAL: + aName = _rsTypeNames.getToken(TYPE_REAL, ';'); + break; + case DataType::BINARY: + aName = _rsTypeNames.getToken(TYPE_BINARY, ';'); + break; + case DataType::VARBINARY: + aName = _rsTypeNames.getToken(TYPE_VARBINARY, ';'); + break; + case DataType::SQLNULL: + aName = _rsTypeNames.getToken(TYPE_SQLNULL, ';'); + break; + case DataType::OBJECT: + aName = _rsTypeNames.getToken(TYPE_OBJECT, ';'); + break; + case DataType::DISTINCT: + aName = _rsTypeNames.getToken(TYPE_DISTINCT, ';'); + break; + case DataType::STRUCT: + aName = _rsTypeNames.getToken(TYPE_STRUCT, ';'); + break; + case DataType::ARRAY: + aName = _rsTypeNames.getToken(TYPE_ARRAY, ';'); + break; + case DataType::BLOB: + aName = _rsTypeNames.getToken(TYPE_BLOB, ';'); + break; + case DataType::CLOB: + aName = _rsTypeNames.getToken(TYPE_CLOB, ';'); + break; + case DataType::REF: + aName = _rsTypeNames.getToken(TYPE_REF, ';'); + break; + case DataType::OTHER: + aName = _rsTypeNames.getToken(TYPE_OTHER, ';'); + break; + } + if ( !aName.isEmpty() ) + { + pInfo->aUIName = aName; + pInfo->aUIName += " [ "; + } + pInfo->aUIName += pInfo->aTypeName; + if ( !aName.isEmpty() ) + 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,makeAny(_pFieldDesc->GetName())); + _rxColumn->setPropertyValue(PROPERTY_TYPENAME,makeAny(_pFieldDesc->getTypeInfo()->aTypeName)); + _rxColumn->setPropertyValue(PROPERTY_TYPE,makeAny(_pFieldDesc->GetType())); + _rxColumn->setPropertyValue(PROPERTY_PRECISION,makeAny(_pFieldDesc->GetPrecision())); + _rxColumn->setPropertyValue(PROPERTY_SCALE,makeAny(_pFieldDesc->GetScale())); + _rxColumn->setPropertyValue(PROPERTY_ISNULLABLE, makeAny(_pFieldDesc->GetIsNullable())); + _rxColumn->setPropertyValue(PROPERTY_ISAUTOINCREMENT, css::uno::makeAny(_pFieldDesc->IsAutoIncrement())); + _rxColumn->setPropertyValue(PROPERTY_DESCRIPTION,makeAny(_pFieldDesc->GetDescription())); + if ( _rxColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_ISCURRENCY) && _pFieldDesc->IsCurrency() ) + _rxColumn->setPropertyValue(PROPERTY_ISCURRENCY, css::uno::makeAny(_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,makeAny(_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 mapTextAllign(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, + const vcl::Window* _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, makeAny(static_cast(dbaui::mapTextAllign(eJustify)))); + if (bHasFormat) + xAffectedCol->setPropertyValue(PROPERTY_FORMATKEY, makeAny(nFormatKey)); + + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } +} + +bool callColumnFormatDialog(const vcl::Window* _pParent, + SvNumberFormatter* _pFormatter, + sal_Int32 _nDataType, + sal_Int32& _nFormatKey, + SvxCellHorJustify& _eJustify, + bool _bHasFormat) +{ + bool bRet = false; + + // UNO->ItemSet + static SfxItemInfo aItemInfos[] = + { + { 0, false }, + { SID_ATTR_NUMBERFORMAT_VALUE, true }, + { SID_ATTR_ALIGN_HOR_JUSTIFY, true }, + { SID_ATTR_NUMBERFORMAT_ONE_AREA, true }, + { SID_ATTR_NUMBERFORMAT_INFO, true } + }; + static const sal_uInt16 aAttrMap[] = + { + SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY, + SID_ATTR_NUMBERFORMAT_ONE_AREA, SID_ATTR_NUMBERFORMAT_ONE_AREA, + SID_ATTR_NUMBERFORMAT_INFO, SID_ATTR_NUMBERFORMAT_INFO, + 0 + }; + + 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 SfxBoolItem(SID_ATTR_NUMBERFORMAT_ONE_AREA, false), + new SvxNumberInfoItem(SID_ATTR_NUMBERFORMAT_INFO) + }; + + SfxItemPool* pPool = new SfxItemPool("GridBrowserProperties", SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY, aItemInfos, &pDefaults); + pPool->SetDefaultMetric( MapUnit::MapTwip ); // ripped, don't understand why + pPool->FreezeIdRanges(); // the same + + std::unique_ptr pFormatDescriptor(new 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,_pParent->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->GetFrameWeld(), pFormatDescriptor.get(), _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(); + SfxItemPool::Free(pPool); + 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,makeAny(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; + sal_uInt32 nDefaultWidth = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) ); + if ( nDefaultWidth != _pBox->GetColumnWidth( _nColId ) ) + { + Size aSizeMM = _pBox->PixelToLogic( Size( _pBox->GetColumnWidth( _nColId ), 0 ), MapMode( MapUnit::MapMM ) ); + nColSize = aSizeMM.Width() * 10; + } + + Size aDefaultMM = _pBox->PixelToLogic( Size( nDefaultWidth, 0 ), MapMode( MapUnit::MapMM ) ); + + DlgSize aColumnSizeDlg(_pBox->GetFrameWeld(), nColSize, false, aDefaultMM.Width() * 10); + if (aColumnSizeDlg.run() != RET_OK) + return; + + sal_Int32 nValue = aColumnSizeDlg.GetValue(); + if ( -1 == nValue ) + { // default width + nValue = _pBox->GetDefaultColumnWidth( _pBox->GetColumnTitle( _nColId ) ); + } + else + { + Size aSizeMM( nValue / 10, 0 ); + nValue = _pBox->LogicToPixel( aSizeMM, MapMode( MapUnit::MapMM ) ).Width(); + } + _pBox->SetColumnWidth( _nColId, nValue ); +} + +// check if SQL92 name checking is enabled +bool isSQL92CheckEnabled(const Reference& _xConnection) +{ + 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(aInfo.begin(), aInfo.end(), + [](const PropertyValue& lhs) + {return lhs.Name == PROPERTY_AUTOINCREMENTCREATION;} ); + + if ( pValue != aInfo.end() ) + pValue->Value >>= _rsAutoIncrementValue; + pValue =std::find_if(aInfo.begin(), aInfo.end(), + [](const PropertyValue& lhs) + {return lhs.Name == "IsAutoRetrievingEnabled";} ); + + if ( pValue != aInfo.end() ) + 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::getUnoTunnelImplementation(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.get(),"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, const char* pTitle, const char* pText, bool _bAll, const OUString& _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,makeAny(sCatalog)); + xView->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema)); + xView->setPropertyValue(PROPERTY_NAME,makeAny(sTable)); + + xView->setPropertyValue( PROPERTY_COMMAND, makeAny( _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 insertHierachyElement(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(), "insertHierachyElement: 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(), "insertHierachyElement: 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() ) + { + OUString sTargetName,sLabel; + if ( sNewName.isEmpty() || xNameAccess->hasByName(sNewName) ) + { + 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.get(), _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 ? OUString(SERVICE_NAME_FORM_COLLECTION) : OUString(SERVICE_NAME_REPORT_COLLECTION)) : OUString(SERVICE_SDB_DOCUMENTDEFINITION)); + + Reference xNew( xORB->createInstanceWithArguments( sServiceName, aArguments ), UNO_QUERY_THROW ); + Reference< XNameContainer > xNameContainer( xNameAccess, UNO_QUERY_THROW ); + xNameContainer->insertByName( sNewName, makeAny( xNew ) ); + } + catch( const IllegalArgumentException& e ) + { + ::dbtools::throwGenericSQLException( e.Message, e.Context ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + return false; + } + + return true; +} + +Reference< XNumberFormatter > getNumberFormatter(const Reference< XConnection >& _rxConnection, const Reference< css::uno::XComponentContext >& _rxContext ) +{ + // create a formatter working with the connections format supplier + Reference< XNumberFormatter > xFormatter; + + try + { + Reference< css::util::XNumberFormatsSupplier > xSupplier(::dbtools::getNumberFormats(_rxConnection, true, _rxContext)); + + if ( xSupplier.is() ) + { + // create a new formatter + xFormatter.set(util::NumberFormatter::create( _rxContext ), UNO_QUERY_THROW); + xFormatter->attachNumberFormatsSupplier(xSupplier); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xFormatter; +} + +} // dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/UpdateHelperImpl.hxx b/dbaccess/source/ui/misc/UpdateHelperImpl.hxx new file mode 100644 index 000000000..487807246 --- /dev/null +++ b/dbaccess/source/ui/misc/UpdateHelperImpl.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_MISC_UPDATEHELPERIMPL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_MISC_UPDATEHELPERIMPL_HXX + +#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(); + } + }; +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_MISC_UPDATEHELPERIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WCPage.cxx b/dbaccess/source/ui/misc/WCPage.cxx new file mode 100644 index 000000000..35c8a7fe0 --- /dev/null +++ b/dbaccess/source/ui/misc/WCPage.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 +#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_clicked( LINK( this, OCopyTable, AppendDataClickHdl ) ); + + m_xRB_DefData->connect_clicked( LINK( this, OCopyTable, RadioChangeHdl ) ); + m_xRB_Def->connect_clicked( LINK( this, OCopyTable, RadioChangeHdl ) ); + m_xRB_View->connect_clicked( LINK( this, OCopyTable, RadioChangeHdl ) ); + + m_xCB_PrimaryColumn->connect_clicked(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() +{ +} + +IMPL_LINK_NOARG( OCopyTable, AppendDataClickHdl, weld::Button&, void ) +{ + SetAppendDataRadio(); +} + +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::Button&, rButton, void) +{ + m_pParent->EnableNextButton(&rButton != m_xRB_View.get()); + bool bKey = m_bPKeyAllowed && &rButton != m_xRB_View.get(); + 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::Button&, 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 000000000..785061051 --- /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 OString& rID) + : ::vcl::OWizardPage(pPage, pWizard, rUIXMLDescription, rID) + , m_pParent(pWizard) + , m_bFirstTime(true) +{ +} + +OWizardPage::~OWizardPage() +{ +} + +// OWizColumnSelect +OWizColumnSelect::OWizColumnSelect(weld::Container* pPage, OCopyTableWizard* pWizard) + : OWizardPage(pPage, pWizard, "dbaccess/ui/applycolpage.ui", "ApplyColPage") + , m_xOrgColumnNames(m_xBuilder->weld_tree_view("from")) + , m_xColumn_RH(m_xBuilder->weld_button("colrh")) + , m_xColumns_RH(m_xBuilder->weld_button("colsrh")) + , m_xColumn_LH(m_xBuilder->weld_button("collh")) + , m_xColumns_LH(m_xBuilder->weld_button("colslh")) + , m_xNewColumnNames(m_xBuilder->weld_tree_view("to")) +{ + m_xColumn_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + m_xColumn_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + m_xColumns_RH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + m_xColumns_LH->connect_clicked(LINK(this,OWizColumnSelect,ButtonClickHdl)); + + m_xOrgColumnNames->set_selection_mode(SelectionMode::Multiple); + m_xNewColumnNames->set_selection_mode(SelectionMode::Multiple); + + m_xOrgColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl)); + m_xNewColumnNames->connect_row_activated(LINK(this,OWizColumnSelect,ListDoubleClickHdl)); +} + +OWizColumnSelect::~OWizColumnSelect() +{ + while (m_xNewColumnNames->n_children()) + { + delete reinterpret_cast(m_xNewColumnNames->get_id(0).toInt64()); + 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(OUString::number(reinterpret_cast(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(OUString::number(reinterpret_cast(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 = reinterpret_cast(m_xNewColumnNames->get_id(i).toInt64()); + 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, + const OUString& _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(OUString::number(reinterpret_cast(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, + const OUString& _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 = reinterpret_cast(_pLeft->get_id(_pLeft->find_text(_sColumnName)).toInt64()); + 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(OUString::number(reinterpret_cast(aSrcIter->second))); + const OUString& rStr = (*aIter).first; + _pRight->insert(nullptr, nPos, &rStr, &sId, nullptr, 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, + const OUString& _sColumnName, + ODatabaseExport::TColumnVector::size_type nCurrentPos, + const ::comphelper::UStringMixEqual& _aCase) +{ + sal_Int32 nAdjustedPos = 0; + + // if returning all entries to their original position, + // then there is no need to adjust the positions. + if (m_xColumns_LH->has_focus()) + return nAdjustedPos; + + const sal_Int32 nCount = _pLeft->n_children(); + OUString sColumnString; + for(sal_Int32 i=0; i < nCount; ++i) + { + sColumnString = _pLeft->get_text(i); + if(_sColumnName != sColumnString) + { + // find the new column in the dest name mapping to obtain the old column + OCopyTableWizard::TNameMapping::const_iterator aIter = std::find_if(m_pParent->m_mNameMapping.begin(),m_pParent->m_mNameMapping.end(), + [&_aCase, &sColumnString] (const OCopyTableWizard::TNameMapping::value_type& nameMap) { + return _aCase(nameMap.second, sColumnString); + }); + + OSL_ENSURE(aIter != m_pParent->m_mNameMapping.end(),"Column must be defined"); + const ODatabaseExport::TColumns& rSrcColumns = m_pParent->getSourceColumns(); + ODatabaseExport::TColumns::const_iterator aSrcIter = rSrcColumns.find((*aIter).first); + if ( aSrcIter != rSrcColumns.end() ) + { + // we need also the old position of this column to insert it back on that position again + const ODatabaseExport::TColumnVector& rSrcVector = m_pParent->getSrcVector(); + ODatabaseExport::TColumnVector::const_iterator aPos = std::find(rSrcVector.begin(), rSrcVector.end(), aSrcIter); + ODatabaseExport::TColumnVector::size_type nPos = aPos - rSrcVector.begin(); + if( nPos < nCurrentPos) + { + nAdjustedPos++; + } + } + } + } + + return nAdjustedPos; +} + +void OWizColumnSelect::enableButtons() +{ + bool bEntries = m_xNewColumnNames->n_children() != 0; + if (!bEntries) + m_pParent->m_mNameMapping.clear(); + + m_pParent->GetOKButton().set_sensitive(bEntries); + m_pParent->EnableNextButton(bEntries && m_pParent->getOperation() != CopyTableOperation::AppendData); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WCopyTable.cxx b/dbaccess/source/ui/misc/WCopyTable.cxx new file mode 100644 index 000000000..58dbc4d65 --- /dev/null +++ b/dbaccess/source/ui/misc/WCopyTable.cxx @@ -0,0 +1,1558 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::task; +using namespace dbtools; + +namespace CopyTableOperation = ::com::sun::star::sdb::application::CopyTableOperation; + +#define MAX_PAGES 4 // max. number of pages, which are shown + +namespace +{ + void clearColumns(ODatabaseExport::TColumns& _rColumns, ODatabaseExport::TColumnVector& _rColumnsVec) + { + for (auto const& column : _rColumns) + delete column.second; + + _rColumnsVec.clear(); + _rColumns.clear(); + } +} + +// ICopyTableSourceObject +ICopyTableSourceObject::~ICopyTableSourceObject() +{ +} + +// ObjectCopySource +ObjectCopySource::ObjectCopySource( const Reference< XConnection >& _rxConnection, const Reference< XPropertySet >& _rxObject ) + :m_xConnection( _rxConnection, UNO_SET_THROW ) + ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ) + ,m_xObject( _rxObject, UNO_SET_THROW ) + ,m_xObjectPSI( _rxObject->getPropertySetInfo(), UNO_SET_THROW ) + ,m_xObjectColumns( Reference< XColumnsSupplier >( _rxObject, UNO_QUERY_THROW )->getColumns(), UNO_SET_THROW ) +{ +} + +OUString ObjectCopySource::getQualifiedObjectName() const +{ + OUString sName; + + if ( !m_xObjectPSI->hasPropertyByName( PROPERTY_COMMAND ) ) + sName = ::dbtools::composeTableName( m_xMetaData, m_xObject, ::dbtools::EComposeRule::InDataManipulation, false ); + else + m_xObject->getPropertyValue( PROPERTY_NAME ) >>= sName; + return sName; +} + +bool ObjectCopySource::isView() const +{ + bool bIsView = false; + try + { + if ( m_xObjectPSI->hasPropertyByName( PROPERTY_TYPE ) ) + { + OUString sObjectType; + OSL_VERIFY( m_xObject->getPropertyValue( PROPERTY_TYPE ) >>= sObjectType ); + bIsView = sObjectType == "VIEW"; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bIsView; +} + +void ObjectCopySource::copyUISettingsTo( const Reference< XPropertySet >& _rxObject ) const +{ + const OUString aCopyProperties[] = { + OUString(PROPERTY_FONT), OUString(PROPERTY_ROW_HEIGHT), OUString(PROPERTY_TEXTCOLOR),OUString(PROPERTY_TEXTLINECOLOR),OUString(PROPERTY_TEXTEMPHASIS),OUString(PROPERTY_TEXTRELIEF) + }; + for (const auto & aCopyPropertie : aCopyProperties) + { + if ( m_xObjectPSI->hasPropertyByName( aCopyPropertie ) ) + _rxObject->setPropertyValue( aCopyPropertie, m_xObject->getPropertyValue( aCopyPropertie ) ); + } +} + +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 & aPropertie : aProperties) + { + if ( m_xObjectPSI->hasPropertyByName( aPropertie.first ) ) + { + OUString sFilter; + m_xObject->getPropertyValue( aPropertie.first ) >>= sFilter; + if ( !sFilter.isEmpty() ) + { + sStatement.append(aPropertie.second); + sFilter = sFilter.replaceFirst(sSourceName,sTargetNameTemp); + _rxObject->setPropertyValue( aPropertie.first, makeAny(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; + aSQL.append( "SELECT " ); + + // we need to create the sql stmt with column names + // otherwise it is possible that names don't match + const OUString sQuote = m_xMetaData->getIdentifierQuoteString(); + + Sequence< OUString > aColumnNames = getColumnNames(); + const OUString* pColumnName = aColumnNames.getConstArray(); + const OUString* pEnd = pColumnName + aColumnNames.getLength(); + for ( ; pColumnName != pEnd; ) + { + aSQL.append( ::dbtools::quoteName( sQuote, *pColumnName++ ) ); + + if ( pColumnName == pEnd ) + aSQL.append( " " ); + else + aSQL.append( ", " ); + } + + aSQL.append( "FROM " ).append( ::dbtools::composeTableNameForSelect( m_xConnection, m_xObject ) ); + + sSelectStatement = aSQL.makeStringAndClear(); + } + + return sSelectStatement; +} + +::utl::SharedUNOComponent< XPreparedStatement > ObjectCopySource::getPreparedSelectStatement() const +{ + ::utl::SharedUNOComponent< XPreparedStatement > xStatement( + m_xConnection->prepareStatement( getSelectStatement() ), + ::utl::SharedUNOComponent< XPreparedStatement >::TakeOwnership + ); + return xStatement; +} + +// NamedTableCopySource +NamedTableCopySource::NamedTableCopySource( const Reference< XConnection >& _rxConnection, const OUString& _rTableName ) + :m_xConnection( _rxConnection, UNO_SET_THROW ) + ,m_xMetaData( _rxConnection->getMetaData(), UNO_SET_THROW ) + ,m_sTableName( _rTableName ) + ,m_aColumnInfo() +{ + ::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( makeAny( 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() ); + size_t nPos = 0; + for (auto const& elem : m_aColumnInfo) + aNames[ nPos++ ] = elem.GetName(); + + return aNames; +} + +Sequence< OUString > NamedTableCopySource::getPrimaryKeyColumnNames() const +{ + Sequence< OUString > aPKColNames; + + try + { + Reference< XResultSet > xPKDesc( m_xMetaData->getPrimaryKeys( makeAny( 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[ 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 +{ + OUStringBuffer aSQL; + aSQL.append( "SELECT * FROM " ); + + aSQL.append( ::dbtools::composeTableNameForSelect( m_xConnection, m_sTableCatalog, m_sTableSchema, m_sTableBareName ) ); + + return aSQL.makeStringAndClear(); +} + +::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() +{ + OString sIdent(OString::number(m_nPageCount)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + return pPageContainer; +} + +OCopyTableWizard::OCopyTableWizard( weld::Window* pParent, const OUString& _rDefaultName, sal_Int16 _nOperation, + const 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(_rSourceColumns) + , m_mNameMapping(_xConnection->getMetaData().is() && _xConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers()) + , m_xDestConnection( _xConnection ) + , m_rSourceObject( DummyCopySource::Instance() ) + , m_xFormatter(_xFormatter) + , m_xContext(_rxContext) + , m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + , m_nPageCount(0) + , m_bDeleteSourceColumns(false) + , m_bInterConnectionCopy( false ) + , m_sName(_rDefaultName) + , m_nOperation( _nOperation ) + , m_ePressed( WIZARD_NONE ) + , m_bCreatePrimaryKeyColumn(false) + , m_bUseHeaderLine(false) +{ + construct(); + for (auto const& sourceCol : _rSourceColVec) + { + m_vSourceVec.emplace_back(m_vSourceColumns.find(sourceCol->first)); + } + + ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aTypeInfo, m_aTypeInfoIndex ); + ::dbaui::fillTypeInfo( _xConnection, m_sTypeNames, m_aDestTypeInfo, m_aDestTypeInfoIndex ); + + m_xInteractionHandler = InteractionHandler::createWithParent(m_xContext, nullptr); + + std::unique_ptr 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_xNextPage->set_has_default(true); + else + m_xFinish->set_has_default(true); + + 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(); +} + +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; + aError.Message = sMsg; + ::rtl::Reference xRequest( new ::comphelper::OInteractionRequest( makeAny( aError ) ) ); + ::rtl::Reference xYes = new ::comphelper::OInteractionApprove; + xRequest->addContinuation( xYes.get() ); + xRequest->addContinuation( new ::comphelper::OInteractionDisapprove ); + ::rtl::Reference< ::comphelper::OInteractionAbort > xAbort = new ::comphelper::OInteractionAbort; + xRequest->addContinuation( xAbort.get() ); + + m_xInteractionHandler->handle( xRequest.get() ); + + 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; + OUString const sCreateParam("x"); + // ReadOnly-Flag + // On drop no line must be editable. + // On add only empty lines must be editable. + // On Add and Drop all lines can be edited. + Sequence< OUString > aColumns( _rSourceObject.getColumnNames() ); + const OUString* pColumn = aColumns.getConstArray(); + const OUString* pColumnEnd = pColumn + aColumns.getLength(); + + for ( ; pColumn != pColumnEnd; ++pColumn ) + { + // get the properties of the column + pActFieldDescr = _rSourceObject.createFieldDescription( *pColumn ); + OSL_ENSURE( pActFieldDescr, "OCopyTableWizard::loadData: illegal field description!" ); + if ( !pActFieldDescr ) + continue; + + sal_Int32 nType = pActFieldDescr->GetType(); + sal_Int32 nScale = pActFieldDescr->GetScale(); + sal_Int32 nPrecision = pActFieldDescr->GetPrecision(); + bool bAutoIncrement = pActFieldDescr->IsAutoIncrement(); + OUString sTypeName = pActFieldDescr->GetTypeName(); + + // search for type + bool bForce; + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreateParam,nPrecision,nScale,bAutoIncrement,bForce); + if ( !pTypeInfo ) + pTypeInfo = m_pTypeInfo; + + pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false); + _rColVector.emplace_back(_rColumns.emplace(pActFieldDescr->GetName(),pActFieldDescr).first); + } + + // determine which columns belong to the primary key + Sequence< OUString > aPrimaryKeyColumns( _rSourceObject.getPrimaryKeyColumnNames() ); + const OUString* pKeyColName = aPrimaryKeyColumns.getConstArray(); + const OUString* pKeyColEnd = pKeyColName + aPrimaryKeyColumns.getLength(); + + for( ; pKeyColName != pKeyColEnd; ++pKeyColName ) + { + ODatabaseExport::TColumns::const_iterator keyPos = _rColumns.find( *pKeyColName ); + if ( keyPos != _rColumns.end() ) + { + keyPos->second->SetPrimaryKey( true ); + keyPos->second->SetIsNullable( ColumnValue::NO_NULLS ); + } + } +} + +void OCopyTableWizard::clearDestColumns() +{ + clearColumns(m_vDestColumns,m_aDestVec); + m_bAddPKFirstTime = true; + m_mNameMapping.clear(); +} + +void OCopyTableWizard::appendColumns( Reference 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,makeAny(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,makeAny(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() +{ + 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,makeAny(sCatalog)); + xTable->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema)); + xTable->setPropertyValue(PROPERTY_NAME,makeAny(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, + const OUString& _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; + OUString const sCreate("x"); + pType = ::dbaui::getTypeInfoFromType(m_aDestTypeInfo,DataType::VARCHAR,_pType->aTypeName,sCreate,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(const OUString& _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.get() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WExtendPages.cxx b/dbaccess/source/ui/misc/WExtendPages.cxx new file mode 100644 index 000000000..f34661cab --- /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, + 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, + m_pParent->GetColumnPositions(), + m_pParent->GetFormatter(), + m_pParent->GetComponentContext(), + &m_pParent->getDestVector(), + &m_pParent->getTypeInfo(), + m_pParent->shouldCreatePrimaryKey()); + xParser->CallParser(); +} + +void OWizNormalExtend::createReaderAndCallParser(sal_Int32 /*_nRows*/) +{ +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WNameMatch.cxx b/dbaccess/source/ui/misc/WNameMatch.cxx new file mode 100644 index 000000000..83ad642d8 --- /dev/null +++ b/dbaccess/source/ui/misc/WNameMatch.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 + +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)); + + std::vector aWidths; + aWidths.push_back(m_xCTRL_LEFT->get_checkbox_column_width()); + m_xCTRL_LEFT->set_column_fixed_widths(aWidths); + + 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 = reinterpret_cast(m_xCTRL_LEFT->get_id(*xLeftEntry).toInt64()); + 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, 0) == TRISTATE_TRUE) + { + OFieldDescription* pDestField = reinterpret_cast(m_xCTRL_RIGHT->get_id(*xRightEntry).toInt64()); + 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 = reinterpret_cast(m_xCTRL_RIGHT->get_id(nPos).toInt64()); + 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, 0); + return false; + }); +} + +void OWizNameMatching::FillListBox(weld::TreeView& rTreeView, const ODatabaseExport::TColumnVector& rList, bool bCheckButtons) +{ + rTreeView.clear(); + + int nRow(0); + + const int nTextCol = bCheckButtons ? 1 : 0; + + for (auto const& elem : rList) + { + rTreeView.append(); + if (bCheckButtons) + { + bool bChecked = !elem->second->IsAutoIncrement(); + rTreeView.set_toggle(nRow, bChecked ? TRISTATE_TRUE : TRISTATE_FALSE, 0); + } + rTreeView.set_text(nRow, elem->first, nTextCol); + rTreeView.set_id(nRow, OUString::number(reinterpret_cast(elem->second))); + ++nRow; + } + + if (rTreeView.n_children()) + rTreeView.select(0); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/WTypeSelect.cxx b/dbaccess/source/ui/misc/WTypeSelect.cxx new file mode 100644 index 000000000..c06de9bca --- /dev/null +++ b/dbaccess/source/ui/misc/WTypeSelect.cxx @@ -0,0 +1,419 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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::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, 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(long 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 = reinterpret_cast< OFieldDescription* >( pListBox->get_id(nPos).toInt64() ); + 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, OUString::number(reinterpret_cast(pCurFieldDescr))); + + pWiz->replaceColumn(nPos,pCurFieldDescr,sOldName); + } + break; + } + saveCurrentFieldDescData(); +} + +css::lang::Locale OWizTypeSelectControl::GetLocale() const +{ + return m_pParentTabPage->m_pParent->GetLocale(); +} + +Reference< XNumberFormatter > OWizTypeSelectControl::GetFormatter() const +{ + return m_pParentTabPage->m_pParent->GetFormatter(); +} + +TOTypeInfoSP OWizTypeSelectControl::getTypeInfo(sal_Int32 _nPos) +{ + return m_pParentTabPage->m_pParent->getDestTypeInfo(_nPos); +} + +const OTypeInfoMap* OWizTypeSelectControl::getTypeInfo() const +{ + return &m_pParentTabPage->m_pParent->getDestTypeInfo(); +} + +css::uno::Reference< css::sdbc::XDatabaseMetaData> OWizTypeSelectControl::getMetaData() +{ + return m_pParentTabPage->m_pParent->m_xDestConnection->getMetaData(); +} + +css::uno::Reference< css::sdbc::XConnection> OWizTypeSelectControl::getConnection() +{ + return m_pParentTabPage->m_pParent->m_xDestConnection; +} + +bool OWizTypeSelectControl::isAutoIncrementValueEnabled() const +{ + return m_pParentTabPage->m_bAutoIncrementEnabled; +} + +OUString OWizTypeSelectControl::getAutoIncrementValue() const +{ + return m_pParentTabPage->m_sAutoIncrementValue; +} + +OWizTypeSelect::OWizTypeSelect(weld::Container* pPage, OCopyTableWizard* pWizard, SvStream* pStream) + : OWizardPage(pPage, pWizard, "dbaccess/ui/typeselectpage.ui", "TypeSelect") + , m_xColumnNames(new OWizTypeSelectList(m_xBuilder->weld_tree_view("columnnames"))) + , m_xColumns(m_xBuilder->weld_label("columns")) + , m_xControlContainer(m_xBuilder->weld_container("control_container")) + , m_xTypeControl(VclPtr::Create(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->Show(); + 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() +{ + m_xTypeControl.disposeAndClear(); +} + +OUString OWizTypeSelect::GetTitle() const +{ + return DBA_RES(STR_WIZ_TYPE_SELECT_TITLE); +} + +IMPL_LINK_NOARG(OWizTypeSelect, ColumnSelectHdl, weld::TreeView&, void) +{ + OFieldDescription* pField = reinterpret_cast(m_xColumnNames->get_selected_id().toInt64()); + 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(OUString::number(reinterpret_cast(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 = reinterpret_cast(m_xColumnNames->get_selected_id().toInt64()); + 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 = reinterpret_cast(m_xControl->get_id(aRows[j]).toInt64()); + 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 ) + { + OUString sImage(BMP_PRIMARY_KEY); + m_xControl->set_image(_nPos, sImage); + } + 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 = reinterpret_cast(m_xControl->get_id(j).toInt64()); + // if at least one of the fields is selected but not in the primary key, + // or is in the primary key but not selected, then don't check the + // primary key checkbox. + if( pFieldDescr && pFieldDescr->IsPrimaryKey() != m_xControl->is_selected(j) ) + { + bCheckOk = false; + break; + } + if (!bCheckOk && m_xControl->is_selected(j)) + bCheckOk = true; + } + + if (bCheckOk) + xContextMenu->set_active("primarykey", true); + + OString sCommand(xContextMenu->popup_at_rect(m_xControl.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)))); + if (sCommand == "primarykey") + { + for (sal_Int32 j = 0 ; j < nCount; ++j) + { + OFieldDescription* pFieldDescr = reinterpret_cast(m_xControl->get_id(j).toInt64()); + if (pFieldDescr) + { + if(!bCheckOk && m_xControl->is_selected(j)) + { + setPrimaryKey(pFieldDescr,j,true); + } + else + { + setPrimaryKey(pFieldDescr,j); + } + } + } + m_aChangeHdl.Call(*m_xControl); + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/asyncmodaldialog.cxx b/dbaccess/source/ui/misc/asyncmodaldialog.cxx new file mode 100644 index 000000000..3c59a58f8 --- /dev/null +++ b/dbaccess/source/ui/misc/asyncmodaldialog.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#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 000000000..86e55b226 --- /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 + +namespace dbaui +{ + using namespace ::dbtools; + + // OCharsetDisplay + OCharsetDisplay::OCharsetDisplay() + : OCharsetMap() + , m_aSystemDisplayName(DBA_RES( STR_RSC_CHARSETS )) + { + } + + bool OCharsetDisplay::approveEncoding( const rtl_TextEncoding _eEncoding, const rtl_TextEncodingInfo& _rInfo ) const + { + if ( !OCharsetMap::approveEncoding( _eEncoding, _rInfo ) ) + return false; + + if ( RTL_TEXTENCODING_DONTKNOW == _eEncoding ) + return true; + + return !SvxTextEncodingTable::GetTextString(_eEncoding).isEmpty(); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::begin() const + { + return const_iterator( this, OCharsetMap::begin() ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::end() const + { + return const_iterator( this, OCharsetMap::end() ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::findEncoding(const rtl_TextEncoding _eEncoding) const + { + OCharsetMap::const_iterator aBaseIter = OCharsetMap::find(_eEncoding); + return const_iterator( this, aBaseIter ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::findIanaName(const OUString& _rIanaName) const + { + OCharsetMap::const_iterator aBaseIter = OCharsetMap::findIanaName(_rIanaName); + return const_iterator( this, aBaseIter ); + } + + OCharsetDisplay::const_iterator OCharsetDisplay::findDisplayName(const OUString& _rDisplayName) const + { + rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW; + if ( _rDisplayName != m_aSystemDisplayName ) + { + eEncoding = SvxTextEncodingTable::GetTextEncoding(_rDisplayName); + OSL_ENSURE( RTL_TEXTENCODING_DONTKNOW != eEncoding, + "OCharsetDisplay::find: non-empty display name, but DONTKNOW!" ); + } + return const_iterator( this, OCharsetMap::find( eEncoding ) ); + } + + // CharsetDisplayDerefHelper + CharsetDisplayDerefHelper::CharsetDisplayDerefHelper(const CharsetDisplayDerefHelper& _rSource) + :CharsetDisplayDerefHelper_Base(_rSource) + ,m_sDisplayName(_rSource.m_sDisplayName) + { + } + + CharsetDisplayDerefHelper::CharsetDisplayDerefHelper(const ::dbtools::CharsetIteratorDerefHelper& _rBase, const OUString& _rDisplayName) + :CharsetDisplayDerefHelper_Base(_rBase) + ,m_sDisplayName(_rDisplayName) + { + OSL_ENSURE( !m_sDisplayName.isEmpty(), "CharsetDisplayDerefHelper::CharsetDisplayDerefHelper: invalid display name!" ); + } + + // OCharsetDisplay::ExtendedCharsetIterator + OCharsetDisplay::ExtendedCharsetIterator::ExtendedCharsetIterator( const OCharsetDisplay* _pContainer, const base_iterator& _rPosition ) + :m_pContainer(_pContainer) + ,m_aPosition(_rPosition) + { + OSL_ENSURE(m_pContainer, "OCharsetDisplay::ExtendedCharsetIterator::ExtendedCharsetIterator : invalid container!"); + } + + CharsetDisplayDerefHelper OCharsetDisplay::ExtendedCharsetIterator::operator*() const + { + OSL_ENSURE( m_aPosition != m_pContainer->OCharsetDisplay_Base::end(), "OCharsetDisplay::ExtendedCharsetIterator::operator* : invalid position!"); + + rtl_TextEncoding eEncoding = (*m_aPosition).getEncoding(); + return CharsetDisplayDerefHelper( + *m_aPosition, + RTL_TEXTENCODING_DONTKNOW == eEncoding ? m_pContainer->m_aSystemDisplayName : SvxTextEncodingTable::GetTextString(eEncoding) + ); + } + + const OCharsetDisplay::ExtendedCharsetIterator& OCharsetDisplay::ExtendedCharsetIterator::operator++() + { + OSL_ENSURE( m_aPosition != m_pContainer->OCharsetDisplay_Base::end(), "OCharsetDisplay::ExtendedCharsetIterator::operator++ : invalid position!"); + if ( m_aPosition != m_pContainer->OCharsetDisplay_Base::end() ) + ++m_aPosition; + return *this; + } + + bool operator==(const OCharsetDisplay::ExtendedCharsetIterator& lhs, const OCharsetDisplay::ExtendedCharsetIterator& rhs) + { + return (lhs.m_pContainer == rhs.m_pContainer) && (lhs.m_aPosition == rhs.m_aPosition); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/controllerframe.cxx b/dbaccess/source/ui/misc/controllerframe.cxx new file mode 100644 index 000000000..599398e5d --- /dev/null +++ b/dbaccess/source/ui/misc/controllerframe.cxx @@ -0,0 +1,393 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::frame::FrameAction; + using ::com::sun::star::frame::FrameAction_FRAME_ACTIVATED; + using ::com::sun::star::frame::FrameAction_FRAME_UI_ACTIVATED; + using ::com::sun::star::frame::FrameAction_FRAME_DEACTIVATING; + using ::com::sun::star::frame::FrameAction_FRAME_UI_DEACTIVATING; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::frame::XController; + using ::com::sun::star::frame::XController2; + using ::com::sun::star::awt::XTopWindow; + using ::com::sun::star::awt::XTopWindowListener; + using ::com::sun::star::awt::XWindow2; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::document::XDocumentEventBroadcaster; + using ::com::sun::star::awt::XWindow; + + // FrameWindowActivationListener + typedef ::cppu::WeakImplHelper< XTopWindowListener + > FrameWindowActivationListener_Base; + + namespace { + + class FrameWindowActivationListener : public FrameWindowActivationListener_Base + { + public: + explicit FrameWindowActivationListener( ControllerFrame_Data& _rData ); + + void dispose(); + + protected: + virtual ~FrameWindowActivationListener() override; + + // XTopWindowListener + virtual void SAL_CALL windowOpened( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowClosing( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowClosed( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowMinimized( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowNormalized( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowActivated( const css::lang::EventObject& e ) override; + virtual void SAL_CALL windowDeactivated( const css::lang::EventObject& e ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + private: + void impl_checkDisposed_throw() const; + void impl_registerOnFrameContainerWindow_nothrow( bool _bRegister ); + + private: + ControllerFrame_Data* m_pData; + }; + + } + + // ControllerFrame_Data + struct ControllerFrame_Data + { + explicit ControllerFrame_Data( IController& _rController ) + :m_rController( _rController ) + ,m_xFrame() + ,m_xDocEventBroadcaster() + ,m_pListener() + ,m_bActive( false ) + ,m_bIsTopLevelDocumentWindow( false ) + { + } + + IController& m_rController; + Reference< XFrame > m_xFrame; + Reference< XDocumentEventBroadcaster > m_xDocEventBroadcaster; + ::rtl::Reference< FrameWindowActivationListener > m_pListener; + bool m_bActive; + bool m_bIsTopLevelDocumentWindow; + }; + + // helper + static void lcl_setFrame_nothrow( ControllerFrame_Data& _rData, const Reference< XFrame >& _rxFrame ) + { + // release old listener + if (_rData.m_pListener) + { + _rData.m_pListener->dispose(); + _rData.m_pListener = nullptr; + } + + // remember new frame + _rData.m_xFrame = _rxFrame; + + // create new listener + if ( _rData.m_xFrame.is() ) + _rData.m_pListener = new FrameWindowActivationListener( _rData ); + + // at this point in time, we can assume the controller also has a model set, if it supports models + try + { + Reference< XController > xController( _rData.m_rController.getXController(), UNO_SET_THROW ); + Reference< XModel > xModel( xController->getModel() ); + if ( xModel.is() ) + _rData.m_xDocEventBroadcaster.set( xModel, UNO_QUERY ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + static bool lcl_isActive_nothrow( const Reference< XFrame >& _rxFrame ) + { + bool bIsActive = false; + try + { + if ( _rxFrame.is() ) + { + Reference< XWindow2 > xWindow( _rxFrame->getContainerWindow(), UNO_QUERY_THROW ); + bIsActive = xWindow->isActive(); + } + + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return bIsActive; + } + + /** updates various global and local states with a new active component + + In particular, the following are updated + * the global working document (aka Basic's ThisComponent in the application + Basic), with our controller's model, or the controller itself if there is no such + model. + */ + static void lcl_updateActiveComponents_nothrow( const ControllerFrame_Data& _rData ) + { + try + { + Reference< XController > xCompController( _rData.m_rController.getXController() ); + OSL_ENSURE( xCompController.is(), "lcl_updateActiveComponents_nothrow: can't do anything without a controller!" ); + if ( !xCompController.is() ) + return; + + if ( _rData.m_bActive && _rData.m_bIsTopLevelDocumentWindow ) + { + // set the "current component" at the SfxObjectShell + Reference< XModel > xModel( xCompController->getModel() ); + Reference< XInterface > xCurrentComponent; + if ( xModel.is() ) + xCurrentComponent = xModel; + else + xCurrentComponent = xCompController; + SfxObjectShell::SetCurrentComponent( xCurrentComponent ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + /** broadcasts the OnFocus resp. OnUnfocus event + */ + static void lcl_notifyFocusChange_nothrow( ControllerFrame_Data& _rData, bool _bActive ) + { + try + { + if ( _rData.m_xDocEventBroadcaster.is() ) + { + OUString sEventName = _bActive ? OUString("OnFocus") : OUString("OnUnfocus"); + Reference< XController2 > xController( _rData.m_rController.getXController(), UNO_QUERY_THROW ); + _rData.m_xDocEventBroadcaster->notifyDocumentEvent( sEventName, xController, Any() ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + static void lcl_updateActive_nothrow( ControllerFrame_Data& _rData, bool _bActive ) + { + if ( _rData.m_bActive == _bActive ) + return; + _rData.m_bActive = _bActive; + + lcl_updateActiveComponents_nothrow( _rData ); + lcl_notifyFocusChange_nothrow( _rData, _bActive ); + } + + FrameWindowActivationListener::FrameWindowActivationListener( ControllerFrame_Data& _rData ) + :m_pData( &_rData ) + { + impl_registerOnFrameContainerWindow_nothrow( true ); + } + + FrameWindowActivationListener::~FrameWindowActivationListener() + { + } + + void FrameWindowActivationListener::dispose() + { + impl_registerOnFrameContainerWindow_nothrow( false ); + m_pData = nullptr; + } + + void FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow( bool _bRegister ) + { + OSL_ENSURE( m_pData && m_pData->m_xFrame.is(), "FrameWindowActivationListener::impl_registerOnFrameContainerWindow_nothrow: no frame!" ); + if ( !m_pData || !m_pData->m_xFrame.is() ) + return; + + try + { + void ( SAL_CALL XTopWindow::*pListenerAction )( const Reference< XTopWindowListener >& ) = + _bRegister ? &XTopWindow::addTopWindowListener : &XTopWindow::removeTopWindowListener; + + const Reference< XWindow > xContainerWindow( m_pData->m_xFrame->getContainerWindow(), UNO_SET_THROW ); + if ( _bRegister ) + { + const vcl::Window* pContainerWindow = VCLUnoHelper::GetWindow( xContainerWindow ); + ENSURE_OR_THROW( pContainerWindow, "no Window implementation for the frame's container window!" ); + + m_pData->m_bIsTopLevelDocumentWindow = bool( pContainerWindow->GetExtendedStyle() & WindowExtendedStyle::Document ); + } + + const Reference< XTopWindow > xFrameContainer( xContainerWindow, UNO_QUERY ); + if ( xFrameContainer.is() ) + (xFrameContainer.get()->*pListenerAction)( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void FrameWindowActivationListener::impl_checkDisposed_throw() const + { + if ( !m_pData ) + throw DisposedException( OUString(), *const_cast< FrameWindowActivationListener* >( this ) ); + } + + void SAL_CALL FrameWindowActivationListener::windowOpened( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowClosing( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowClosed( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowMinimized( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowNormalized( const EventObject& /*_rEvent*/ ) + { + // not interested in + } + + void SAL_CALL FrameWindowActivationListener::windowActivated( const EventObject& /*_rEvent*/ ) + { + impl_checkDisposed_throw(); + lcl_updateActive_nothrow( *m_pData, true ); + } + + void SAL_CALL FrameWindowActivationListener::windowDeactivated( const EventObject& /*_rEvent*/ ) + { + impl_checkDisposed_throw(); + lcl_updateActive_nothrow( *m_pData, false ); + } + + void SAL_CALL FrameWindowActivationListener::disposing( const EventObject& /*_rEvent*/ ) + { + dispose(); + } + + // ControllerFrame + ControllerFrame::ControllerFrame( IController& _rController ) + :m_pData( new ControllerFrame_Data( _rController ) ) + { + } + + ControllerFrame::~ControllerFrame() + { + } + + const Reference< XFrame >& ControllerFrame::attachFrame( const Reference< XFrame >& _rxFrame ) + { + // set new frame, including listener handling + lcl_setFrame_nothrow( *m_pData, _rxFrame ); + + // determine whether we're active + m_pData->m_bActive = lcl_isActive_nothrow( m_pData->m_xFrame ); + + // update active component + if ( m_pData->m_bActive ) + { + lcl_updateActiveComponents_nothrow( *m_pData ); + lcl_notifyFocusChange_nothrow( *m_pData, true ); + } + + return m_pData->m_xFrame; + } + + const Reference< XFrame >& ControllerFrame::getFrame() const + { + return m_pData->m_xFrame; + } + + bool ControllerFrame::isActive() const + { + return m_pData->m_bActive; + } + + void ControllerFrame::frameAction( FrameAction _eAction ) + { + bool bActive = m_pData->m_bActive; + + switch ( _eAction ) + { + case FrameAction_FRAME_ACTIVATED: + case FrameAction_FRAME_UI_ACTIVATED: + bActive = true; + break; + + case FrameAction_FRAME_DEACTIVATING: + case FrameAction_FRAME_UI_DEACTIVATING: + bActive = false; + break; + + default: + break; + } + + lcl_updateActive_nothrow( *m_pData, bActive ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/databaseobjectview.cxx b/dbaccess/source/ui/misc/databaseobjectview.cxx new file mode 100644 index 000000000..49d3cfe55 --- /dev/null +++ b/dbaccess/source/ui/misc/databaseobjectview.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 +#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, + const OUString& _rComponentURL ) + :m_xORB ( _rxORB ) + ,m_xParentFrame ( _rxParentFrame ) + ,m_xFrameLoader ( ) + ,m_xApplication ( _rxApplication ) + ,m_sComponentURL ( _rComponentURL ) + { + OSL_ENSURE( m_xORB.is(), "DatabaseObjectView::DatabaseObjectView: invalid service factory!" ); + OSL_ENSURE( m_xApplication.is(), "DatabaseObjectView::DatabaseObjectView: invalid connection!" ); + } + + Reference< XConnection > DatabaseObjectView::getConnection() const + { + Reference< XConnection > xConnection; + if ( m_xApplication.is() ) + xConnection = m_xApplication->getActiveConnection(); + return xConnection; + } + + Reference< XComponent > DatabaseObjectView::createNew( const Reference< XDataSource >& _xDataSource, const ::comphelper::NamedValueCollection& i_rDispatchArgs ) + { + return doCreateView( makeAny( _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(3); + NamedValue aProp; + sal_Int32 nArg = 0; + + aProp.Name = "ParentFrame"; + aProp.Value <<= m_xParentFrame; + lArgs[nArg++] <<= aProp; + + aProp.Name = "TopWindow"; + aProp.Value <<= true; + lArgs[nArg++] <<= aProp; + + aProp.Name = "SupportPersistentWindowState"; + aProp.Value <<= true; + lArgs[nArg++] <<= aProp; + + 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( OUString(PROPERTY_DATASOURCENAME), sDataSource ); + } + else if ( _aDataSource >>= xDataSource ) + { + i_rDispatchArgs.put( OUString(PROPERTY_DATASOURCE), xDataSource ); + } + + i_rDispatchArgs.put( OUString(PROPERTY_ACTIVE_CONNECTION), getConnection() ); + } + + // QueryDesigner + QueryDesigner::QueryDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, + const Reference< XFrame >& _rxParentFrame, bool _bCreateView ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, _bCreateView ? OUString(URL_COMPONENT_VIEWDESIGN) : OUString(URL_COMPONENT_QUERYDESIGN) ) + ,m_nCommandType( _bCreateView ? CommandType::TABLE : CommandType::QUERY ) + { + } + + void QueryDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource, + const OUString& _rObjectName ) + { + DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName ); + + const bool bIncludeQueryName = !_rObjectName.isEmpty(); + const bool bGraphicalDesign = i_rDispatchArgs.getOrDefault( PROPERTY_GRAPHICAL_DESIGN, true ); + const bool bEditViewAsSQLCommand = ( m_nCommandType == CommandType::TABLE ) && !bGraphicalDesign; + + i_rDispatchArgs.put( OUString(PROPERTY_COMMAND_TYPE), m_nCommandType ); + + if ( bIncludeQueryName ) + { + i_rDispatchArgs.put( OUString(PROPERTY_COMMAND), _rObjectName ); + } + + if ( bEditViewAsSQLCommand ) + { + i_rDispatchArgs.put( OUString(PROPERTY_ESCAPE_PROCESSING), false ); + } + } + + // TableDesigner + TableDesigner::TableDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_TABLEDESIGN ) ) + { + } + + void TableDesigner::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource, + const OUString& _rObjectName ) + { + DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rObjectName ); + + if ( !_rObjectName.isEmpty() ) + { + i_rDispatchArgs.put( OUString(PROPERTY_CURRENTTABLE), _rObjectName ); + } + } + + Reference< XComponent > TableDesigner::doCreateView( const Any& _rDataSource, const OUString& _rObjectName, + const ::comphelper::NamedValueCollection& i_rCreationArgs ) + { + bool bIsNewDesign = _rObjectName.isEmpty(); + + // let's see whether the connection can provide a dedicated table designer + Reference< XInterface > xDesigner; + if ( !bIsNewDesign ) + xDesigner = impl_getConnectionProvidedDesigner_nothrow( _rObjectName ); + + if ( !xDesigner.is() ) + return DatabaseObjectView::doCreateView( _rDataSource, _rObjectName, i_rCreationArgs ); + + // try whether the designer is a dialog + Reference< XExecutableDialog > xDialog( xDesigner, UNO_QUERY_THROW ); + try { AsyncDialogExecutor::executeModalDialogAsync( xDialog ); } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); } + return nullptr; + } + + Reference< XInterface > TableDesigner::impl_getConnectionProvidedDesigner_nothrow( const OUString& _rTableName ) + { + Reference< XInterface > xDesigner; + try + { + Reference< XTableUIProvider > xTableUIProv( getConnection(), UNO_QUERY ); + if ( xTableUIProv.is() ) + xDesigner = xTableUIProv->getTableEditor( getApplicationUI(), _rTableName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + return xDesigner; + } + + // ResultSetBrowser + ResultSetBrowser::ResultSetBrowser( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame, + bool _bTable ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast < OUString >( URL_COMPONENT_DATASOURCEBROWSER ) ) + ,m_bTable(_bTable) + { + } + + void ResultSetBrowser::fillDispatchArgs( ::comphelper::NamedValueCollection& i_rDispatchArgs, const Any& _aDataSource, + const OUString& _rQualifiedName) + { + DatabaseObjectView::fillDispatchArgs( i_rDispatchArgs, _aDataSource, _rQualifiedName ); + OSL_ENSURE( !_rQualifiedName.isEmpty(),"A Table name must be set"); + OUString sCatalog; + OUString sSchema; + OUString sTable; + if ( m_bTable ) + ::dbtools::qualifiedNameComponents( getConnection()->getMetaData(), _rQualifiedName, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation ); + + i_rDispatchArgs.put( OUString(PROPERTY_COMMAND_TYPE), (m_bTable ? CommandType::TABLE : CommandType::QUERY) ); + i_rDispatchArgs.put( OUString(PROPERTY_COMMAND), _rQualifiedName ); + i_rDispatchArgs.put( OUString(PROPERTY_ENABLE_BROWSER), false ); + + if ( m_bTable ) + { + i_rDispatchArgs.put( OUString(PROPERTY_UPDATE_CATALOGNAME), sCatalog ); + i_rDispatchArgs.put( OUString(PROPERTY_UPDATE_SCHEMANAME), sSchema ); + i_rDispatchArgs.put( OUString(PROPERTY_UPDATE_TABLENAME), sTable ); + } + } + + // RelationDesigner + RelationDesigner::RelationDesigner( const Reference< XComponentContext >& _rxORB, const Reference< XDatabaseDocumentUI >& _rxApplication, const Reference< XFrame >& _rxParentFrame ) + :DatabaseObjectView( _rxORB, _rxApplication, _rxParentFrame, static_cast< OUString >( URL_COMPONENT_RELATIONDESIGN ) ) + { + } +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/datasourceconnector.cxx b/dbaccess/source/ui/misc/datasourceconnector.cxx new file mode 100644 index 000000000..49053e569 --- /dev/null +++ b/dbaccess/source/ui/misc/datasourceconnector.cxx @@ -0,0 +1,202 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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, + const OUString& _rContextInformation ) + :m_pErrorMessageParent(_pMessageParent) + ,m_xContext(_rxContext) + ,m_sContextInformation( _rContextInformation ) + { + } + + Reference< XConnection > ODatasourceConnector::connect( const OUString& _rDataSourceName, + ::dbtools::SQLExceptionInfo* _pErrorInfo ) const + { + Reference< XConnection > xConnection; + + OSL_ENSURE(isValid(), "ODatasourceConnector::connect: invalid object!"); + if (!isValid()) + return xConnection; + + // get the data source + Reference< XDataSource > xDatasource = + getDataSourceByName( _rDataSourceName, m_pErrorMessageParent, m_xContext, _pErrorInfo ); + + if ( xDatasource.is() ) + xConnection = connect( xDatasource, _pErrorInfo ); + return xConnection; + } + + Reference< XConnection > ODatasourceConnector::connect(const Reference< XDataSource>& _xDataSource, + ::dbtools::SQLExceptionInfo* _pErrorInfo ) const + { + Reference< XConnection > xConnection; + + OSL_ENSURE( isValid() && _xDataSource.is(), "ODatasourceConnector::connect: invalid object or argument!" ); + if ( !isValid() || !_xDataSource.is() ) + return xConnection; + + // get user/password + OUString sPassword, sUser; + bool bPwdRequired = false; + Reference xProp(_xDataSource,UNO_QUERY); + try + { + xProp->getPropertyValue(PROPERTY_PASSWORD) >>= sPassword; + xProp->getPropertyValue(PROPERTY_ISPASSWORDREQUIRED) >>= bPwdRequired; + xProp->getPropertyValue(PROPERTY_USER) >>= sUser; + } + catch(Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // try to connect + SQLExceptionInfo aInfo; + try + { + if (bPwdRequired && sPassword.isEmpty()) + { // password required, but empty -> connect using an interaction handler + Reference< XCompletedConnection > xConnectionCompletion( _xDataSource, UNO_QUERY_THROW ); + + Reference< XModel > xModel( getDataSourceOrModel( _xDataSource ), UNO_QUERY_THROW ); + ::comphelper::NamedValueCollection aArgs( xModel->getArgs() ); + Reference< XInteractionHandler > xHandler( aArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) ); + + if ( !xHandler.is() ) + { + // instantiate the default SDB interaction handler + xHandler = InteractionHandler::createWithParent(m_xContext, m_pErrorMessageParent ? m_pErrorMessageParent->GetXWindow() : nullptr); + } + + xConnection = xConnectionCompletion->connectWithCompletion(xHandler); + } + else + { + xConnection = _xDataSource->getConnection(sUser, sPassword); + } + } + catch( const SQLException& ) + { + aInfo = ::cppu::getCaughtException(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( !aInfo.isValid() ) + { + // there was no error during connecting, but perhaps a warning? + Reference< XWarningsSupplier > xConnectionWarnings( xConnection, UNO_QUERY ); + if ( xConnectionWarnings.is() ) + { + try + { + Any aWarnings( xConnectionWarnings->getWarnings() ); + if ( aWarnings.hasValue() ) + { + OUString sMessage( DBA_RES( STR_WARNINGS_DURING_CONNECT ) ); + sMessage = sMessage.replaceFirst( "$buttontext$", GetStandardText( StandardButtonType::More ) ); + sMessage = OutputDevice::GetNonMnemonicString( sMessage ); + + SQLWarning aContext; + aContext.Message = sMessage; + aContext.NextException = aWarnings; + aInfo = aContext; + } + xConnectionWarnings->clearWarnings(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + else + { + if ( !m_sContextInformation.isEmpty() ) + { + SQLException aError; + aError.Message = m_sContextInformation; + aError.NextException = aInfo.get(); + + aInfo = aError; + } + } + + // was there an error? + if ( aInfo.isValid() ) + { + if ( _pErrorInfo ) + { + *_pErrorInfo = aInfo; + } + else + { + showError(aInfo, m_pErrorMessageParent ? m_pErrorMessageParent->GetXWindow() : nullptr, m_xContext); + } + } + return xConnection; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/dbaundomanager.cxx b/dbaccess/source/ui/misc/dbaundomanager.cxx new file mode 100644 index 000000000..d8659ce61 --- /dev/null +++ b/dbaccess/source/ui/misc/dbaundomanager.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 + +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 ) + ,aUndoManager() + ,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( ) throw () + { + m_xImpl->rParent.acquire(); + } + + void SAL_CALL UndoManager::release( ) throw () + { + m_xImpl->rParent.release(); + } + + void UndoManager::disposing() + { + { + ::osl::MutexGuard aGuard( m_xImpl->rMutex ); + m_xImpl->bDisposed = true; + } + m_xImpl->aUndoHelper.disposing(); + } + + void SAL_CALL UndoManager::enterUndoContext( const OUString& i_title ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.enterUndoContext( i_title, aGuard ); + } + + void SAL_CALL UndoManager::enterHiddenUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.enterHiddenUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::leaveUndoContext( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.leaveUndoContext( aGuard ); + } + + void SAL_CALL UndoManager::addUndoAction( const Reference< XUndoAction >& i_action ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.addUndoAction( i_action, aGuard ); + } + + void SAL_CALL UndoManager::undo( ) + { + SolarMutexGuard aSolarGuard; + // (all our UndoActions work directly on VCL code, usually, so ...) + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.undo( aGuard ); + } + + void SAL_CALL UndoManager::redo( ) + { + SolarMutexGuard aSolarGuard; + // (all our UndoActions work directly on VCL code, usually, so ...) + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.redo( aGuard ); + } + + sal_Bool SAL_CALL UndoManager::isUndoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.isUndoPossible(); + } + + sal_Bool SAL_CALL UndoManager::isRedoPossible( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.isRedoPossible(); + } + + OUString SAL_CALL UndoManager::getCurrentUndoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getCurrentUndoActionTitle(); + } + + OUString SAL_CALL UndoManager::getCurrentRedoActionTitle( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getCurrentRedoActionTitle(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllUndoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getAllUndoActionTitles(); + } + + Sequence< OUString > SAL_CALL UndoManager::getAllRedoActionTitles( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.getAllRedoActionTitles(); + } + + void SAL_CALL UndoManager::clear( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.clear( aGuard ); + } + + void SAL_CALL UndoManager::clearRedo( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.clearRedo( aGuard ); + } + + void SAL_CALL UndoManager::reset( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.reset( aGuard ); + } + + void SAL_CALL UndoManager::addUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.addUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::removeUndoManagerListener( const Reference< XUndoManagerListener >& i_listener ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.removeUndoManagerListener( i_listener ); + } + + void SAL_CALL UndoManager::lock( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.lock(); + } + + void SAL_CALL UndoManager::unlock( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + m_xImpl->aUndoHelper.unlock(); + } + + sal_Bool SAL_CALL UndoManager::isLocked( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->aUndoHelper.isLocked(); + } + + Reference< XInterface > SAL_CALL UndoManager::getParent( ) + { + UndoManagerMethodGuard aGuard( *m_xImpl ); + return m_xImpl->rParent; + } + + void SAL_CALL UndoManager::setParent( const Reference< XInterface >& ) + { + throw NoSupportException( OUString(), m_xImpl->getThis() ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx new file mode 100644 index 000000000..63e30d06a --- /dev/null +++ b/dbaccess/source/ui/misc/dbsubcomponentcontroller.cxx @@ -0,0 +1,606 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#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::OInterfaceContainerHelper2 + 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_aDocScriptSupport() + ,m_aModifyListeners( i_rMutex ) + ,m_nDocStartNumber(0) + ,m_bSuspended( false ) + ,m_bEditable(true) + ,m_bModified(false) + ,m_bNotAttached(true) + { + } + + bool documentHasScriptSupport() const + { + OSL_PRECOND( !!m_aDocScriptSupport, + "DBSubComponentController_Impl::documentHasScriptSupport: not completely initialized, yet - don't know!?" ); + return !!m_aDocScriptSupport && *m_aDocScriptSupport; + } + + void setDocumentScriptSupport( const bool _bSupport ) + { + OSL_PRECOND( !m_aDocScriptSupport, + "DBSubComponentController_Impl::setDocumentScriptSupport: already initialized!" ); + m_aDocScriptSupport = ::std::optional< bool >( _bSupport ); + } + }; + + // DBSubComponentController + DBSubComponentController::DBSubComponentController(const Reference< XComponentContext >& _rxORB) + :DBSubComponentController_Base( _rxORB ) + ,m_pImpl( new DBSubComponentController_Impl( getMutex() ) ) + { + } + + DBSubComponentController::~DBSubComponentController() + { + } + + void DBSubComponentController::impl_initialize() + { + OGenericUnoController::impl_initialize(); + + const ::comphelper::NamedValueCollection& rArguments( getInitParams() ); + + Reference< XConnection > xConnection; + xConnection = rArguments.getOrDefault( PROPERTY_ACTIVE_CONNECTION, xConnection ); + + if ( !xConnection.is() ) + ::dbtools::isEmbeddedInDatabase( getModel(), xConnection ); + + if ( xConnection.is() ) + initializeConnection( xConnection ); + + bool bShowError = true; + if ( !isConnected() ) + { + reconnect( false ); + bShowError = false; + } + if ( !isConnected() ) + { + if ( bShowError ) + connectionLostMessage(); + throw IllegalArgumentException(); + } + } + + Any SAL_CALL DBSubComponentController::queryInterface(const Type& _rType) + { + if ( _rType.equals( cppu::UnoType::get() ) ) + { + if ( m_pImpl->documentHasScriptSupport() ) + return makeAny( 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 newEnd = std::remove_if( aTypes.begin(), aTypes.end(), + [](const Type& type) + { return type == cppu::UnoType::get(); } ); + aTypes.realloc( std::distance(aTypes.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).get(); + 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(" : "); + } + sTitle.append( getPrivateTitle() ); + return sTitle.makeStringAndClear(); + } + + sal_Int32 DBSubComponentController::getCurrentStartNumber() const + { + return m_pImpl->m_nDocStartNumber; + } + + Reference< XEmbeddedScripts > SAL_CALL DBSubComponentController::getScriptContainer() + { + ::osl::MutexGuard aGuard( getMutex() ); + if ( !m_pImpl->documentHasScriptSupport() ) + return nullptr; + + return Reference< XEmbeddedScripts >( getDatabaseDocument(), UNO_QUERY_THROW ); + } + + void SAL_CALL DBSubComponentController::addModifyListener( const Reference< XModifyListener >& i_Listener ) + { + ::osl::MutexGuard aGuard( getMutex() ); + m_pImpl->m_aModifyListeners.addInterface( i_Listener ); + } + + void SAL_CALL DBSubComponentController::removeModifyListener( const Reference< XModifyListener >& i_Listener ) + { + ::osl::MutexGuard aGuard( getMutex() ); + m_pImpl->m_aModifyListeners.removeInterface( i_Listener ); + } + + sal_Bool SAL_CALL DBSubComponentController::isModified( ) + { + ::osl::MutexGuard aGuard( getMutex() ); + return impl_isModified(); + } + + void SAL_CALL DBSubComponentController::setModified( sal_Bool i_bModified ) + { + ::osl::ClearableMutexGuard aGuard( getMutex() ); + + if ( m_pImpl->m_bModified == bool(i_bModified) ) + return; + + m_pImpl->m_bModified = i_bModified; + impl_onModifyChanged(); + + EventObject aEvent( *this ); + aGuard.clear(); + m_pImpl->m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent ); + } + + bool DBSubComponentController::impl_isModified() const + { + return m_pImpl->m_bModified; + } + + void DBSubComponentController::impl_onModifyChanged() + { + InvalidateFeature( ID_BROWSER_SAVEDOC ); + if ( isFeatureSupported( ID_BROWSER_SAVEASDOC ) ) + InvalidateFeature( ID_BROWSER_SAVEASDOC ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx b/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx new file mode 100644 index 000000000..34fac13d1 --- /dev/null +++ b/dbaccess/source/ui/misc/defaultobjectnamecheck.cxx @@ -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 . + */ + +#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::XObjectNames; + using ::com::sun::star::sdb::tools::XConnectionTools; + using ::com::sun::star::uno::UNO_QUERY; + + using namespace dbtools; + + namespace CommandType = ::com::sun::star::sdb::CommandType; + + // helper + namespace + { + void lcl_fillNameExistsError( const OUString& _rObjectName, SQLExceptionInfo& _out_rErrorToDisplay ) + { + SQLException aError; + OUString sErrorMessage = DBA_RES(STR_NAMED_OBJECT_ALREADY_EXISTS); + aError.Message = sErrorMessage.replaceAll("$#$", _rObjectName); + _out_rErrorToDisplay = aError; + } + + } + + // HierarchicalNameCheck_Impl + struct HierarchicalNameCheck_Impl + { + Reference< XHierarchicalNameAccess > xHierarchicalNames; + OUString sRelativeRoot; + }; + + // HierarchicalNameCheck + HierarchicalNameCheck::HierarchicalNameCheck( const Reference< XHierarchicalNameAccess >& _rxNames, const OUString& _rRelativeRoot ) + :m_pImpl( new HierarchicalNameCheck_Impl ) + { + m_pImpl->xHierarchicalNames = _rxNames; + m_pImpl->sRelativeRoot = _rRelativeRoot; + + if ( !m_pImpl->xHierarchicalNames.is() ) + throw IllegalArgumentException(); + } + + HierarchicalNameCheck::~HierarchicalNameCheck() + { + } + + bool HierarchicalNameCheck::isNameValid( const OUString& _rObjectName, SQLExceptionInfo& _out_rErrorToDisplay ) const + { + try + { + OUStringBuffer aCompleteName; + if ( !m_pImpl->sRelativeRoot.isEmpty() ) + { + aCompleteName.append( m_pImpl->sRelativeRoot ); + aCompleteName.append( "/" ); + } + aCompleteName.append( _rObjectName ); + + OUString sCompleteName( aCompleteName.makeStringAndClear() ); + if ( !m_pImpl->xHierarchicalNames->hasByHierarchicalName( sCompleteName ) ) + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + lcl_fillNameExistsError( _rObjectName, _out_rErrorToDisplay ); + return false; + } + + // DynamicTableOrQueryNameCheck_Impl + struct DynamicTableOrQueryNameCheck_Impl + { + sal_Int32 nCommandType; + Reference< XObjectNames > xObjectNames; + }; + + // DynamicTableOrQueryNameCheck + DynamicTableOrQueryNameCheck::DynamicTableOrQueryNameCheck( const Reference< XConnection >& _rxSdbLevelConnection, sal_Int32 _nCommandType ) + :m_pImpl( new DynamicTableOrQueryNameCheck_Impl ) + { + Reference< XConnectionTools > xConnTools( _rxSdbLevelConnection, UNO_QUERY ); + if ( xConnTools.is() ) + m_pImpl->xObjectNames.set( xConnTools->getObjectNames() ); + if ( !m_pImpl->xObjectNames.is() ) + throw IllegalArgumentException(); + + if ( ( _nCommandType != CommandType::QUERY ) && ( _nCommandType != CommandType::TABLE ) ) + throw IllegalArgumentException(); + m_pImpl->nCommandType = _nCommandType; + } + + DynamicTableOrQueryNameCheck::~DynamicTableOrQueryNameCheck() + { + } + + bool DynamicTableOrQueryNameCheck::isNameValid( const OUString& _rObjectName, ::dbtools::SQLExceptionInfo& _out_rErrorToDisplay ) const + { + try + { + m_pImpl->xObjectNames->checkNameForCreate( m_pImpl->nCommandType, _rObjectName ); + return true; + } + catch( const SQLException& ) + { + _out_rErrorToDisplay = ::dbtools::SQLExceptionInfo( ::cppu::getCaughtException() ); + } + return false; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/dsmeta.cxx b/dbaccess/source/ui/misc/dsmeta.cxx new file mode 100644 index 000000000..58831f081 --- /dev/null +++ b/dbaccess/source/ui/misc/dsmeta.cxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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; + const char* pAsciiFeatureName; + }; + + } + + // global tables + static const FeatureMapping* lcl_getFeatureMappings() + { + static 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" }, + { 0, nullptr } + }; + return s_aMappings; + } + + 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() ); + + const FeatureMapping* pFeatureMapping = lcl_getFeatureMappings(); + while ( pFeatureMapping->pAsciiFeatureName ) + { + if ( aCurrentFeatures.has( pFeatureMapping->pAsciiFeatureName ) ) + aCurrentSet.put( pFeatureMapping->nItemID ); + ++pFeatureMapping; + } + + tmp[ pattern ] = aCurrentSet; + } + return tmp; + }(); + + OSL_ENSURE( s_aFeatureSets.find( _rURL ) != s_aFeatureSets.end(), "invalid URL/pattern!" ); + return s_aFeatureSets[ _rURL ]; + } + + static AuthenticationMode getAuthenticationMode( const OUString& _sURL ) + { + static std::map< OUString, FeatureSupport > s_aSupport = [&]() + { + std::map< OUString, FeatureSupport > tmp; + ::connectivity::DriversConfig aDriverConfig(::comphelper::getProcessComponentContext()); + const uno::Sequence< OUString > aURLs = aDriverConfig.getURLs(); + const OUString* pIter = aURLs.getConstArray(); + const OUString* pEnd = pIter + aURLs.getLength(); + for(;pIter != pEnd;++pIter) + { + FeatureSupport aInit( AuthNone ); + const ::comphelper::NamedValueCollection& aMetaData = aDriverConfig.getMetaData(*pIter); + if ( aMetaData.has("Authentication") ) + { + OUString sAuth; + aMetaData.get("Authentication") >>= sAuth; + if ( sAuth == "UserPassword" ) + aInit = FeatureSupport(AuthUserPwd); + else if ( sAuth == "Password" ) + aInit = FeatureSupport(AuthPwd); + } + tmp.insert(std::make_pair(*pIter,aInit)); + } + return tmp; + }(); + OSL_ENSURE(s_aSupport.find(_sURL) != s_aSupport.end(),"Illegal URL!"); + return s_aSupport[ _sURL ].eAuthentication; + } + + // DataSourceMetaData_Impl + class DataSourceMetaData_Impl + { + public: + explicit DataSourceMetaData_Impl(const OUString& rURL); + + const OUString& getType() const { return m_sURL; } + + private: + const OUString m_sURL; + }; + + DataSourceMetaData_Impl::DataSourceMetaData_Impl( const OUString& _sURL ) + :m_sURL( _sURL ) + { + } + + // DataSourceMetaData + DataSourceMetaData::DataSourceMetaData( const OUString& _sURL ) + :m_pImpl( std::make_shared( _sURL ) ) + { + } + + DataSourceMetaData::~DataSourceMetaData() + { + } + + const FeatureSet& DataSourceMetaData::getFeatureSet() const + { + return lcl_getFeatureSet( m_pImpl->getType() ); + } + + AuthenticationMode DataSourceMetaData::getAuthentication( const OUString& _sURL ) + { + return getAuthenticationMode( _sURL ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/imageprovider.cxx b/dbaccess/source/ui/misc/imageprovider.cxx new file mode 100644 index 000000000..8cd3b397e --- /dev/null +++ b/dbaccess/source/ui/misc/imageprovider.cxx @@ -0,0 +1,266 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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; + + // ImageProvider_Data + struct ImageProvider_Data + { + /// the connection we work with + Reference< XConnection > xConnection; + /// the views of the connection, if the DB supports views + Reference< XNameAccess > xViews; + /// interface for providing table's UI + Reference< XTableUIProvider > xTableUI; + }; + + namespace + { + void lcl_getConnectionProvidedTableIcon_nothrow( const ImageProvider_Data& _rData, + const OUString& _rName, Reference< XGraphic >& _out_rxGraphic ) + { + try + { + if ( _rData.xTableUI.is() ) + _out_rxGraphic = _rData.xTableUI->getTableIcon( _rName, GraphicColorMode::NORMAL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void lcl_getTableImageResourceID_nothrow( const ImageProvider_Data& _rData, const OUString& _rName, + OUString& _out_rResourceID) + { + _out_rResourceID = OUString(); + try + { + bool bIsView = _rData.xViews.is() && _rData.xViews->hasByName( _rName ); + if ( bIsView ) + { + _out_rResourceID = VIEW_TREE_ICON; + } + else + { + _out_rResourceID = TABLE_TREE_ICON; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + } + // ImageProvider + ImageProvider::ImageProvider() + :m_pData( std::make_shared() ) + { + } + + ImageProvider::ImageProvider( const Reference< XConnection >& _rxConnection ) + :m_pData( std::make_shared() ) + { + m_pData->xConnection = _rxConnection; + try + { + Reference< XViewsSupplier > xSuppViews( m_pData->xConnection, UNO_QUERY ); + if ( xSuppViews.is() ) + m_pData->xViews.set( xSuppViews->getViews(), UNO_SET_THROW ); + + m_pData->xTableUI.set( _rxConnection, UNO_QUERY ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + void ImageProvider::getImages( const OUString& _rName, const sal_Int32 _nDatabaseObjectType, Image& _out_rImage ) + { + if ( _nDatabaseObjectType != DatabaseObject::TABLE ) + { + // for types other than tables, the icon does not depend on the concrete object + _out_rImage = getDefaultImage( _nDatabaseObjectType ); + } + else + { + // check whether the connection can give us an icon + Reference< XGraphic > xGraphic; + lcl_getConnectionProvidedTableIcon_nothrow( *m_pData, _rName, xGraphic ); + if ( xGraphic.is() ) + _out_rImage = Image( xGraphic ); + + if ( !_out_rImage ) + { + // no -> determine by type + OUString sImageResourceID; + lcl_getTableImageResourceID_nothrow( *m_pData, _rName, sImageResourceID ); + + if (!sImageResourceID.isEmpty() && !_out_rImage) + _out_rImage = Image(StockImage::Yes, sImageResourceID); + } + } + } + + OUString ImageProvider::getImageId(const OUString& _rName, const sal_Int32 _nDatabaseObjectType) + { + if (_nDatabaseObjectType != DatabaseObject::TABLE) + { + // for types other than tables, the icon does not depend on the concrete object + return getDefaultImageResourceID( _nDatabaseObjectType ); + } + else + { + // no -> determine by type + OUString sImageResourceID; + lcl_getTableImageResourceID_nothrow( *m_pData, _rName, sImageResourceID ); + return sImageResourceID; + } + } + + Reference 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( *m_pData, _rName, xGraphic ); + } + return xGraphic; + } + + Image ImageProvider::getDefaultImage( sal_Int32 _nDatabaseObjectType ) + { + Image aObjectImage; + OUString sImageResourceID( getDefaultImageResourceID( _nDatabaseObjectType) ); + if (!sImageResourceID.isEmpty()) + aObjectImage = Image(StockImage::Yes, sImageResourceID); + return aObjectImage; + } + + 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; + } + + Image ImageProvider::getFolderImage( 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; + } + + Image aFolderImage; + if (!sImageResourceID.isEmpty()) + aFolderImage = Image(StockImage::Yes, sImageResourceID); + return aFolderImage; + } + + 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; + } + + Image ImageProvider::getDatabaseImage() + { + return Image(StockImage::Yes, DATABASE_TREE_ICON); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/indexcollection.cxx b/dbaccess/source/ui/misc/indexcollection.cxx new file mode 100644 index 000000000..fb83377f1 --- /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 const char s_sNamePropertyName[] = "Name"; + // the index' own props + xIndexDescriptor->setPropertyValue("IsUnique", css::uno::makeAny(_rPos->bUnique)); + xIndexDescriptor->setPropertyValue(s_sNamePropertyName, makeAny(_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::makeAny(field.bSortAscending)); + xColDescriptor->setPropertyValue(s_sNamePropertyName, makeAny(field.sFieldName)); + xAppendCols->appendByDescriptor(xColDescriptor); + } + } + + xAppendIndex->appendByDescriptor(xIndexDescriptor); + + _rPos->flagAsCommitted(GrantIndexAccess()); + _rPos->clearModified(); + } + catch(SQLException&) + { // allowed to pass + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + bool OIndexCollection::dropNoRemove(const Indexes::iterator& _rPos) + { + try + { + OSL_ENSURE(m_xIndexes->hasByName(_rPos->getOriginalName()), "OIndexCollection::drop: invalid name!"); + + Reference< XDrop > xDropIndex(m_xIndexes, UNO_QUERY); + if (!xDropIndex.is()) + { + OSL_FAIL("OIndexCollection::drop: no XDrop interface!"); + return false; + } + + xDropIndex->dropByName(_rPos->getOriginalName()); + } + catch(SQLException&) + { // allowed to pass + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + return false; + } + + // adjust the OIndex structure + Indexes::iterator aDropped = findOriginal(_rPos->getOriginalName()); + OSL_ENSURE(aDropped != m_aIndexes.end(), "OIndexCollection::drop: invalid original name, but successful commit?!"); + aDropped->flagAsNew(GrantIndexAccess()); + + return true; + } + + bool OIndexCollection::drop(const Indexes::iterator& _rPos) + { + OSL_ENSURE((_rPos >= m_aIndexes.begin()) && (_rPos < m_aIndexes.end()), + "OIndexCollection::drop: invalid position (fasten your seatbelt... this will crash)!"); + + if (!_rPos->isNew()) + if (!dropNoRemove(_rPos)) + return false; + + // adjust the index array + m_aIndexes.erase(_rPos); + return true; + } + + void OIndexCollection::implFillIndexInfo(OIndex& _rIndex) + { + // get the UNO descriptor for the index + Reference< XPropertySet > xIndex; + m_xIndexes->getByName(_rIndex.getOriginalName()) >>= xIndex; + if (!xIndex.is()) + { + OSL_FAIL("OIndexCollection::implFillIndexInfo: got an invalid index object!"); + } + else + implFillIndexInfo(_rIndex, xIndex); + } + + void OIndexCollection::implFillIndexInfo(OIndex& _rIndex, const Reference< XPropertySet >& _rxDescriptor) + { + _rIndex.bPrimaryKey = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsPrimaryKeyIndex")); + _rIndex.bUnique = ::cppu::any2bool(_rxDescriptor->getPropertyValue("IsUnique")); + _rxDescriptor->getPropertyValue("Catalog") >>= _rIndex.sDescription; + + // the columns + Reference< XColumnsSupplier > xSuppCols(_rxDescriptor, UNO_QUERY); + Reference< XNameAccess > xCols; + if (xSuppCols.is()) + xCols = xSuppCols->getColumns(); + OSL_ENSURE(xCols.is(), "OIndexCollection::implFillIndexInfo: the index does not have columns!"); + if (!xCols.is()) + return; + + Sequence< OUString > aFieldNames = xCols->getElementNames(); + _rIndex.aFields.resize(aFieldNames.getLength()); + + const OUString* pFieldNames = aFieldNames.getConstArray(); + const OUString* pFieldNamesEnd = pFieldNames + aFieldNames.getLength(); + IndexFields::iterator aCopyTo = _rIndex.aFields.begin(); + + Reference< XPropertySet > xIndexColumn; + for (;pFieldNames < pFieldNamesEnd; ++pFieldNames, ++aCopyTo) + { + // extract the column + xIndexColumn.clear(); + xCols->getByName(*pFieldNames) >>= xIndexColumn; + if (!xIndexColumn.is()) + { + OSL_FAIL("OIndexCollection::implFillIndexInfo: invalid index column!"); + --aCopyTo; + continue; + } + + // get the relevant properties + aCopyTo->sFieldName = *pFieldNames; + aCopyTo->bSortAscending = ::cppu::any2bool(xIndexColumn->getPropertyValue("IsAscending")); + } + + _rIndex.aFields.resize(aCopyTo - _rIndex.aFields.begin()); + // (just in case some fields were invalid ...) + } + + void OIndexCollection::resetIndex(const Indexes::iterator& _rPos) + { + OSL_ENSURE(_rPos >= m_aIndexes.begin() && _rPos < m_aIndexes.end(), + "OIndexCollection::resetIndex: invalid position!"); + + try + { + _rPos->sName = _rPos->getOriginalName(); + implFillIndexInfo(*_rPos); + + _rPos->clearModified(); + _rPos->flagAsCommitted(GrantIndexAccess()); + } + catch(SQLException&) + { // allowed to pass + throw; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + } + + Indexes::iterator OIndexCollection::insert(const OUString& _rName) + { + OSL_ENSURE(end() == find(_rName), "OIndexCollection::insert: invalid new name!"); + OIndex aNewIndex((OUString())); // the empty string indicates the index is a new one + aNewIndex.sName = _rName; + m_aIndexes.push_back(aNewIndex); + return m_aIndexes.end() - 1; // the last element is the new one ... + } + + void OIndexCollection::implConstructFrom(const Reference< XNameAccess >& _rxIndexes) + { + detach(); + + m_xIndexes = _rxIndexes; + if (!m_xIndexes.is()) + return; + + // loop through all the indexes + Sequence< OUString > aNames = m_xIndexes->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + const OUString* pEnd = pNames + aNames.getLength(); + for (; pNames < pEnd; ++pNames) + { + // extract the index object + Reference< XPropertySet > xIndex; + m_xIndexes->getByName(*pNames) >>= xIndex; + if (!xIndex.is()) + { + OSL_FAIL("OIndexCollection::implConstructFrom: got an invalid index object ... ignoring!"); + continue; + } + + // fill the OIndex structure + OIndex aCurrentIndex(*pNames); + implFillIndexInfo(aCurrentIndex); + m_aIndexes.push_back(aCurrentIndex); + } + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/linkeddocuments.cxx b/dbaccess/source/ui/misc/linkeddocuments.cxx new file mode 100644 index 000000000..13effe4cc --- /dev/null +++ b/dbaccess/source/ui/misc/linkeddocuments.cxx @@ -0,0 +1,356 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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( 16 ); + aResult[0] = static_cast(n1 >> 24); + aResult[1] = static_cast(( n1 << 8 ) >> 24); + aResult[2] = static_cast(( n1 << 16 ) >> 24); + aResult[3] = static_cast(( n1 << 24 ) >> 24); + aResult[4] = static_cast(n2 >> 8); + aResult[5] = static_cast(( n2 << 8 ) >> 8); + aResult[6] = static_cast(n3 >> 8); + aResult[7] = static_cast(( n3 << 8 ) >> 8); + aResult[8] = b8; + aResult[9] = b9; + aResult[10] = b10; + aResult[11] = b11; + aResult[12] = b12; + aResult[13] = b13; + aResult[14] = b14; + aResult[15] = b15; + + return aResult; + } + } + + // OLinkedDocumentsAccess + OLinkedDocumentsAccess::OLinkedDocumentsAccess( weld::Window* pDialogParent, const Reference< XDatabaseDocumentUI >& i_rDocumentUI, + const Reference< XComponentContext >& _rxContext, const Reference< XNameAccess >& _rxContainer, + const Reference< XConnection>& _xConnection, const OUString& _sDataSourceName ) + :m_xContext(_rxContext) + ,m_xDocumentContainer(_rxContainer) + ,m_xConnection(_xConnection) + ,m_xDocumentUI( i_rDocumentUI ) + ,m_pDialogParent(pDialogParent) + ,m_sDataSourceName(_sDataSourceName) + { + OSL_ENSURE(m_xContext.is(), "OLinkedDocumentsAccess::OLinkedDocumentsAccess: invalid service factory!"); + assert(m_pDialogParent && "OLinkedDocumentsAccess::OLinkedDocumentsAccess: really need a dialog parent!"); + } + OLinkedDocumentsAccess::~OLinkedDocumentsAccess() + { + } + Reference< XComponent> OLinkedDocumentsAccess::impl_open( const OUString& _rLinkName, Reference< XComponent >& _xDefinition, + ElementOpenMode _eOpenMode, const ::comphelper::NamedValueCollection& _rAdditionalArgs ) + { + Reference< XComponent> xRet; + OSL_ENSURE(m_xDocumentContainer.is(), "OLinkedDocumentsAccess::OLinkedDocumentsAccess: invalid document container!"); + Reference< XComponentLoader > xComponentLoader(m_xDocumentContainer,UNO_QUERY); + if ( !xComponentLoader.is() ) + return xRet; + + weld::WaitObject aWaitCursor(m_pDialogParent); + + ::comphelper::NamedValueCollection aArguments; + OUString sOpenMode; + switch ( _eOpenMode ) + { + case E_OPEN_NORMAL: + sOpenMode = "open"; + break; + + case E_OPEN_FOR_MAIL: + aArguments.put( "Hidden", true ); + [[fallthrough]]; + + case E_OPEN_DESIGN: + sOpenMode = "openDesign"; + break; + + default: + OSL_FAIL( "OLinkedDocumentsAccess::implOpen: invalid open mode!" ); + break; + } + aArguments.put( "OpenMode", sOpenMode ); + + aArguments.put( OUString(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( OUString(PROPERTY_ACTIVE_CONNECTION), m_xConnection ); + + // separate values which are real creation args from args relevant for opening the doc + ::comphelper::NamedValueCollection aCommandArgs; + if ( aCreationArgs.has( "Hidden" ) ) + { + aCommandArgs.put( "Hidden", aCreationArgs.get( "Hidden" ) ); + aCreationArgs.remove( "Hidden" ); + } + + Reference< XCommandProcessor > xContent( xORB->createInstanceWithArguments( + SERVICE_SDB_DOCUMENTDEFINITION, + aCreationArgs.getWrappedPropertyValues() + ), + UNO_QUERY_THROW + ); + o_rDefinition.set( xContent, UNO_QUERY ); + + // put the OpenMode into the OpenArgs + OpenCommandArgument aOpenModeArg; + aOpenModeArg.Mode = OpenMode::DOCUMENT; + aCommandArgs.put( "OpenMode", aOpenModeArg ); + + Command aCommand; + aCommand.Name = "openDesign"; + aCommand.Argument <<= aCommandArgs.getPropertyValues(); + weld::WaitObject aWaitCursor(m_pDialogParent); + xNewDocument.set( xContent->execute( aCommand, xContent->createCommandIdentifier(), nullptr ), UNO_QUERY ); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + return xNewDocument; + } + + Reference< XComponent > OLinkedDocumentsAccess::open( const OUString& _rLinkName, Reference< XComponent >& _xDefinition, + ElementOpenMode _eOpenMode, const ::comphelper::NamedValueCollection& _rAdditionalArgs ) + { + dbtools::SQLExceptionInfo aInfo; + Reference< XComponent > xRet; + try + { + xRet = impl_open( _rLinkName, _xDefinition, _eOpenMode, _rAdditionalArgs ); + if ( !xRet.is() ) + { + OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC); + sMessage = sMessage.replaceFirst("$file$",_rLinkName); + + css::sdbc::SQLException aSQLException; + aSQLException.Message = sMessage; + aInfo = dbtools::SQLExceptionInfo(aSQLException); + } + } + catch(const css::io::WrongFormatException &e) + { + css::sdbc::SQLException aSQLException; + aSQLException.Message = e.Message; + aSQLException.Context = e.Context; + aInfo = dbtools::SQLExceptionInfo(aSQLException); + + // more like a hack, insert an empty message + OUString sText( DBA_RES( RID_STR_EXTENSION_NOT_PRESENT ) ); + sText = sText.replaceFirst("$file$",_rLinkName); + aInfo.prepend(sText); + + OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC); + sMessage = sMessage.replaceFirst("$file$",_rLinkName); + aInfo.prepend(sMessage); + } + catch(const Exception& e) + { + Any aAny = ::cppu::getCaughtException(); + css::sdbc::SQLException a; + if ( !(aAny >>= a) || (a.ErrorCode != dbtools::ParameterInteractionCancelled) ) + { + css::sdbc::SQLException aSQLException; + aSQLException.Message = e.Message; + aSQLException.Context = e.Context; + aInfo = dbtools::SQLExceptionInfo(aSQLException); + + // more like a hack, insert an empty message + aInfo.prepend(" \n"); + + OUString sMessage = DBA_RES(STR_COULDNOTOPEN_LINKEDDOC); + sMessage = sMessage.replaceFirst("$file$",_rLinkName); + aInfo.prepend(sMessage); + } + } + if (aInfo.isValid()) + { + showError(aInfo, m_pDialogParent->GetXWindow(), m_xContext); + } + return xRet; + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/propertystorage.cxx b/dbaccess/source/ui/misc/propertystorage.cxx new file mode 100644 index 000000000..c3c504994 --- /dev/null +++ b/dbaccess/source/ui/misc/propertystorage.cxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#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 000000000..c07da46c9 --- /dev/null +++ b/dbaccess/source/ui/misc/singledoccontroller.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 + +namespace dbaui +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::document::XUndoManager; + using ::com::sun::star::beans::PropertyValue; + + // OSingleDocumentController_Data + struct OSingleDocumentController_Data + { + // no Reference! see UndoManager::acquire + std::unique_ptr m_pUndoManager; + + OSingleDocumentController_Data( ::cppu::OWeakObject& i_parent, ::osl::Mutex& i_mutex ) + : m_pUndoManager(new UndoManager(i_parent, i_mutex)) + { + } + }; + + // OSingleDocumentController + OSingleDocumentController::OSingleDocumentController( const Reference< XComponentContext >& _rxORB ) + :OSingleDocumentController_Base( _rxORB ) + ,m_pData( new OSingleDocumentController_Data( *this, getMutex() ) ) + { + } + + OSingleDocumentController::~OSingleDocumentController() + { + } + + void SAL_CALL OSingleDocumentController::disposing() + { + OSingleDocumentController_Base::disposing(); + ClearUndoManager(); + m_pData->m_pUndoManager->disposing(); + } + + void OSingleDocumentController::ClearUndoManager() + { + GetUndoManager().Clear(); + } + + SfxUndoManager& OSingleDocumentController::GetUndoManager() const + { + return m_pData->m_pUndoManager->GetSfxUndoManager(); + } + + void OSingleDocumentController::addUndoActionAndInvalidate(std::unique_ptr _pAction) + { + // add undo action + GetUndoManager().AddUndoAction( std::move(_pAction) ); + + // when we add an undo action the controller was modified + setModified( true ); + + // now inform me that or states changed + InvalidateFeature( ID_BROWSER_UNDO ); + InvalidateFeature( ID_BROWSER_REDO ); + } + + Reference< XUndoManager > SAL_CALL OSingleDocumentController::getUndoManager( ) + { + // see UndoManager::acquire + return m_pData->m_pUndoManager.get(); + } + + FeatureState OSingleDocumentController::GetState(sal_uInt16 _nId) const + { + FeatureState aReturn; + switch ( _nId ) + { + case ID_BROWSER_UNDO: + aReturn.bEnabled = isEditable() && GetUndoManager().GetUndoActionCount() != 0; + if ( aReturn.bEnabled ) + { + OUString sUndo = DBA_RES(STR_UNDO_COLON) + " " + + GetUndoManager().GetUndoActionComment(); + aReturn.sTitle = sUndo; + } + break; + + case ID_BROWSER_REDO: + aReturn.bEnabled = isEditable() && GetUndoManager().GetRedoActionCount() != 0; + if ( aReturn.bEnabled ) + { + OUString sRedo = DBA_RES(STR_REDO_COLON) + " " + + GetUndoManager().GetRedoActionComment(); + aReturn.sTitle = sRedo; + } + break; + + case SID_GETUNDOSTRINGS: + { + size_t nCount(GetUndoManager().GetUndoActionCount()); + Sequence aSeq(nCount); + for (size_t n = 0; n < nCount; ++n) + aSeq[n] = GetUndoManager().GetUndoActionComment(n); + aReturn.aValue <<= aSeq; + aReturn.bEnabled = true; + break; + } + + case SID_GETREDOSTRINGS: + { + size_t nCount(GetUndoManager().GetRedoActionCount()); + Sequence aSeq(nCount); + for (size_t n = 0; n < nCount; ++n) + aSeq[n] = GetUndoManager().GetRedoActionComment(n); + aReturn.aValue <<= aSeq; + aReturn.bEnabled = true; + break; + } + + default: + aReturn = OSingleDocumentController_Base::GetState(_nId); + } + return aReturn; + } + void OSingleDocumentController::Execute( sal_uInt16 _nId, const Sequence< PropertyValue >& _rArgs ) + { + switch ( _nId ) + { + case ID_BROWSER_UNDO: + case ID_BROWSER_REDO: + { + sal_Int16 nCount(1); + if (_rArgs.hasElements() && _rArgs[0].Name != "KeyModifier") + _rArgs[0].Value >>= nCount; + + while (nCount--) + { + if (_nId == ID_BROWSER_UNDO) + GetUndoManager().Undo(); + else + GetUndoManager().Redo(); + } + + InvalidateFeature( ID_BROWSER_UNDO ); + InvalidateFeature( ID_BROWSER_REDO ); + break; + } + + default: + OSingleDocumentController_Base::Execute( _nId, _rArgs ); + break; + } + InvalidateFeature(_nId); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/misc/stringlistitem.cxx b/dbaccess/source/ui/misc/stringlistitem.cxx new file mode 100644 index 000000000..c5da8c219 --- /dev/null +++ b/dbaccess/source/ui/misc/stringlistitem.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 + +namespace dbaui +{ + +using namespace ::com::sun::star::uno; + +// OStringListItem +OStringListItem::OStringListItem(sal_Int16 _nWhich, const Sequence< OUString >& _rList) + :SfxPoolItem(_nWhich) + ,m_aList(_rList) +{ +} + +OStringListItem::OStringListItem(const OStringListItem& _rSource) + :SfxPoolItem(_rSource) + ,m_aList(_rSource.m_aList) +{ +} + +bool OStringListItem::operator==(const SfxPoolItem& _rItem) const +{ + if (!SfxPoolItem::operator==(_rItem)) + return false; + const OStringListItem* pCompare = static_cast( &_rItem ); + if (pCompare->m_aList.getLength() != m_aList.getLength()) + return false; + + // compare all strings individually + for (sal_Int32 i=0; im_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/misc/uiservices.cxx b/dbaccess/source/ui/misc/uiservices.cxx new file mode 100644 index 000000000..4d8a020e3 --- /dev/null +++ b/dbaccess/source/ui/misc/uiservices.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 + +using namespace ::dbaui; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::registry; + +extern "C" { + +static void createRegistryInfo_DBU() +{ + static std::once_flag aInit; + std::call_once(aInit, [&]() + { + createRegistryInfo_OTableFilterDialog(); + createRegistryInfo_ODataSourcePropertyDialog(); + createRegistryInfo_OSQLMessageDialog(); + createRegistryInfo_OBrowser(); + createRegistryInfo_OFormGridView(); + createRegistryInfo_DBContentLoader(); + createRegistryInfo_OInteractionHandler(); + createRegistryInfo_SbaXGridControl(); + createRegistryInfo_OQueryControl(); + createRegistryInfo_OViewControl(); + createRegistryInfo_OTableControl(); + createRegistryInfo_ORelationControl(); + createRegistryInfo_ComposerDialogs(); + createRegistryInfo_ODBApplication(); + createRegistryInfo_ODirectSQLDialog(); + createRegistryInfo_OAdvancedSettingsDialog(); + createRegistryInfo_ODBTypeWizDialog(); + createRegistryInfo_ODBTypeWizDialogSetup(); + createRegistryInfo_OUserSettingsDialog(); + createRegistryInfo_OColumnControlModel(); + createRegistryInfo_OColumnControl(); + createRegistryInfo_CopyTableWizard(); + createRegistryInfo_OTextConnectionSettingsDialog(); + createRegistryInfo_LimitBoxController(); + return true; + }); +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT void* dbu_component_getFactory( + const char* pImplementationName, + void* pServiceManager, + void* /*pRegistryKey*/) +{ + createRegistryInfo_DBU(); + + Reference< XInterface > xRet; + if (pServiceManager && pImplementationName) + { + xRet = ::dbaui::OModuleRegistration::getComponentFactory( + OUString::createFromAscii(pImplementationName), + static_cast< XMultiServiceFactory* >(pServiceManager)); + } + + if (xRet.is()) + xRet->acquire(); + return xRet.get(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/ConnectionLine.cxx b/dbaccess/source/ui/querydesign/ConnectionLine.cxx new file mode 100644 index 000000000..cf5af7def --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLine.cxx @@ -0,0 +1,344 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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; +const long DESCRIPT_LINE_WIDTH = 15; +const 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 long nRowHeight = pListBox->GetEntryHeight(); + 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 _pEntry the source or dest entry + @param _rNewConPos (in/out) the connection pos + @param _rNewDescrPos (in/out) the description pos + */ + void calcPointsYValue(const OTableWindow* _pWin,SvTreeListEntry* _pEntry,Point& _rNewConPos,Point& _rNewDescrPos) + { + const OTableWindowListBox* pListBox = _pWin->GetListBox(); + _rNewConPos.setY( _pWin->GetPosPixel().Y() ); + if ( _pEntry ) + { + const long nRowHeight = pListBox->GetEntryHeight(); + _rNewConPos.AdjustY(pListBox->GetPosPixel().Y() ); + long nEntryPos = pListBox->GetEntryPosition( _pEntry ).Y(); + + if( nEntryPos >= 0 ) + { + _rNewConPos.AdjustY(nEntryPos ); + _rNewConPos.AdjustY(static_cast( 0.5 * nRowHeight ) ); + } + else + _rNewConPos.AdjustY( -static_cast( 0.5 * nRowHeight ) ); + + 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 const & _pLineData ) + : m_pTabConn( _pConn ) + , m_pData( _pLineData ) +{ +} + +OConnectionLine::OConnectionLine( const OConnectionLine& _rLine ) + : m_pTabConn(nullptr) +{ + m_pData = new OConnectionLineData( *_rLine.GetData() ); + *this = _rLine; +} + +OConnectionLine::~OConnectionLine() +{ +} + +OConnectionLine& OConnectionLine::operator=( const OConnectionLine& rLine ) +{ + if( &rLine != this ) + { + // as the data does not belong to me, I don't delete the old one + m_pData->CopyFrom(*rLine.GetData()); + // CopyFrom is virtual, therefore it is not a problem, if m_pData is of a type derived from OTableConnectionData + + m_pTabConn = rLine.m_pTabConn; + m_aSourceConnPos = rLine.m_aSourceConnPos; + m_aDestConnPos = rLine.m_aDestConnPos; + m_aSourceDescrLinePos = rLine.m_aSourceDescrLinePos; + m_aDestDescrLinePos = rLine.m_aDestDescrLinePos; + } + + return *this; +} + +tools::Rectangle OConnectionLine::GetBoundingRect() const +{ + // determine surrounding rectangle + tools::Rectangle aBoundingRect( Point(0,0), Point(0,0) ); + if( !IsValid() ) + return aBoundingRect; + + Point aTopLeft; + Point aBottomRight; + + if( m_aSourceDescrLinePos.Y() <= m_aDestDescrLinePos.Y() ) + { + aTopLeft.setY( m_aSourceDescrLinePos.Y() ); + aBottomRight.setY( m_aDestDescrLinePos.Y() ); + } + else + { + aTopLeft.setY( m_aDestDescrLinePos.Y() ); + aBottomRight.setY( m_aSourceDescrLinePos.Y() ); + } + + if( m_aSourceDescrLinePos.X() <= m_aDestDescrLinePos.X() ) + { + aTopLeft.setX( m_aSourceDescrLinePos.X() ); + aBottomRight.setX( m_aDestDescrLinePos.X() ); + } + else + { + aTopLeft.setX( m_aDestDescrLinePos.X() ); + aBottomRight.setX( m_aSourceDescrLinePos.X() ); + } + + const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin(); + const OTableWindow* pDestWin = m_pTabConn->GetDestWin(); + // line proceeds in z-Form + if( pSourceWin == pDestWin || std::abs(m_aSourceConnPos.X() - m_aDestConnPos.X()) > std::abs(m_aSourceDescrLinePos.X() - m_aDestDescrLinePos.X()) ) + { + aTopLeft.AdjustX( -DESCRIPT_LINE_WIDTH ); + aBottomRight.AdjustX(DESCRIPT_LINE_WIDTH ); + } + + aBoundingRect = tools::Rectangle( aTopLeft-Point(2,17), aBottomRight+Point(2,2) ); + + return aBoundingRect; +} + +static void calcPointX1(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos) +{ + _rNewConPos.setX( _pWin->GetPosPixel().X() + _pWin->GetSizePixel().Width() ); + _rNewDescrPos.setX( _rNewConPos.X() ); + _rNewConPos.AdjustX(DESCRIPT_LINE_WIDTH ); +} + +static void calcPointX2(const OTableWindow* _pWin,Point& _rNewConPos,Point& _rNewDescrPos) +{ + _rNewConPos.setX( _pWin->GetPosPixel().X() ); + _rNewDescrPos.setX( _rNewConPos.X() ); + _rNewConPos.AdjustX( -DESCRIPT_LINE_WIDTH ); +} + +bool OConnectionLine::RecalcLine() +{ + // Windows and entries must be set + const OTableWindow* pSourceWin = m_pTabConn->GetSourceWin(); + const OTableWindow* pDestWin = m_pTabConn->GetDestWin(); + + if( !pSourceWin || !pDestWin ) + return false; + + SvTreeListEntry* pSourceEntry = pSourceWin->GetListBox()->GetEntryFromText( GetData()->GetSourceFieldName() ); + SvTreeListEntry* pDestEntry = 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 && pSourceEntry != pDestEntry ) + calcPointX2(pFirstWin,*pFirstConPos,*pFirstDescrPos); + else + calcPointX1(pFirstWin,*pFirstConPos,*pFirstDescrPos); + calcPointX2(pSecondWin,*pSecondConPos,*pSecondDescrPos); + + // determine aSourceConnPosY + calcPointsYValue(pSourceWin,pSourceEntry,m_aSourceConnPos,m_aSourceDescrLinePos); + + // determine aDestConnPosY + calcPointsYValue(pDestWin,pDestEntry,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 = sqrt(static_cast(v.X()*v.X() + v.Y()*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( long(p1.X() + a * v.X()) ); + q.setY( long(p1.Y() + a * v.Y()) ); + return l; +} + +bool OConnectionLine::CheckHit( const Point& rMousePos ) const +{ + /* + course of action with HitTest: + the distance is calculated according to Euklid. + */ + Point q; + double l = fabs(dist_Euklid(m_aSourceConnPos,m_aDestConnPos,rMousePos,q)); + if( l < HIT_SENSITIVE_RADIUS) + { + if(std::min(m_aSourceConnPos.X(),m_aDestConnPos.X()) <= q.X() && std::min(m_aSourceConnPos.Y(),m_aDestConnPos.Y()) <= q.Y() + && q.X() <= std::max(m_aDestConnPos.X(),m_aSourceConnPos.X()) && q.Y() <= std::max(m_aDestConnPos.Y(),m_aSourceConnPos.Y())) + return true; + } + + return false; +} + +tools::Rectangle OConnectionLine::GetSourceTextPos() const +{ + return GetTextPos(m_pTabConn->GetSourceWin(),m_aSourceConnPos,m_aSourceDescrLinePos); +} + +tools::Rectangle OConnectionLine::GetDestTextPos() const +{ + return GetTextPos(m_pTabConn->GetDestWin(),m_aDestConnPos,m_aDestDescrLinePos); +} + +Point OConnectionLine::getMidPoint() const +{ + Point aDest = m_aDestConnPos - m_aSourceConnPos; + aDest.setX( aDest.X() / 2 ); + aDest.setY( aDest.Y() / 2 ); + + return m_aSourceConnPos + aDest; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx b/dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx new file mode 100644 index 000000000..763e53990 --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLineAccess.cxx @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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) + : VCLXAccessibleComponent(_pLine->GetComponentInterface().is() ? _pLine->GetWindowPeer() : nullptr) + ,m_pLine(_pLine) + { + } + void SAL_CALL OConnectionLineAccess::disposing() + { + m_pLine = nullptr; + VCLXAccessibleComponent::disposing(); + } + Any SAL_CALL OConnectionLineAccess::queryInterface( const Type& aType ) + { + Any aRet(VCLXAccessibleComponent::queryInterface( aType )); + return aRet.hasValue() ? aRet : OConnectionLineAccess_BASE::queryInterface( aType ); + } + Sequence< Type > SAL_CALL OConnectionLineAccess::getTypes( ) + { + return ::comphelper::concatSequences(VCLXAccessibleComponent::getTypes(),OConnectionLineAccess_BASE::getTypes()); + } + OUString SAL_CALL OConnectionLineAccess::getImplementationName() + { + return "org.openoffice.comp.dbu.ConnectionLineAccessibility"; + } + // XAccessibleContext + sal_Int32 SAL_CALL OConnectionLineAccess::getAccessibleChildCount( ) + { + return 0; + } + Reference< XAccessible > SAL_CALL OConnectionLineAccess::getAccessibleChild( sal_Int32 /*i*/ ) + { + return Reference< XAccessible >(); + } + sal_Int32 SAL_CALL OConnectionLineAccess::getAccessibleIndexInParent( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int32 nIndex = -1; + if( m_pLine ) + { + // search the position of our table window in the table window map + // TODO JNA Shouldn't nIndex begin at 0? + nIndex = m_pLine->GetParent()->GetTabWinMap().size(); + const auto& rVec = m_pLine->GetParent()->getTableConnections(); + bool bFound = false; + for (auto const& elem : rVec) + { + if (elem.get() == m_pLine) + { + bFound = true; + break; + } + ++nIndex; + } + nIndex = bFound ? nIndex : -1; + } + return nIndex; + } + sal_Int16 SAL_CALL OConnectionLineAccess::getAccessibleRole( ) + { + return AccessibleRole::UNKNOWN; // ? or may be an AccessibleRole::WINDOW + } + OUString SAL_CALL OConnectionLineAccess::getAccessibleDescription( ) + { + return "Relation"; + } + Reference< XAccessibleRelationSet > SAL_CALL OConnectionLineAccess::getAccessibleRelationSet( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return this; + } + // XAccessibleComponent + Reference< XAccessible > SAL_CALL OConnectionLineAccess::getAccessibleAtPoint( const awt::Point& /*_aPoint*/ ) + { + return Reference< XAccessible >(); + } + awt::Rectangle SAL_CALL OConnectionLineAccess::getBounds( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + tools::Rectangle aRect(m_pLine ? m_pLine->GetBoundingRect() : tools::Rectangle()); + return awt::Rectangle(aRect.getX(),aRect.getY(),aRect.getWidth(),aRect.getHeight()); + } + awt::Point SAL_CALL OConnectionLineAccess::getLocation( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Point aPoint(m_pLine ? m_pLine->GetBoundingRect().TopLeft() : Point()); + return awt::Point(aPoint.X(),aPoint.Y()); + } + awt::Point SAL_CALL OConnectionLineAccess::getLocationOnScreen( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Point aPoint(m_pLine ? m_pLine->GetParent()->ScreenToOutputPixel(m_pLine->GetBoundingRect().TopLeft()) : Point()); + return awt::Point(aPoint.X(),aPoint.Y()); + } + awt::Size SAL_CALL OConnectionLineAccess::getSize( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Size aSize(m_pLine ? m_pLine->GetBoundingRect().GetSize() : Size()); + return awt::Size(aSize.Width(),aSize.Height()); + } + // XAccessibleRelationSet + sal_Int32 SAL_CALL OConnectionLineAccess::getRelationCount( ) + { + return 1; + } + AccessibleRelation SAL_CALL OConnectionLineAccess::getRelation( sal_Int32 nIndex ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if( nIndex < 0 || nIndex >= getRelationCount() ) + throw IndexOutOfBoundsException(); + + Sequence< Reference > aSeq(m_pLine ? 2 : 0); + if( m_pLine ) + { + aSeq[0] = m_pLine->GetSourceWin()->GetAccessible(); + aSeq[1] = m_pLine->GetDestWin()->GetAccessible(); + } + + return AccessibleRelation(AccessibleRelationType::CONTROLLED_BY,aSeq); + } + sal_Bool SAL_CALL OConnectionLineAccess::containsRelation( sal_Int16 aRelationType ) + { + return AccessibleRelationType::CONTROLLED_BY == aRelationType; + } + AccessibleRelation SAL_CALL OConnectionLineAccess::getRelationByType( sal_Int16 aRelationType ) + { + if( AccessibleRelationType::CONTROLLED_BY == aRelationType ) + return getRelation(0); + return AccessibleRelation(); + } + Reference< XAccessible > OTableConnection::CreateAccessible() + { + return new OConnectionLineAccess(this); + } + OTableConnection::~OTableConnection() + { + disposeOnce(); + } + void OTableConnection::dispose() + { + // clear vector + clearLineData(); + m_pParent.clear(); + vcl::Window::dispose(); + } + Reference< XAccessibleContext > SAL_CALL OConnectionLineAccess::getAccessibleContext( ) + { + return this; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/ConnectionLineData.cxx b/dbaccess/source/ui/querydesign/ConnectionLineData.cxx new file mode 100644 index 000000000..db7177294 --- /dev/null +++ b/dbaccess/source/ui/querydesign/ConnectionLineData.cxx @@ -0,0 +1,76 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +using namespace dbaui; +OConnectionLineData::OConnectionLineData() +{ +} + +OConnectionLineData::OConnectionLineData( const OUString& rSourceFieldName, const OUString& rDestFieldName ) + :m_aSourceFieldName( rSourceFieldName ) + ,m_aDestFieldName( rDestFieldName ) +{ +} + +OConnectionLineData::OConnectionLineData( const OConnectionLineData& rConnLineData ) + : ::salhelper::SimpleReferenceObject() +{ + *this = rConnLineData; +} + +OConnectionLineData::~OConnectionLineData() +{ +} + +void OConnectionLineData::CopyFrom(const OConnectionLineData& rSource) +{ + *this = rSource; + // Here I rely on the (non-virtual) operator=, which only copies my members +} + +OConnectionLineData& OConnectionLineData::operator=( const OConnectionLineData& rConnLineData ) +{ + if (&rConnLineData == this) + return *this; + + m_aSourceFieldName = rConnLineData.GetSourceFieldName(); + m_aDestFieldName = rConnLineData.GetDestFieldName(); + + return *this; +} + +void OConnectionLineData::Reset() +{ + m_aDestFieldName.clear(); + m_aSourceFieldName.clear(); +} + +namespace dbaui +{ +bool operator==(const OConnectionLineData& lhs, const OConnectionLineData& rhs) +{ + return (lhs.m_aSourceFieldName == rhs.m_aSourceFieldName) + && (lhs.m_aDestFieldName == rhs.m_aDestFieldName); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/JAccess.cxx b/dbaccess/source/ui/querydesign/JAccess.cxx new file mode 100644 index 000000000..8068f0fa7 --- /dev/null +++ b/dbaccess/source/ui/querydesign/JAccess.cxx @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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) + :VCLXAccessibleComponent(_pTableView->GetComponentInterface().is() ? _pTableView->GetWindowPeer() : nullptr) + ,m_pTableView(_pTableView) + { + } + OUString SAL_CALL OJoinDesignViewAccess::getImplementationName() + { + return "org.openoffice.comp.dbu.JoinViewAccessibility"; + } + void OJoinDesignViewAccess::clearTableView() + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_pTableView = nullptr; + } + // XAccessibleContext + sal_Int32 SAL_CALL OJoinDesignViewAccess::getAccessibleChildCount( ) + { + // TODO may be this will change to only visible windows + // this is the same assumption mt implements + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int32 nChildCount = 0; + if ( m_pTableView ) + nChildCount = m_pTableView->GetTabWinCount() + m_pTableView->getTableConnections().size(); + return nChildCount; + } + Reference< XAccessible > SAL_CALL OJoinDesignViewAccess::getAccessibleChild( sal_Int32 i ) + { + Reference< XAccessible > aRet; + ::osl::MutexGuard aGuard( m_aMutex ); + if(i < 0 || i >= getAccessibleChildCount() || !m_pTableView) + throw IndexOutOfBoundsException(); + // check if we should return a table window or a connection + sal_Int32 nTableWindowCount = m_pTableView->GetTabWinCount(); + if( i < nTableWindowCount ) + { + OJoinTableView::OTableWindowMap::const_iterator aIter = std::next(m_pTableView->GetTabWinMap().begin(), i); + aRet = aIter->second->GetAccessible(); + } + else if( o3tl::make_unsigned(i - nTableWindowCount) < m_pTableView->getTableConnections().size() ) + aRet = m_pTableView->getTableConnections()[i - nTableWindowCount]->GetAccessible(); + return aRet; + } + sal_Int16 SAL_CALL OJoinDesignViewAccess::getAccessibleRole( ) + { + return AccessibleRole::VIEW_PORT; + } + Reference< XAccessibleContext > SAL_CALL OJoinDesignViewAccess::getAccessibleContext( ) + { + return this; + } + // XInterface + IMPLEMENT_FORWARD_XINTERFACE2( OJoinDesignViewAccess, VCLXAccessibleComponent, OJoinDesignViewAccess_BASE ) + // XTypeProvider + IMPLEMENT_FORWARD_XTYPEPROVIDER2( OJoinDesignViewAccess, VCLXAccessibleComponent, OJoinDesignViewAccess_BASE ) +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/JoinController.cxx b/dbaccess/source/ui/querydesign/JoinController.cxx new file mode 100644 index 000000000..49ad53027 --- /dev/null +++ b/dbaccess/source/ui/querydesign/JoinController.cxx @@ -0,0 +1,405 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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, long nOffsetX, 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 ) ); + } + 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, long nOffsetX, long nOffsetY ) +{ + // Deletion and recreation of the old implementation with the current model is not correct anymore: + // The TabWins have a pointer to their data, but they are managed by me. When I delete the old ones, the TabWins suddenly have a pointer to objects, which no longer exist. + // If the TabWins had a SetData, I could save that effort... but they don't, further I also would still have to set information anew, which actually didn't change. + // So I don't delete the TabWinDatas, but only update them. + OSL_ENSURE(m_vTableData.size() == pTabWinList->size(), + "OJoinController::SaveTabWinsPosSize : inconsistent state : should have as many TabWinDatas as TabWins !"); + + for (auto const& tabWin : *pTabWinList) + SaveTabWinPosSize(tabWin.second, nOffsetX, nOffsetY); +} + +void OJoinController::removeConnectionData(const TTableConnectionData::value_type& _pData) +{ + m_vTableConnectionData.erase( std::remove(m_vTableConnectionData.begin(),m_vTableConnectionData.end(),_pData),m_vTableConnectionData.end()); +} + +void OJoinController::describeSupportedFeatures() +{ + OJoinController_BASE::describeSupportedFeatures(); + implDescribeSupportedFeature( ".uno:Redo", ID_BROWSER_REDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:Save", ID_BROWSER_SAVEDOC, CommandGroup::DOCUMENT ); + implDescribeSupportedFeature( ".uno:Undo", ID_BROWSER_UNDO, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:AddTable", ID_BROWSER_ADDTABLE,CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:EditDoc", ID_BROWSER_EDITDOC, CommandGroup::EDIT ); + implDescribeSupportedFeature( ".uno:GetUndoStrings", SID_GETUNDOSTRINGS ); + implDescribeSupportedFeature( ".uno:GetRedoStrings", SID_GETREDOSTRINGS ); +} + +sal_Bool SAL_CALL OJoinController::suspend(sal_Bool _bSuspend) +{ + if ( getBroadcastHelper().bInDispose || getBroadcastHelper().bDisposed ) + return true; + + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + if ( getView() && getView()->IsInModalMode() ) + return false; + bool bCheck = true; + if ( _bSuspend ) + { + bCheck = saveModified() != RET_CANCEL; + if ( bCheck ) + OSingleDocumentController::suspend(_bSuspend); + } + return bCheck; +} + +void OJoinController::loadTableWindows( const ::comphelper::NamedValueCollection& i_rViewSettings ) +{ + m_vTableData.clear(); + + m_aMinimumTableViewSize = Point(); + + Sequence< PropertyValue > aWindowData; + aWindowData = i_rViewSettings.getOrDefault( "Tables", aWindowData ); + + const PropertyValue* pTablesIter = aWindowData.getConstArray(); + const PropertyValue* pTablesEnd = pTablesIter + aWindowData.getLength(); + for ( ; pTablesIter != pTablesEnd; ++pTablesIter ) + { + ::comphelper::NamedValueCollection aSingleTableData( pTablesIter->Value ); + loadTableWindow( aSingleTableData ); + } + if ( m_aMinimumTableViewSize != Point() ) + { + getJoinView()->getScrollHelper()->resetRange( m_aMinimumTableViewSize ); + } +} + +void OJoinController::loadTableWindow( const ::comphelper::NamedValueCollection& i_rTableWindowSettings ) +{ + sal_Int32 nX = -1, nY = -1, nHeight = -1, nWidth = -1; + + OUString sComposedName,sTableName,sWindowName; + bool bShowAll = false; + + sComposedName = i_rTableWindowSettings.getOrDefault( "ComposedName", sComposedName ); + sTableName = i_rTableWindowSettings.getOrDefault( "TableName", sTableName ); + sWindowName = i_rTableWindowSettings.getOrDefault( "WindowName", sWindowName ); + nY = i_rTableWindowSettings.getOrDefault( "WindowTop", nY ); + nX = i_rTableWindowSettings.getOrDefault( "WindowLeft", nX ); + nWidth = i_rTableWindowSettings.getOrDefault( "WindowWidth", nWidth ); + nHeight = i_rTableWindowSettings.getOrDefault( "WindowHeight", nHeight ); + bShowAll = i_rTableWindowSettings.getOrDefault( "ShowAll", bShowAll ); + + TTableWindowData::value_type pData = createTableWindowData(sComposedName,sTableName,sWindowName); + if ( pData ) + { + pData->SetPosition(Point(nX,nY)); + pData->SetSize( Size( nWidth, nHeight ) ); + pData->ShowAll(bShowAll); + m_vTableData.push_back(pData); + if ( m_aMinimumTableViewSize.X() < (nX+nWidth) ) + m_aMinimumTableViewSize.setX( nX+nWidth ); + if ( m_aMinimumTableViewSize.Y() < (nY+nHeight) ) + m_aMinimumTableViewSize.setY( nY+nHeight ); + } +} + +void OJoinController::saveTableWindows( ::comphelper::NamedValueCollection& o_rViewSettings ) const +{ + if ( m_vTableData.empty() ) + return; + + ::comphelper::NamedValueCollection aAllTablesData; + + sal_Int32 i = 1; + for (auto const& elem : m_vTableData) + { + ::comphelper::NamedValueCollection aWindowData; + aWindowData.put( "ComposedName", elem->GetComposedName() ); + aWindowData.put( "TableName", elem->GetTableName() ); + aWindowData.put( "WindowName", elem->GetWinName() ); + aWindowData.put( "WindowTop", static_cast(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 000000000..c0d3ea81c --- /dev/null +++ b/dbaccess/source/ui/querydesign/JoinDesignView.cxx @@ -0,0 +1,100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 000000000..312c9d8e9 --- /dev/null +++ b/dbaccess/source/ui/querydesign/JoinExchange.cxx @@ -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 . + */ + +#include +#include +#include +#include + +namespace dbaui +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::datatransfer; + + OJoinExchObj::OJoinExchObj(const OJoinExchangeData& jxdSource,bool _bFirstEntry) + :m_bFirstEntry(_bFirstEntry) + ,m_jxdSourceDescription(jxdSource) + ,m_pDragListener(nullptr) + { + // add available types to list + } + + OJoinExchObj::~OJoinExchObj() + { + } + + void OJoinExchObj::StartDrag( vcl::Window* _pWindow, sal_Int8 _nDragSourceActions, IDragTransferableListener* _pListener ) + { + m_pDragListener = _pListener; + TransferableHelper::StartDrag(_pWindow, _nDragSourceActions); + } + + void OJoinExchObj::DragFinished( sal_Int8 /*nDropAction*/ ) + { + if (m_pDragListener) + m_pDragListener->dragFinished(); + m_pDragListener = nullptr; + } + + 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::getUnoTunnelImplementation(_rxObject); + if (pImplementation) + aReturn = pImplementation->m_jxdSourceDescription; + return aReturn; + } + + Sequence< sal_Int8 > OJoinExchObj::getUnoTunnelId() + { + static ::cppu::OImplementationId implId; + + return implId.getImplementationId(); + } + + sal_Int64 SAL_CALL OJoinExchObj::getSomething( const Sequence< sal_Int8 >& _rIdentifier ) + { + if (isUnoTunnelId(_rIdentifier)) + return reinterpret_cast(this); + + return 0; + } + + 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 = TransferableHelper::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = OJoinExchObj_Base::queryInterface(_rType); + return aReturn; + } + + void SAL_CALL OJoinExchObj::acquire( ) throw() + { + TransferableHelper::acquire( ); + } + + void SAL_CALL OJoinExchObj::release( ) throw() + { + TransferableHelper::release( ); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/JoinTableView.cxx b/dbaccess/source/ui/querydesign/JoinTableView.cxx new file mode 100644 index 000000000..54ea53f0e --- /dev/null +++ b/dbaccess/source/ui/querydesign/JoinTableView.cxx @@ -0,0 +1,1566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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, WB_HSCROLL|WB_REPEAT|WB_DRAG) ) + ,m_aVScrollBar( VclPtr::Create(this, WB_VSCROLL|WB_REPEAT|WB_DRAG) ) + ,m_pCornerWindow(VclPtr::Create(this, WB_3DLOOK)) + ,m_pTableView(nullptr) +{ + + // ScrollBars + + GetHScrollBar().SetRange( Range(0, 1000) ); + GetVScrollBar().SetRange( Range(0, 1000) ); + + GetHScrollBar().SetLineSize( LINE_SIZE ); + GetVScrollBar().SetLineSize( LINE_SIZE ); + + GetHScrollBar().Show(); + GetVScrollBar().Show(); + m_pCornerWindow->Show(); + + // normally we should be SCROLL_PANE + SetAccessibleRole(AccessibleRole::SCROLL_PANE); +} + +OScrollWindowHelper::~OScrollWindowHelper() +{ + disposeOnce(); +} + +void OScrollWindowHelper::dispose() +{ + m_aHScrollBar.disposeAndClear(); + m_aVScrollBar.disposeAndClear(); + m_pCornerWindow.disposeAndClear(); + m_pTableView.clear(); + vcl::Window::dispose(); +} + +void OScrollWindowHelper::setTableView(OJoinTableView* _pTableView) +{ + m_pTableView = _pTableView; + // ScrollBars + GetHScrollBar().SetScrollHdl( LINK(m_pTableView, OJoinTableView, ScrollHdl) ); + GetVScrollBar().SetScrollHdl( LINK(m_pTableView, OJoinTableView, ScrollHdl) ); +} + +void OScrollWindowHelper::resetRange(const Point& _aSize) +{ + Point aPos = PixelToLogic(_aSize); + GetHScrollBar().SetRange( Range(0, aPos.X() + TABWIN_SPACING_X) ); + GetVScrollBar().SetRange( Range(0, aPos.Y() + TABWIN_SPACING_Y) ); +} + +void OScrollWindowHelper::Resize() +{ + Window::Resize(); + + Size aTotalOutputSize = GetOutputSizePixel(); + long nHScrollHeight = GetHScrollBar().GetSizePixel().Height(); + long nVScrollWidth = GetVScrollBar().GetSizePixel().Width(); + + GetHScrollBar().SetPosSizePixel( + Point( 0, aTotalOutputSize.Height()-nHScrollHeight ), + Size( aTotalOutputSize.Width()-nVScrollWidth, nHScrollHeight ) + ); + + GetVScrollBar().SetPosSizePixel( + Point( aTotalOutputSize.Width()-nVScrollWidth, 0 ), + Size( nVScrollWidth, aTotalOutputSize.Height()-nHScrollHeight ) + ); + + m_pCornerWindow->SetPosSizePixel( + Point( aTotalOutputSize.Width() - nVScrollWidth, aTotalOutputSize.Height() - nHScrollHeight), + Size( nVScrollWidth, nHScrollHeight ) + ); + + GetHScrollBar().SetPageSize( aTotalOutputSize.Width() ); + GetHScrollBar().SetVisibleSize( aTotalOutputSize.Width() ); + + GetVScrollBar().SetPageSize( aTotalOutputSize.Height() ); + GetVScrollBar().SetVisibleSize( aTotalOutputSize.Height() ); + + // adjust the ranges of the scrollbars if necessary + 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_aDragOffset( Point(0,0) ) + ,m_aScrollOffset( Point(0,0) ) + ,m_pDragWin( nullptr ) + ,m_pSizingWin( nullptr ) + ,m_pSelectedConn( nullptr ) + ,m_pLastFocusTabWin(nullptr) + ,m_pView( pView ) + ,m_pAccessible(nullptr) +{ + SetSizePixel( Size(1000, 1000) ); + + InitColors(); + + m_aDragScrollIdle.SetInvokeHandler(LINK(this, OJoinTableView, OnDragScrollTimer)); +} + +OJoinTableView::~OJoinTableView() +{ + disposeOnce(); +} + +void OJoinTableView::dispose() +{ + if( m_pAccessible ) + { + m_pAccessible->clearTableView(); + m_pAccessible = nullptr; + } + // delete lists + clearLayoutInformation(); + m_pDragWin.clear(); + m_pSizingWin.clear(); + m_pSelectedConn.clear(); + m_pLastFocusTabWin.clear(); + m_pView.clear(); + m_vTableConnection.clear(); + vcl::Window::dispose(); +} + +IMPL_LINK( OJoinTableView, ScrollHdl, ScrollBar*, pScrollBar, void ) +{ + // move all windows + ScrollPane( pScrollBar->GetDelta(), (pScrollBar == &GetHScrollBar()), false ); +} + +void OJoinTableView::Resize() +{ + Window::Resize(); + m_aOutputSize = GetSizePixel(); + + // tab win positions may not be up-to-date + if (m_aTableMap.empty()) + // no tab wins ... + return; + + // we have at least one table so resize it + m_aScrollOffset.setX( GetHScrollBar().GetThumbPos() ); + m_aScrollOffset.setY( GetVScrollBar().GetThumbPos() ); + + VclPtr pCheck = m_aTableMap.begin()->second; + Point aRealPos = pCheck->GetPosPixel(); + Point aAssumedPos = pCheck->GetData()->GetPosition() - GetScrollOffset(); + + if (aRealPos == aAssumedPos) + // all ok + return; + + for (auto const& elem : m_aTableMap) + { + OTableWindow* pCurrent = elem.second; + Point aPos(pCurrent->GetData()->GetPosition() - GetScrollOffset()); + pCurrent->SetPosPixel(aPos); + } +} + +sal_uLong OJoinTableView::GetTabWinCount() const +{ + return m_aTableMap.size(); +} + +bool OJoinTableView::RemoveConnection(VclPtr& 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, + makeAny(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(), + makeAny(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, + makeAny(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,long nDelta, bool bHoriz) + { + // adjust ScrollBar-Positions + ScrollBar& rBar = bHoriz ? _pView->GetHScrollBar() : _pView->GetVScrollBar() ; + + long nOldThumbPos = rBar.GetThumbPos(); + 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,long& _nScrollX,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) +{ + 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) +{ + 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().IsInside(aBottom.X())) + GetHScrollBar().SetRange( Range(0, aBottom.X()) ); + if(!GetVScrollBar().GetRange().IsInside(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( long nDelta, bool bHoriz, bool bPaintScrollBars ) +{ + bool bRet = true; + + // adjust ScrollBar-Positions + if( bPaintScrollBars ) + { + if( bHoriz ) + { + long nOldThumbPos = GetHScrollBar().GetThumbPos(); + 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 + { + long nOldThumbPos = GetVScrollBar().GetThumbPos(); + 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()->SelectAll(false); + + pWin = pConn->GetDestWin(); + if (pWin && pWin->GetListBox()) + pWin->GetListBox()->SelectAll(false); + + 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->SelectAll(false); + pDestBox->SelectAll(false); + + SvTreeListEntry* pFirstSourceVisible = pSourceBox->GetFirstEntryInView(); + SvTreeListEntry* pFirstDestVisible = pDestBox->GetFirstEntryInView(); + + const std::vector>& rLines = pConn->GetConnLineList(); + auto aIter = rLines.rbegin(); + for(;aIter != rLines.rend();++aIter) + { + if ((*aIter)->IsValid()) + { + SvTreeListEntry* pSourceEntry = pSourceBox->GetEntryFromText((*aIter)->GetData()->GetSourceFieldName()); + if (pSourceEntry) + { + pSourceBox->Select(pSourceEntry); + pSourceBox->MakeVisible(pSourceEntry); + } + + SvTreeListEntry* pDestEntry = pDestBox->GetEntryFromText((*aIter)->GetData()->GetDestFieldName()); + if (pDestEntry) + { + pDestBox->Select(pDestEntry); + pDestBox->MakeVisible(pDestEntry); + } + + } + } + + if ((pFirstSourceVisible != pSourceBox->GetFirstEntryInView()) + || (pFirstDestVisible != pDestBox->GetFirstEntryInView())) + // 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& _aPos, VclPtr& rSelConnection) +{ + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/joinviewmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + aContextMenu->Execute(this, _aPos); + OString sIdent = aContextMenu->GetCurItemIdent(); + 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 _bSupressCrossOrNaturalJoin) 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 ( _bSupressCrossOrNaturalJoin ) + { + if ( supressCrossNaturalJoin(pData->GetData()) ) + continue; + } + pConn = pData; + break; + } + } + } + return pConn; +} + +bool OJoinTableView::PreNotify(NotifyEvent& rNEvt) +{ + bool bHandled = false; + switch (rNEvt.GetType()) + { + case MouseNotifyEvent::COMMAND: + { + const CommandEvent* pCommand = rNEvt.GetCommandEvent(); + if (pCommand->GetCommand() == CommandEventId::Wheel) + { + const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData(); + if (pData->GetMode() == CommandWheelMode::SCROLL) + { + if (pData->GetDelta() > 0) + ScrollPane(-10 * pData->GetScrollLines(), pData->IsHorz(), true); + else + ScrollPane(10 * pData->GetScrollLines(), pData->IsHorz(), true); + bHandled = true; + } + } + } + break; + case MouseNotifyEvent::KEYINPUT: + { + if (m_aTableMap.empty()) + // no tab wins -> no conns -> no traveling + break; + + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + if (!pKeyEvent->GetKeyCode().IsMod1()) + { + switch (pKeyEvent->GetKeyCode().GetCode()) + { + case KEY_TAB: + { + if (!HasChildPathFocus()) + break; + + bool bForward = !pKeyEvent->GetKeyCode().IsShift(); + // is there an active tab win ? + OTableWindowMap::const_iterator aIter = std::find_if(m_aTableMap.begin(), m_aTableMap.end(), + [](const OTableWindowMap::value_type& rEntry) { return rEntry.second && rEntry.second->HasChildPathFocus(); }); + + OTableWindow* pNextWin = nullptr; + OTableConnection* pNextConn = nullptr; + + if (aIter != m_aTableMap.end()) + { // there is a currently active tab win + // check if there is an "overflow" and we should select a conn instead of a win + if (!m_vTableConnection.empty()) + { + if ((aIter->second == m_aTableMap.rbegin()->second) && bForward) + // the last win is active and we're travelling forward -> select the first conn + pNextConn = m_vTableConnection.begin()->get(); + if ((aIter == m_aTableMap.begin()) && !bForward) + // the first win is active and we're traveling backward -> select the last conn + pNextConn = m_vTableConnection.rbegin()->get(); + } + + if (!pNextConn) + { + // no conn for any reason -> select the next or previous tab win + if(bForward) + { + if ( aIter->second == m_aTableMap.rbegin()->second ) + pNextWin = m_aTableMap.begin()->second; + else + { + ++aIter; + pNextWin = aIter->second; + } + } + else + { + if (aIter == m_aTableMap.begin()) + pNextWin = m_aTableMap.rbegin()->second; + else + { + --aIter; + pNextWin = aIter->second; + } + } + } + } + else + { // no active tab win -> travel the connections + // find the currently selected conn within the conn list + sal_Int32 i(0); + for (auto const& elem : m_vTableConnection) + { + if ( elem.get() == GetSelectedConn() ) + break; + ++i; + } + if (i == sal_Int32(m_vTableConnection.size() - 1) && bForward) + // the last conn is active and we're travelling forward -> select the first win + pNextWin = m_aTableMap.begin()->second; + if ((i == 0) && !bForward && !m_aTableMap.empty()) + // the first conn is active and we're travelling backward -> select the last win + pNextWin = m_aTableMap.rbegin()->second; + + if (pNextWin) + DeselectConn(GetSelectedConn()); + else + // no win for any reason -> select the next or previous conn + if (i < static_cast(m_vTableConnection.size())) + // there is a currently active conn + pNextConn = m_vTableConnection[(i + (bForward ? 1 : m_vTableConnection.size() - 1)) % m_vTableConnection.size()].get(); + else + { // no tab win selected, no conn selected + if (!m_vTableConnection.empty()) + pNextConn = m_vTableConnection[bForward ? 0 : m_vTableConnection.size() - 1].get(); + else if (!m_aTableMap.empty()) + { + if(bForward) + pNextWin = m_aTableMap.begin()->second; + else + pNextWin = m_aTableMap.rbegin()->second; + } + } + } + + // now select the object + if (pNextWin) + { + if (pNextWin->GetListBox()) + pNextWin->GetListBox()->GrabFocus(); + else + pNextWin->GrabFocus(); + EnsureVisible(pNextWin); + } + else if (pNextConn) + { + GrabFocus(); + // necessary : a conn may be selected even if a tab win has the focus, in this case + // the next travel would select the same conn again if we would not reset the focus ... + SelectConn(pNextConn); + } + } + break; + case KEY_RETURN: + { + if (!pKeyEvent->GetKeyCode().IsShift() && GetSelectedConn() && HasFocus()) + ConnDoubleClicked(GetSelectedConn()); + break; + } + } + } + } + break; + case MouseNotifyEvent::GETFOCUS: + { + if (m_aTableMap.empty()) + // no tab wins -> no conns -> no focus change + break; + vcl::Window* pSource = rNEvt.GetWindow(); + if (pSource) + { + vcl::Window* pSearchFor = nullptr; + if (pSource->GetParent() == this) + // it may be one of the tab wins + pSearchFor = pSource; + else if (pSource->GetParent() && (pSource->GetParent()->GetParent() == this)) + // it may be one of th list boxes of one of the tab wins + pSearchFor = pSource->GetParent(); + + if (pSearchFor) + { + for (auto const& elem : m_aTableMap) + { + if (elem.second == pSearchFor) + { + m_pLastFocusTabWin = elem.second; + break; + } + } + } + } + } + break; + default: + break; + } + + if (!bHandled) + return Window::PreNotify(rNEvt); + return true; +} + +void OJoinTableView::GrabTabWinFocus() +{ + if (m_pLastFocusTabWin && m_pLastFocusTabWin->IsVisible()) + { + if (m_pLastFocusTabWin->GetListBox()) + m_pLastFocusTabWin->GetListBox()->GrabFocus(); + else + m_pLastFocusTabWin->GrabFocus(); + } + else if (!m_aTableMap.empty() && m_aTableMap.begin()->second && m_aTableMap.begin()->second->IsVisible()) + { + VclPtr 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(*this, 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(), + makeAny(_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::supressCrossNaturalJoin(const TTableConnectionData::value_type& ) const +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableConnection.cxx b/dbaccess/source/ui/querydesign/QTableConnection.cxx new file mode 100644 index 000000000..c5db155f2 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableConnection.cxx @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "QTableConnection.hxx" +#include +#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 000000000..b15a26102 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableConnection.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLECONNECTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLECONNECTION_HXX + +#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; } + + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLECONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableConnectionData.cxx b/dbaccess/source/ui/querydesign/QTableConnectionData.cxx new file mode 100644 index 000000000..f96a5b1cd --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableConnectionData.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 "QTableConnectionData.hxx" +#include "QTableWindow.hxx" + +#include + +using namespace dbaui; + +OQueryTableConnectionData::OQueryTableConnectionData() + : OTableConnectionData() + , 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 000000000..41639470f --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableConnectionData.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLECONNECTIONDATA_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLECONNECTIONDATA_HXX + +#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; } + }; + +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLECONNECTIONDATA_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableWindow.cxx b/dbaccess/source/ui/querydesign/QTableWindow.cxx new file mode 100644 index 000000000..6d2916683 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableWindow.cxx @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "QTableWindow.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "TableFieldInfo.hxx" +#include +#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(SvTreeListEntry* pEntry) +{ + OSL_ENSURE(pEntry != nullptr, "OQueryTableWindow::OnEntryDoubleClicked : pEntry must not be NULL !"); + // you could also scan that and then return, but like this it could possibly hint to faults at the caller + + if (getTableView()->getDesignView()->getController().isReadOnly()) + return; + + OTableFieldInfo* pInf = static_cast(pEntry->GetUserData()); + OSL_ENSURE(pInf != nullptr, "OQueryTableWindow::OnEntryDoubleClicked : field doesn't have FieldInfo !"); + + // build up DragInfo + OTableFieldDescRef aInfo = new OTableFieldDesc(GetTableName(), m_xListBox->GetEntryText(pEntry)); + aInfo->SetTabWindow(this); + aInfo->SetAlias(GetAliasName()); + aInfo->SetFieldIndex(m_xListBox->GetModel()->GetAbsPos(pEntry)); + 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()) + { + SvTreeListEntry* pEntry = m_xListBox->First(); + try + { + Reference xMeta = xConnection->getMetaData(); + ::comphelper::UStringMixEqual bCase(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers()); + + while (pEntry) + { + if (bCase(strFieldName,m_xListBox->GetEntryText(pEntry))) + { + OTableFieldInfo* pInf = static_cast(pEntry->GetUserData()); + assert(pInf && "OQueryTableWindow::ExistsField : field doesn't have FieldInfo !"); + + rInfo->SetTabWindow(this); + rInfo->SetField(strFieldName); + rInfo->SetTable(GetTableName()); + rInfo->SetAlias(GetAliasName()); + rInfo->SetFieldIndex(m_xListBox->GetModel()->GetAbsPos(pEntry)); + rInfo->SetDataType(pInf->GetDataType()); + bExists = true; + break; + } + pEntry = m_xListBox->Next(pEntry); + } + } + 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 000000000..e64fd2e85 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableWindow.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLEWINDOW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLEWINDOW_HXX + +#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(SvTreeListEntry* pEntry) 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLEWINDOW_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableWindowData.cxx b/dbaccess/source/ui/querydesign/QTableWindowData.cxx new file mode 100644 index 000000000..d8f2f2efd --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableWindowData.cxx @@ -0,0 +1,34 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "QTableWindowData.hxx" + +using namespace dbaui; +using namespace ::com::sun::star::uno; + +OQueryTableWindowData::OQueryTableWindowData(const OUString& _rComposedName, const OUString& rTableName, const OUString& rTableAlias ) + :OTableWindowData(nullptr,_rComposedName, rTableName, rTableAlias) +{ +} + +OQueryTableWindowData::~OQueryTableWindowData() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QTableWindowData.hxx b/dbaccess/source/ui/querydesign/QTableWindowData.hxx new file mode 100644 index 000000000..382611eec --- /dev/null +++ b/dbaccess/source/ui/querydesign/QTableWindowData.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLEWINDOWDATA_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLEWINDOWDATA_HXX + +#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); } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QTABLEWINDOWDATA_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx b/dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.hxx new file mode 100644 index 000000000..37e13213d --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryAddTabConnUndoAction.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYADDTABCONNUNDOACTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYADDTABCONNUNDOACTION_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYADDTABCONNUNDOACTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx new file mode 100644 index 000000000..63f09af2e --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryDesignFieldUndoAct.hxx @@ -0,0 +1,140 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYDESIGNFIELDUNDOACT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYDESIGNFIELDUNDOACT_HXX + +#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, const char* 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 + { + long m_nNextWidth; + + public: + explicit OTabFieldSizedUndoAct(OSelectionBrowseBox* pSelBrwBox) : OQueryDesignFieldUndoAct(pSelBrwBox, STR_QUERY_UNDO_SIZE_COLUMN), m_nNextWidth(0) { } + + void SetOriginalWidth(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, const char* 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) { } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYDESIGNFIELDUNDOACT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx b/dbaccess/source/ui/querydesign/QueryDesignUndoAction.hxx new file mode 100644 index 000000000..817e00341 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryDesignUndoAction.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYDESIGNUNDOACTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYDESIGNUNDOACTION_HXX + +#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, const char* pCommentID) : OCommentUndoAction(pCommentID), m_pOwner(pOwner) { } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYDESIGNUNDOACTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryDesignView.cxx b/dbaccess/source/ui/querydesign/QueryDesignView.cxx new file mode 100644 index 000000000..30afb7593 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryDesignView.cxx @@ -0,0 +1,3442 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "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 + +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 +{ + static const char C_AND[] = " AND "; + static const char C_OR[] = " OR "; + + bool InsertJoin( const OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode *pNode); + + SqlParseError InstallFields(OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode* pNode, + OJoinTableView::OTableWindowMap* pTabList ); + + SqlParseError GetGroupCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pSelectRoot ); + + SqlParseError GetHavingCriteria(OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pSelectRoot, + sal_uInt16& rLevel ); + + SqlParseError GetOrderCriteria( OQueryDesignView* _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode* pParseRoot ); + + SqlParseError AddFunctionCondition(OQueryDesignView const * _pView, + OSelectionBrowseBox* _pSelectionBrw, + const ::connectivity::OSQLParseNode * pCondition, + const sal_uInt16 nLevel, + bool bHaving, + bool _bAddOrOnOneLine); + + OUString quoteTableAlias(bool _bQuote, const OUString& _sAliasName, const OUString& _sQuote) + { + OUString sRet; + if ( _bQuote && !_sAliasName.isEmpty() ) + { + sRet = ::dbtools::quoteName(_sQuote,_sAliasName) + "."; + } + return sRet; + } + OUString getTableRange(const OQueryDesignView* _pView,const ::connectivity::OSQLParseNode* _pTableRef) + { + Reference< XConnection> xConnection = static_cast(_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()) + { + OUString aTmp(aSourceFieldName); + aSourceFieldName = aDestFieldName; + aDestFieldName = aTmp; + } + pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName); + pConn->UpdateLineList(); + // Modified-Flag + // SetModified(); + // and redraw + pConn->RecalcLines(); + // for the following Invalidate, the new Connection must first be able + // to determine its BoundingRect + pConn->InvalidateConnection(); + } + } + OUString ParseCondition( OQueryController& rController + ,const ::connectivity::OSQLParseNode* pCondition + ,const OUString& _sDecimal + ,const css::lang::Locale& _rLocale + ,sal_uInt32 _nStartIndex) + { + OUString aCondition; + Reference< XConnection> xConnection = rController.getConnection(); + if ( xConnection.is() ) + { + sal_uInt32 nCount = pCondition->count(); + for(sal_uInt32 i = _nStartIndex ; i < nCount ; ++i) + pCondition->getChild(i)->parseNodeToPredicateStr(aCondition, + xConnection, + rController.getNumberFormatter(), + _rLocale, + _sDecimal, + &rController.getParser().getContext()); + } + return aCondition; + } + SqlParseError FillOuterJoins(OQueryDesignView const * _pView, + const ::connectivity::OSQLParseNode* pTableRefList) + { + SqlParseError eErrorCode = eOk; + sal_uInt32 nCount = pTableRefList->count(); + bool bError = false; + for (sal_uInt32 i=0; !bError && i < nCount; ++i) + { + const ::connectivity::OSQLParseNode* pParseNode = pTableRefList->getChild(i); + const ::connectivity::OSQLParseNode* pJoinNode = nullptr; + + if ( SQL_ISRULE( pParseNode, qualified_join ) || SQL_ISRULE( pParseNode, joined_table ) || SQL_ISRULE( pParseNode, cross_union ) ) + pJoinNode = pParseNode; + else if( SQL_ISRULE(pParseNode,table_ref) + && pParseNode->count() == 4 ) // '{' SQL_TOKEN_OJ joined_table '}' + pJoinNode = pParseNode->getChild(2); + + if ( pJoinNode ) + { + if ( !InsertJoin(_pView,pJoinNode) ) + bError = true; + } + } + // check if error occurred + if ( bError ) + eErrorCode = eIllegalJoin; + + return eErrorCode; + } + + /** FillDragInfo fills the field description out of the table + */ + SqlParseError FillDragInfo( const OQueryDesignView* _pView, + const ::connectivity::OSQLParseNode* pColumnRef, + OTableFieldDescRef const & _rDragInfo) + { + SqlParseError eErrorCode = eOk; + + bool bErg = false; + + OUString aTableRange,aColumnName; + sal_uInt16 nCntAccount; + ::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 ) + { + 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)); + aCondition.append(::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_FROM) )); + aCondition.append(" = "); + aCondition.append(quoteTableAlias(true,pData->GetAliasName(JTCS_TO),aQuote)); + aCondition.append(::dbtools::quoteName(aQuote, lineData->GetFieldName(JTCS_TO) )); + } + } + catch(SQLException&) + { + OSL_FAIL("Failure while building Join criteria!"); + } + } + + return aCondition.makeStringAndClear(); + } + /** JoinCycle looks for a join cycle and append it to the string + @param _xConnection the connection + @param _pEntryConn the table connection which holds the data + @param _pEntryTabTo the corresponding table window + @param _rJoin the String which will contain the resulting string + */ + void JoinCycle( const Reference< XConnection>& _xConnection, + OQueryTableConnection* _pEntryConn, + const OQueryTableWindow* _pEntryTabTo, + OUString& _rJoin ) + { + OSL_ENSURE(_pEntryConn,"TableConnection can not be null!"); + + OQueryTableConnectionData* pData = static_cast< OQueryTableConnectionData*>(_pEntryConn->GetData().get()); + if ( !(pData->GetJoinType() != INNER_JOIN && _pEntryTabTo->ExistsAVisitedConn()) ) + return; + + bool bBrace = false; + if(_rJoin.endsWith(")")) + { + bBrace = true; + _rJoin = _rJoin.replaceAt(_rJoin.getLength()-1,1,OUString(' ')); + } + _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, + const OUString& 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 += "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()); + aTmpStr2.append("("); + aTmpStr2.append(aTmpStr.makeStringAndClear()); + aTmpStr2.append(")"); + aTmpStr = aTmpStr2; + } + + if (!rFieldAlias.isEmpty() && + (rFieldName.toChar() != '*' || + field->isNumericOrAggregateFunction() || + field->isOtherFunction())) + { + aTmpStr.append(" AS "); + aTmpStr.append(::dbtools::quoteName(aQuote, rFieldAlias)); + } + aFieldListStr.append(aTmpStr.makeStringAndClear()); + 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 bCritsOnAsterikWarning = 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 (!bCritsOnAsterikWarning) + { + std::unique_ptr xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + DBA_RES(STR_QRY_CRITERIA_ON_ASTERISK))); + xBox->run(); + } + bCritsOnAsterikWarning = 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 bCritsOnAsterikWarning = 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 (!bCritsOnAsterikWarning) + { + std::unique_ptr xBox(Application::CreateMessageDialog(_pView->GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, + DBA_RES(STR_QRY_ORDERBY_ON_ASTERISK))); + xBox->run(); + } + bCritsOnAsterikWarning = 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( ";ASC;DESC" ).getToken( 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, OUString() ); + 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, OUString(' ') ); + 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 ) + { + + 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(comphelper::string::stripEnd(aColumns.getToken(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 ) + { + const char* 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); + + setNoneVisbleRow(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(const OUString& 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(const OUString& sAliasName, weld::ComboBox& rFieldList) +{ + rFieldList.clear(); + + bool bAllTables = sAliasName.isEmpty(); + + 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() == MouseNotifyEvent::GETFOCUS) + { + if ( m_pSelectionBox && m_pSelectionBox->HasChildPathFocus() ) + m_eChildFocus = SELECTION; + else + m_eChildFocus = TABLEVIEW; + } + + return OJoinDesignView::PreNotify(rNEvt); +} + +// check if the statement is correct when not returning false +bool OQueryDesignView::checkStatement() +{ + bool bRet = true; + if ( m_pSelectionBox ) + bRet = m_pSelectionBox->Save(); // an error occurred so we return no + return bRet; +} + +OUString OQueryDesignView::getStatement() +{ + OQueryController& rController = static_cast(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.makeStringAndClear(); + } + aCriteriaListStr = aTmp; + } + // ----------------- construct statement ---------------------- + OUStringBuffer aSqlCmd("SELECT "); + if(rController.isDistinct()) + aSqlCmd.append(" DISTINCT "); + aSqlCmd.append(aFieldListStr); + aSqlCmd.append(" FROM "); + aSqlCmd.append(aTableListStr); + + if (!aCriteriaListStr.isEmpty()) + { + aSqlCmd.append(" WHERE "); + aSqlCmd.append(aCriteriaListStr.makeStringAndClear()); + } + 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 "); + aSqlCmd.append(aHavingStr.makeStringAndClear()); + } + // ----------------- 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 " ).append( 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(); + parse::OParseColumn* pColumn = new parse::OParseColumn( pEntry->GetField(), + OUString(), + OUString(), + OUString(), + ColumnValue::NULLABLE_UNKNOWN, + 0, + 0, + nType, + false, + false, + xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(), + OUString(), + OUString(), + OUString()); + _rxColumn = pColumn; + pColumn->setFunction(true); + pColumn->setRealName(pEntry->GetField()); + } + else + { + if (pWin) + { + Reference 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::setNoneVisbleRow(sal_Int32 _nRows) +{ + m_pSelectionBox->SetNoneVisbleRow(_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 000000000..1e7ca6bb9 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.cxx @@ -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 . + */ + +#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 000000000..38cca8bc6 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryMoveTabWinUndoAct.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYMOVETABWINUNDOACT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYMOVETABWINUNDOACT_HXX + +#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) + { + } +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYMOVETABWINUNDOACT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx b/dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.hxx new file mode 100644 index 000000000..a36eb5eb5 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QuerySizeTabWinUndoAct.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYSIZETABWINUNDOACT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYSIZETABWINUNDOACT_HXX + +#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; + } +} + +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYSIZETABWINUNDOACT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx new file mode 100644 index 000000000..b209a62ce --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.cxx @@ -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 . + */ + +#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, const char* 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 000000000..36b1aae98 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabConnUndoAction.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYTABCONNUNDOACTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYTABCONNUNDOACTION_HXX + +#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, const char* 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; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYTABCONNUNDOACTION_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.hxx new file mode 100644 index 000000000..748ca7c38 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabWinShowUndoAct.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYTABWINSHOWUNDOACT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYTABWINSHOWUNDOACT_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYTABWINSHOWUNDOACT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.cxx new file mode 100644 index 000000000..6242c94fc --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.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 "QueryTabWinUndoAct.hxx" +#include +#include "QTableWindow.hxx" +#include +#include "QueryDesignFieldUndoAct.hxx" +#include + +using namespace dbaui; +OQueryDesignFieldUndoAct::OQueryDesignFieldUndoAct(OSelectionBrowseBox* pSelBrwBox, const char* pCommentID) + : OCommentUndoAction(pCommentID) + , pOwner(pSelBrwBox) + , m_nColumnPosition(BROWSER_INVALIDID) +{ +} + +OQueryDesignFieldUndoAct::~OQueryDesignFieldUndoAct() +{ + pOwner = nullptr; +} + +OQueryTabWinUndoAct::OQueryTabWinUndoAct(OQueryTableView* pOwner, const char* 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); + long nNextWidth = pOwner->GetColumnWidth(nColumnId); + pOwner->SetColWidth(nColumnId, m_nNextWidth); + m_nNextWidth = nNextWidth; + } + pOwner->LeaveUndoMode(); +} + +void OTabFieldMovedUndoAct::Undo() +{ + pOwner->EnterUndoMode(); + OSL_ENSURE(m_nColumnPosition != BROWSER_INVALIDID,"Column position was not set add the undo action!"); + if ( m_nColumnPosition != BROWSER_INVALIDID ) + { + sal_uInt16 nId = pDescr->GetColumnId(); + sal_uInt16 nOldPos = pOwner->GetColumnPos(nId); + pOwner->SetColumnPos(nId,m_nColumnPosition); + pOwner->ColumnMoved(nId,false); + m_nColumnPosition = nOldPos; + } + pOwner->LeaveUndoMode(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.hxx new file mode 100644 index 000000000..008c76260 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTabWinUndoAct.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYTABWINUNDOACT_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYTABWINUNDOACT_HXX + +#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, const char* 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); } + }; + +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYTABWINUNDOACT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryTableView.cxx b/dbaccess/source/ui/querydesign/QueryTableView.cxx new file mode 100644 index 000000000..1847cfe7b --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTableView.cxx @@ -0,0 +1,887 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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()); + + rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), *aIter), rTabWinDataList.end()); + continue; + } + + GetTabWinMap()[pData->GetAliasName()] = pTabWin; // add at the beginning as I am going backwards through the DataList + // Use the default if there is no position or size + if (!pData->HasPosition() && !pData->HasSize()) + SetDefaultTabWinPosSize(pTabWin); + + pTabWin->Show(); + } + + // Add the connections + TTableConnectionData& rTabConnDataList = m_pView->getController().getTableConnectionData(); + TTableConnectionData::const_reverse_iterator aConIter = rTabConnDataList.rbegin(); + + for(;aConIter != rTabConnDataList.rend();++aConIter) + { + OQueryTableConnectionData* pTabConnData = static_cast(aConIter->get()); + + // do both tables for the connection exist ? + OUString strTabExistenceTest = pTabConnData->getReferencingTable()->GetWinName(); + bool bInvalid = std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); + strTabExistenceTest = pTabConnData->getReferencedTable()->GetWinName(); + bInvalid = bInvalid && std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); + + if (bInvalid) + { + // no -> bad luck, no connection + rTabConnDataList.erase( std::remove(rTabConnDataList.begin(), rTabConnDataList.end(), *aConIter), rTabConnDataList.end()); + continue; + } + + // adds a new connection to join view and notifies our accessible and invalidates the controller + addConnection(VclPtr::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,const OUString& _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(), + makeAny(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; + aSourceFieldName = jxdSource.pListBox->GetEntryText(jxdSource.pEntry); + aDestFieldName = jxdDest.pListBox->GetEntryText(jxdDest.pEntry); + + 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.pListBox->GetModel()->GetAbsPos(jxdSource.pEntry); + // Dest + nDestFieldIndex = jxdDest.pListBox->GetModel()->GetAbsPos(jxdDest.pEntry); + + // ... and set them + xNewConnectionData->SetFieldIndex(JTCS_FROM, nSourceFieldIndex); + xNewConnectionData->SetFieldIndex(JTCS_TO, nDestFieldIndex); + + xNewConnectionData->AppendConnLine( aSourceFieldName,aDestFieldName ); + + ScopedVclPtrInstance< OQueryTableConnection > aNewConnection(this, xNewConnectionData); + NotifyTabConnection(*aNewConnection); + // As usual with NotifyTabConnection, using a local variable is fine because a copy is made + } + else + { + // the connection could point on the other side + if(pConn->GetSourceWin() == pDestWin) + { + OUString aTmp(aSourceFieldName); + aSourceFieldName = aDestFieldName; + aDestFieldName = aTmp; + } + + pConn->GetData()->AppendConnLine( aSourceFieldName,aDestFieldName ); + + connectionModified(this,pConn,false); + } +} + +void OQueryTableView::ConnDoubleClicked(VclPtr& 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, + makeAny(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(); + rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), pTabWin->GetData()), rTabWinDataList.end()); + // The data should not be destroyed as TabWin itself - which is still alive - needs them + // Either it goes back into my responsibility, (via ShowTabWin), then I add the data back, + // or the Undo-Action, which currently has full responsibility for the window + // and its data, gets destroyed and destroys both the window and its data + + if (m_pLastFocusTabWin == pTabWin) + m_pLastFocusTabWin = nullptr; + + // collect connections belonging to the window and pass to UndoAction + sal_Int16 nCnt = 0; + const auto& rTabConList = getTableConnections(); + auto aIter2 = rTabConList.begin(); + for(;aIter2 != rTabConList.end();)// the end may change + { + VclPtr 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::supressCrossNaturalJoin(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 000000000..963314690 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryTextView.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#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) + :Window(_pParent) +{ + m_pEdit = VclPtr::Create(this); + m_pEdit->SetRightToLeft(false); + m_pEdit->ClearModifyFlag(); + m_pEdit->SaveValue(); + m_pEdit->SetPosPixel( Point( 0, 0 ) ); + m_pEdit->Show(); +} + +OQueryTextView::~OQueryTextView() +{ + disposeOnce(); +} + +void OQueryTextView::dispose() +{ + m_pEdit.disposeAndClear(); + vcl::Window::dispose(); +} + +void OQueryTextView::GetFocus() +{ + if ( m_pEdit ) + m_pEdit->GrabFocus(); +} + +void OQueryTextView::Resize() +{ + Window::Resize(); + m_pEdit->SetSizePixel( GetOutputSizePixel() ); +} + +OUString OQueryTextView::getStatement() const +{ + return m_pEdit->GetText(); +} + +void OQueryTextView::clear() +{ + std::unique_ptr pUndoAct(new OSqlEditUndoAct( m_pEdit )); + + pUndoAct->SetOriginalText( m_pEdit->GetText() ); + getContainerWindow()->getDesignView()->getController().addUndoActionAndInvalidate( std::move(pUndoAct) ); + + m_pEdit->SetText(OUString()); +} + +void OQueryTextView::setStatement(const OUString& _rsStatement) +{ + m_pEdit->SetText(_rsStatement); +} + +void OQueryTextView::copy() +{ + if(!m_pEdit->IsInAccelAct() ) + m_pEdit->Copy(); +} + +bool OQueryTextView::isCutAllowed() const +{ + return !m_pEdit->GetSelected().isEmpty(); +} + +void OQueryTextView::cut() +{ + if(!m_pEdit->IsInAccelAct() ) + m_pEdit->Cut(); + getContainerWindow()->getDesignView()->getController().setModified(true); +} + +void OQueryTextView::paste() +{ + if(!m_pEdit->IsInAccelAct() ) + m_pEdit->Paste(); + getContainerWindow()->getDesignView()->getController().setModified(true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/QueryViewSwitch.cxx b/dbaccess/source/ui/querydesign/QueryViewSwitch.cxx new file mode 100644 index 000000000..e7d6758f4 --- /dev/null +++ b/dbaccess/source/ui/querydesign/QueryViewSwitch.cxx @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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); + 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->getSqlEdit()->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->getSqlEdit()->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->getSqlEdit()->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::setNoneVisbleRow(sal_Int32 _nRows) +{ + if(m_pDesignView) + m_pDesignView->setNoneVisbleRow(_nRows); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx b/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx new file mode 100644 index 000000000..98d782d8d --- /dev/null +++ b/dbaccess/source/ui/querydesign/SelectionBrowseBox.cxx @@ -0,0 +1,2695 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#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 +#include "QueryDesignFieldUndoAct.hxx" +#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(const OUString& _sFieldName ) + { + bool bAsterisk = _sFieldName.isEmpty() || _sFieldName.toChar() == '*'; + if ( !bAsterisk ) + { + sal_Int32 nTokenCount = comphelper::string::getTokenCount(_sFieldName, '.'); + if ( (nTokenCount == 2 && _sFieldName.getToken(1,'.')[0] == '*' ) + || (nTokenCount == 3 && _sFieldName.getToken(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_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(), 0); + 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->GetBox().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(aTxt.getToken(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(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&) + { + OSL_FAIL("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(long 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; + + long 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*/, long 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 !"); + long 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 (aField.trim() == "*") + { + 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().Check(pEntry->IsVisible()); + m_pVisibleCell->GetBox().SaveValue(); + + 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().Check(pEntry->IsVisible()); + m_pVisibleCell->GetBox().SaveValue(); + m_pVisibleCell->GetBox().Disable(); + m_pVisibleCell->GetBox().EnableInput(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()->ClearModified(); +} + +void OSelectionBrowseBox::notifyTableFieldChanged(const OUString& _sOldAlias, const OUString& _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, const OUString& _sFunctionName, bool& _bListAction, sal_uInt16 _nColumnId) +{ + appendUndoAction(_sOldFunctionName,_sFunctionName,BROW_FUNCTION_ROW,_bListAction); + if ( !m_bVisibleRow[BROW_FUNCTION_ROW] ) + SetRowVisible(BROW_FUNCTION_ROW, true); + RowModified(GetBrowseRow(BROW_FUNCTION_ROW), _nColumnId); +} + +void OSelectionBrowseBox::clearEntryFunctionField(const OUString& _sFieldName,OTableFieldDescRef const & _pEntry, bool& _bListAction,sal_uInt16 _nColumnId) +{ + if ( !(isFieldNameAsterisk( _sFieldName ) && (!_pEntry->isNoneFunction() || _pEntry->IsGroupBy())) ) + return; + + OUString sFunctionName; + GetFunctionName(SQL_TOKEN_COUNT,sFunctionName); + OUString sOldLocalizedFunctionName = _pEntry->GetFunction(); + if ( sOldLocalizedFunctionName != sFunctionName || _pEntry->IsGroupBy() ) + { + // append undo action for the function field + _pEntry->SetFunctionType(FKT_NONE); + _pEntry->SetFunction(OUString()); + _pEntry->SetGroupBy(false); + notifyFunctionFieldChanged(sOldLocalizedFunctionName,_pEntry->GetFunction(),_bListAction,_nColumnId); + } +} + +bool OSelectionBrowseBox::fillColumnRef(const OSQLParseNode* _pColumnRef, const Reference< XConnection >& _rxConnection, OTableFieldDescRef const & _pEntry, bool& _bListAction ) +{ + OSL_ENSURE(_pColumnRef,"No valid parsenode!"); + OUString sColumnName,sTableRange; + OSQLParseTreeIterator::getColumnRange(_pColumnRef,_rxConnection,sColumnName,sTableRange); + return fillColumnRef(sColumnName,sTableRange,_rxConnection->getMetaData(),_pEntry,_bListAction); +} + +bool OSelectionBrowseBox::fillColumnRef(const OUString& _sColumnName, const OUString& _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.isEmpty() && (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( "*", OUString(), 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()->IsModified()) + { + // for the Undo-action + OUString strOldCellContents,sNewValue; + long nRow = GetRealRow(GetCurRow()); + bool bAppendRow = false; + switch (nRow) + { + case BROW_VIS_ROW: + { + bool bOldValue = m_pVisibleCell->GetBox().GetSavedValue() != TRISTATE_FALSE; + strOldCellContents = bOldValue ? OUStringLiteral("1") : OUStringLiteral("0"); + sNewValue = !bOldValue ? OUStringLiteral("1") : OUStringLiteral("0"); + } + if((m_bOrderByUnRelated || pEntry->GetOrderDir() == ORDER_NONE) && + (m_bGroupByUnRelated || !pEntry->IsGroupBy())) + { + pEntry->SetVisible(m_pVisibleCell->GetBox().IsChecked()); + } + else + { + pEntry->SetVisible(); + m_pVisibleCell->GetBox().Check(); + } + 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().Check(); + 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->GetText()); + 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); + OUString sGroupFunctionName = m_aFunctionStrings.copy(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().Check(); + appendUndoAction("0","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->GetText(), ' '); + + 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()->ClearModified(); + + 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","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(long 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; + + long 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(); + long 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, 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(); + long 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 + OUString aFieldName = jxdSource.pListBox->GetEntryText(jxdSource.pEntry); + sal_uInt32 nFieldIndex = jxdSource.pListBox->GetModel()->GetAbsPos(jxdSource.pEntry); + OTableFieldInfo* pInf = static_cast(jxdSource.pEntry->GetUserData()); + + // 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() +{ + long 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().Check(); + pEntry->SetVisible(); + } + else + pEntry->SetVisible(m_pVisibleCell->GetBox().IsChecked()); + } + 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() )); + long 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()) + { + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/querycolmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + sal_uInt16 nItemId = aContextMenu->Execute(this, aMenuPos); + if (nItemId == aContextMenu->GetItemId("delete")) + RemoveField(nColId); + else if (nItemId == aContextMenu->GetItemId("width")) + adjustBrowseBoxColumnWidth( this, nColId ); + } + } + else if(nRow >= 0 && nColId <= HANDLE_ID) + { + if (!static_cast(getDesignView()->getController()).isReadOnly()) + { + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/queryfuncmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + aContextMenu->CheckItem("functions", m_bVisibleRow[BROW_FUNCTION_ROW]); + aContextMenu->CheckItem("tablename", m_bVisibleRow[BROW_TABLE_ROW]); + aContextMenu->CheckItem("alias", m_bVisibleRow[BROW_COLUMNALIAS_ROW]); + aContextMenu->CheckItem("distinct", static_cast(getDesignView()->getController()).isDistinct()); + + aContextMenu->Execute(this, aMenuPos); + + OString sIdent = aContextMenu->GetCurItemIdent(); + 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(_nWhichIsEmpty() ) + 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() ? OUStringLiteral("1") : OUStringLiteral("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: + { + OUString sGroupFunctionName = m_aFunctionStrings.copy(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() && !sGroupFunctionName.equalsIgnoreAsciiCase(strNewText) ) + pEntry->SetGroupBy(false); + + if ( sGroupFunctionName.equalsIgnoreAsciiCase(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); + } + + 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(long 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 !"); + + long nRow = GetRealRow(nRowId); + OUString strText(GetCellText(nRow, nColId)); + return GetDataWindow().LogicToPixel(Size(GetDataWindow().GetTextWidth(strText),0)).Width(); +} + +bool OSelectionBrowseBox::isCutAllowed() const +{ + bool bCutAllowed = false; + long 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: + bCutAllowed = !m_pTextCell->GetSelected().isEmpty(); + break; + } + return bCutAllowed; +} + +void OSelectionBrowseBox::cut() +{ + long nRow = GetRealRow(GetCurRow()); + switch (nRow) + { + case BROW_FIELD_ROW: + { + weld::ComboBox& rComboBox = m_pFieldCell->get_widget(); + rComboBox.cut_entry_clipboard(); + break; + } + default: + m_pTextCell->Cut(); + m_pTextCell->SetModifyFlag(); + } + SaveModified(); + RowModified(GetBrowseRow(nRow), GetCurColumnId()); + + invalidateUndoRedo(); +} + +void OSelectionBrowseBox::paste() +{ + long nRow = GetRealRow(GetCurRow()); + switch (nRow) + { + case BROW_FIELD_ROW: + { + weld::ComboBox& rComboBox = m_pFieldCell->get_widget(); + rComboBox.paste_entry_clipboard(); + break; + } + default: + m_pTextCell->Paste(); + m_pTextCell->SetModifyFlag(); + } + RowModified(GetBrowseRow(nRow), GetCurColumnId()); + invalidateUndoRedo(); +} + +bool OSelectionBrowseBox::isPasteAllowed() const +{ + bool bPasteAllowed = true; + long 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() +{ + long nRow = GetRealRow(GetCurRow()); + switch (nRow) + { + case BROW_FIELD_ROW: + { + weld::ComboBox& rComboBox = m_pFieldCell->get_widget(); + rComboBox.copy_entry_clipboard(); + break; + } + default: + m_pTextCell->Copy(); + } +} + +void OSelectionBrowseBox::appendUndoAction(const OUString& _rOldValue, const OUString& _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,const OUString& _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 OString& _sHelpId) +{ + m_pTextCell->SetText(_sText); + m_pTextCell->ClearModifyFlag(); + 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( ::vcl::AccessibleBrowseBoxObjType _eObjType,sal_Int32 _nPosition) const +{ + OUString sRetText; + switch( _eObjType ) + { + case ::vcl::BBTYPE_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(getFields().size() > o3tl::make_unsigned(_nColumnPos - 1)) + 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(const OUString& rFieldName, OTableFieldDescRef const & rInfo) const +{ + for (auto const& field : getFields()) + { + if ( field->GetFieldAlias() == rFieldName ) + { + *rInfo = *field; + return true; + } + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx b/dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx new file mode 100644 index 000000000..1668b4913 --- /dev/null +++ b/dbaccess/source/ui/querydesign/SelectionBrowseBox.hxx @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_SELECTIONBROWSEBOX_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_SELECTIONBROWSEBOX_HXX + +#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; + + long m_nSeekRow; + BrowserMode m_nMode; // remember the BrowseModes + VclPtr 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(const OUString& 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, 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 SetNoneVisbleRow(long 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(long _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( ::vcl::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( long 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(long nRow, sal_uInt16 nCol) override; + virtual void InitController(::svt::CellControllerRef& rController, long 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(long 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 ); + long GetRealRow(long nRow) const; + long GetBrowseRow(long nRowId) const; + bool GetFunctionName(sal_uInt32 _nFunctionTokenId, OUString& rFkt); + void appendUndoAction(const OUString& _rOldValue,const OUString& _rNewValue,sal_Int32 _nRow, bool& _bListAction); + void appendUndoAction(const OUString& _rOldValue,const OUString& _rNewValue,sal_Int32 _nRow); + OTableFields& getFields() const; + static void enableControl(const OTableFieldDescRef& _rEntry,Window* _pControl); + void setTextCellContext(const OTableFieldDescRef& _rEntry,const OUString& _sText,const OString& _sHelpId); + void invalidateUndoRedo(); + OTableFieldDescRef getEntry(OTableFields::size_type _nPos); + + void adjustSelectionMode( bool _bClickedOntoHeader, bool _bClickedOntoHandleCol ); + + /** save the field change in save modified + @param _sFieldName + The field name inserted by the user. + @param _pEntry + The entry which will contain the necessary entries. + @param _bListAction + Will be set to 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, + const OUString& _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,const OUString& _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,const OUString& _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(const OUString& _sFieldName,OTableFieldDescRef const & _pEntry, bool& _bListAction,sal_uInt16 _nColumnId); + + /** remove or insert the necessary function types + @param _pEntry + The currently edited entry. + */ + void setFunctionCell(OTableFieldDescRef const & _pEntry); + + using ::svt::EditBrowseBox::AcceptDrop; + using ::svt::EditBrowseBox::ExecuteDrop; + using ::svt::EditBrowseBox::MouseButtonDown; + using ::svt::EditBrowseBox::MouseButtonUp; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_SELECTIONBROWSEBOX_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableConnection.cxx b/dbaccess/source/ui/querydesign/TableConnection.cxx new file mode 100644 index 000000000..ada4b5990 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableConnection.cxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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,const TTableConnectionData::value_type& _pTabConnData ) + :Window(_pContainer) + ,m_pData( _pTabConnData ) + ,m_pParent( _pContainer ) + ,m_bSelected( false ) + { + Init(); + Show(); + } + + OTableConnection::OTableConnection( const OTableConnection& _rConn ) + : VclReferenceBase() + ,Window(_rConn.m_pParent.get()) + ,m_pData(_rConn.GetData()->NewInstance()) + ,m_pParent(nullptr) + { + *this = _rConn; + } + + void OTableConnection::Init() + { + // initialise linelist with defaults + OConnectionLineDataVec& rLineData = GetData()->GetConnLineDataList(); + m_vConnLine.reserve(rLineData.size()); + for (auto const& elem : rLineData) + m_vConnLine.emplace_back( new OConnectionLine(this, elem) ); + } + + void OTableConnection::clearLineData() + { + m_vConnLine.clear(); + } + void OTableConnection::UpdateLineList() + { + // delete linelist + clearLineData(); + + Init(); + } + + OTableConnection& OTableConnection::operator=( const OTableConnection& rConn ) + { + if( &rConn == this ) + return *this; + + // delete linelist + clearLineData(); + + // copy linelist + if(! rConn.GetConnLineList().empty() ) + { + const std::vector>& 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 000000000..107d8a9d1 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableConnectionData.cxx @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include + +using namespace dbaui; + +OTableConnectionData::OTableConnectionData() +{ + Init(); +} + +OTableConnectionData::OTableConnectionData(const TTableWindowData::value_type& _pReferencingTable + ,const TTableWindowData::value_type& _pReferencedTable ) + :m_pReferencingTable(_pReferencingTable) + ,m_pReferencedTable(_pReferencedTable) +{ + Init(); +} + +void OTableConnectionData::Init() +{ + // initialise linedatalist with defaults + OSL_ENSURE(m_vConnLineData.empty(), "OTableConnectionData::Init() : call only with empty line list!"); + ResetConnLines(); + // this creates the defaults +} + +OTableConnectionData::OTableConnectionData( const OTableConnectionData& rConnData ) +{ + *this = rConnData; +} + +void OTableConnectionData::CopyFrom(const OTableConnectionData& rSource) +{ + *this = rSource; + // here I revert to the (non-virtual) operator =, which only copies my members +} + +OTableConnectionData::~OTableConnectionData() +{ + // delete LineDataList + OConnectionLineDataVec().swap(m_vConnLineData); +} + +OTableConnectionData& OTableConnectionData::operator=( const OTableConnectionData& rConnData ) +{ + if (&rConnData == this) + return *this; + + m_pReferencingTable = rConnData.m_pReferencingTable; + m_pReferencedTable = rConnData.m_pReferencedTable; + m_aConnName = rConnData.m_aConnName; + + // clear line list + ResetConnLines(); + + // and copy + for (auto const& elem : rConnData.GetConnLineDataList()) + m_vConnLineData.push_back(new OConnectionLineData(*elem)); + + return *this; +} + +void OTableConnectionData::SetConnLine( sal_uInt16 nIndex, const OUString& rSourceFieldName, const OUString& rDestFieldName ) +{ + if (sal_uInt16(m_vConnLineData.size()) < nIndex) + return; + + // == still allowed, this corresponds to an Append + + if (m_vConnLineData.size() == nIndex) + { + AppendConnLine(rSourceFieldName, rDestFieldName); + return; + } + + OConnectionLineDataRef pConnLineData = m_vConnLineData[nIndex]; + OSL_ENSURE(pConnLineData != nullptr, "OTableConnectionData::SetConnLine : have invalid LineData object"); + + pConnLineData->SetSourceFieldName( rSourceFieldName ); + pConnLineData->SetDestFieldName( rDestFieldName ); +} + +bool OTableConnectionData::AppendConnLine( const OUString& rSourceFieldName, const OUString& rDestFieldName ) +{ + for (auto const& elem : m_vConnLineData) + { + if(elem->GetDestFieldName() == rDestFieldName && elem->GetSourceFieldName() == rSourceFieldName) + return true; + } + OConnectionLineDataRef pNew = new OConnectionLineData(rSourceFieldName, rDestFieldName); + if (!pNew.is()) + return false; + + m_vConnLineData.push_back(pNew); + return true; +} + +void OTableConnectionData::ResetConnLines() +{ + OConnectionLineDataVec().swap(m_vConnLineData); +} + +std::shared_ptr OTableConnectionData::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 000000000..95476cafd --- /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 +#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() ); + for (auto const& criteria : m_aCriteria) + { + aCriteria[c].Name = "Criterion_" + OUString::number( c ); + aCriteria[c].Value <<= criteria; + ++c; + } + + o_rSettings.put( "Criteria", aCriteria ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableFieldInfo.cxx b/dbaccess/source/ui/querydesign/TableFieldInfo.cxx new file mode 100644 index 000000000..15c60b833 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableFieldInfo.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 "TableFieldInfo.hxx" + +using namespace dbaui; + +OTableFieldInfo::OTableFieldInfo() : + m_eFieldType(TAB_NORMAL_FIELD), m_eDataType(1000) +{ +} + +OTableFieldInfo::~OTableFieldInfo() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableFieldInfo.hxx b/dbaccess/source/ui/querydesign/TableFieldInfo.hxx new file mode 100644 index 000000000..7d0e83b4c --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableFieldInfo.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_TABLEFIELDINFO_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_TABLEFIELDINFO_HXX + +#include +#include + +namespace dbaui +{ + class OTableFieldInfo + { + private: + ETableFieldType m_eFieldType; + sal_Int32 m_eDataType; + + public: + OTableFieldInfo(); + ~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; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_TABLEFIELDINFO_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableWindow.cxx b/dbaccess/source/ui/querydesign/TableWindow.cxx new file mode 100644 index 000000000..d32ba27b9 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindow.cxx @@ -0,0 +1,744 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 ::utl; +using namespace ::com::sun::star; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::sdbcx; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::accessibility; + +namespace DatabaseObject = css::sdb::application::DatabaseObject; + +#define TABWIN_SIZING_AREA 4 +#define TABWIN_WIDTH_MIN 90 +#define TABWIN_HEIGHT_MIN 80 + +namespace { + +void Draw3DBorder(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + // Use the System Style-Settings for my colours + const StyleSettings& aSystemStyle = Application::GetSettings().GetStyleSettings(); + + // Black lines for bottom and right + rRenderContext.SetLineColor(aSystemStyle.GetDarkShadowColor()); + rRenderContext.DrawLine(rRect.BottomLeft(), rRect.BottomRight()); + rRenderContext.DrawLine(rRect.BottomRight(), rRect.TopRight()); + + // Dark grey lines over the black lines + rRenderContext.SetLineColor(aSystemStyle.GetShadowColor()); + Point aEHvector(1, 1); + rRenderContext.DrawLine(rRect.BottomLeft() + Point(1, -1), rRect.BottomRight() - aEHvector); + rRenderContext.DrawLine(rRect.BottomRight() - aEHvector, rRect.TopRight() + Point(-1, 1)); + + // Light grey lines for top and left + rRenderContext.SetLineColor(aSystemStyle.GetLightColor()); + rRenderContext.DrawLine(rRect.BottomLeft() + Point(1, -2), rRect.TopLeft() + aEHvector); + rRenderContext.DrawLine(rRect.TopLeft() + aEHvector, rRect.TopRight() + Point(-2, 1)); +} + +} + +OTableWindow::OTableWindow( vcl::Window* pParent, const TTableWindowData::value_type& pTabWinData ) + : ::comphelper::OContainerListener(m_aMutex) + ,Window( pParent, WB_3DLOOK|WB_MOVEABLE ) + ,m_aTypeImage( VclPtr::Create(this) ) + ,m_xTitle( VclPtr::Create(this) ) + ,m_pData( pTabWinData ) + ,m_nMoveCount(0) + ,m_nMoveIncrement(1) + ,m_nSizingFlags( SizingFlags::NONE ) +{ + + // Set position and size + if( GetData()->HasPosition() ) + SetPosPixel( GetData()->GetPosition() ); + + if( GetData()->HasSize() ) + SetSizePixel( GetData()->GetSize() ); + + // Set background + const StyleSettings& aSystemStyle = Application::GetSettings().GetStyleSettings(); + SetBackground(Wallpaper(aSystemStyle.GetFaceColor())); + // Set the text colour even though there is no text, + // because derived classes might need it + SetTextColor(aSystemStyle.GetButtonTextColor()); + + EnableClipSiblings(); +} + +OTableWindow::~OTableWindow() +{ + disposeOnce(); +} + +void OTableWindow::dispose() +{ + if (m_xListBox) + { + OSL_ENSURE(m_xListBox->GetEntryCount()==0,"Forgot to call EmptyListbox()!"); + } + m_xListBox.disposeAndClear(); + if ( m_pContainerListener.is() ) + m_pContainerListener->dispose(); + + m_aTypeImage.disposeAndClear(); + 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() +{ + m_xListBox->Clear(); + 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 + Image aPrimKeyImage(StockImage::Yes, BMP_PRIMARY_KEY); + + if (GetData()->IsShowAll()) + { + SvTreeListEntry* pEntry = m_xListBox->InsertEntry( OUString("*") ); + pEntry->SetUserData( createUserData(nullptr,false) ); + } + + Reference xPKeyColumns; + try + { + xPKeyColumns = dbtools::getPrimaryKeyColumns_throw(m_pData->getTable()); + } + catch(Exception&) + { + OSL_FAIL("Exception occurred!"); + } + 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(); + + SvTreeListEntry* pEntry = nullptr; + for (; pIter != pEnd; ++pIter) + { + bool bPrimaryKeyColumn = xPKeyColumns.is() && xPKeyColumns->hasByName( *pIter ); + // is this column in the primary key + if ( bPrimaryKeyColumn ) + pEntry = m_xListBox->InsertEntry(*pIter, aPrimKeyImage, aPrimKeyImage); + else + pEntry = m_xListBox->InsertEntry(*pIter); + + Reference xColumn(xColumns->getByName(*pIter),UNO_QUERY); + if ( xColumn.is() ) + pEntry->SetUserData( createUserData(xColumn,bPrimaryKeyColumn) ); + } + } + } + catch(Exception&) + { + OSL_FAIL("Exception occurred!"); + } +} + +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; + + SvTreeListEntry* pEntry = m_xListBox->First(); + + while(pEntry) + { + void* pUserData = pEntry->GetUserData(); + deleteUserData(pUserData); + SvTreeListEntry* pNextEntry = m_xListBox->Next(pEntry); + m_xListBox->GetModel()->Remove(pEntry); + pEntry = pNextEntry; + } +} + +void OTableWindow::impl_updateImage() +{ + ImageProvider aImageProvider( getDesignView()->getController().getConnection() ); + + Image aImage; + aImageProvider.getImages( GetComposedName(), m_pData->isQuery() ? DatabaseObject::QUERY : DatabaseObject::TABLE, aImage ); + + if ( !aImage ) + { + OSL_FAIL( "OTableWindow::impl_updateImage: no images!" ); + return; + } + + m_aTypeImage->SetModeImage( aImage ); + m_aTypeImage->Show(); +} + +bool OTableWindow::Init() +{ + // create list box if necessary + if ( !m_xListBox ) + { + m_xListBox = VclPtr::Create(this); + OSL_ENSURE( m_xListBox != nullptr, "OTableWindow::Init() : CreateListBox returned NULL !" ); + m_xListBox->SetSelectionMode( SelectionMode::Multiple ); + } + + // Set the title + m_xTitle->SetText( m_pData->GetWinName() ); + m_xTitle->Show(); + + m_xListBox->Show(); + + // add the fields to the ListBox + clearListBox(); + FillListBox(); + m_xListBox->SelectAll( false ); + + 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())); + + long nTitleHeight = CalcZoom( GetTextHeight() )+ CalcZoom( 4 ); + + // Set the title and ListBox + long n5Pos = CalcZoom(5); + long nPositionX = n5Pos; + long nPositionY = n5Pos; + + // position the image which indicates the type + m_aTypeImage->SetPosPixel( Point( nPositionX, nPositionY ) ); + Size aImageSize( m_aTypeImage->GetImage().GetSizePixel() ); + m_aTypeImage->SetSizePixel( aImageSize ); + + if ( nTitleHeight < aImageSize.Height() ) + nTitleHeight = aImageSize.Height(); + + nPositionX += aImageSize.Width() + CalcZoom( 2 ); + m_xTitle->SetPosSizePixel( Point( nPositionX, nPositionY ), Size( aOutSize.Width() - nPositionX - n5Pos, nTitleHeight ) ); + + 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 ) +{ + vcl::Font aFont = m_xTitle->GetFont(); + aFont.SetWeight( bBold?WEIGHT_BOLD:WEIGHT_NORMAL ); + m_xTitle->SetFont( aFont ); + m_xTitle->Invalidate(); +} + +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 && m_xListBox->GetSelectionCount() != 0) + m_xListBox->SelectAll(false); +} + +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::HandleKeyInput( const KeyEvent& rEvt ) +{ + const vcl::KeyCode& rCode = rEvt.GetKeyCode(); + sal_uInt16 nCode = rCode.GetCode(); + bool bShift = rCode.IsShift(); + bool bCtrl = rCode.IsMod1(); + + bool bHandle = false; + + if( !bCtrl && !bShift && (nCode==KEY_DELETE) ) + { + Remove(); + bHandle = true; + } + return bHandle; +} + +bool OTableWindow::ExistsAConn() const +{ + return getTableView()->ExistsAConn(this); +} + +void OTableWindow::EnumValidFields(std::vector< OUString>& arrstrFields) +{ + arrstrFields.clear(); + // This default implementation counts every item in the ListBox ... for any other behaviour it must be over-written + if ( m_xListBox ) + { + arrstrFields.reserve(m_xListBox->GetEntryCount()); + SvTreeListEntry* pEntryLoop = m_xListBox->First(); + while (pEntryLoop) + { + arrstrFields.push_back(m_xListBox->GetEntryText(pEntryLoop)); + pEntryLoop = m_xListBox->Next(pEntryLoop); + } + } +} + +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(*this, 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 + { + SvTreeListEntry* pCurrent = m_xListBox->GetCurEntry(); + if ( pCurrent ) + ptWhere = m_xListBox->GetEntryPosition(pCurrent); + else + ptWhere = m_xTitle->GetPosPixel(); + } + + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/jointablemenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + if (aContextMenu->Execute(this, ptWhere)) + Remove(); + } + break; + } + default: + Window::Command(rEvt); + } +} + +bool OTableWindow::PreNotify(NotifyEvent& rNEvt) +{ + bool bHandled = false; + switch (rNEvt.GetType()) + { + case MouseNotifyEvent::KEYINPUT: + { + if ( getDesignView()->getController().isReadOnly() ) + break; + + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + const vcl::KeyCode& rCode = pKeyEvent->GetKeyCode(); + if ( rCode.IsMod1() ) + { + Point aStartPoint = GetPosPixel(); + if ( rCode.IsShift() ) + { + aStartPoint.setX( GetSizePixel().Width() ); + aStartPoint.setY( GetSizePixel().Height() ); + } + + switch( rCode.GetCode() ) + { + case KEY_DOWN: + bHandled = true; + aStartPoint.AdjustY(m_nMoveIncrement ); + break; + case KEY_UP: + bHandled = true; + aStartPoint.AdjustY(-m_nMoveIncrement ); + break; + case KEY_LEFT: + bHandled = true; + aStartPoint.AdjustX(-m_nMoveIncrement ); + break; + case KEY_RIGHT: + bHandled = true; + aStartPoint.AdjustX(m_nMoveIncrement ); + break; + } + if ( bHandled ) + { + if ( rCode.IsShift() ) + { + OJoinTableView* pView = getTableView(); + Point ptOld = GetPosPixel(); + Size aSize = pView->getRealOutputSize(); + Size aNewSize(aStartPoint.X(),aStartPoint.Y()); + if ( ((ptOld.X() + aNewSize.Width()) <= aSize.Width()) + && ((ptOld.Y() + aNewSize.Height()) <= aSize.Height()) ) + { + if ( aNewSize.Width() < TABWIN_WIDTH_MIN ) + aNewSize.setWidth( TABWIN_WIDTH_MIN ); + if ( aNewSize.Height() < TABWIN_HEIGHT_MIN ) + aNewSize.setHeight( TABWIN_HEIGHT_MIN ); + + Size szOld = GetSizePixel(); + + aNewSize = Size(pView->CalcZoom(aNewSize.Width()),pView->CalcZoom(aNewSize.Height())); + SetPosSizePixel( ptOld, aNewSize ); + pView->TabWinSized(this, ptOld, szOld); + Invalidate( InvalidateFlags::NoChildren ); + } + } + else + { + // remember how often the user moved our window + ++m_nMoveCount; + if( m_nMoveCount == 5 ) + m_nMoveIncrement = 10; + else if( m_nMoveCount > 15 ) + m_nMoveCount = m_nMoveIncrement = 20; + + Point aOldDataPoint = GetData()->GetPosition(); + Point aNewDataPoint = aStartPoint + getTableView()->GetScrollOffset(); + if ( aNewDataPoint.X() > -1 && aNewDataPoint.Y() > -1 ) + { + OJoinTableView* pView = getTableView(); + if ( pView->isMovementAllowed(aNewDataPoint, GetData()->GetSize()) ) + { + SetPosPixel(aStartPoint); + + // aNewDataPoint can not be used here because SetPosPixel reset it + pView->EnsureVisible(GetData()->GetPosition(), GetData()->GetSize()); + pView->TabWinMoved(this,aOldDataPoint); + Invalidate(InvalidateFlags::NoChildren); + getDesignView()->getController().setModified( true ); + } + else + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + } + else + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + } + m_nSizingFlags = SizingFlags::NONE; + } + else + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + } + else + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + break; + } + case MouseNotifyEvent::KEYUP: + { + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + const vcl::KeyCode& rCode = pKeyEvent->GetKeyCode(); + sal_uInt16 nKeyCode = rCode.GetCode(); + if ( rCode.IsMod2() && nKeyCode != KEY_UP && nKeyCode != KEY_DOWN && nKeyCode != KEY_LEFT && nKeyCode != KEY_RIGHT ) + { + m_nMoveCount = 0; // reset our movement count + m_nMoveIncrement = 1; + } + break; + } + default: + break; + } + if (!bHandled) + return Window::PreNotify(rNEvt); + return true; +} + +OUString OTableWindow::getTitle() const +{ + return m_xTitle->GetText(); +} + +void OTableWindow::_elementInserted( const container::ContainerEvent& /*_rEvent*/ ) +{ + FillListBox(); +} + +void OTableWindow::_elementRemoved( const container::ContainerEvent& /*_rEvent*/ ) +{ + FillListBox(); +} + +void OTableWindow::_elementReplaced( const container::ContainerEvent& /*_rEvent*/ ) +{ + FillListBox(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableWindowAccess.cxx b/dbaccess/source/ui/querydesign/TableWindowAccess.cxx new file mode 100644 index 000000000..3cd87ded7 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowAccess.cxx @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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) + :VCLXAccessibleComponent(_pTable->GetComponentInterface().is() ? _pTable->GetWindowPeer() : nullptr) + ,m_pTable(_pTable) + { + } + void SAL_CALL OTableWindowAccess::disposing() + { + m_pTable = nullptr; + VCLXAccessibleComponent::disposing(); + } + void OTableWindowAccess::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) + { + if ( rVclWindowEvent.GetId() == VclEventId::ObjectDying ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_pTable = nullptr; + } + + VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent ); + } + Any SAL_CALL OTableWindowAccess::queryInterface( const Type& aType ) + { + Any aRet(VCLXAccessibleComponent::queryInterface( aType )); + return aRet.hasValue() ? aRet : OTableWindowAccess_BASE::queryInterface( aType ); + } + Sequence< Type > SAL_CALL OTableWindowAccess::getTypes( ) + { + return ::comphelper::concatSequences(VCLXAccessibleComponent::getTypes(),OTableWindowAccess_BASE::getTypes()); + } + OUString SAL_CALL OTableWindowAccess::getImplementationName() + { + return "org.openoffice.comp.dbu.TableWindowAccessibility"; + } + Sequence< OUString > SAL_CALL OTableWindowAccess::getSupportedServiceNames() + { + return { "com.sun.star.accessibility.Accessible", + "com.sun.star.accessibility.AccessibleContext" }; + } + // XAccessibleContext + sal_Int32 SAL_CALL OTableWindowAccess::getAccessibleChildCount( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int32 nCount = 0; + if(m_pTable) + { + ++nCount; + if(m_pTable->GetListBox()) + ++nCount; + } + return nCount; + } + Reference< XAccessible > SAL_CALL OTableWindowAccess::getAccessibleChild( sal_Int32 i ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XAccessible > aRet; + if (m_pTable && !m_pTable->IsDisposed()) + { + switch(i) + { + case 0: + { + VclPtr 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_Int32 SAL_CALL OTableWindowAccess::getAccessibleIndexInParent( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int32 nIndex = -1; + if( m_pTable ) + { + // search the position of our table window in the table window map + bool bFoundElem = false; + for (auto const& tabWin : m_pTable->getTableView()->GetTabWinMap()) + { + if (tabWin.second == m_pTable) + { + bFoundElem = true; + break; + } + ++nIndex; + } + nIndex = bFoundElem? nIndex : -1; + } + return nIndex; + } + sal_Int16 SAL_CALL OTableWindowAccess::getAccessibleRole( ) + { + return AccessibleRole::PANEL; // ? or may be an AccessibleRole::WINDOW + } + Reference< XAccessibleRelationSet > SAL_CALL OTableWindowAccess::getAccessibleRelationSet( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return this; + } + // XAccessibleComponent + Reference< XAccessible > SAL_CALL OTableWindowAccess::getAccessibleAtPoint( const awt::Point& _aPoint ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XAccessible > aRet; + if(m_pTable && !m_pTable->IsDisposed()) + { + Point aPoint(_aPoint.X,_aPoint.Y); + tools::Rectangle aRect(m_pTable->GetDesktopRectPixel()); + if( aRect.IsInside(aPoint) ) + aRet = this; + else if( m_pTable->GetListBox()->GetDesktopRectPixel().IsInside(aPoint)) + aRet = m_pTable->GetListBox()->GetAccessible(); + } + return aRet; + } + Reference< XAccessible > OTableWindowAccess::getParentChild(sal_Int32 _nIndex) + { + Reference< XAccessible > xReturn; + Reference< XAccessible > xParent = getAccessibleParent(); + if ( xParent.is() ) + { + Reference< XAccessibleContext > xParentContext = xParent->getAccessibleContext(); + if ( xParentContext.is() ) + { + xReturn = xParentContext->getAccessibleChild(_nIndex); + } + } + return xReturn; + } + + sal_Int32 SAL_CALL OTableWindowAccess::getRelationCount( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return m_pTable ? m_pTable->getTableView()->getConnectionCount(m_pTable) : sal_Int32(0); + } + AccessibleRelation SAL_CALL OTableWindowAccess::getRelation( sal_Int32 nIndex ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if( nIndex < 0 || nIndex >= getRelationCount() ) + throw IndexOutOfBoundsException(); + + AccessibleRelation aRet; + if( m_pTable ) + { + OJoinTableView* pView = m_pTable->getTableView(); + auto aIter = pView->getTableConnections(m_pTable) + nIndex; + aRet.TargetSet.realloc(1); + aRet.TargetSet[0] = 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 000000000..d07c8214a --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowData.cxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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 + ,const OUString& _rComposedName + ,const OUString& rTableName + ,const OUString& rWinName ) + :m_xTable(_xTable) + ,m_aTableName( rTableName ) + ,m_aWinName( rWinName ) + ,m_sComposedName(_rComposedName) + ,m_aPosition( Point(-1,-1) ) + ,m_aSize( Size(-1,-1) ) + ,m_bShowAll( true ) + ,m_bIsQuery(false) + ,m_bIsValid(true) +{ + if( m_aWinName.isEmpty() ) + m_aWinName = m_aTableName; + + listen(); +} + +OTableWindowData::~OTableWindowData() +{ + Reference xComponent( 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 000000000..a4ba5f002 --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowListBox.cxx @@ -0,0 +1,370 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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) + , pEntry(pBox->FirstSelected()) +{ } + +const sal_uLong SCROLLING_TIMESPAN = 500; +const long LISTBOX_SCROLLING_AREA = 6; +OTableWindowListBox::OTableWindowListBox( OTableWindow* pParent ) + :SvTreeListBox( pParent, WB_HASBUTTONS | WB_BORDER) + ,m_aMousePos( Point(0,0) ) + ,m_pTabWin( pParent ) + ,m_nDropEvent(nullptr) + ,m_nUiEvent(nullptr) + ,m_bReallyScrolled( false ) +{ + m_aScrollTimer.SetTimeout( SCROLLING_TIMESPAN ); + SetDoubleClickHdl( LINK(this, OTableWindowListBox, OnDoubleClick) ); + + SetSelectionMode(SelectionMode::Single); + + SetHighlightRange( ); +} + +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); + if( m_aScrollTimer.IsActive() ) + m_aScrollTimer.Stop(); + m_pTabWin.clear(); + SvTreeListBox::dispose(); +} + +SvTreeListEntry* OTableWindowListBox::GetEntryFromText( const OUString& rEntryText ) +{ + // iterate through the list + SvTreeList* pTreeList = GetModel(); + SvTreeListEntry* pEntry = pTreeList->First(); + 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(); + } + while( pEntry ) + { + if(bCase ? rEntryText == GetEntryText(pEntry) : rEntryText.equalsIgnoreAsciiCase(GetEntryText(pEntry))) + { + return pEntry; + } + pEntry = pTreeList->Next(pEntry); + } + } + catch(SQLException&) + { + } + + return nullptr; +} + +void OTableWindowListBox::NotifyScrolled() +{ + m_bReallyScrolled = true; +} + +void OTableWindowListBox::NotifyEndScroll() +{ + if (m_bReallyScrolled) + // connections of this table, if any, should be redrawn + m_pTabWin->getTableView()->Invalidate(InvalidateFlags::NoChildren); + + // without InvalidateFlags::NoChildren all tables would be redrawn, + // so: flickering + m_bReallyScrolled = false; +} + +bool OTableWindowListBox::PreNotify(NotifyEvent& rNEvt) +{ + bool bHandled = false; + switch (rNEvt.GetType()) + { + case MouseNotifyEvent::KEYINPUT: + { + const KeyEvent* pKeyEvent = rNEvt.GetKeyEvent(); + const vcl::KeyCode& rCode = pKeyEvent->GetKeyCode(); + + if (rCode.GetCode() != KEY_RETURN) + { + if(m_pTabWin) + { + bHandled = m_pTabWin->HandleKeyInput(*pKeyEvent); + } + break; + } + + if (rCode.IsMod1() || rCode.IsMod2() || rCode.IsShift()) + break; + if (FirstSelected()) + static_cast(Window::GetParent())->OnEntryDoubleClicked(FirstSelected()); + break; + } + default: + break; + } + + if (!bHandled) + return SvTreeListBox::PreNotify(rNEvt); + return true; +} + +IMPL_LINK_NOARG( OTableWindowListBox, ScrollUpHdl, Timer*, void ) +{ + SvTreeListEntry* pEntry = GetEntry( m_aMousePos ); + if( !pEntry ) + return; + + if( pEntry != Last() ) + { + ScrollOutputArea( -1 ); + pEntry = GetEntry( m_aMousePos ); + Select( pEntry ); + } +} + +IMPL_LINK_NOARG( OTableWindowListBox, ScrollDownHdl, Timer*, void ) +{ + SvTreeListEntry* pEntry = GetEntry( m_aMousePos ); + if( !pEntry ) + return; + + if( pEntry != Last() ) + { + ScrollOutputArea( 1 ); + pEntry = GetEntry( m_aMousePos ); + Select( pEntry ); + } +} + +void OTableWindowListBox::StartDrag( sal_Int8 /*nAction*/, const Point& /*rPosPixel*/ ) +{ + 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 = FirstSelected() == First() && m_pTabWin->GetData()->IsShowAll(); + EndSelection(); + // create a description of the source + OJoinExchangeData jxdSource(this); + // put it into an exchange object + rtl::Reference pJoin = new OJoinExchObj(jxdSource,bFirstNotAllowed); + pJoin->StartDrag(this, DND_ACTION_LINK, this); + } +} + +sal_Int8 OTableWindowListBox::AcceptDrop( const AcceptDropEvent& _rEvt ) +{ + sal_Int8 nDND_Action = DND_ACTION_NONE; + // check the format + if ( !OJoinExchObj::isFormatAvailable(GetDataFlavorExVector(),SotClipboardFormatId::SBA_TABID) // this means that the first entry is to be dragged + && OJoinExchObj::isFormatAvailable(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) + SelectAll(false); + else + { + // hit test + m_aMousePos = _rEvt.maPosPixel; + Size aOutputSize = GetOutputSizePixel(); + SvTreeListEntry* pEntry = GetEntry( m_aMousePos ); + if( !pEntry ) + return DND_ACTION_NONE; + + // Scrolling Areas + tools::Rectangle aBottomScrollArea( Point(0, aOutputSize.Height()-LISTBOX_SCROLLING_AREA), + Size(aOutputSize.Width(), LISTBOX_SCROLLING_AREA) ); + tools::Rectangle aTopScrollArea( Point(0,0), Size(aOutputSize.Width(), LISTBOX_SCROLLING_AREA) ); + + // scroll up if the pointer is on the upper scroll area + if( aBottomScrollArea.IsInside(m_aMousePos) ) + { + if( !m_aScrollTimer.IsActive() ) + { + m_aScrollTimer.SetInvokeHandler( LINK(this, OTableWindowListBox, ScrollUpHdl) ); + ScrollUpHdl( nullptr ); + } + } + // scroll down if the pointer is on the lower scroll area + else if( aTopScrollArea.IsInside(m_aMousePos) ) + { + if( !m_aScrollTimer.IsActive() ) + { + m_aScrollTimer.SetInvokeHandler( LINK(this, OTableWindowListBox, ScrollDownHdl) ); + ScrollDownHdl( nullptr ); + } + } + else + { + if( m_aScrollTimer.IsActive() ) + m_aScrollTimer.Stop(); + } + + // automatically select right entry when dragging + if ((FirstSelected() != pEntry) || NextSelected(FirstSelected())) + SelectAll(false); + Select(pEntry); + + // one cannot drop on the first (*) entry + if(!( m_pTabWin->GetData()->IsShowAll() && (pEntry==First()) )) + 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); + + return DND_ACTION_LINK; + } + return DND_ACTION_NONE; +} + +void OTableWindowListBox::LoseFocus() +{ + if(m_pTabWin) + m_pTabWin->setActive(false); + SvTreeListBox::LoseFocus(); +} + +void OTableWindowListBox::GetFocus() +{ + if(m_pTabWin) + m_pTabWin->setActive(); + + if (GetCurEntry() != nullptr) + { + if ( GetSelectionCount() == 0 || GetCurEntry() != FirstSelected() ) + { + if ( FirstSelected() ) + Select(FirstSelected(), false); + Select(GetCurEntry()); + } + else + ShowFocusRect(FirstSelected()); + } + SvTreeListBox::GetFocus(); +} + +IMPL_LINK_NOARG( OTableWindowListBox, OnDoubleClick, SvTreeListBox *, bool ) +{ + // tell my parent + vcl::Window* pParent = Window::GetParent(); + OSL_ENSURE(pParent != nullptr, "OTableWindowListBox::OnDoubleClick : have no Parent !"); + + static_cast(pParent)->OnEntryDoubleClicked(GetHdlEntry()); + + return false; +} + +void OTableWindowListBox::Command(const CommandEvent& rEvt) +{ + switch (rEvt.GetCommand()) + { + case CommandEventId::ContextMenu: + { + static_cast(Window::GetParent())->Command(rEvt); + break; + } + default: + SvTreeListBox::Command(rEvt); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/TableWindowTitle.cxx b/dbaccess/source/ui/querydesign/TableWindowTitle.cxx new file mode 100644 index 000000000..952063d5d --- /dev/null +++ b/dbaccess/source/ui/querydesign/TableWindowTitle.cxx @@ -0,0 +1,187 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#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 ) : + FixedText( pParent, WB_3DLOOK|WB_LEFT|WB_NOLABEL|WB_VCENTER ) + ,m_pTabWin( pParent ) +{ + // set background- and text colour + StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings(); + SetBackground(Wallpaper(aSystemStyle.GetFaceColor())); + SetTextColor(aSystemStyle.GetButtonTextColor()); + + vcl::Font aFont( GetFont() ); + aFont.SetTransparent( true ); + SetFont( aFont ); +} + +OTableWindowTitle::~OTableWindowTitle() +{ + disposeOnce(); +} + +void OTableWindowTitle::dispose() +{ + m_pTabWin.clear(); + FixedText::dispose(); +} + +void OTableWindowTitle::GetFocus() +{ + if(m_pTabWin) + m_pTabWin->GetFocus(); + else + FixedText::GetFocus(); +} + +void OTableWindowTitle::LoseFocus() +{ + if (m_pTabWin) + m_pTabWin->LoseFocus(); + else + FixedText::LoseFocus(); +} + +void OTableWindowTitle::RequestHelp( const HelpEvent& rHEvt ) +{ + if(!m_pTabWin) + return; + + OUString aHelpText = m_pTabWin->GetComposedName(); + if( aHelpText.isEmpty()) + return; + + // show help + tools::Rectangle aItemRect(Point(0,0),GetSizePixel()); + aItemRect = LogicToPixel( aItemRect ); + Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); + aItemRect.SetLeft( aPt.X() ); + aItemRect.SetTop( aPt.Y() ); + aPt = OutputToScreenPixel( aItemRect.BottomRight() ); + aItemRect.SetRight( aPt.X() ); + aItemRect.SetBottom( aPt.Y() ); + if( rHEvt.GetMode() == HelpEventMode::BALLOON ) + Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aHelpText); + else + Help::ShowQuickHelp( this, aItemRect, aHelpText ); +} + +void OTableWindowTitle::Command( const CommandEvent& rEvt ) +{ + if ( rEvt.GetCommand() == CommandEventId::ContextMenu ) + { + GrabFocus(); + if ( m_pTabWin ) + { + // tdf#94709 - protect shutdown code-path. + VclPtr xTabWin(m_pTabWin); + xTabWin->Command( rEvt ); + } + else + Control::Command(rEvt); + } +} + +void OTableWindowTitle::KeyInput( const KeyEvent& rEvt ) +{ + if ( m_pTabWin ) + m_pTabWin->KeyInput( rEvt ); +} + +void OTableWindowTitle::MouseButtonDown( const MouseEvent& rEvt ) +{ + if( rEvt.IsLeft() ) + { + if( rEvt.GetClicks() == 2) + { + Size aSize(GetTextWidth(GetText()) + 20, + m_pTabWin->GetSizePixel().Height() - m_pTabWin->GetListBox()->GetSizePixel().Height()); + + aSize.AdjustHeight((m_pTabWin->GetListBox()->GetEntryCount() + 2) * m_pTabWin->GetListBox()->GetEntryHeight() ); + 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 ); + } + GrabFocus(); + } + else + Control::MouseButtonDown( rEvt ); +} + +void OTableWindowTitle::DataChanged(const DataChangedEvent& rDCEvt) +{ + if (rDCEvt.GetType() == DataChangedEventType::SETTINGS) + { + // assume worst-case: colours have changed, therefore I have to adept + StyleSettings aSystemStyle = Application::GetSettings().GetStyleSettings(); + SetBackground(Wallpaper(aSystemStyle.GetFaceColor())); + SetTextColor(aSystemStyle.GetButtonTextColor()); + } +} + +void OTableWindowTitle::StateChanged( StateChangedType nType ) +{ + Window::StateChanged( nType ); + + if ( nType == StateChangedType::Zoom ) + { + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + vcl::Font aFont = rStyleSettings.GetGroupFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetZoomedPointFont(*this, aFont); + + Resize(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/class.jpg b/dbaccess/source/ui/querydesign/class.jpg new file mode 100644 index 000000000..b1a3b6d27 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 000000000..47aa5c98c --- /dev/null +++ b/dbaccess/source/ui/querydesign/limitboxcontroller.cxx @@ -0,0 +1,321 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 + +#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")) + { + 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); + } + + virtual void GetFocus() override + { + if (m_xWidget) + m_xWidget->grab_focus(); + InterimItemWindow::GetFocus(); + } + + 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; + uno::Sequence< beans::PropertyValue > aArgs( 1 ); + aArgs[0].Name = "DBLimit.Value"; + 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); + aArgs[0].Value <<= nLimit; + m_pControl->dispatchCommand( aArgs ); + } + + ///Initialize entries + void LoadDefaultLimits() + { + m_xWidget->freeze(); + m_xWidget->append_text(DBA_RES(STR_QUERY_LIMIT_ALL)); + for (auto nIndex : aDefLimitAry) + { + m_xWidget->append_text(OUString::number(nIndex)); + } + m_xWidget->thaw(); + } +}; + +IMPL_LINK(LimitBox, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bHandled = false; + const sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + switch (nCode) + { + case KEY_ESCAPE: + m_xWidget->set_entry_text(m_xWidget->get_saved_value()); + bHandled = true; + break; + case KEY_RETURN: + { + bHandled = ActivateHdl(*m_xWidget); + break; + } + } + return bHandled || ChildKeyInput(rKEvt); +} + +IMPL_LINK_NOARG(LimitBox, FocusOutHdl, weld::Widget&, void) +{ + if (!m_xWidget || m_xWidget->has_focus()) // comboboxes can be comprised of multiple widgets, ensure all have lost focus + return; + Apply(); +} + +IMPL_LINK(LimitBox, ChangeHdl, weld::ComboBox&, rComboBox, void) +{ + if (rComboBox.changed_by_direct_pick()) + ActivateHdl(rComboBox); +} + +IMPL_LINK_NOARG(LimitBox, ActivateHdl, weld::ComboBox&, bool) +{ + GrabFocusToDocument(); + Apply(); + return true; +} + +LimitBoxController::LimitBoxController( + const uno::Reference< uno::XComponentContext >& rxContext ) : + svt::ToolboxController( rxContext, + uno::Reference< frame::XFrame >(), + ".uno:DBLimit" ), + m_xLimitBox( nullptr ) +{ +} + +LimitBoxController::~LimitBoxController() +{ +} + +/// XInterface +uno::Any SAL_CALL LimitBoxController::queryInterface( const uno::Type& aType ) +{ + uno::Any a = ToolboxController::queryInterface( aType ); + if ( a.hasValue() ) + return a; + + return ::cppu::queryInterface( aType, static_cast< lang::XServiceInfo* >( this )); +} + +void SAL_CALL LimitBoxController::acquire() throw () +{ + ToolboxController::acquire(); +} + +void SAL_CALL LimitBoxController::release() throw () +{ + ToolboxController::release(); +} + + +/// XServiceInfo +IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(LimitBoxController, "org.libreoffice.comp.dbu.LimitBoxController") +IMPLEMENT_SERVICE_INFO_SUPPORTS(LimitBoxController) +IMPLEMENT_SERVICE_INFO_GETSUPPORTED1_STATIC(LimitBoxController, "com.sun.star.frame.ToolbarController") + +uno::Reference< uno::XInterface > + LimitBoxController::Create(const uno::Reference< css::lang::XMultiServiceFactory >& _rxORB) +{ + return static_cast< XServiceInfo* >(new LimitBoxController( comphelper::getComponentContext(_rxORB) )); +} + +/// 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" void createRegistryInfo_LimitBoxController() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::LimitBoxController > aAutoRegistration; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/limitboxcontroller.hxx b/dbaccess/source/ui/querydesign/limitboxcontroller.hxx new file mode 100644 index 000000000..cf3727625 --- /dev/null +++ b/dbaccess/source/ui/querydesign/limitboxcontroller.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/. + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_LIMITBOXCONTROLLER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_LIMITBOXCONTROLLER_HXX + +#include +#include +#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 + */ +class LimitBoxController: public svt::ToolboxController, + public css::lang::XServiceInfo +{ + public: + explicit LimitBoxController( + const css::uno::Reference< css::uno::XComponentContext >& rxContext ); + virtual ~LimitBoxController() override; + + /// XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire() throw () override; + virtual void SAL_CALL release() throw () override; + + /// XServiceInfo + DECLARE_SERVICE_INFO(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + /// 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 + +#endif /// INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_LIMITBOXCONTROLLER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/querycontainerwindow.cxx b/dbaccess/source/ui/querydesign/querycontainerwindow.cxx new file mode 100644 index 000000000..aef183bb6 --- /dev/null +++ b/dbaccess/source/ui/querydesign/querycontainerwindow.cxx @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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() == MouseNotifyEvent::GETFOCUS && m_pViewSwitch) + { + OJoinController& rController = m_pViewSwitch->getDesignView()->getController(); + rController.InvalidateFeature(SID_CUT); + rController.InvalidateFeature(SID_COPY); + rController.InvalidateFeature(SID_PASTE); + } + return ODataView::PreNotify(rNEvt); + } + void OQueryContainerWindow::showPreview(const Reference& _xFrame) + { + 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() ) + { + const OUString aAutomaticToolbars( "AutomaticToolbars" ); + xLMPropSet->setPropertyValue( aAutomaticToolbars, 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 long nFrameHeight = LogicToPixel(Size(0, 3), MapMode(MapUnit::MapAppFont)).Height(); + Point aPos(0,aBeamer.Height()+nFrameHeight); + + m_pBeamer->SetPosSizePixel(Point(0,0),aBeamer); + m_pBeamer->Show(); + + m_pSplitter->SetPosSizePixel( Point(0,aBeamer.Height()), Size(aSize.Width(),nFrameHeight) ); + // a default pos for the splitter, so that the listbox is about 80 (logical) pixels wide + m_pSplitter->SetSplitPosPixel( aBeamer.Height() ); + m_pViewSwitch->SetPosSizePixel(aPos,Size(aBeamer.Width(),aSize.Height() - aBeamer.Height()-nFrameHeight)); + + m_pSplitter->Show(); + + Resize(); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/querycontroller.cxx b/dbaccess/source/ui/querydesign/querycontroller.cxx new file mode 100644 index 000000000..2a9935675 --- /dev/null +++ b/dbaccess/source/ui/querydesign/querycontroller.cxx @@ -0,0 +1,1819 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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" void createRegistryInfo_OQueryControl() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OQueryController > aAutoRegistration; +} + +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 getImplementationName_Static(); + } + virtual Sequence< OUString> SAL_CALL getSupportedServiceNames() override + { + return getSupportedServiceNames_Static(); + } + + public: + explicit OViewController(const Reference< XComponentContext >& _rM) : OQueryController(_rM){} + + // need by registration + /// @throws RuntimeException + static OUString getImplementationName_Static() + { + return "org.openoffice.comp.dbu.OViewDesign"; + } + /// @throws RuntimeException + static Sequence< OUString > getSupportedServiceNames_Static() + { + Sequence aSupported { "com.sun.star.sdb.ViewDesign" }; + return aSupported; + } + static Reference< XInterface > Create(const Reference< XMultiServiceFactory >& _rM) + { + return *(new OViewController(comphelper::getComponentContext(_rM))); + } + }; + + } +} + +extern "C" void createRegistryInfo_OViewControl() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OViewController > aAutoRegistration; +} + +namespace dbaui +{ + using namespace ::connectivity; + + namespace + { + OUString lcl_getObjectResourceString(const char* 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 const char s_sDesignToolbar[] = "private:resource/toolbar/designobjectbar"; + static const char s_sSqlToolbar[] = "private:resource/toolbar/sqlobjectbar"; + if ( _bDesign ) + { + xLayoutManager->destroyElement( s_sSqlToolbar ); + xLayoutManager->createElement( s_sDesignToolbar ); + } + else + { + xLayoutManager->destroyElement( s_sDesignToolbar ); + xLayoutManager->createElement( s_sSqlToolbar ); + } + xLayoutManager->unlock(); + xLayoutManager->doLayout(); + } + + /** + * The value of m_nLimit is updated when LimitBox loses its focus + * So in those case when execution needs recent data, grab the focus + * (e.g. execute SQL statement, change views) + */ + void grabFocusFromLimitBox( OQueryController& _rController ) + { + Reference< XLayoutManager > xLayoutManager = OGenericUnoController::getLayoutManager( _rController.getFrame() ); + Reference< XUIElement > xUIElement = xLayoutManager->getElement("private:resource/toolbar/designobjectbar"); + if (xUIElement.is()) + { + Reference< XWindow > xWindow(xUIElement->getRealInterface(), css::uno::UNO_QUERY); + VclPtr pWindow = VCLUnoHelper::GetWindow( xWindow ); + if( pWindow && pWindow->HasChildPathFocus() ) + { + pWindow->GrabFocusToDocument(); + } + } + } +} + +OUString SAL_CALL OQueryController::getImplementationName() +{ + return getImplementationName_Static(); +} + +OUString OQueryController::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.OQueryDesign"; +} + +Sequence< OUString> OQueryController::getSupportedServiceNames_Static() +{ + Sequence aSupported { "com.sun.star.sdb.QueryDesign" }; + return aSupported; +} + +Sequence< OUString> SAL_CALL OQueryController::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference< XInterface > OQueryController::Create(const Reference& _rxFactory) +{ + return *(new OQueryController(comphelper::getComponentContext(_rxFactory))); +} + +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( OUString(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 ); + aProps[ nLength ] = Property( + "CurrentQueryDesign", + PROPERTY_ID_CURRENT_QUERY_DESIGN, + ::cppu::UnoType< Sequence< PropertyValue > >::get(), + PropertyAttribute::READONLY + ); + + std::sort( + aProps.begin(), + aProps.end(), + ::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 + { + OUString aErrorMsg; + 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 + { + std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree(aErrorMsg,m_sStatement,m_bGraphicalDesign); + if ( pNode ) + { + delete m_pSqlIterator->getParseTree(); + m_pSqlIterator->setParseTree(pNode.release()); + m_pSqlIterator->traverseAll(); + + if ( m_pSqlIterator->hasErrors() ) + { + aError = m_pSqlIterator->getErrors(); + } + else + { + const OSQLTables& rTabs = m_pSqlIterator->getTables(); + if ( m_pSqlIterator->getStatementType() != OSQLStatementType::Select || rTabs.empty() ) + { + aError = SQLException( + DBA_RES(STR_QRY_NOSELECT), + nullptr, + "S1000", + 1000, + Any() + ); + } + else + { + // change the view of the data + m_bGraphicalDesign = !m_bGraphicalDesign; + OUString sNewStatement; + m_pSqlIterator->getParseTree()->parseNodeToStr( sNewStatement, getConnection() ); + setStatement_fireEvent( sNewStatement ); + getContainer()->SaveUIConfig(); + m_vTableConnectionData.clear(); + impl_setViewMode( &aError ); + } + } + } + else + { + aError = SQLException( + DBA_RES(STR_QRY_SYNTAX), + nullptr, + "S1000", + 1000, + Any() + ); + } + } + } + catch(const SQLException&) + { + aError = ::cppu::getCaughtException(); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + if ( aError.isValid() ) + showError( aError ); + + if(m_bGraphicalDesign) + { + InvalidateFeature(ID_BROWSER_ADDTABLE); + InvalidateFeature(SID_RELATION_ADD_RELATION); + } + } + break; + case SID_BROWSER_CLEAR_QUERY: + { + GetUndoManager().EnterListAction(DBA_RES(STR_QUERY_UNDO_TABWINDELETE), OUString(), 0, ViewShellId(-1) ); + getContainer()->clear(); + GetUndoManager().LeaveListAction(); + + setStatement_fireEvent( OUString() ); + if(m_bGraphicalDesign) + InvalidateFeature(ID_BROWSER_ADDTABLE); + } + break; + case SID_QUERY_VIEW_FUNCTIONS: + case SID_QUERY_VIEW_TABLES: + case SID_QUERY_VIEW_ALIASES: + getContainer()->setSlotEnabled(_nId,!getContainer()->isSlotEnabled(_nId)); + setModified(true); + break; + case SID_QUERY_DISTINCT_VALUES: + m_bDistinct = !m_bDistinct; + setModified(true); + break; + case SID_QUERY_LIMIT: + if ( aArgs.hasElements() && aArgs[0].Name == "DBLimit.Value" ) + { + aArgs[0].Value >>= m_nLimit; + setModified(true); + } + break; + case SID_QUERY_PROP_DLG: + grabFocusFromLimitBox(*this); + execute_QueryPropDlg(); + break; + case ID_BROWSER_QUERY_EXECUTE: + grabFocusFromLimitBox(*this); + if ( getContainer()->checkStatement() ) + executeQuery(); + break; + case SID_DB_QUERY_PREVIEW: + try + { + Reference< css::util::XCloseable > xCloseFrame( getContainer()->getPreviewFrame(), UNO_QUERY ); + if ( xCloseFrame.is() ) + { + try + { + xCloseFrame->close( true ); + } + catch(const Exception&) + { + OSL_FAIL( "OQueryController::Execute(SID_DB_QUERY_PREVIEW): *nobody* is expected to veto closing the preview frame!" ); + } + } + else + Execute(ID_BROWSER_QUERY_EXECUTE,Sequence< PropertyValue >()); + } + catch(const Exception&) + { + } + break; + default: + OJoinController::Execute(_nId,aArgs); + return; // else we would invalidate twice + } + InvalidateFeature(_nId); +} + +void OQueryController::impl_showAutoSQLViewError( const css::uno::Any& _rErrorDetails ) +{ + SQLContext aErrorContext; + aErrorContext.Message = lcl_getObjectResourceString( STR_ERROR_PARSING_STATEMENT, m_nCommandType ); + aErrorContext.Context = *this; + aErrorContext.Details = lcl_getObjectResourceString( STR_INFO_OPENING_IN_SQL_VIEW, m_nCommandType ); + aErrorContext.NextException = _rErrorDetails; + showError( aErrorContext ); +} + +void OQueryController::impl_setViewMode( ::dbtools::SQLExceptionInfo* _pErrorInfo ) +{ + OSL_PRECOND( getContainer(), "OQueryController::impl_setViewMode: illegal call!" ); + + bool wasModified = isModified(); + + SQLExceptionInfo aError; + bool bSuccess = getContainer()->switchView( &aError ); + if ( !bSuccess ) + { + m_bGraphicalDesign = !m_bGraphicalDesign; + // restore old state + getContainer()->switchView( nullptr ); + // don't pass &aError here, this would overwrite the error which the first switchView call + // returned in this location. + if ( _pErrorInfo ) + *_pErrorInfo = aError; + else + showError( aError ); + } + else + { + ensureToolbars( *this, m_bGraphicalDesign ); + } + + setModified( wasModified ); +} + +void OQueryController::impl_initialize() +{ + OJoinController::impl_initialize(); + + const NamedValueCollection& rArguments( getInitParams() ); + + OUString sCommand; + m_nCommandType = CommandType::QUERY; + + // reading parameters: + + // legacy parameters first (later overwritten by regular parameters) + OUString sIndependentSQLCommand; + if ( rArguments.get_ensureType( "IndependentSQLCommand", sIndependentSQLCommand ) ) + { + OSL_FAIL( "OQueryController::impl_initialize: IndependentSQLCommand is regognized for compatibility only!" ); + sCommand = sIndependentSQLCommand; + m_nCommandType = CommandType::COMMAND; + } + + OUString sCurrentQuery; + if ( rArguments.get_ensureType( "CurrentQuery", sCurrentQuery ) ) + { + OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" ); + sCommand = sCurrentQuery; + m_nCommandType = CommandType::QUERY; + } + + bool bCreateView( false ); + if ( rArguments.get_ensureType( "CreateView", bCreateView ) && bCreateView ) + { + OSL_FAIL( "OQueryController::impl_initialize: CurrentQuery is regognized for compatibility only!" ); + m_nCommandType = CommandType::TABLE; + } + + // non-legacy parameters which overwrite the legacy parameters + rArguments.get_ensureType( PROPERTY_COMMAND, sCommand ); + rArguments.get_ensureType( PROPERTY_COMMAND_TYPE, m_nCommandType ); + + // translate Command/Type into proper members + // TODO/Later: all this (including those members) should be hidden behind some abstract interface, + // which is implemented for all the three commands + switch ( m_nCommandType ) + { + case CommandType::QUERY: + m_sName = sCommand; + break; + case CommandType::TABLE: + m_sName = sCommand; + break; + case CommandType::COMMAND: + setStatement_fireEvent( sCommand ); + m_sName.clear(); + break; + default: + OSL_FAIL( "OQueryController::impl_initialize: logic error in code!" ); + throw RuntimeException(); + } + + // more legacy parameters + bool bGraphicalDesign( true ); + if ( rArguments.get_ensureType( PROPERTY_QUERYDESIGNVIEW, bGraphicalDesign ) ) + { + OSL_FAIL( "OQueryController::impl_initialize: QueryDesignView is regognized for compatibility only!" ); + m_bGraphicalDesign = bGraphicalDesign; + } + + // more non-legacy + rArguments.get_ensureType( PROPERTY_GRAPHICAL_DESIGN, m_bGraphicalDesign ); + + bool bEscapeProcessing( true ); + if ( rArguments.get_ensureType( PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing ) ) + { + setEscapeProcessing_fireEvent( bEscapeProcessing ); + + OSL_ENSURE( m_bEscapeProcessing || !m_bGraphicalDesign, "OQueryController::impl_initialize: can't do the graphical design without escape processing!" ); + if ( !m_bEscapeProcessing ) + m_bGraphicalDesign = false; + } + + // initial design + bool bForceInitialDesign = false; + Sequence< PropertyValue > aCurrentQueryDesignProps; + aCurrentQueryDesignProps = rArguments.getOrDefault( "CurrentQueryDesign", aCurrentQueryDesignProps ); + + if ( aCurrentQueryDesignProps.hasElements() ) + { + ::comphelper::NamedValueCollection aCurrentQueryDesign( aCurrentQueryDesignProps ); + if ( aCurrentQueryDesign.has( OUString(PROPERTY_GRAPHICAL_DESIGN) ) ) + { + aCurrentQueryDesign.get_ensureType( PROPERTY_GRAPHICAL_DESIGN, m_bGraphicalDesign ); + } + if ( aCurrentQueryDesign.has( OUString(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 aDefaultName.getToken(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, makeAny(sDataSourceName) }, + { PROPERTY_COMMAND_TYPE, makeAny(CommandType::COMMAND) }, + { PROPERTY_COMMAND, makeAny(sTranslatedStmt) }, + { PROPERTY_ENABLE_BROWSER, makeAny(false) }, + { PROPERTY_ACTIVE_CONNECTION, makeAny(getConnection()) }, + { PROPERTY_UPDATE_CATALOGNAME, makeAny(m_sUpdateCatalogName) }, + { PROPERTY_UPDATE_SCHEMANAME, makeAny(m_sUpdateSchemaName) }, + { PROPERTY_UPDATE_TABLENAME, makeAny(OUString()) }, + { PROPERTY_ESCAPE_PROCESSING, makeAny(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, makeAny( 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, makeAny( sTranslatedStmt ) ); + + if ( editingView() ) + { + xQuery->setPropertyValue( PROPERTY_CATALOGNAME, makeAny( m_sUpdateCatalogName ) ); + xQuery->setPropertyValue( PROPERTY_SCHEMANAME, makeAny( m_sUpdateSchemaName ) ); + } + + if ( editingQuery() ) + { + xQuery->setPropertyValue( PROPERTY_UPDATE_TABLENAME, makeAny( OUString() ) ); + xQuery->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, css::uno::makeAny( 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, makeAny( xQuery ) ); + } + + if ( editingView() ) + { + Reference< XPropertySet > xViewProps; + if ( xElements->hasByName( m_sName ) ) + xViewProps.set( xElements->getByName( m_sName ), UNO_QUERY ); + + if ( !xViewProps.is() ) // correct name and try again + m_sName = ::dbtools::composeTableName( getMetaData(), xQuery, ::dbtools::EComposeRule::InDataManipulation, false ); + + OSL_ENSURE( xElements->hasByName( m_sName ), "OQueryController::doSaveAsDoc: newly created view does not exist!" ); + + if ( xElements->hasByName( m_sName ) ) + m_xAlterView.set( xElements->getByName( m_sName ), UNO_QUERY ); + + // now check if our datasource has set a tablefilter and if so, append the new table name to it + ::dbaui::appendToFilter(getConnection(), m_sName, getORB(), getFrameWeld()); + } + Reference< XTitleChangeListener> xEventListener(impl_getTitleHelper_throw(),UNO_QUERY); + if ( xEventListener.is() ) + { + TitleChangedEvent aEvent; + xEventListener->titleChanged(aEvent); + } + releaseNumberForComponent(); + } + + setModified( false ); + bSuccess = true; + + } + catch(const SQLException&) + { + if ( !bNew ) + m_sName = sOriginalName; + aInfo = SQLExceptionInfo( ::cppu::getCaughtException() ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + if ( !bNew ) + m_sName = sOriginalName; + } + + showError( aInfo ); + + // if we successfully saved a view we were creating, then close the designer + if ( bSuccess && editingView() && !m_xAlterView.is() ) + { + closeTask(); + } + + if ( bSuccess && editingView() ) + InvalidateFeature( ID_BROWSER_EDITDOC ); + + return bSuccess; +} + +namespace { +struct CommentStrip +{ + OUString maComment; + bool mbLastOnLine; + CommentStrip( const OUString& rComment, bool bLastOnLine ) + : maComment( rComment), mbLastOnLine( bLastOnLine) {} +}; + +} + +/** Obtain all comments in a query. + + See also delComment() implementation for OSQLParser::parseTree(). + */ +static std::vector< CommentStrip > getComment( const OUString& rQuery ) +{ + std::vector< CommentStrip > aRet; + // First a quick search if there is any "--" or "//" or "/*", if not then + // the whole copying loop is pointless. + if (rQuery.indexOf( "--" ) < 0 && rQuery.indexOf( "//" ) < 0 && + rQuery.indexOf( "/*" ) < 0) + return aRet; + + const sal_Unicode* pCopy = rQuery.getStr(); + const sal_Int32 nQueryLen = rQuery.getLength(); + bool bIsText1 = false; // "text" + bool bIsText2 = false; // 'text' + bool bComment2 = false; // /* comment */ + bool bComment = false; // -- or // comment + OUStringBuffer aBuf; + for (sal_Int32 i=0; i < nQueryLen; ++i) + { + if (bComment2) + { + aBuf.append( &pCopy[i], 1); + if ((i+1) < nQueryLen) + { + if (pCopy[i]=='*' && pCopy[i+1]=='/') + { + bComment2 = false; + aBuf.append( &pCopy[++i], 1); + aRet.emplace_back( aBuf.makeStringAndClear(), false); + } + } + else + { + // comment can't close anymore, actually an error, but... + aRet.emplace_back( aBuf.makeStringAndClear(), false); + } + continue; + } + if (pCopy[i] == '\n' || i == nQueryLen-1) + { + if (bComment) + { + if (i == nQueryLen-1 && pCopy[i] != '\n') + aBuf.append( &pCopy[i], 1); + aRet.emplace_back( aBuf.makeStringAndClear(), true); + bComment = false; + } + else if (!aRet.empty()) + aRet.back().mbLastOnLine = true; + } + else if (!bComment) + { + if (pCopy[i] == '\"' && !bIsText2) + bIsText1 = !bIsText1; + else if (pCopy[i] == '\'' && !bIsText1) + bIsText2 = !bIsText2; + if (!bIsText1 && !bIsText2 && (i+1) < nQueryLen) + { + if ((pCopy[i]=='-' && pCopy[i+1]=='-') || (pCopy[i]=='/' && pCopy[i+1]=='/')) + bComment = true; + else if (pCopy[i]=='/' && pCopy[i+1]=='*') + bComment2 = true; + } + } + if (bComment || bComment2) + aBuf.append( &pCopy[i], 1); + } + return aRet; +} + +/** Concat/insert comments that were previously obtained with getComment(). + + NOTE: The current parser implementation does not preserve newlines, so all + comments are always appended to the entire query, also inline comments + that would need positioning anyway that can't be obtained after + recomposition. This is ugly but at least allows commented queries while + preserving the comments _somehow_. + */ +static OUString concatComment( const OUString& rQuery, const std::vector< CommentStrip >& rComments ) +{ + // No comments => return query. + if (rComments.empty()) + return rQuery; + + const sal_Unicode* pBeg = rQuery.getStr(); + const sal_Int32 nLen = rQuery.getLength(); + const size_t nComments = rComments.size(); + // Obtaining the needed size once should be faster than reallocating. + // Also add a blank or linefeed for each comment. + sal_Int32 nBufSize = nLen + nComments; + for (auto const& comment : rComments) + nBufSize += comment.maComment.getLength(); + OUStringBuffer aBuf( nBufSize ); + sal_Int32 nIndBeg = 0; + sal_Int32 nIndLF = rQuery.indexOf('\n'); + size_t i = 0; + while (nIndLF >= 0 && i < nComments) + { + aBuf.append( pBeg + nIndBeg, nIndLF - nIndBeg); + do + { + aBuf.append( rComments[i].maComment); + } while (!rComments[i++].mbLastOnLine && i < nComments); + aBuf.append( pBeg + nIndLF, 1); // the LF + nIndBeg = nIndLF + 1; + nIndLF = (nIndBeg < nLen ? rQuery.indexOf( '\n', nIndBeg) : -1); + } + // Append remainder of query. + if (nIndBeg < nLen) + aBuf.append( pBeg + nIndBeg, nLen - nIndBeg); + // Append all remaining comments, preserve lines. + bool bNewLine = false; + for ( ; i < nComments; ++i) + { + if (!bNewLine) + aBuf.append( ' '); + aBuf.append( rComments[i].maComment); + if (rComments[i].mbLastOnLine) + { + aBuf.append( '\n'); + bNewLine = true; + } + else + bNewLine = false; + } + return aBuf.makeStringAndClear(); +} + +OUString OQueryController::translateStatement( bool _bFireStatementChange ) +{ + // now set the properties + setStatement_fireEvent( getContainer()->getStatement(), _bFireStatementChange ); + OUString sTranslatedStmt; + if(!m_sStatement.isEmpty() && m_xComposer.is() && m_bEscapeProcessing) + { + try + { + OUString aErrorMsg; + + std::vector< CommentStrip > aComments = getComment( m_sStatement); + + std::unique_ptr<::connectivity::OSQLParseNode> pNode = m_aSqlParser.parseTree( aErrorMsg, m_sStatement, m_bGraphicalDesign ); + if(pNode) + { + pNode->parseNodeToStr( sTranslatedStmt, getConnection() ); + } + + m_xComposer->setQuery(sTranslatedStmt); + sTranslatedStmt = m_xComposer->getComposedQuery(); + sTranslatedStmt = concatComment( sTranslatedStmt, aComments); + } + catch(const SQLException& e) + { + ::dbtools::SQLExceptionInfo aInfo(e); + showError(aInfo); + // an error occurred so we clear the statement + sTranslatedStmt.clear(); + } + } + else if(m_sStatement.isEmpty()) + { + showError(SQLException(DBA_RES(STR_QRY_NOSELECT), nullptr, "S1000", 1000, Any())); + } + else + sTranslatedStmt = m_sStatement; + + return sTranslatedStmt; +} + +short OQueryController::saveModified() +{ + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( getMutex() ); + short nRet = RET_YES; + if ( !isConnected() || !isModified() ) + return nRet; + + if ( !m_bGraphicalDesign + || ( !m_vTableFieldDesc.empty() + && !m_vTableData.empty() + ) + ) + { + OUString sMessageText( lcl_getObjectResourceString( STR_QUERY_SAVEMODIFIED, m_nCommandType ) ); + + std::unique_ptr 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( makeAny( 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()->setNoneVisbleRow(m_nVisibleRows); +} + +void OQueryController::reset() +{ + impl_reset(); + getContainer()->reset(); + ClearUndoManager(); +} + +void OQueryController::setStatement_fireEvent( const OUString& _rNewStatement, bool _bFireStatementChange ) +{ + Any aOldValue = makeAny( m_sStatement ); + m_sStatement = _rNewStatement; + Any aNewValue = makeAny( 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 = makeAny( m_bEscapeProcessing ); + m_bEscapeProcessing = _bEscapeProcessing; + Any aNewValue = makeAny( 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 makeAny( aViewSettings.getPropertyValues() ); +} + +void SAL_CALL OQueryController::restoreViewData(const Any& /*Data*/) +{ + // TODO +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/querydesign/querydlg.cxx b/dbaccess/source/ui/querydesign/querydlg.cxx new file mode 100644 index 000000000..422eeb935 --- /dev/null +++ b/dbaccess/source/ui/querydesign/querydlg.cxx @@ -0,0 +1,313 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "querydlg.hxx" +#include +#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; + const char* pResId = nullptr; + const sal_Int32 nPos = m_xLB_JoinType->get_active(); + const sal_Int32 nJoinType = m_xLB_JoinType->get_id(nPos).toInt32(); + bool bAddHint = true; + switch ( nJoinType ) + { + default: + case ID_INNER_JOIN: + pResId = STR_QUERY_INNER_JOIN; + bAddHint = false; + eJoinType = INNER_JOIN; + break; + case ID_LEFT_JOIN: + pResId = STR_QUERY_LEFTRIGHT_JOIN; + eJoinType = LEFT_JOIN; + break; + case ID_RIGHT_JOIN: + { + pResId = STR_QUERY_LEFTRIGHT_JOIN; + eJoinType = RIGHT_JOIN; + OUString sTemp = sFirstWinName; + sFirstWinName = sSecondWinName; + sSecondWinName = sTemp; + } + break; + case ID_FULL_JOIN: + pResId = STR_QUERY_FULL_JOIN; + eJoinType = FULL_JOIN; + break; + case ID_CROSS_JOIN: + { + pResId = STR_QUERY_CROSS_JOIN; + eJoinType = CROSS_JOIN; + + m_pConnData->ResetConnLines(); + m_xTableControl->lateInit(); + m_xCBNatural->set_active(false); + m_xTableControl->enableRelation(false); + m_pConnData->AppendConnLine("",""); + m_xPB_OK->set_sensitive(true); + } + break; + } + + m_xCBNatural->set_sensitive(eJoinType != CROSS_JOIN); + + if ( eJoinType != eOldJoinType && eOldJoinType == CROSS_JOIN ) + { + m_pConnData->ResetConnLines(); + } + if ( eJoinType != CROSS_JOIN ) + { + m_xTableControl->NotifyCellChange(); + NaturalToggleHdl(*m_xCBNatural); + } + + m_xTableControl->Invalidate(); + + OUString sHelpText = DBA_RES(pResId); + if( nPos ) + { + sHelpText = sHelpText.replaceFirst( "%1", sFirstWinName ); + sHelpText = sHelpText.replaceFirst( "%2", sSecondWinName ); + } + if ( bAddHint ) + { + sHelpText += "\n" + DBA_RES( STR_JOIN_TYPE_HINT ); + } + + m_xML_HelpText->set_label( sHelpText ); +} + +IMPL_LINK_NOARG(DlgQryJoin, OKClickHdl, weld::Button&, void) +{ + m_pConnData->Update(); + m_pOrigConnData->CopyFrom( *m_pConnData ); + + m_xDialog->response(RET_OK); +} + +IMPL_LINK_NOARG(DlgQryJoin, NaturalToggleHdl, weld::ToggleButton&, 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 000000000..4631d7fbe --- /dev/null +++ b/dbaccess/source/ui/querydesign/querydlg.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYDLG_HXX + +#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::ToggleButton&, 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_QUERYDESIGN_QUERYDLG_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RTableConnection.cxx b/dbaccess/source/ui/relationdesign/RTableConnection.cxx new file mode 100644 index 000000000..b4bc2cfe1 --- /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; + long nTop = GetBoundingRect().Bottom(); + 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 000000000..dabdfe47d --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RTableConnection.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_RELATIONDESIGN_RTABLECONNECTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_RELATIONDESIGN_RTABLECONNECTION_HXX + +#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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_RELATIONDESIGN_RTABLECONNECTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RTableConnectionData.cxx b/dbaccess/source/ui/relationdesign/RTableConnectionData.cxx new file mode 100644 index 000000000..e9b87f28e --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RTableConnectionData.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 +#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() + :OTableConnectionData() + ,m_nUpdateRules(KeyRule::NO_ACTION) + ,m_nDeleteRules(KeyRule::NO_ACTION) + ,m_nCardinality(Cardinality::Undefined) +{ +} + +ORelationTableConnectionData::ORelationTableConnectionData( const TTableWindowData::value_type& _pReferencingTable, + const TTableWindowData::value_type& _pReferencedTable, + const OUString& rConnName ) + :OTableConnectionData( _pReferencingTable, _pReferencedTable ) + ,m_nUpdateRules(KeyRule::NO_ACTION) + ,m_nDeleteRules(KeyRule::NO_ACTION) + ,m_nCardinality(Cardinality::Undefined) +{ + m_aConnName = rConnName; + + if ( !m_aConnName.isEmpty() ) + SetCardinality(); +} + +ORelationTableConnectionData::ORelationTableConnectionData( const ORelationTableConnectionData& rConnData ) + :OTableConnectionData( rConnData ) +{ + *this = rConnData; +} + +ORelationTableConnectionData::~ORelationTableConnectionData() +{ +} + +void ORelationTableConnectionData::DropRelation() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + // delete relation + Reference< XIndexAccess> xKeys = getReferencingTable()->getKeys(); + if( !(!m_aConnName.isEmpty() && xKeys.is()) ) + return; + + const sal_Int32 nCount = xKeys->getCount(); + for(sal_Int32 i = 0;i < nCount;++i) + { + Reference< XPropertySet> xKey(xKeys->getByIndex(i),UNO_QUERY); + OSL_ENSURE(xKey.is(),"Key is not valid!"); + if(xKey.is()) + { + OUString sName; + xKey->getPropertyValue(PROPERTY_NAME) >>= sName; + if(sName == m_aConnName) + { + Reference< XDrop> xDrop(xKeys,UNO_QUERY); + OSL_ENSURE(xDrop.is(),"can't drop key because we haven't a drop interface!"); + if(xDrop.is()) + xDrop->dropByIndex(i); + break; + } + } + } +} + +void ORelationTableConnectionData::ChangeOrientation() +{ + // exchange Source- and DestFieldName of the lines + OUString sTempString; + for (auto const& elem : m_vConnLineData) + { + sTempString = elem->GetSourceFieldName(); + elem->SetSourceFieldName( elem->GetDestFieldName() ); + elem->SetDestFieldName( sTempString ); + } + + // adapt member + TTableWindowData::value_type pTemp = m_pReferencingTable; + m_pReferencingTable = m_pReferencedTable; + m_pReferencedTable = pTemp; +} + +void ORelationTableConnectionData::SetCardinality() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + m_nCardinality = Cardinality::Undefined; + + if( IsSourcePrimKey() ) + { + if( IsDestPrimKey() ) + m_nCardinality = Cardinality::OneOne; + else + m_nCardinality = Cardinality::OneMany; + } + + if( IsDestPrimKey() ) + { + if( !IsSourcePrimKey() ) + m_nCardinality = Cardinality::ManyOne; + } + +} + +bool ORelationTableConnectionData::checkPrimaryKey(const Reference< XPropertySet>& i_xTable,EConnectionSide _eEConnectionSide) const +{ + // check if Table has the primary key column depending on _eEConnectionSide + sal_uInt16 nPrimKeysCount = 0, + nValidLinesCount = 0; + const Reference< XNameAccess> xKeyColumns = dbtools::getPrimaryKeyColumns_throw(i_xTable); + if ( xKeyColumns.is() ) + { + Sequence< OUString> aKeyColumns = xKeyColumns->getElementNames(); + const OUString* pKeyIter = aKeyColumns.getConstArray(); + const OUString* pKeyEnd = pKeyIter + aKeyColumns.getLength(); + + for(;pKeyIter != pKeyEnd;++pKeyIter) + { + for (auto const& elem : m_vConnLineData) + { + ++nValidLinesCount; + if ( elem->GetFieldName(_eEConnectionSide) == *pKeyIter ) + { + ++nPrimKeysCount; + break; + } + } + } + if ( nPrimKeysCount != aKeyColumns.getLength() ) + return false; + } + return nPrimKeysCount && nPrimKeysCount == nValidLinesCount; +} + +void ORelationTableConnectionData::IsConnectionPossible() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + // if the SourceFields are a PrimKey, it's only the orientation which is wrong + if ( IsSourcePrimKey() && !IsDestPrimKey() ) + ChangeOrientation(); +} + +void ORelationTableConnectionData::CopyFrom(const OTableConnectionData& rSource) +{ + // retract to the (non-virtual) operator= like in the base class + *this = *static_cast(&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,makeAny(sKeyName)); + xKey->setPropertyValue(PROPERTY_TYPE,makeAny(KeyType::FOREIGN)); + xKey->setPropertyValue(PROPERTY_REFERENCEDTABLE,makeAny(getReferencedTable()->GetTableName())); + xKey->setPropertyValue(PROPERTY_UPDATERULE, makeAny(GetUpdateRules())); + xKey->setPropertyValue(PROPERTY_DELETERULE, makeAny(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,makeAny(elem->GetSourceFieldName())); + xColumn->setPropertyValue(PROPERTY_RELATEDCOLUMN,makeAny(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 000000000..3b59a9d9d --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RTableWindow.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_RELATIONDESIGN_RTABLEWINDOW_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_RELATIONDESIGN_RTABLEWINDOW_HXX + +#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(); } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_RELATIONDESIGN_RTABLEWINDOW_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RelationController.cxx b/dbaccess/source/ui/relationdesign/RelationController.cxx new file mode 100644 index 000000000..21a7c9e8b --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RelationController.cxx @@ -0,0 +1,566 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 + +#define MAX_THREADS 10 + +extern "C" void createRegistryInfo_ORelationControl() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::ORelationController > aAutoRegistration; +} + +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 getImplementationName_Static(); +} + +OUString ORelationController::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.ORelationDesign"; +} + +Sequence< OUString> ORelationController::getSupportedServiceNames_Static() +{ + Sequence aSupported { "com.sun.star.sdb.RelationDesign" }; + return aSupported; +} + +Sequence< OUString> SAL_CALL ORelationController::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference< XInterface > ORelationController::Create(const Reference& _rxFactory) +{ + return *(new ORelationController(comphelper::getComponentContext(_rxFactory))); +} + +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, makeAny( 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() ); + + std::copy( _aConnectionData.begin(), _aConnectionData.end(), std::back_inserter( m_vTableConnectionData )); + // 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(const OUString& _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 000000000..014579cf7 --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RelationDesignView.cxx @@ -0,0 +1,74 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#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() == MouseNotifyEvent::GETFOCUS) + { + if(m_pTableView && !m_pTableView->HasChildPathFocus()) + { + m_pTableView->GrabTabWinFocus(); + bDone = true; + } + } + if(!bDone) + bDone = OJoinDesignView::PreNotify(rNEvt); + return bDone; +} + +void ORelationDesignView::GetFocus() +{ + OJoinDesignView::GetFocus(); + if ( m_pTableView && m_pTableView->IsVisible() && !m_pTableView->GetTabWinMap().empty() ) + m_pTableView->GrabTabWinFocus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/relationdesign/RelationTableView.cxx b/dbaccess/source/ui/relationdesign/RelationTableView.cxx new file mode 100644 index 000000000..a55222096 --- /dev/null +++ b/dbaccess/source/ui/relationdesign/RelationTableView.cxx @@ -0,0 +1,407 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "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()); + + rTabWinDataList.erase( std::remove(rTabWinDataList.begin(), rTabWinDataList.end(), *aIter), rTabWinDataList.end()); + continue; + } + + GetTabWinMap()[pData->GetComposedName()] = pTabWin; // insert at the beginning, as the Datalist is walked through backward + // if there's no position or size contained in the data -> Default + if (!pData->HasPosition() && !pData->HasSize()) + SetDefaultTabWinPosSize(pTabWin); + + pTabWin->Show(); + } + + // insert connection + TTableConnectionData& rTabConnDataList = m_pView->getController().getTableConnectionData(); + TTableConnectionData::const_reverse_iterator aConIter = rTabConnDataList.rbegin(); + + for(;aConIter != rTabConnDataList.rend();++aConIter) + { + ORelationTableConnectionData* pTabConnData = static_cast(aConIter->get()); + if ( !arrInvalidTables.empty() ) + { + // do the tables to the connection exist? + OUString strTabExistenceTest = pTabConnData->getReferencingTable()->GetTableName(); + bool bInvalid = std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); + strTabExistenceTest = pTabConnData->getReferencedTable()->GetTableName(); + bInvalid = bInvalid || std::find(arrInvalidTables.begin(),arrInvalidTables.end(),strTabExistenceTest) != arrInvalidTables.end(); + + if (bInvalid) + { + // no -> bad luck, the connection is gone + rTabConnDataList.erase( std::remove(rTabConnDataList.begin(), rTabConnDataList.end(), *aConIter), rTabConnDataList.end() ); + continue; + } + } + + addConnection( VclPtr::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 + OUString sSourceFieldName = jxdSource.pListBox->GetEntryText(jxdSource.pEntry); + OUString sDestFieldName = jxdDest.pListBox->GetEntryText(jxdDest.pEntry); + + // 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&) + { + OSL_FAIL("ORelationTableView::AddConnection: Exception occurred!"); + } + } +} + +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&) + { + OSL_FAIL("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(), + makeAny(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/FieldDescGenWin.cxx b/dbaccess/source/ui/tabledesign/FieldDescGenWin.cxx new file mode 100644 index 000000000..1a052c190 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/FieldDescGenWin.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 "FieldDescGenWin.hxx" +#include +#include +#include +#include "TableFieldControl.hxx" +#include +#include "TEditControl.hxx" + +using namespace dbaui; + +OFieldDescGenWin::OFieldDescGenWin( vcl::Window* pParent, OTableDesignHelpBar* pHelp ) : + TabPage( pParent, WB_3DLOOK | WB_DIALOGCONTROL ) +{ + m_pFieldControl = VclPtr::Create(this,pHelp); + m_pFieldControl->SetHelpId(HID_TAB_DESIGN_FIELDCONTROL); + m_pFieldControl->Show(); +} + +OFieldDescGenWin::~OFieldDescGenWin() +{ + disposeOnce(); +} + +void OFieldDescGenWin::dispose() +{ + m_pFieldControl.disposeAndClear(); + TabPage::dispose(); +} + +void OFieldDescGenWin::Init() +{ + OSL_ENSURE(GetEditorCtrl() != nullptr, "OFieldDescGenWin::Init : have no editor control !"); + + m_pFieldControl->Init(); +} + +void OFieldDescGenWin::Resize() +{ + m_pFieldControl->SetPosSizePixel(Point(0,0),GetSizePixel()); + m_pFieldControl->Resize(); +} + +void OFieldDescGenWin::SetReadOnly( bool bReadOnly ) +{ + + m_pFieldControl->SetReadOnly(bReadOnly); +} + +void OFieldDescGenWin::SetControlText( sal_uInt16 nControlId, const OUString& rText ) +{ + // set texts of the controls + m_pFieldControl->SetControlText(nControlId,rText); +} + +void OFieldDescGenWin::DisplayData( OFieldDescription* pFieldDescr ) +{ + m_pFieldControl->DisplayData(pFieldDescr); +} + +OTableEditorCtrl* OFieldDescGenWin::GetEditorCtrl() +{ + OTableDesignView* pDesignWin = static_cast(GetParent()->GetParent()->GetParent()); + return pDesignWin->GetEditorCtrl(); +} + +void OFieldDescGenWin::SaveData( OFieldDescription* pFieldDescr ) +{ + m_pFieldControl->SaveData(pFieldDescr); +} + +void OFieldDescGenWin::GetFocus() +{ + // sets the focus to the control that was active last + TabPage::GetFocus(); + if(m_pFieldControl) + m_pFieldControl->GetFocus(); + +} + +void OFieldDescGenWin::LoseFocus() +{ + if (m_pFieldControl) + m_pFieldControl->LoseFocus(); + TabPage::LoseFocus(); +} + +OUString OFieldDescGenWin::BoolStringPersistent(const OUString& rUIString) const +{ + return m_pFieldControl->BoolStringPersistent(rUIString); +} + +OUString OFieldDescGenWin::BoolStringUI(const OUString& rPersistentString) const +{ + return m_pFieldControl->BoolStringUI(rPersistentString); +} + +bool OFieldDescGenWin::isCopyAllowed() +{ + return (m_pFieldControl && m_pFieldControl->isCutAllowed()); +} + +bool OFieldDescGenWin::isCutAllowed() +{ + return (m_pFieldControl && m_pFieldControl->isCutAllowed()); +} + +bool OFieldDescGenWin::isPasteAllowed() +{ + return (m_pFieldControl && m_pFieldControl->isPasteAllowed()); +} + +void OFieldDescGenWin::cut() +{ + if(m_pFieldControl) + m_pFieldControl->cut(); +} + +void OFieldDescGenWin::copy() +{ + if(m_pFieldControl) + m_pFieldControl->copy(); +} + +void OFieldDescGenWin::paste() +{ + if(m_pFieldControl) + m_pFieldControl->paste(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/FieldDescGenWin.hxx b/dbaccess/source/ui/tabledesign/FieldDescGenWin.hxx new file mode 100644 index 000000000..b43f8d1fa --- /dev/null +++ b/dbaccess/source/ui/tabledesign/FieldDescGenWin.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_FIELDDESCGENWIN_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_FIELDDESCGENWIN_HXX + +#include +#include + +namespace dbaui +{ + class OTableDesignHelpBar; + class OFieldDescription; + class OTableFieldControl; + class OTableEditorCtrl; + class OFieldDescGenWin : public TabPage + ,public IClipboardTest + { + + VclPtr m_pFieldControl; + protected: + virtual void Resize() override; + + public: + OFieldDescGenWin( vcl::Window* pParent, OTableDesignHelpBar* pHelpBar ); + virtual ~OFieldDescGenWin() override; + virtual void dispose() override; + + virtual void GetFocus() override; + virtual void LoseFocus() override; + void Init(); + + void DisplayData( OFieldDescription* pFieldDescr ); + void SaveData( OFieldDescription* pFieldDescr ); + void SetControlText( sal_uInt16 nControlId, const OUString& rText ); + void SetReadOnly( bool bReadOnly ); + OTableEditorCtrl* GetEditorCtrl(); + + // short GetFormatCategory(OFieldDescription* pFieldDescr); + // gives you one of the CAT_xxx-values (CAT_NUMBER, CAT_DATE ...) belonging to the format specified by the field + + OUString BoolStringPersistent(const OUString& rUIString) const; + OUString BoolStringUI(const OUString& rPersistentString) const; + + // 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; + + OTableFieldControl* getFieldControl() const { return m_pFieldControl; } + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_FIELDDESCGENWIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx new file mode 100644 index 000000000..6882f1216 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/FieldDescriptions.cxx @@ -0,0 +1,641 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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_pType() + ,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_pType() + ,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.get() == nullptr || 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::TIMESTAMP: + 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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny(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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny(_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,makeAny( dbaui::mapTextAllign(_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,makeAny(_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,makeAny(_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,makeAny(GetFormatKey())); + if ( GetHorJustify() != SvxCellHorJustify::Standard && xInfo->hasPropertyByName(PROPERTY_ALIGN) ) + _rxColumn->setPropertyValue(PROPERTY_ALIGN,makeAny(dbaui::mapTextAllign(GetHorJustify()))); + if ( !GetHelpText().isEmpty() && xInfo->hasPropertyByName(PROPERTY_HELPTEXT) ) + _rxColumn->setPropertyValue(PROPERTY_HELPTEXT,makeAny(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,makeAny(m_bHidden)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TEditControl.cxx b/dbaccess/source/ui/tabledesign/TEditControl.cxx new file mode 100644 index 000000000..6f5128faa --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TEditControl.cxx @@ -0,0 +1,1633 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "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_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) + :OTableRowView(pWindow) + ,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 + long 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 = EDIT_NOLIMIT; + OUString sExtraNameChars; + Reference xCon; + try + { + xCon = GetView()->getController().getConnection(); + Reference< XDatabaseMetaData> xMetaData = xCon.is() ? xCon->getMetaData() : Reference< XDatabaseMetaData>(); + + nMaxTextLen = xMetaData.is() ? xMetaData->getMaxColumnNameLength() : 0; + + if( nMaxTextLen == 0 ) + nMaxTextLen = EDIT_NOLIMIT; + sExtraNameChars = xMetaData.is() ? xMetaData->getExtraNameCharacters() : OUString(); + + } + catch(SQLException&) + { + OSL_FAIL("getMaxColumnNameLength"); + } + + pNameCell = VclPtr::Create(&GetDataWindow(), WB_LEFT, sExtraNameChars); + pNameCell->SetMaxTextLen( nMaxTextLen ); + pNameCell->setCheck( isSQL92CheckEnabled(xCon) ); + + // Cell type + pTypeCell = VclPtr::Create( &GetDataWindow() ); + + // Cell description + pDescrCell = VclPtr::Create( &GetDataWindow(), WB_LEFT ); + pDescrCell->SetMaxTextLen( MAX_DESCR_LEN ); + + pHelpTextCell = VclPtr::Create( &GetDataWindow(), WB_LEFT ); + pHelpTextCell->SetMaxTextLen( 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->ClearModifyFlag(); + pDescrCell->ClearModifyFlag(); + pHelpTextCell->ClearModifyFlag(); + 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.clear(); + OTableRowView::dispose(); +} + +bool OTableEditorCtrl::SetDataPtr( long 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(long _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( PushFlags::CLIPREGION ); + rDev.SetClipRegion(vcl::Region(rRect)); + rDev.DrawText( rRect, aText, DrawTextFlags::Left | DrawTextFlags::VCenter ); + rDev.Pop(); +} + +CellController* OTableEditorCtrl::GetController(long 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&, long 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(); + pNameCell->SetText( aInitString ); + pNameCell->SaveValue(); + 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(); + pHelpTextCell->SetText( aInitString ); + pHelpTextCell->SaveValue(); + break; + case COLUMN_DESCRIPTION: + if( pActFieldDescr ) + aInitString = pActFieldDescr->GetDescription(); + pDescrCell->SetText( aInitString ); + pDescrCell->SaveValue(); + break; + + } +} + +EditBrowseBox::RowStatus OTableEditorCtrl::GetRowStatus(long 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(long 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( const OUString& 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(long 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 + const OUString aName(pNameCell->GetText()); + + 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 ); + pNameCell->ClearModifyFlag(); + + break; + } + + // Store the field type + case FIELD_TYPE: + break; + + // Store DescrCell + case HELP_TEXT: + { + // if the current field description is NULL, set Default + if( !pActFieldDescr ) + { + pHelpTextCell->SetText(OUString()); + pHelpTextCell->ClearModifyFlag(); + } + else + pActFieldDescr->SetHelpText( pHelpTextCell->GetText() ); + break; + } + case COLUMN_DESCRIPTION: + { + // Set the default if the field description is null + if( !pActFieldDescr ) + { + pDescrCell->SetText(OUString()); + pDescrCell->ClearModifyFlag(); + } + else + pActFieldDescr->SetDescription( pDescrCell->GetText() ); + 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(long 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( long 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); + CellControllerRef xController(Controller()); + if(xController.is()) + xController->SetModified(); + + // 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( 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(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( long 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(); + long 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,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 + 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( long nRow ) +{ + OSL_ENSURE(GetView()->getController().isAddAllowed(),"Call of InsertNewRows not valid here. Please check isAppendAllowed!"); + // Create Undo-Action + long nInsertRows = GetSelectRowCount(); + if( !nInsertRows ) + nInsertRows = 1; + GetUndoManager().AddUndoAction( std::make_unique(this, nRow, nInsertRows) ); + // Insert the number of selected rows + for( 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( long 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( long 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( long 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()->getFieldControl()->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(makeAny(sValue)); + break; + + case FIELD_PROPERTY_FORMAT: + { + sValue = ::comphelper::getString(_rNewData); + pFieldDescr->SetFormatKey(sValue.toInt32()); + } + break; + } + + SetControlText(nRow,nColId,sValue); +} + +Any OTableEditorCtrl::GetCellData( long 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 makeAny(sValue); +} + +OUString OTableEditorCtrl::GetCellText( long nRow, sal_uInt16 nColId ) const +{ + OUString sCellText; + const_cast< OTableEditorCtrl* >( this )->GetCellData( nRow, nColId ) >>= sCellText; + return sCellText; +} + +sal_uInt32 OTableEditorCtrl::GetTotalCellWidth(long nRow, sal_uInt16 nColId) +{ + return GetTextWidth(GetCellText(nRow, nColId)) + 2 * GetTextWidth("0"); +} + +OFieldDescription* OTableEditorCtrl::GetFieldDescr( long 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) + { + switch(m_eChildFocus) + { + case DESCRIPTION: + bIsCutAllowed = !pDescrCell->GetSelected().isEmpty(); + break; + case HELPTEXT: + bIsCutAllowed = !pHelpTextCell->GetSelected().isEmpty(); + break; + case NAME: + bIsCutAllowed = !pNameCell->GetSelected().isEmpty(); + break; + case ROW: + bIsCutAllowed = IsCopyAllowed(); + break; + default: + bIsCutAllowed = false; + break; + } + } + + return bIsCutAllowed; +} + +bool OTableEditorCtrl::IsCopyAllowed() +{ + bool bIsCopyAllowed = false; + if(m_eChildFocus == DESCRIPTION ) + bIsCopyAllowed = !pDescrCell->GetSelected().isEmpty(); + else if(HELPTEXT == m_eChildFocus ) + bIsCopyAllowed = !pHelpTextCell->GetSelected().isEmpty(); + else if(m_eChildFocus == NAME) + bIsCopyAllowed = !pNameCell->GetSelected().isEmpty(); + 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; + 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->Cut(); + CellModified(-1,FIELD_NAME); + } + } + else if(m_eChildFocus == DESCRIPTION) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,COLUMN_DESCRIPTION); + pDescrCell->Cut(); + CellModified(-1,COLUMN_DESCRIPTION); + } + } + else if(HELPTEXT == m_eChildFocus ) + { + if(GetView()->getController().isAlterAllowed()) + { + SaveData(-1,HELP_TEXT); + pHelpTextCell->Cut(); + 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) + pNameCell->Copy(); + else if(HELPTEXT == m_eChildFocus ) + pHelpTextCell->Copy(); + else if(m_eChildFocus == DESCRIPTION ) + pDescrCell->Copy(); +} + +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->Paste(); + CellModified(); + } + } + else if(HELPTEXT == m_eChildFocus ) + { + if(GetView()->getController().isAlterAllowed()) + { + pHelpTextCell->Paste(); + CellModified(); + } + } + else if(m_eChildFocus == DESCRIPTION) + { + if(GetView()->getController().isAlterAllowed()) + { + pDescrCell->Paste(); + CellModified(); + } + } +} + +bool OTableEditorCtrl::IsDeleteAllowed() +{ + + return GetSelectRowCount() != 0 && GetView()->getController().isDropAllowed(); +} + +bool OTableEditorCtrl::IsInsertNewAllowed( long 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). + 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())); + long 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 ); + + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/querycolmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + aContextMenu->EnableItem(aContextMenu->GetItemId("delete"), false); + aContextMenu->RemoveDisabledEntries(true, true); + if (aContextMenu->Execute(this, aMenuPos) == aContextMenu->GetItemId("width")) + adjustBrowseBoxColumnWidth( this, nColId ); + } + } + } + else + { + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/tabledesignrowmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + + aContextMenu->EnableItem(aContextMenu->GetItemId("cut"), IsCutAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("copy"), IsCopyAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("paste"), IsPasteAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("delete"), IsDeleteAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("primarykey"), IsPrimaryKeyAllowed()); + aContextMenu->EnableItem(aContextMenu->GetItemId("insert"), IsInsertNewAllowed(nRow)); + aContextMenu->CheckItem("primarykey", IsRowSelected(GetCurRow()) && IsPrimaryKey()); + + // remove all the disable entries + aContextMenu->RemoveDisabledEntries(true, true); + + 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(); + aContextMenu->Execute(this, aMenuPos); + OString sIdent = aContextMenu->GetCurItemIdent(); + 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 ) + { + 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 ? + 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 + long nRow(GetCurRow()); + OFieldDescription* pActFieldDescr = GetFieldDescr( nRow ); + if( pActFieldDescr ) + // Store the old description + pDescrWin->SaveData( pActFieldDescr ); + + if ( nRow < 0 || nRow > static_cast(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 static_cast(GetParent()->GetParent()); +} + +void OTableEditorCtrl::DeactivateCell(bool bUpdate) +{ + OTableRowView::DeactivateCell(bUpdate); + // now we have to deactivate the field description + long nRow(GetCurRow()); + if (pDescrWin) + pDescrWin->SetReadOnly(bReadOnly || !SetDataPtr(nRow) || GetActRow()->IsReadOnly()); +} + +bool OTableEditorCtrl::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if( pHelpTextCell && pHelpTextCell->HasChildPathFocus() ) + m_eChildFocus = HELPTEXT; + else if( pDescrCell && pDescrCell->HasChildPathFocus() ) + m_eChildFocus = DESCRIPTION; + else if(pNameCell && pNameCell->HasChildPathFocus() ) + m_eChildFocus = NAME; + else + m_eChildFocus = ROW; + } + + return OTableRowView::PreNotify(rNEvt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TEditControl.hxx b/dbaccess/source/ui/tabledesign/TEditControl.hxx new file mode 100644 index 000000000..44469bf29 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TEditControl.hxx @@ -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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TEDITCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TEDITCONTROL_HXX + +#include +#include +#include "TableFieldDescWin.hxx" +#include +#include + +class Edit; +class SfxUndoManager; +namespace dbaui +{ + class OSQLNameEdit; + + class OTableEditorCtrl : public OTableRowView + { + enum ChildFocusState + { + HELPTEXT, + DESCRIPTION, + NAME, + ROW, + NONE + }; + + std::vector< std::shared_ptr >* m_pRowList; + + VclPtr pNameCell; + VclPtr< ::svt::ListBoxControl> pTypeCell; + VclPtr pHelpTextCell; + VclPtr pDescrCell; + VclPtr pDescrWin; // properties of one column + + std::shared_ptr pActRow; + + ImplSVEvent * nCutEvent; + ImplSVEvent * nPasteEvent; + ImplSVEvent * nDeleteEvent; + ImplSVEvent * nInsNewRowsEvent; + ImplSVEvent * nInvalidateTypeEvent; + ChildFocusState m_eChildFocus; + + 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(long nRow) override; + virtual void PaintCell(OutputDevice& rDev, const tools::Rectangle& rRect, + sal_uInt16 nColumnId ) const override; + + virtual void CursorMoved() override; + virtual RowStatus GetRowStatus(long nRow) const override; + + virtual ::svt::CellController* GetController(long nRow, sal_uInt16 nCol) override; + virtual void InitController(::svt::CellControllerRef& rController, long 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(long nRow, sal_uInt16 nColId) const override; + virtual sal_uInt32 GetTotalCellWidth(long nRow, sal_uInt16 nColId) override; + + virtual void CopyRows() override; + virtual void InsertRows( long nRow ) override; + virtual void DeleteRows() override; + virtual void InsertNewRows( long nRow ) override; + + virtual bool IsPrimaryKeyAllowed() override; + virtual bool IsInsertNewAllowed( long nRow ) override; + virtual bool IsDeleteAllowed() override; + + void ClearModified(); + + void SetPrimaryKey( bool bSet ); + bool IsPrimaryKey(); + + public: + explicit OTableEditorCtrl(vcl::Window* pParentWin); + virtual ~OTableEditorCtrl() override; + virtual void dispose() override; + virtual bool CursorMoving(long 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( long nRow ); + + virtual void SetCellData( long nRow, sal_uInt16 nColId, const TOTypeInfoSP& _pTypeInfo ) override; + virtual void SetCellData( long nRow, sal_uInt16 nColId, const css::uno::Any& _rSaveData ) override; + virtual css::uno::Any GetCellData( long nRow, sal_uInt16 nColId ) override; + virtual void SetControlText( long 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( long 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( long 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( const OUString& rFieldName ); + OUString GenerateName( const OUString& rName ); + bool SetDataPtr( long nRow ); + + void SaveData(long 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(); + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TEDITCONTROL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableController.cxx b/dbaccess/source/ui/tabledesign/TableController.cxx new file mode 100644 index 000000000..f88110b48 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableController.cxx @@ -0,0 +1,1511 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include + +extern "C" void createRegistryInfo_OTableControl() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OTableController > aAutoRegistration; +} + +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 getImplementationName_Static(); +} + +OUString OTableController::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.OTableDesign"; +} + +Sequence< OUString> OTableController::getSupportedServiceNames_Static() +{ + return { "com.sun.star.sdb.TableDesign" }; +} + +Sequence< OUString> SAL_CALL OTableController::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +Reference< XInterface > OTableController::Create(const Reference& _rxFactory) +{ + return *(new OTableController(comphelper::getComponentContext(_rxFactory))); +} + +OTableController::OTableController(const Reference< XComponentContext >& _rM) : OTableController_BASE(_rM) + ,m_sTypeNames(DBA_RES(STR_TABLEDESIGN_DBFIELDTYPES)) + ,m_pTypeInfo() + ,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() && m_aCurrentFrame.isActive() && getView() && static_cast(getView())->isCutAllowed(); + break; + case ID_BROWSER_COPY: + aReturn.bEnabled = m_aCurrentFrame.isActive() && getView() && static_cast(getView())->isCopyAllowed(); + break; + case ID_BROWSER_PASTE: + aReturn.bEnabled = isEditable() && m_aCurrentFrame.isActive() && 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,makeAny(sCatalog)); + xTable->setPropertyValue(PROPERTY_SCHEMANAME,makeAny(sSchema)); + xTable->setPropertyValue(PROPERTY_NAME,makeAny(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,makeAny(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,makeAny(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; + OUString const sCreate("x"); + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(m_aTypeInfo,nType,sTypeName,sCreate,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,makeAny(pField->GetHelpText())); + + if(xInfo->hasPropertyByName(PROPERTY_CONTROLDEFAULT)) + xColumn->setPropertyValue(PROPERTY_CONTROLDEFAULT,pField->GetControlDefault()); + if(xInfo->hasPropertyByName(PROPERTY_FORMATKEY)) + xColumn->setPropertyValue(PROPERTY_FORMATKEY,makeAny(pField->GetFormatKey())); + if(xInfo->hasPropertyByName(PROPERTY_ALIGN)) + xColumn->setPropertyValue(PROPERTY_ALIGN,makeAny(dbaui::mapTextAllign(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&) + { + OUString sError( DBA_RES( STR_TABLEDESIGN_COULD_NOT_DROP_COL ) ); + sError = sError.replaceFirst( "$column$", rColumnName ); + + SQLException aNewException; + aNewException.Message = sError; + aNewException.SQLState = "S1000"; + aNewException.NextException = ::cppu::getCaughtException(); + + throw aNewException; + } + } + } + } + + // third append the new columns + for(const auto& rxRow : m_vRowList) + { + OSL_ENSURE(rxRow,"OTableRow is null!"); + OFieldDescription* pField = rxRow->GetActFieldDescr(); + if ( !pField || rxRow->IsReadOnly() || aColumns.find(pField->GetName()) != aColumns.end() ) + continue; + + Reference 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 = aName.getToken(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 000000000..2fe3e5ec9 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignControl.cxx @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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; +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())); + long nRow = GetRowAtYPosPixel(rEvt.GetMousePosPixel().Y()); + + if ( nColId == HANDLE_ID ) + { + VclBuilder aBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "dbaccess/ui/querycolmenu.ui", ""); + VclPtr aContextMenu(aBuilder.get_menu("menu")); + long nSelectRowCount = GetSelectRowCount(); + aContextMenu->EnableItem(aContextMenu->GetItemId("cut"), nSelectRowCount != 0); + aContextMenu->EnableItem(aContextMenu->GetItemId("copy"), nSelectRowCount != 0); + aContextMenu->EnableItem(aContextMenu->GetItemId("paste"), false); + aContextMenu->EnableItem(aContextMenu->GetItemId("delete"), false); + aContextMenu->Execute(this, rEvt.GetMousePosPixel()); + OString sIdent = aContextMenu->GetCurItemIdent(); + if (sIdent == "cut") + cut(); + else if (sIdent == "copy") + copy(); + else if (sIdent == "paste") + { + Paste( nRow ); + SetNoSelection(); + GoToRow( nRow ); + SeekRow( nRow ); + } + else if (sIdent == "delete") + DeleteRows(); + 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( long nRow ) +{ + InsertRows( nRow ); +} + +EditBrowseBox::RowStatus OTableRowView::GetRowStatus(long nRow) const +{ + if (nRow >= 0 && m_nDataPos == nRow) + return CURRENT; + else + return CLEAN; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx b/dbaccess/source/ui/tabledesign/TableDesignHelpBar.cxx new file mode 100644 index 000000000..3d73ff0e6 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignHelpBar.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 +#include +#include +#include + +using namespace dbaui; +#define STANDARD_MARGIN 6 +OTableDesignHelpBar::OTableDesignHelpBar( vcl::Window* pParent ) : + TabPage( pParent, WB_3DLOOK ) +{ + m_pTextWin = VclPtr::Create( this, WB_VSCROLL | WB_LEFT | WB_BORDER | WB_NOTABSTOP | WB_READONLY); + m_pTextWin->SetHelpId(HID_TABLE_DESIGN_HELP_WINDOW); + m_pTextWin->SetReadOnly(); + m_pTextWin->SetControlBackground( GetSettings().GetStyleSettings().GetFaceColor() ); + m_pTextWin->Show(); +} + +OTableDesignHelpBar::~OTableDesignHelpBar() +{ + disposeOnce(); +} + +void OTableDesignHelpBar::dispose() +{ + m_pTextWin.disposeAndClear(); + TabPage::dispose(); +} + +void OTableDesignHelpBar::SetHelpText( const OUString& rText ) +{ + if(m_pTextWin) + m_pTextWin->SetText( rText ); + Invalidate(); +} + +void OTableDesignHelpBar::Resize() +{ + // parent window dimensions + Size aOutputSize( GetOutputSizePixel() ); + + // adapt the TextWin + if(m_pTextWin) + m_pTextWin->SetPosSizePixel( Point(STANDARD_MARGIN+1, STANDARD_MARGIN+1), + Size(aOutputSize.Width()-(2*STANDARD_MARGIN)-2, + aOutputSize.Height()-(2*STANDARD_MARGIN)-2) ); + +} + +bool OTableDesignHelpBar::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::LOSEFOCUS) + SetHelpText(OUString()); + return TabPage::PreNotify(rNEvt); +} + +bool OTableDesignHelpBar::isCopyAllowed() +{ + return m_pTextWin && !m_pTextWin->GetSelected().isEmpty(); +} + +bool OTableDesignHelpBar::isCutAllowed() +{ + return false; +} + +bool OTableDesignHelpBar::isPasteAllowed() +{ + return false; +} + +void OTableDesignHelpBar::cut() +{ +} + +void OTableDesignHelpBar::copy() +{ + if ( m_pTextWin ) + m_pTextWin->Copy(); +} + +void OTableDesignHelpBar::paste() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableDesignView.cxx b/dbaccess/source/ui/tabledesign/TableDesignView.cxx new file mode 100644 index 000000000..af223a287 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableDesignView.cxx @@ -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 . + */ + +#include +#include +#include +#include +#include "TEditControl.hxx" +#include "TableFieldDescWin.hxx" +#include +#include +#include +#include +#include + +using namespace ::dbaui; +using namespace ::utl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::datatransfer::clipboard; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +OTableBorderWindow::OTableBorderWindow(vcl::Window* pParent) : Window(pParent,WB_BORDER) + ,m_aHorzSplitter( VclPtr::Create(this) ) +{ + + ImplInitSettings(); + // create children + m_pEditorCtrl = VclPtr::Create( this); + m_pFieldDescWin = VclPtr::Create( this ); + + m_pFieldDescWin->SetHelpId(HID_TAB_DESIGN_DESCWIN); + + // set depending windows and controls + m_pEditorCtrl->SetDescrWin(m_pFieldDescWin); + + // set up splitter + m_aHorzSplitter->SetSplitHdl( LINK(this, OTableBorderWindow, SplitHdl) ); + m_aHorzSplitter->Show(); +} + +OTableBorderWindow::~OTableBorderWindow() +{ + disposeOnce(); +} + +void OTableBorderWindow::dispose() +{ + // destroy children + // ::dbaui::notifySystemWindow(this,m_pFieldDescWin,::comphelper::mem_fun(&TaskPaneList::RemoveWindow)); + m_pEditorCtrl->Hide(); + m_pFieldDescWin->Hide(); + m_pEditorCtrl.disposeAndClear(); + m_pFieldDescWin.disposeAndClear(); + m_aHorzSplitter.disposeAndClear(); + vcl::Window::dispose(); +} + +void OTableBorderWindow::Resize() +{ + const long nSplitterHeight(3); + + // dimensions of parent window + Size aOutputSize( GetOutputSize() ); + long nOutputWidth = aOutputSize.Width(); + long nOutputHeight = aOutputSize.Height(); + long nSplitPos = m_aHorzSplitter->GetSplitPosPixel(); + + // shift range of the splitter is the middle third of the output + long nDragPosY = nOutputHeight/3; + long nDragSizeHeight = nOutputHeight/3; + m_aHorzSplitter->SetDragRectPixel( tools::Rectangle(Point(0,nDragPosY), Size(nOutputWidth,nDragSizeHeight) ), this ); + if( (nSplitPos < nDragPosY) || (nSplitPos > (nDragPosY+nDragSizeHeight)) ) + nSplitPos = nDragPosY+nDragSizeHeight-5; + + // set splitter + m_aHorzSplitter->SetPosSizePixel( Point( 0, nSplitPos ), Size(nOutputWidth, nSplitterHeight)); + m_aHorzSplitter->SetSplitPosPixel( nSplitPos ); + + // set window + m_pEditorCtrl->SetPosSizePixel( Point(0, 0), Size(nOutputWidth , nSplitPos) ); + + m_pFieldDescWin->SetPosSizePixel( Point(0, nSplitPos+nSplitterHeight), + Size(nOutputWidth, nOutputHeight-nSplitPos-nSplitterHeight) ); +} + +IMPL_LINK( OTableBorderWindow, SplitHdl, Splitter*, pSplit, void ) +{ + if(pSplit == m_aHorzSplitter.get()) + { + m_aHorzSplitter->SetPosPixel( Point( m_aHorzSplitter->GetPosPixel().X(),m_aHorzSplitter->GetSplitPosPixel() ) ); + Resize(); + } +} + +void OTableBorderWindow::ImplInitSettings() +{ + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + + // FIXME RenderContext + + vcl::Font aFont = rStyleSettings.GetAppFont(); + if ( IsControlFont() ) + aFont.Merge( GetControlFont() ); + SetPointFont(*this, aFont); + + Color aTextColor = rStyleSettings.GetButtonTextColor(); + if ( IsControlForeground() ) + aTextColor = GetControlForeground(); + SetTextColor( aTextColor ); + + if( IsControlBackground() ) + SetBackground( GetControlBackground() ); + else + SetBackground( rStyleSettings.GetFaceColor() ); +} + +void OTableBorderWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + Window::DataChanged( rDCEvt ); + + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + ImplInitSettings(); + Invalidate(); + } +} + +void OTableBorderWindow::GetFocus() +{ + Window::GetFocus(); + + // forward the focus to the current cell of the editor control + if (m_pEditorCtrl) + m_pEditorCtrl->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->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 ) ); +} + +bool OTableDesignView::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if( GetDescWin() && GetDescWin()->HasChildPathFocus() ) + m_eChildFocus = DESCRIPTION; + else if ( GetEditorCtrl() && GetEditorCtrl()->HasChildPathFocus() ) + m_eChildFocus = EDITOR; + else + m_eChildFocus = NONE; + } + + return ODataView::PreNotify(rNEvt); +} + +IClipboardTest* OTableDesignView::getActiveChild() const +{ + IClipboardTest* pTest = nullptr; + switch(m_eChildFocus) + { + case DESCRIPTION: + pTest = GetDescWin(); + break; + case EDITOR: + pTest = GetEditorCtrl(); + break; + case NONE: + break; + } + return pTest; +} + +bool OTableDesignView::isCopyAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isCopyAllowed(); +} + +bool OTableDesignView::isCutAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isCutAllowed(); +} + +bool OTableDesignView::isPasteAllowed() +{ + IClipboardTest* pTest = getActiveChild(); + return pTest && pTest->isPasteAllowed(); +} + +void OTableDesignView::copy() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->copy(); +} + +void OTableDesignView::cut() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->cut(); +} + +void OTableDesignView::paste() +{ + IClipboardTest* pTest = getActiveChild(); + if ( pTest ) + pTest->paste(); +} + +// set the view readonly or not +void OTableDesignView::setReadOnly(bool _bReadOnly) +{ + GetDescWin()->SetReadOnly(_bReadOnly); + GetEditorCtrl()->SetReadOnly(_bReadOnly); +} + +void OTableDesignView::reSync() +{ + GetEditorCtrl()->DeactivateCell(); + std::shared_ptr pRow = (*GetEditorCtrl()->GetRowList())[GetEditorCtrl()->GetCurRow()]; + OFieldDescription* pFieldDescr = pRow ? pRow->GetActFieldDescr() : nullptr; + if ( pFieldDescr ) + GetDescWin()->DisplayData(pFieldDescr); +} + +void OTableDesignView::GetFocus() +{ + if ( GetEditorCtrl() ) + GetEditorCtrl()->GrabFocus(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldControl.cxx b/dbaccess/source/ui/tabledesign/TableFieldControl.cxx new file mode 100644 index 000000000..cbd99179c --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldControl.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 "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(vcl::Window* pParent, OTableDesignHelpBar* pHelpBar) + : OFieldDescControl(nullptr, pParent, pHelpBar) +{ +} + +void OTableFieldControl::CellModified(long nRow, sal_uInt16 nColId ) +{ + GetCtrl()->CellModified(nRow,nColId); +} + +OTableEditorCtrl* OTableFieldControl::GetCtrl() const +{ + OTableDesignView* pDesignWin = static_cast(GetParent()->GetParent()->GetParent()->GetParent()); + OSL_ENSURE(pDesignWin,"no view!"); + return pDesignWin->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 000000000..42697bdb7 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldControl.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDCONTROL_HXX + +#include + +namespace dbaui +{ + class OTableEditorCtrl; + class OTableDesignHelpBar; + // OTableFieldControl + class OTableFieldControl : public OFieldDescControl + { + OTableEditorCtrl* GetCtrl() const; + protected: + virtual void ActivateAggregate( EControlType eType ) override; + virtual void DeactivateAggregate( EControlType eType ) override; + // are to be implemented by the derived classes + virtual void CellModified(long 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( vcl::Window* pParent, OTableDesignHelpBar* pHelpBar); + + using OFieldDescControl::BoolStringPersistent; + using OFieldDescControl::BoolStringUI; + + virtual css::uno::Reference< css::sdbc::XDatabaseMetaData> getMetaData() override; + virtual css::uno::Reference< css::sdbc::XConnection> getConnection() override; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDCONTROL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx b/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx new file mode 100644 index 000000000..950750794 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.cxx @@ -0,0 +1,275 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include + +#define STANDARD_MARGIN 6 +#define DETAILS_HEADER_HEIGHT 25 +#define CONTROL_SPACING_X 18 // 6 +#define CONTROL_SPACING_Y 5 +#define CONTROL_HEIGHT 20 +#define CONTROL_WIDTH_1 140 // 100 +#define CONTROL_WIDTH_3 250 +#define CONTROL_WIDTH_4 (CONTROL_WIDTH_3 - CONTROL_HEIGHT - 5) +#define DETAILS_OPT_PAGE_WIDTH (CONTROL_WIDTH_1 + CONTROL_SPACING_X + CONTROL_WIDTH_4 + 50) +#define DETAILS_OPT_PAGE_HEIGHT ((CONTROL_HEIGHT + CONTROL_SPACING_Y) * 5) +#define DETAILS_MIN_HELP_WIDTH 100 +#define DETAILS_OPT_HELP_WIDTH 200 +#define DETAILS_MIN_HELP_HEIGHT 50 +#define DETAILS_OPT_HELP_HEIGHT 100 + +using namespace dbaui; +OTableFieldDescWin::OTableFieldDescWin( vcl::Window* pParent) + : TabPage(pParent, WB_3DLOOK) + , m_eChildFocus(NONE) +{ + // Header + m_pHeader = VclPtr::Create( this, WB_CENTER ); + m_pHeader->SetText(DBA_RES(STR_TAB_PROPERTIES)); + m_pHeader->Show(); + + // HelpBar + m_pHelpBar = VclPtr::Create( this ); + m_pHelpBar->SetHelpId(HID_TAB_DESIGN_HELP_TEXT_FRAME); + m_pHelpBar->Show(); + + m_pGenPage = VclPtr::Create( this, m_pHelpBar ); + getGenPage()->SetHelpId( HID_TABLE_DESIGN_TABPAGE_GENERAL ); + getGenPage()->Show(); +} + +OTableFieldDescWin::~OTableFieldDescWin() +{ + disposeOnce(); +} + +void OTableFieldDescWin::dispose() +{ + // destroy children + m_pHelpBar->Hide(); + getGenPage()->Hide(); + m_pHeader->Hide(); + + m_pGenPage.disposeAndClear(); + m_pHeader.disposeAndClear(); + m_pHelpBar.disposeAndClear(); + TabPage::dispose(); +} + +void OTableFieldDescWin::Init() +{ + OSL_ENSURE(getGenPage() != nullptr, "OTableFieldDescWin::Init : ups ... no GenericPage ... this will crash ..."); + getGenPage()->Init(); +} + +void OTableFieldDescWin::SetReadOnly( bool bRead ) +{ + getGenPage()->SetReadOnly( bRead ); +} + +void OTableFieldDescWin::DisplayData( OFieldDescription* pFieldDescr ) +{ + getGenPage()->DisplayData( pFieldDescr ); +} + +void OTableFieldDescWin::SaveData( OFieldDescription* pFieldDescr ) +{ + getGenPage()->SaveData( pFieldDescr ); +} + +void OTableFieldDescWin::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/) +{ + // 3D-line at the top window border + const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); + + rRenderContext.SetLineColor(rStyleSettings.GetLightColor()); + rRenderContext.DrawLine(Point(0,0), Point(GetSizePixel().Width(), 0)); + + // 3D-line for the separation of the header + rRenderContext.DrawLine(Point(3, DETAILS_HEADER_HEIGHT), Point(GetSizePixel().Width() - 6, DETAILS_HEADER_HEIGHT)); + rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); + rRenderContext.DrawLine(Point(3, DETAILS_HEADER_HEIGHT - 1), Point(GetSizePixel().Width() - 6, DETAILS_HEADER_HEIGHT - 1)); +} + +void OTableFieldDescWin::Resize() +{ + // dimensions of the parent window + Size aOutputSize( GetOutputSizePixel() ); + long nOutputWidth = aOutputSize.Width(); + long nOutputHeight = aOutputSize.Height(); + + // since the GenPage can scroll, but I can't, I position the HelpWindow, in case I become too slim, + // _below_ the Genpage, not on the right side. But before that I try to make it a bit smaller + + long nHelpX, nHelpY; + long nHelpWidth, nHelpHeight; + long nPageWidth, nPageHeight; + + // do both fit next to each other (margin + page + margin + help)? + if (STANDARD_MARGIN + DETAILS_OPT_PAGE_WIDTH + STANDARD_MARGIN + DETAILS_MIN_HELP_WIDTH <= nOutputWidth) + { // yes -> then we wonder if can give the help its optimum width + nHelpWidth = DETAILS_OPT_HELP_WIDTH; + nPageWidth = nOutputWidth - nHelpWidth - STANDARD_MARGIN - STANDARD_MARGIN; + if (nPageWidth < DETAILS_OPT_PAGE_WIDTH) + { // rather resize the help from its optimal width to its minimum width + long nTransfer = DETAILS_OPT_PAGE_WIDTH - nPageWidth; + nPageWidth += nTransfer; + nHelpWidth -= nTransfer; + } + nHelpX = nOutputWidth - nHelpWidth; + // the heights are simple in that case... + nHelpY = DETAILS_HEADER_HEIGHT + 1; + nHelpHeight = nOutputHeight - nHelpY; + nPageHeight = nOutputHeight - STANDARD_MARGIN - DETAILS_HEADER_HEIGHT - STANDARD_MARGIN; + } + else + { // doesn't work next to each other, thus below each other (margin + header + page + help) + if (STANDARD_MARGIN + DETAILS_HEADER_HEIGHT + DETAILS_OPT_PAGE_HEIGHT + DETAILS_MIN_HELP_HEIGHT <= nOutputHeight) + { // it's at least enough, to fit both below each other (page optimal, help minimal) + nHelpHeight = DETAILS_OPT_HELP_HEIGHT; + nPageHeight = nOutputHeight - nHelpHeight - DETAILS_HEADER_HEIGHT - STANDARD_MARGIN; + if (nPageHeight < DETAILS_OPT_PAGE_HEIGHT) + { // like above: page optimal, help gets whatever is left (which is bigger/equal to its minimum) + long nTransfer = DETAILS_OPT_PAGE_HEIGHT - nPageHeight; + nPageHeight += nTransfer; + nHelpHeight -= nTransfer; + } + nHelpY = nOutputHeight - nHelpHeight; + // and across the entire width + nHelpX = 0; // without margin, since the HelpCtrl has its own one + nHelpWidth = nOutputWidth; // dito + nPageWidth = nOutputWidth - STANDARD_MARGIN - STANDARD_MARGIN; + } + else + { // unfortunately that's not even enough, to show page at its optimum and help with minimum width + nHelpX = nHelpY = nHelpWidth = nHelpHeight = 0; // thus no help window + nPageWidth = nOutputWidth - STANDARD_MARGIN - STANDARD_MARGIN; + nPageHeight = nOutputHeight - STANDARD_MARGIN - DETAILS_HEADER_HEIGHT - STANDARD_MARGIN; + } + } + + m_pHeader->SetPosSizePixel( Point(0, STANDARD_MARGIN), Size(nOutputWidth, 15) ); + + getGenPage()->SetPosSizePixel(Point ( STANDARD_MARGIN, + STANDARD_MARGIN + DETAILS_HEADER_HEIGHT + ), + Size ( nPageWidth, + nPageHeight + ) + ); + if (nHelpHeight) + { + m_pHelpBar->Show(); + m_pHelpBar->SetPosSizePixel(Point ( nHelpX, + nHelpY + ), + Size ( nHelpWidth, + nHelpHeight + ) + ); + } + else + { + m_pHelpBar->Hide(); + } + Invalidate(); +} + +IClipboardTest* OTableFieldDescWin::getActiveChild() const +{ + IClipboardTest* pTest = nullptr; + switch(m_eChildFocus) + { + case DESCRIPTION: + pTest = getGenPage(); + break; + default: + pTest = m_pHelpBar; + break; + } + return pTest; +} + +bool OTableFieldDescWin::isCopyAllowed() +{ + return getActiveChild() && getActiveChild()->isCopyAllowed(); +} + +bool OTableFieldDescWin::isCutAllowed() +{ + return (getGenPage() && getGenPage()->HasChildPathFocus() && getGenPage()->isCutAllowed()); +} + +bool OTableFieldDescWin::isPasteAllowed() +{ + return (getGenPage() && getGenPage()->HasChildPathFocus() && getGenPage()->isPasteAllowed()); +} + +void OTableFieldDescWin::cut() +{ + if ( getGenPage() && getGenPage()->HasChildPathFocus() ) + getGenPage()->cut(); +} + +void OTableFieldDescWin::copy() +{ + if ( getActiveChild() ) + getActiveChild()->copy(); +} + +void OTableFieldDescWin::paste() +{ + if ( getGenPage() && getGenPage()->HasChildPathFocus() ) + getGenPage()->paste(); +} + +void OTableFieldDescWin::GetFocus() +{ + if ( getGenPage() ) + getGenPage()->GetFocus(); +} + +void OTableFieldDescWin::LoseFocus() +{ + if ( getGenPage() ) + getGenPage()->LoseFocus(); +} + +bool OTableFieldDescWin::PreNotify( NotifyEvent& rNEvt ) +{ + if (rNEvt.GetType() == MouseNotifyEvent::GETFOCUS) + { + if( getGenPage() && getGenPage()->HasChildPathFocus() ) + m_eChildFocus = DESCRIPTION; + else + m_eChildFocus = HELP; + } + return TabPage::PreNotify(rNEvt); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx b/dbaccess/source/ui/tabledesign/TableFieldDescWin.hxx new file mode 100644 index 000000000..e85557f24 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableFieldDescWin.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDDESCWIN_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDDESCWIN_HXX + +#include +#include "FieldDescGenWin.hxx" +#include + +class FixedText; +namespace dbaui +{ + class OFieldDescGenWin; + class OTableDesignHelpBar; + class OFieldDescription; + // derivative of TabPage is a trick of TH, + // to notice a change in system colours + class OTableFieldDescWin : public TabPage + ,public IClipboardTest + { + enum ChildFocusState + { + DESCRIPTION, + HELP, + NONE + }; + private: + VclPtr m_pHelpBar; + VclPtr m_pGenPage; + VclPtr m_pHeader; + ChildFocusState m_eChildFocus; + + IClipboardTest* getActiveChild() const; + + protected: + virtual void Resize() override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + + public: + explicit OTableFieldDescWin( vcl::Window* pParent); + virtual ~OTableFieldDescWin() override; + virtual void dispose() override; + + void Init(); + + void DisplayData( OFieldDescription* pFieldDescr ); + void SaveData( OFieldDescription* pFieldDescr ); + void SetReadOnly( bool bReadOnly ); + + // Window overrides + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + virtual void GetFocus() override; + virtual void LoseFocus() override; + + void SetControlText( sal_uInt16 nControlId, const OUString& rText ) + { m_pGenPage->SetControlText(nControlId,rText); } + + // short GetFormatCategory(OFieldDescription* pFieldDescr) { return m_pGenPage ? m_pGenPage->GetFormatCategory(pFieldDescr) : -1; } + // delivers a CAT_xxx (CAT_NUMBER, CAT_DATE ...) value to a Format set in the field + + OUString BoolStringPersistent(const OUString& rUIString) const { return m_pGenPage->BoolStringPersistent(rUIString); } + OUString BoolStringUI(const OUString& rPersistentString) const { return m_pGenPage->BoolStringUI(rPersistentString); } + + // 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; + + OFieldDescGenWin* getGenPage() const { return m_pGenPage; } + + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEFIELDDESCWIN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableRow.cxx b/dbaccess/source/ui/tabledesign/TableRow.cxx new file mode 100644 index 000000000..c84ebc834 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableRow.cxx @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 Reference< XPropertySet >& xAffectedCol) + :m_pActFieldDescr( nullptr ) + ,m_nPos( -1 ) + ,m_bReadOnly( false ) + ,m_bOwnsDescriptions(true) +{ + m_pActFieldDescr = new OFieldDescription(xAffectedCol); +} + +OTableRow::OTableRow( const OTableRow& rRow, 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 ) + { + 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 000000000..53b54cef4 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableRowExchange.cxx @@ -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 . + */ + +#include +#include +#include +#include + +namespace dbaui +{ + constexpr sal_uInt32 FORMAT_OBJECT_ID_SBA_TABED = 1; + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + OTableRowExchange::OTableRowExchange(const std::vector< std::shared_ptr >& _rvTableRow) + : m_vTableRow(_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 000000000..3824880de --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableUndo.cxx @@ -0,0 +1,352 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "TableUndo.hxx" +#include +#include "TEditControl.hxx" +#include +#include +#include +#include +#include + +using namespace dbaui; +using namespace ::svt; + + +OTableDesignUndoAct::OTableDesignUndoAct(OTableRowView* pOwner, const char* 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, long 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->ClearModified(); + 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, const char* pCommentID) + : OTableDesignUndoAct(pOwner, pCommentID) + , pTabEdCtrl(pOwner) +{ +} + +OTableEditorUndoAct::~OTableEditorUndoAct() +{ +} + +OTableEditorTypeSelUndoAct::OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, long nRowID, sal_uInt16 nColumn, const TOTypeInfoSP& _pOldType ) + :OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_TYPE_CHANGED) + ,m_nCol( nColumn ) + ,m_nRow( nRowID ) + ,m_pOldType( _pOldType ) +{ +} + +OTableEditorTypeSelUndoAct::~OTableEditorTypeSelUndoAct() +{ +} + +void OTableEditorTypeSelUndoAct::Undo() +{ + // restore type + OFieldDescription* pFieldDesc = pTabEdCtrl->GetFieldDescr(m_nRow); + if(pFieldDesc) + m_pNewType = pFieldDesc->getTypeInfo(); + else + m_pNewType = TOTypeInfoSP(); + pTabEdCtrl->SetCellData(m_nRow,m_nCol,m_pOldType); + pTabEdCtrl->SwitchType( m_pOldType ); + + OTableEditorUndoAct::Undo(); +} + +void OTableEditorTypeSelUndoAct::Redo() +{ + // new type + pTabEdCtrl->GoToRowColumnId( m_nRow ,m_nCol); + pTabEdCtrl->SetCellData(m_nRow,m_nCol,m_pNewType); + + OTableEditorUndoAct::Redo(); +} + +OTableEditorDelUndoAct::OTableEditorDelUndoAct( OTableEditorCtrl* pOwner) : + OTableEditorUndoAct( pOwner ,STR_TABED_UNDO_ROWDELETED) +{ + // fill DeletedRowList + std::vector< std::shared_ptr >* 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_uLong 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, + long nInsertPosition , + const std::vector< std::shared_ptr >& _vInsertedRows) + :OTableEditorUndoAct( pOwner,STR_TABED_UNDO_ROWINSERTED ) + ,m_vInsertedRows(_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 + long 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, long nInsertPosition, long 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( 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; + long nIndex; + + // delete inserted keys + for( nIndex = m_aInsKeys.FirstSelected(); nIndex != 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 != 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(); + long nIndex; + + // delete the deleted keys + for( nIndex = m_aDelKeys.FirstSelected(); nIndex != long(SFX_ENDOFSELECTION); nIndex=m_aDelKeys.NextSelected() ) + (*pRowList)[nIndex]->SetPrimaryKey( false ); + + // restore the inserted keys + for( nIndex = m_aInsKeys.FirstSelected(); nIndex != long(SFX_ENDOFSELECTION); nIndex=m_aInsKeys.NextSelected() ) + (*pRowList)[nIndex]->SetPrimaryKey( true ); + + m_pEditorCtrl->InvalidateHandleColumn(); + OTableEditorUndoAct::Redo(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/tabledesign/TableUndo.hxx b/dbaccess/source/ui/tabledesign/TableUndo.hxx new file mode 100644 index 000000000..d4beb0f53 --- /dev/null +++ b/dbaccess/source/ui/tabledesign/TableUndo.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEUNDO_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEUNDO_HXX + +#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, const char* pCommentID); + virtual ~OTableDesignUndoAct() override; + }; + + class OTableEditorCtrl; + class OTableEditorUndoAct : public OTableDesignUndoAct + { + protected: + VclPtr pTabEdCtrl; + + public: + OTableEditorUndoAct(OTableEditorCtrl* pOwner, const char* pCommentID); + virtual ~OTableEditorUndoAct() override; + }; + + class OTableDesignCellUndoAct final : public OTableDesignUndoAct + { + sal_uInt16 m_nCol; + long m_nRow; + css::uno::Any m_sOldText; + css::uno::Any m_sNewText; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableDesignCellUndoAct( OTableRowView* pOwner, long nRowID, sal_uInt16 nColumn ); + virtual ~OTableDesignCellUndoAct() override; + }; + + class OTableEditorTypeSelUndoAct final : public OTableEditorUndoAct + { + sal_uInt16 m_nCol; + long m_nRow; + TOTypeInfoSP m_pOldType; + TOTypeInfoSP m_pNewType; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorTypeSelUndoAct( OTableEditorCtrl* pOwner, long nRowID, sal_uInt16 nColumn, const 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; + long m_nInsPos; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorInsUndoAct( OTableEditorCtrl* pOwner, + long nInsertPosition, + const std::vector< std::shared_ptr >& _vInsertedRows); + virtual ~OTableEditorInsUndoAct() override; + }; + + class OTableEditorInsNewUndoAct final : public OTableEditorUndoAct + { + long m_nInsPos; + long m_nInsRows; + + virtual void Undo() override; + virtual void Redo() override; + public: + OTableEditorInsNewUndoAct( OTableEditorCtrl* pOwner, long nInsertPosition, long 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; + }; +} +#endif // INCLUDED_DBACCESS_SOURCE_UI_TABLEDESIGN_TABLEUNDO_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx b/dbaccess/source/ui/uno/AdvancedSettingsDlg.cxx new file mode 100644 index 000000000..3debcbe3b --- /dev/null +++ b/dbaccess/source/ui/uno/AdvancedSettingsDlg.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 + +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 > + { + + protected: + explicit OAdvancedSettingsDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + public: + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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(); + } + + Reference< XInterface > OAdvancedSettingsDialog::Create(const Reference< XMultiServiceFactory >& _rxFactory) + { + return *(new OAdvancedSettingsDialog( comphelper::getComponentContext(_rxFactory) )); + } + + OUString SAL_CALL OAdvancedSettingsDialog::getImplementationName() + { + return getImplementationName_Static(); + } + + OUString OAdvancedSettingsDialog::getImplementationName_Static() + { + return "org.openoffice.comp.dbu.OAdvancedSettingsDialog"; + } + + css::uno::Sequence SAL_CALL OAdvancedSettingsDialog::getSupportedServiceNames() + { + return getSupportedServiceNames_Static(); + } + + css::uno::Sequence OAdvancedSettingsDialog::getSupportedServiceNames_Static() + { + 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" void createRegistryInfo_OAdvancedSettingsDialog() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OAdvancedSettingsDialog > aAutoRegistration; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnControl.cxx b/dbaccess/source/ui/uno/ColumnControl.cxx new file mode 100644 index 000000000..03c2c80bf --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnControl.cxx @@ -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 . + */ + +#include "ColumnControl.hxx" +#include "ColumnPeer.hxx" +#include +#include +#include +#include +#include + +extern "C" void createRegistryInfo_OColumnControl() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OColumnControl> aAutoRegistration; +} + +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) + :UnoControl(), m_xContext(rxContext) +{ +} + +IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(OColumnControl, SERVICE_CONTROLDEFAULT) +IMPLEMENT_SERVICE_INFO_SUPPORTS(OColumnControl) +IMPLEMENT_SERVICE_INFO_GETSUPPORTED2_STATIC(OColumnControl, "com.sun.star.awt.UnoControl","com.sun.star.sdb.ColumnDescriptorControl") + +Reference< XInterface > OColumnControl::Create(const Reference< XMultiServiceFactory >& _rxORB) +{ + return static_cast< XServiceInfo* >(new OColumnControl(comphelper::getComponentContext(_rxORB))); +} + +OUString OColumnControl::GetComponentServiceName() +{ + return "com.sun.star.sdb.ColumnDescriptorControl"; +} + +void SAL_CALL OColumnControl::createPeer(const Reference< XToolkit >& /*rToolkit*/, const Reference< XWindowPeer >& rParentPeer) +{ + ::osl::ClearableMutexGuard aGuard( GetMutex() ); + if ( getPeer().is() ) + return; + + mbCreatingPeer = true; + + vcl::Window* pParentWin = nullptr; + if (rParentPeer.is()) + { + VCLXWindow* pParent = comphelper::getUnoTunnelImplementation(rParentPeer); + if (pParent) + pParentWin = pParent->GetWindow().get(); + } + + OColumnPeer* pPeer = new OColumnPeer( pParentWin, m_xContext ); + OSL_ENSURE(pPeer != nullptr, "FmXGridControl::createPeer : imp_CreatePeer didn't return a peer !"); + setPeer( pPeer ); + + UnoControlComponentInfos aComponentInfos(maComponentInfos); + Reference< XGraphics > xGraphics( mxGraphics ); + Reference< XView > xV(getPeer(), UNO_QUERY); + Reference< XWindow > xW(getPeer(), UNO_QUERY); + + aGuard.clear(); + + updateFromModel(); + + xV->setZoom( aComponentInfos.nZoomX, aComponentInfos.nZoomY ); + setPosSize( aComponentInfos.nX, aComponentInfos.nY, aComponentInfos.nWidth, aComponentInfos.nHeight, css::awt::PosSize::POSSIZE ); + + Reference 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 000000000..1d69e1ea2 --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnControl.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_COLUMNCONTROL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_COLUMNCONTROL_HXX + +#include +#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() override; + + // XServiceInfo + DECLARE_SERVICE_INFO(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_COLUMNCONTROL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnModel.cxx b/dbaccess/source/ui/uno/ColumnModel.cxx new file mode 100644 index 000000000..b56fdcfbb --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnModel.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 "ColumnModel.hxx" +#include +#include + +#include +#include + +extern "C" void createRegistryInfo_OColumnControlModel() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OColumnControlModel> aAutoRegistration; +} + +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(); +} + +IMPLEMENT_GETTYPES2(OColumnControlModel,OColumnControlModel_BASE,comphelper::OPropertyContainer) +IMPLEMENT_PROPERTYCONTAINER_DEFAULTS(OColumnControlModel) +IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(OColumnControlModel, "com.sun.star.comp.dbu.OColumnControlModel") +IMPLEMENT_SERVICE_INFO_SUPPORTS(OColumnControlModel) +IMPLEMENT_SERVICE_INFO_GETSUPPORTED2_STATIC(OColumnControlModel, "com.sun.star.awt.UnoControlModel","com.sun.star.sdb.ColumnDescriptorControlModel") +css::uno::Reference< css::uno::XInterface > + OColumnControlModel::Create(const css::uno::Reference< css::lang::XMultiServiceFactory >& ) +{ + return static_cast< XServiceInfo* >(new OColumnControlModel()); +} +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 000000000..f89b26e91 --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnModel.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_COLUMNMODEL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_COLUMNMODEL_HXX + +#include +#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(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + 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 + DECLARE_PROPERTYCONTAINER_DEFAULTS( ); + + virtual css::uno::Reference< css::util::XCloneable > SAL_CALL createClone( ) override; +}; + +} // namespace dbaui +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_COLUMNMODEL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnPeer.cxx b/dbaccess/source/ui/uno/ColumnPeer.cxx new file mode 100644 index 000000000..36bad3a10 --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnPeer.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 "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->setEditWidth(_nWidth); +} + +void OColumnPeer::setColumn(const Reference< XPropertySet>& _xColumn) +{ + SolarMutexGuard aGuard; + + VclPtr pFieldControl = GetAs(); + if ( !pFieldControl ) + return; + + 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 + OUString const sCreateParam("x"); + bool bForce; + TOTypeInfoSP pTypeInfo = ::dbaui::getTypeInfoFromType(*pFieldControl->getTypeInfo(),nType,sTypeName,sCreateParam,nPrecision,nScale,bAutoIncrement,bForce); + if ( !pTypeInfo ) + pTypeInfo = pFieldControl->getDefaultTyp(); + + m_pActFieldDescr->FillFromTypeInfo(pTypeInfo,true,false); + m_xColumn = _xColumn; + } + pFieldControl->DisplayData(m_pActFieldDescr); +} + +void OColumnPeer::setConnection(const Reference< XConnection>& _xCon) +{ + SolarMutexGuard aGuard; + VclPtr pFieldControl = GetAs(); + if ( pFieldControl ) + pFieldControl->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< OFieldDescControl > pFieldControl = GetAs< OFieldDescControl >(); + if (pFieldControl && _rPropertyName == PROPERTY_COLUMN) + { + aProp <<= m_xColumn; + } + else if (pFieldControl && _rPropertyName == PROPERTY_ACTIVE_CONNECTION) + { + aProp <<= pFieldControl->getConnection(); + } + else + aProp = VCLXWindow::getProperty(_rPropertyName); + return aProp; +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/ColumnPeer.hxx b/dbaccess/source/ui/uno/ColumnPeer.hxx new file mode 100644 index 000000000..91ebbdc7f --- /dev/null +++ b/dbaccess/source/ui/uno/ColumnPeer.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 . + */ +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_COLUMNPEER_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_COLUMNPEER_HXX + +#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 +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_COLUMNPEER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/DBTypeWizDlg.cxx b/dbaccess/source/ui/uno/DBTypeWizDlg.cxx new file mode 100644 index 000000000..4906d080b --- /dev/null +++ b/dbaccess/source/ui/uno/DBTypeWizDlg.cxx @@ -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 . + */ + +#include +#include +#include "DBTypeWizDlg.hxx" +#include +#include +#include + +using namespace dbaui; + +extern "C" void createRegistryInfo_ODBTypeWizDialog() +{ + static OMultiInstanceAutoRegistration< ODBTypeWizDialog > aAutoRegistration; +} + +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(); +} + +Reference< XInterface > ODBTypeWizDialog::Create(const Reference< XMultiServiceFactory >& _rxFactory) +{ + return *(new ODBTypeWizDialog( comphelper::getComponentContext(_rxFactory) )); +} + +OUString SAL_CALL ODBTypeWizDialog::getImplementationName() +{ + return getImplementationName_Static(); +} + +OUString ODBTypeWizDialog::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.ODBTypeWizDialog"; +} + +css::uno::Sequence SAL_CALL ODBTypeWizDialog::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +css::uno::Sequence ODBTypeWizDialog::getSupportedServiceNames_Static() +{ + 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 000000000..1d134421f --- /dev/null +++ b/dbaccess/source/ui/uno/DBTypeWizDlg.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_DBTYPEWIZDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_DBTYPEWIZDLG_HXX + +#include + +#include + +namespace dbaui +{ +class ODBTypeWizDialog final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< ODBTypeWizDialog > +{ + + explicit ODBTypeWizDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + +public: + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_DBTYPEWIZDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx new file mode 100644 index 000000000..ebf4f0964 --- /dev/null +++ b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.cxx @@ -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 . + */ + +#include +#include +#include "DBTypeWizDlgSetup.hxx" +#include +#include +#include +#include +#include + +using namespace dbaui; + +extern "C" void createRegistryInfo_ODBTypeWizDialogSetup() +{ + static OMultiInstanceAutoRegistration< ODBTypeWizDialogSetup > aAutoRegistration; +} + +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(); +} + +Reference< XInterface > ODBTypeWizDialogSetup::Create(const Reference< XMultiServiceFactory >& _rxFactory) +{ + Reference < XInterface > xDBWizard = *(new ODBTypeWizDialogSetup( comphelper::getComponentContext(_rxFactory) )); + return xDBWizard; +} + +OUString SAL_CALL ODBTypeWizDialogSetup::getImplementationName() +{ + return getImplementationName_Static(); +} + +OUString ODBTypeWizDialogSetup::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.ODBTypeWizDialogSetup"; +} + +css::uno::Sequence SAL_CALL ODBTypeWizDialogSetup::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +css::uno::Sequence ODBTypeWizDialogSetup::getSupportedServiceNames_Static() +{ + css::uno::Sequence aSupported { "com.sun.star.sdb.DatabaseWizardDialog" }; + return aSupported; +} + +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 000000000..65a25b5f0 --- /dev/null +++ b/dbaccess/source/ui/uno/DBTypeWizDlgSetup.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_DBTYPEWIZDLGSETUP_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_DBTYPEWIZDLGSETUP_HXX + +#include + +#include + +namespace dbaui +{ +class ODBTypeWizDialogSetup final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< ODBTypeWizDialogSetup > +{ + bool m_bOpenDatabase; + bool m_bStartTableWizard; + + explicit ODBTypeWizDialogSetup(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + +public: + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_DBTYPEWIZDLGSETUP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/TableFilterDlg.cxx b/dbaccess/source/ui/uno/TableFilterDlg.cxx new file mode 100644 index 000000000..17fb72660 --- /dev/null +++ b/dbaccess/source/ui/uno/TableFilterDlg.cxx @@ -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 . + */ + +#include +#include +#include "TableFilterDlg.hxx" +#include +#include +#include + +using namespace dbaui; + +extern "C" void createRegistryInfo_OTableFilterDialog() +{ + static OMultiInstanceAutoRegistration< OTableFilterDialog > aAutoRegistration; +} + +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(); +} + +Reference< XInterface > OTableFilterDialog::Create(const Reference< XMultiServiceFactory >& _rxFactory) +{ + return *(new OTableFilterDialog( comphelper::getComponentContext(_rxFactory) )); +} + +OUString SAL_CALL OTableFilterDialog::getImplementationName() +{ + return getImplementationName_Static(); +} + +OUString OTableFilterDialog::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.OTableFilterDialog"; +} + +css::uno::Sequence SAL_CALL OTableFilterDialog::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +css::uno::Sequence OTableFilterDialog::getSupportedServiceNames_Static() +{ + 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 000000000..6e80a1d5c --- /dev/null +++ b/dbaccess/source/ui/uno/TableFilterDlg.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_TABLEFILTERDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_TABLEFILTERDLG_HXX + +#include + +#include + +namespace dbaui +{ + +class OTableFilterDialog final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< OTableFilterDialog > +{ + + explicit OTableFilterDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + +public: + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_TABLEFILTERDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/UserSettingsDlg.cxx b/dbaccess/source/ui/uno/UserSettingsDlg.cxx new file mode 100644 index 000000000..88ab03961 --- /dev/null +++ b/dbaccess/source/ui/uno/UserSettingsDlg.cxx @@ -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 . + */ + +#include +#include +#include "UserSettingsDlg.hxx" +#include +#include +#include + +using namespace dbaui; + +extern "C" void createRegistryInfo_OUserSettingsDialog() +{ + static OMultiInstanceAutoRegistration< OUserSettingsDialog > aAutoRegistration; +} + +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(); +} + +Reference< XInterface > OUserSettingsDialog::Create(const Reference< XMultiServiceFactory >& _rxFactory) +{ + return *(new OUserSettingsDialog( comphelper::getComponentContext(_rxFactory) )); +} + +OUString SAL_CALL OUserSettingsDialog::getImplementationName() +{ + return getImplementationName_Static(); +} + +OUString OUserSettingsDialog::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.OUserSettingsDialog"; +} + +css::uno::Sequence SAL_CALL OUserSettingsDialog::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +css::uno::Sequence OUserSettingsDialog::getSupportedServiceNames_Static() +{ + 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 000000000..e70a57f60 --- /dev/null +++ b/dbaccess/source/ui/uno/UserSettingsDlg.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_USERSETTINGSDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_USERSETTINGSDLG_HXX + +#include + +#include + +namespace dbaui +{ +// OUserSettingsDialog +class OUserSettingsDialog final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< OUserSettingsDialog > +{ + + explicit OUserSettingsDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + +public: + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_USERSETTINGSDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/admindlg.cxx b/dbaccess/source/ui/uno/admindlg.cxx new file mode 100644 index 000000000..b9ebc6f2e --- /dev/null +++ b/dbaccess/source/ui/uno/admindlg.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 +#include +#include "admindlg.hxx" +#include +#include +#include + +using namespace dbaui; + +extern "C" void createRegistryInfo_ODataSourcePropertyDialog() +{ + static OMultiInstanceAutoRegistration< ODataSourcePropertyDialog > aAutoRegistration; +} + +namespace dbaui +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + +ODataSourcePropertyDialog::ODataSourcePropertyDialog(const Reference< XComponentContext >& _rxORB) + :ODatabaseAdministrationDialog(_rxORB) +{ +} + +Sequence SAL_CALL ODataSourcePropertyDialog::getImplementationId( ) +{ + return css::uno::Sequence(); +} + +Reference< XInterface > ODataSourcePropertyDialog::Create(const Reference< XMultiServiceFactory >& _rxFactory) +{ + return *(new ODataSourcePropertyDialog( comphelper::getComponentContext(_rxFactory) )); +} + +OUString SAL_CALL ODataSourcePropertyDialog::getImplementationName() +{ + return getImplementationName_Static(); +} + +OUString ODataSourcePropertyDialog::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.ODatasourceAdministrationDialog"; +} + +css::uno::Sequence SAL_CALL ODataSourcePropertyDialog::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +css::uno::Sequence ODataSourcePropertyDialog::getSupportedServiceNames_Static() +{ + 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< Property > 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 000000000..e4c817c3c --- /dev/null +++ b/dbaccess/source/ui/uno/admindlg.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_ADMINDLG_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_ADMINDLG_HXX + +#include + +#include + +namespace dbaui +{ +class ODataSourcePropertyDialog final + :public ODatabaseAdministrationDialog + ,public ::comphelper::OPropertyArrayUsageHelper< ODataSourcePropertyDialog > +{ + + explicit ODataSourcePropertyDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + +public: + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XServiceInfo - static methods + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static(); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + // 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_ADMINDLG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/composerdialogs.cxx b/dbaccess/source/ui/uno/composerdialogs.cxx new file mode 100644 index 000000000..15dea317d --- /dev/null +++ b/dbaccess/source/ui/uno/composerdialogs.cxx @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include + +extern "C" void createRegistryInfo_ComposerDialogs() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::RowsetOrderDialog > aOrderDialogRegistration; + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::RowsetFilterDialog > aFilterDialogRegistration; +} + +namespace dbaui +{ + +#define PROPERTY_ID_QUERYCOMPOSER 100 +#define PROPERTY_ID_ROWSET 101 + +#define PROPERTY_QUERYCOMPOSER "QueryComposer" +#define PROPERTY_ROWSET "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(); + } + + IMPLEMENT_PROPERTYCONTAINER_DEFAULTS( ComposerDialog ) + + 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 ) + { + } + + IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(RowsetFilterDialog, "com.sun.star.uno.comp.sdb.RowsetFilterDialog") + IMPLEMENT_SERVICE_INFO_SUPPORTS(RowsetFilterDialog) + IMPLEMENT_SERVICE_INFO_GETSUPPORTED1_STATIC(RowsetFilterDialog, "com.sun.star.sdb.FilterDialog") + + css::uno::Reference< css::uno::XInterface > + RowsetFilterDialog::Create(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB) + { + return static_cast< XServiceInfo* >(new RowsetFilterDialog( comphelper::getComponentContext(_rxORB))); + } + + 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", makeAny( xQueryComposer ) ); + setPropertyValue( "RowSet", makeAny( xRowSet ) ); + setPropertyValue( "ParentWindow", makeAny( 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 ) + { + } + + IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(RowsetOrderDialog, "com.sun.star.uno.comp.sdb.RowsetOrderDialog") + IMPLEMENT_SERVICE_INFO_SUPPORTS(RowsetOrderDialog) + IMPLEMENT_SERVICE_INFO_GETSUPPORTED1_STATIC(RowsetOrderDialog, "com.sun.star.sdb.OrderDialog") + + css::uno::Reference< css::uno::XInterface > + RowsetOrderDialog::Create(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB) + { + return static_cast< XServiceInfo* >(new RowsetOrderDialog( comphelper::getComponentContext(_rxORB))); + } + + 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", makeAny( xQueryComposer ) ); + setPropertyValue( "RowSet", makeAny( xRowSet ) ); + if (aArguments.getLength() == 3) + { + Reference xParentWindow; + aArguments[2] >>= xParentWindow; + setPropertyValue("ParentWindow", makeAny(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 000000000..f50ce5d79 --- /dev/null +++ b/dbaccess/source/ui/uno/composerdialogs.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_COMPOSERDIALOGS_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_COMPOSERDIALOGS_HXX + +#include +#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; + + DECLARE_PROPERTYCONTAINER_DEFAULTS( ); + + 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(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + 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(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_COMPOSERDIALOGS_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/copytablewizard.cxx b/dbaccess/source/ui/uno/copytablewizard.cxx new file mode 100644 index 000000000..aed45a484 --- /dev/null +++ b/dbaccess/source/ui/uno/copytablewizard.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 +#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::makeAny; + 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; + + // XServiceInfo - static methods + /// @throws RuntimeException + static Sequence< OUString > getSupportedServiceNames_Static(); + /// @throws RuntimeException + static OUString getImplementationName_Static(); + static Reference< XInterface > Create( const Reference< XMultiServiceFactory >& ); + + // 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(); } + + protected: + explicit CopyTableWizard( const Reference< XComponentContext >& _rxORB ); + virtual ~CopyTableWizard() override; + + // 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::OInterfaceContainerHelper2 + 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_sDestinationTable() + ,m_aPrimaryKeyName( false, "ID" ) + ,m_bUseHeaderLineAsColumnNames( true ) + ,m_xSourceConnection() + ,m_nCommandType( CommandType::COMMAND ) + ,m_pSourceObject() + ,m_xSourceResultSet() + ,m_aSourceSelection() + ,m_bSourceSelectionBookmarks( true ) + ,m_xDestConnection() + ,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? +} + +Reference< XInterface > CopyTableWizard::Create( const Reference< XMultiServiceFactory >& _rxFactory ) +{ + return *( new CopyTableWizard( comphelper::getComponentContext(_rxFactory) ) ); +} + +OUString SAL_CALL CopyTableWizard::getImplementationName() +{ + return getImplementationName_Static(); +} + +OUString CopyTableWizard::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.CopyTableWizard"; +} + +css::uno::Sequence SAL_CALL CopyTableWizard::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +css::uno::Sequence CopyTableWizard::getSupportedServiceNames_Static() +{ + 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() ) + { + ::comphelper::NamedValueCollection aModelArgs( xDocumentModel->getArgs() ); + xHandler = aModelArgs.getOrDefault( "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[] = { + OUString(PROPERTY_FILTER), OUString(PROPERTY_ORDER), OUString(PROPERTY_HAVING_CLAUSE), OUString(PROPERTY_GROUP_BY) + }; + for (const auto & aSetting : aSettings) + { + if ( lcl_hasNonEmptyStringValue_throw( _rxSourceDescriptor, xPSI, aSetting ) ) + { + sUnsupportedSetting = aSetting; + break; + } + } + + if ( !sUnsupportedSetting.isEmpty() ) + { + OUString sMessage( + DBA_RES(STR_CTW_ERROR_UNSUPPORTED_SETTING). + replaceFirst("$name$", sUnsupportedSetting)); + throw IllegalArgumentException( + sMessage, + *const_cast< CopyTableWizard* >( this ), + 1 + ); + } + +} + +std::unique_ptr< ICopyTableSourceObject > CopyTableWizard::impl_extractSourceObject_throw( const Reference< XPropertySet >& _rxDescriptor, sal_Int32& _out_rCommandType ) const +{ + OSL_PRECOND( _rxDescriptor.is() && m_xSourceConnection.is(), "CopyTableWizard::impl_extractSourceObject_throw: illegal arguments!" ); + + Reference< XPropertySetInfo > xPSI( _rxDescriptor->getPropertySetInfo(), UNO_SET_THROW ); + if ( !xPSI->hasPropertyByName( PROPERTY_COMMAND ) + || !xPSI->hasPropertyByName( PROPERTY_COMMAND_TYPE ) + ) + throw IllegalArgumentException("Expecting a table or query specification.", + // TODO: resource + *const_cast< CopyTableWizard* >( this ), 1); + + OUString sCommand; + _out_rCommandType = CommandType::COMMAND; + OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand ); + OSL_VERIFY( _rxDescriptor->getPropertyValue( PROPERTY_COMMAND_TYPE ) >>= _out_rCommandType ); + + std::unique_ptr< ICopyTableSourceObject > pSourceObject; + Reference< XNameAccess > xContainer; + switch ( _out_rCommandType ) + { + case CommandType::TABLE: + { + Reference< XTablesSupplier > xSuppTables( m_xSourceConnection.getTyped(), UNO_QUERY ); + if ( xSuppTables.is() ) + xContainer.set( xSuppTables->getTables(), UNO_SET_THROW ); + } + break; + case CommandType::QUERY: + { + Reference< XQueriesSupplier > xSuppQueries( m_xSourceConnection.getTyped(), UNO_QUERY ); + if ( xSuppQueries.is() ) + xContainer.set( xSuppQueries->getQueries(), UNO_SET_THROW ); + } + break; + default: + throw IllegalArgumentException( + DBA_RES( STR_CTW_ONLY_TABLES_AND_QUERIES_SUPPORT ), + *const_cast< CopyTableWizard* >( this ), + 1 + ); + } + + if ( xContainer.is() ) + { + pSourceObject.reset( new ObjectCopySource( m_xSourceConnection, + Reference< XPropertySet >( xContainer->getByName( sCommand ), UNO_QUERY_THROW ) ) ); + } + else + { + // our source connection is an SDBC level connection only, not a SDBCX level one + // Which means it cannot provide the to-be-copied object as component. + + if ( _out_rCommandType == CommandType::QUERY ) + // we cannot copy a query if the connection cannot provide it ... + throw IllegalArgumentException( + DBA_RES( STR_CTW_ERROR_NO_QUERY ), + *const_cast< CopyTableWizard* >( this ), + 1 + ); + pSourceObject.reset( new NamedTableCopySource( m_xSourceConnection, sCommand ) ); + } + + return pSourceObject; +} + +void CopyTableWizard::impl_extractSourceResultSet_throw( const Reference< XPropertySet >& i_rDescriptor ) +{ + Reference< XPropertySetInfo > xPSI( i_rDescriptor->getPropertySetInfo(), UNO_SET_THROW ); + + // extract relevant settings + if ( xPSI->hasPropertyByName( PROPERTY_RESULT_SET ) ) + m_xSourceResultSet.set( i_rDescriptor->getPropertyValue( PROPERTY_RESULT_SET ), UNO_QUERY ); + + if ( xPSI->hasPropertyByName( PROPERTY_SELECTION ) ) + OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_SELECTION ) >>= m_aSourceSelection ); + + if ( xPSI->hasPropertyByName( PROPERTY_BOOKMARK_SELECTION ) ) + OSL_VERIFY( i_rDescriptor->getPropertyValue( PROPERTY_BOOKMARK_SELECTION ) >>= m_bSourceSelectionBookmarks ); + + // sanity checks + const bool bHasResultSet = m_xSourceResultSet.is(); + const bool bHasSelection = m_aSourceSelection.hasElements(); + if ( bHasSelection && !bHasResultSet ) + throw IllegalArgumentException("A result set is needed when specifying a selection to copy.", + // TODO: resource + *this, 1); + + if ( bHasSelection && m_bSourceSelectionBookmarks ) + { + Reference< XRowLocate > xRowLocate( m_xSourceResultSet, UNO_QUERY ); + if ( !xRowLocate.is() ) + { + ::dbtools::throwGenericSQLException( + DBA_RES(STR_CTW_COPY_SOURCE_NEEDS_BOOKMARKS), + *this + ); + } + } +} + +SharedConnection CopyTableWizard::impl_extractConnection_throw( const Reference< XPropertySet >& _rxDataSourceDescriptor, + Reference< XInteractionHandler >& _out_rxDocInteractionHandler ) const +{ + SharedConnection xConnection; + + OSL_PRECOND( _rxDataSourceDescriptor.is(), "CopyTableWizard::impl_extractConnection_throw: no descriptor!" ); + if ( !_rxDataSourceDescriptor.is() ) + return xConnection; + + Reference< XInteractionHandler > xInteractionHandler; + + do + { + Reference< XPropertySetInfo > xPSI( _rxDataSourceDescriptor->getPropertySetInfo(), UNO_SET_THROW ); + + // if there's an ActiveConnection, use it + if ( xPSI->hasPropertyByName( PROPERTY_ACTIVE_CONNECTION ) ) + { + Reference< XConnection > xPure; + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xPure ); + xConnection.reset( xPure, SharedConnection::NoTakeOwnership ); + } + if ( xConnection.is() ) + { + xInteractionHandler = lcl_getInteractionHandler_throw( xConnection.getTyped(), m_xInteractionHandler ); + SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" ); + break; + } + + // there could be a DataSourceName or a DatabaseLocation, describing the css.sdb.DataSource + OUString sDataSource, sDatabaseLocation; + if ( xPSI->hasPropertyByName( PROPERTY_DATASOURCENAME ) ) + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATASOURCENAME ) >>= sDataSource ); + if ( xPSI->hasPropertyByName( PROPERTY_DATABASE_LOCATION ) ) + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_DATABASE_LOCATION ) >>= sDatabaseLocation ); + + // need a DatabaseContext for loading the data source + Reference< XDatabaseContext > xDatabaseContext = DatabaseContext::create( m_xContext ); + Reference< XDataSource > xDataSource; + if ( !sDataSource.isEmpty() ) + xDataSource.set( xDatabaseContext->getByName( sDataSource ), UNO_QUERY_THROW ); + if ( !xDataSource.is() && !sDatabaseLocation.isEmpty() ) + xDataSource.set( xDatabaseContext->getByName( sDatabaseLocation ), UNO_QUERY_THROW ); + + if ( xDataSource.is() ) + { + // first, try connecting with completion + xInteractionHandler = lcl_getInteractionHandler_throw( xDataSource, m_xInteractionHandler ); + SAL_WARN_IF( !xInteractionHandler.is(), "dbaccess.ui", "CopyTableWizard::impl_extractConnection_throw: lcl_getInteractionHandler_throw returned nonsense!" ); + if ( xInteractionHandler.is() ) + { + Reference< XCompletedConnection > xInteractiveConnection( xDataSource, UNO_QUERY ); + if ( xInteractiveConnection.is() ) + xConnection.reset( xInteractiveConnection->connectWithCompletion( xInteractionHandler ), SharedConnection::TakeOwnership ); + } + + // interactively connecting was not successful or possible -> connect without interaction + if ( !xConnection.is() ) + { + xConnection.reset( xDataSource->getConnection( OUString(), OUString() ), SharedConnection::TakeOwnership ); + } + } + + if ( xConnection.is() ) + break; + + // finally, there could be a ConnectionResource/ConnectionInfo + OUString sConnectionResource; + Sequence< PropertyValue > aConnectionInfo; + if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_RESOURCE ) ) + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_RESOURCE ) >>= sConnectionResource ); + if ( xPSI->hasPropertyByName( PROPERTY_CONNECTION_INFO ) ) + OSL_VERIFY( _rxDataSourceDescriptor->getPropertyValue( PROPERTY_CONNECTION_INFO ) >>= aConnectionInfo ); + + Reference< XDriverManager > xDriverManager; + try { + xDriverManager.set( ConnectionPool::create( m_xContext ), UNO_QUERY_THROW ); + } catch( const Exception& ) { } + if ( !xDriverManager.is() ) + // no connection pool installed + xDriverManager.set( DriverManager::create( m_xContext ), UNO_QUERY_THROW ); + + if ( aConnectionInfo.hasElements() ) + xConnection.set( xDriverManager->getConnectionWithInfo( sConnectionResource, aConnectionInfo ), UNO_SET_THROW ); + else + xConnection.set( xDriverManager->getConnection( sConnectionResource ), UNO_SET_THROW ); + } + while ( false ); + + if ( xInteractionHandler != m_xInteractionHandler ) + _out_rxDocInteractionHandler = xInteractionHandler; + + return xConnection; +} + +::utl::SharedUNOComponent< XPreparedStatement > CopyTableWizard::impl_createSourceStatement_throw() const +{ + OSL_PRECOND( m_xSourceConnection.is(), "CopyTableWizard::impl_createSourceStatement_throw: illegal call!" ); + if ( !m_xSourceConnection.is() ) + throw RuntimeException( "CopyTableWizard::impl_createSourceStatement_throw: illegal call!", *const_cast< CopyTableWizard* >( this )); + + ::utl::SharedUNOComponent< XPreparedStatement > xStatement; + switch ( m_nCommandType ) + { + case CommandType::TABLE: + xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW ); + break; + + case CommandType::QUERY: + { + OUString sQueryCommand( m_pSourceObject->getSelectStatement() ); + xStatement.set( m_pSourceObject->getPreparedSelectStatement(), UNO_SET_THROW ); + + // check whether we have to fill in parameter values + // create and fill a composer + + Reference< XMultiServiceFactory > xFactory( m_xSourceConnection, UNO_QUERY ); + ::utl::SharedUNOComponent< XSingleSelectQueryComposer > xComposer; + if ( xFactory.is() ) + // note: connections below the sdb-level are allowed to not support the XMultiServiceFactory interface + xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY ); + + if ( xComposer.is() ) + { + xComposer->setQuery( sQueryCommand ); + + Reference< XParameters > xStatementParams( xStatement, UNO_QUERY ); + OSL_ENSURE( xStatementParams.is(), "CopyTableWizard::impl_createSourceStatement_throw: no access to the statement's parameters!" ); + // the statement should be a css.sdbc.PreparedStatement (this is what + // we created), and a prepared statement is required to support XParameters + if ( xStatementParams.is() ) + { + OSL_ENSURE( m_xInteractionHandler.is(), + "CopyTableWizard::impl_createSourceStatement_throw: no interaction handler for the parameters request!" ); + // we should always have an interaction handler - as last fallback, we create an own one in ::initialize + + if ( m_xInteractionHandler.is() ) + ::dbtools::askForParameters( xComposer, xStatementParams, m_xSourceConnection, m_xInteractionHandler ); + } + } + } + break; + + default: + // this should not have survived initialization phase + throw RuntimeException("No case matched, this should not have survived the initialization phase", *const_cast< CopyTableWizard* >( this )); + } + + return xStatement; +} + +namespace +{ + class ValueTransfer + { + public: + ValueTransfer( const sal_Int32& _rSourcePos, const sal_Int32& _rDestPos, const std::vector< sal_Int32 >& _rColTypes, + const Reference< XRow >& _rxSource, const Reference< XParameters >& _rxDest ) + :m_rSourcePos( _rSourcePos ) + ,m_rDestPos( _rDestPos ) + ,m_rColTypes( _rColTypes ) + ,m_xSource( _rxSource ) + ,m_xDest( _rxDest ) + { + } + + template< typename VALUE_TYPE > + void transferValue( VALUE_TYPE ( SAL_CALL XRow::*_pGetter )( sal_Int32 ), + void (SAL_CALL XParameters::*_pSetter)( sal_Int32, VALUE_TYPE ) ) + { + VALUE_TYPE value( (m_xSource.get()->*_pGetter)( m_rSourcePos ) ); + if ( m_xSource->wasNull() ) + m_xDest->setNull( m_rDestPos, m_rColTypes[ m_rSourcePos ] ); + else + (m_xDest.get()->*_pSetter)( m_rDestPos, value ); + } + template< typename VALUE_TYPE > + void transferComplexValue( 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)( m_rSourcePos ) ); + if ( m_xSource->wasNull() ) + m_xDest->setNull( m_rDestPos, m_rColTypes[ m_rSourcePos ] ); + else + (m_xDest.get()->*_pSetter)( m_rDestPos, value ); + } + private: + const sal_Int32& m_rSourcePos; + const sal_Int32& m_rDestPos; + const std::vector< sal_Int32 > m_rColTypes; + const Reference< XRow > m_xSource; + const Reference< XParameters > m_xDest; + }; +} + +bool CopyTableWizard::impl_processCopyError_nothrow( const CopyTableRowEvent& _rEvent ) +{ + Reference< XCopyTableListener > xListener; + try + { + ::comphelper::OInterfaceIteratorHelper2 aIter( m_aCopyTableListeners ); + while ( aIter.hasMoreElements() ) + { + xListener.set( aIter.next(), UNO_QUERY_THROW ); + sal_Int16 nListenerChoice = xListener->copyRowError( _rEvent ); + switch ( nListenerChoice ) + { + case CopyTableContinuation::Proceed: return true; // continue copying + case CopyTableContinuation::CallNextHandler: continue; // continue the loop, ask next listener + case CopyTableContinuation::Cancel: return false; // cancel copying + case CopyTableContinuation::AskUser: break; // stop asking the listeners, ask the user + + default: + SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_processCopyError_nothrow: invalid listener response!" ); + // ask next listener + continue; + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("dbaccess"); + } + + // no listener felt responsible for the error, or a listener told to ask the user + + try + { + SQLContext aError; + aError.Context = *this; + aError.Message = DBA_RES(STR_ERROR_OCCURRED_WHILE_COPYING); + + ::dbtools::SQLExceptionInfo aInfo( _rEvent.Error ); + if ( aInfo.isValid() ) + aError.NextException = _rEvent.Error; + else + { + // a non-SQL exception happened + Exception aException; + OSL_VERIFY( _rEvent.Error >>= aException ); + SQLContext aContext; + aContext.Context = aException.Context; + aContext.Message = aException.Message; + aContext.Details = _rEvent.Error.getValueTypeName(); + aError.NextException <<= aContext; + } + + ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( makeAny( aError ) ) ); + + ::rtl::Reference< ::comphelper::OInteractionApprove > xYes = new ::comphelper::OInteractionApprove; + xRequest->addContinuation( xYes.get() ); + 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.get() ); + + 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(); + + Reference< XRow > xRow ( _rxSourceResultSet, UNO_QUERY_THROW ); + Reference< XRowLocate > xRowLocate ( _rxSourceResultSet, UNO_QUERY_THROW ); + + Reference< XResultSetMetaDataSupplier > xSuppResMeta( _rxSourceResultSet, UNO_QUERY_THROW ); + Reference< XResultSetMetaData> xMeta( xSuppResMeta->getMetaData() ); + + // we need a vector which all types + sal_Int32 nCount = xMeta->getColumnCount(); + std::vector< sal_Int32 > aSourceColTypes; + aSourceColTypes.reserve( nCount + 1 ); + aSourceColTypes.push_back( -1 ); // just to avoid an every time i-1 call + + std::vector< sal_Int32 > aSourcePrec; + aSourcePrec.reserve( nCount + 1 ); + aSourcePrec.push_back( -1 ); // just to avoid an every time i-1 call + + for ( sal_Int32 k=1; k <= nCount; ++k ) + { + aSourceColTypes.push_back( xMeta->getColumnType( k ) ); + aSourcePrec.push_back( xMeta->getPrecision( k ) ); + } + + // now create, fill and execute the prepared statement + Reference< XPreparedStatement > xStatement( ODatabaseExport::createPreparedStatment( xDestMetaData, _rxDestTable, aColumnPositions ), UNO_SET_THROW ); + Reference< XParameters > xStatementParams( xStatement, UNO_QUERY_THROW ); + + const bool bSelectedRecordsOnly = m_aSourceSelection.hasElements(); + const Any* pSelectedRow = m_aSourceSelection.getConstArray(); + const Any* pSelEnd = pSelectedRow + m_aSourceSelection.getLength(); + + sal_Int32 nRowCount = 0; + bool bContinue = false; + + CopyTableRowEvent aCopyEvent; + aCopyEvent.Source = *this; + aCopyEvent.SourceData = _rxSourceResultSet; + + do // loop as long as there are more rows or the selection ends + { + bContinue = false; + if ( bSelectedRecordsOnly ) + { + if ( pSelectedRow != pSelEnd ) + { + if ( m_bSourceSelectionBookmarks ) + { + bContinue = xRowLocate->moveToBookmark( *pSelectedRow ); + } + else + { + sal_Int32 nPos = 0; + OSL_VERIFY( *pSelectedRow >>= nPos ); + bContinue = _rxSourceResultSet->absolute( nPos ); + } + ++pSelectedRow; + } + } + else + bContinue = _rxSourceResultSet->next(); + + if ( !bContinue ) + { + break; + } + + ++nRowCount; + + aCopyEvent.Error.clear(); + try + { + // notify listeners + m_aCopyTableListeners.notifyEach( &XCopyTableListener::copyingRow, aCopyEvent ); + + sal_Int32 nDestColumn( 0 ); + sal_Int32 nSourceColumn( 1 ); + ValueTransfer aTransfer( nSourceColumn, nDestColumn, aSourceColTypes, xRow, xStatementParams ); + + for ( auto const& rColumnPos : aColumnPositions ) + { + 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 ( ( nSourceColumn < 1 ) || ( nSourceColumn >= static_cast(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( &XRow::getDouble, &XParameters::setDouble ); + break; + + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::DECIMAL: + case DataType::NUMERIC: + aTransfer.transferComplexValue( &XRow::getString, &XParameters::setString ); + break; + + case DataType::BIGINT: + aTransfer.transferValue( &XRow::getLong, &XParameters::setLong ); + break; + + case DataType::FLOAT: + aTransfer.transferValue( &XRow::getFloat, &XParameters::setFloat ); + break; + + case DataType::LONGVARBINARY: + case DataType::BINARY: + case DataType::VARBINARY: + aTransfer.transferComplexValue( &XRow::getBytes, &XParameters::setBytes ); + break; + + case DataType::DATE: + aTransfer.transferComplexValue( &XRow::getDate, &XParameters::setDate ); + break; + + case DataType::TIME: + aTransfer.transferComplexValue( &XRow::getTime, &XParameters::setTime ); + break; + + case DataType::TIMESTAMP: + aTransfer.transferComplexValue( &XRow::getTimestamp, &XParameters::setTimestamp ); + break; + + case DataType::BIT: + if ( aSourcePrec[nSourceColumn] > 1 ) + { + aTransfer.transferComplexValue( &XRow::getBytes, &XParameters::setBytes ); + break; + } + [[fallthrough]]; + case DataType::BOOLEAN: + aTransfer.transferValue( &XRow::getBoolean, &XParameters::setBoolean ); + break; + + case DataType::TINYINT: + aTransfer.transferValue( &XRow::getByte, &XParameters::setByte ); + break; + + case DataType::SMALLINT: + aTransfer.transferValue( &XRow::getShort, &XParameters::setShort ); + break; + + case DataType::INTEGER: + aTransfer.transferValue( &XRow::getInt, &XParameters::setInt ); + break; + + case DataType::BLOB: + aTransfer.transferComplexValue( &XRow::getBlob, &XParameters::setBlob ); + break; + + case DataType::CLOB: + aTransfer.transferComplexValue( &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& ) + { + 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 ); + } + break; + + case CopyTableOperation::CreateAsView: + rWizard.createView(); + break; + + default: + SAL_WARN("dbaccess.ui", "CopyTableWizard::impl_doCopy_nothrow: What operation, please?" ); + break; + } + } + catch( const Exception& ) + { + aError = ::cppu::getCaughtException(); + + // silence the error of the user cancelling the parameter's dialog + SQLException aSQLError; + if ( ( aError >>= aSQLError ) && ( aSQLError.ErrorCode == ::dbtools::ParameterInteractionCancelled ) ) + { + aError.clear(); + m_nOverrideExecutionResult = RET_CANCEL; + } + } + + if ( aError.hasValue() && m_xInteractionHandler.is() ) + { + try + { + ::rtl::Reference< ::comphelper::OInteractionRequest > xRequest( new ::comphelper::OInteractionRequest( aError ) ); + m_xInteractionHandler->handle( xRequest.get() ); + } + 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).append(aDestColumnNames[rColumnPositionPair.second - 1]).append(sQuote); + } + } + const OUString sComposedTableName = ::dbtools::composeTableName( xDestMetaData, _xTable, ::dbtools::EComposeRule::InDataManipulation, true ); + OUString sSql("INSERT INTO " + sComposedTableName + " ( " + sColumns.makeStringAndClear() + " ) " + 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" void createRegistryInfo_CopyTableWizard() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::CopyTableWizard > aAutoRegistration; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/dbinteraction.cxx b/dbaccess/source/ui/uno/dbinteraction.cxx new file mode 100644 index 000000000..c3ba87ab0 --- /dev/null +++ b/dbaccess/source/ui/uno/dbinteraction.cxx @@ -0,0 +1,367 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 +#include +#include +#include +#include + +extern "C" void createRegistryInfo_OInteractionHandler() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::SQLExceptionInteractionHandler > aSQLExceptionInteractionHandler_AutoRegistration; + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::LegacyInteractionHandler > aLegacyInteractionHandler_AutoRegistration; +} + +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 + IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(SQLExceptionInteractionHandler, "com.sun.star.comp.dbaccess.DatabaseInteractionHandler") + IMPLEMENT_SERVICE_INFO_SUPPORTS(SQLExceptionInteractionHandler) + IMPLEMENT_SERVICE_INFO_GETSUPPORTED1_STATIC(SQLExceptionInteractionHandler, "com.sun.star.sdb.DatabaseInteractionHandler") + + Reference< XInterface > + SQLExceptionInteractionHandler::Create(const Reference< XMultiServiceFactory >& _rxORB) + { + return static_cast< XServiceInfo* >(new SQLExceptionInteractionHandler(comphelper::getComponentContext(_rxORB))); + } + + // LegacyInteractionHandler + IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(LegacyInteractionHandler, "com.sun.star.comp.dbaccess.LegacyInteractionHandler") + IMPLEMENT_SERVICE_INFO_SUPPORTS(LegacyInteractionHandler) + IMPLEMENT_SERVICE_INFO_GETSUPPORTED1_STATIC(LegacyInteractionHandler, "com.sun.star.sdb.InteractionHandler") + + Reference< XInterface > + LegacyInteractionHandler::Create(const Reference< XMultiServiceFactory >& _rxORB) + { + return static_cast< XServiceInfo* >(new LegacyInteractionHandler(comphelper::getComponentContext(_rxORB))); + } + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/dbinteraction.hxx b/dbaccess/source/ui/uno/dbinteraction.hxx new file mode 100644 index 000000000..66e0bfb16 --- /dev/null +++ b/dbaccess/source/ui/uno/dbinteraction.hxx @@ -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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_DBINTERACTION_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_DBINTERACTION_HXX + +#include +#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(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + }; + + // 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(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + }; + +} // namespace dbaui + +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_DBINTERACTION_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/textconnectionsettings_uno.cxx b/dbaccess/source/ui/uno/textconnectionsettings_uno.cxx new file mode 100644 index 000000000..a6f826127 --- /dev/null +++ b/dbaccess/source/ui/uno/textconnectionsettings_uno.cxx @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 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 + ,public ::cppu::WeakImplHelper< css::sdb::XTextConnectionSettings > + { + PropertyValues m_aPropertyValues; + + protected: + explicit OTextConnectionSettingsDialog( const Reference& _rContext ); + virtual ~OTextConnectionSettingsDialog() override; + + public: + virtual css::uno::Sequence SAL_CALL getImplementationId() override; + + DECLARE_SERVICE_INFO(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + DECLARE_PROPERTYCONTAINER_DEFAULTS( ); + + 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 ); + } + + OTextConnectionSettingsDialog::~OTextConnectionSettingsDialog() + { + } + + css::uno::Sequence + OTextConnectionSettingsDialog::getImplementationId() + { + return css::uno::Sequence(); + } + + IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(OTextConnectionSettingsDialog, "com.sun.star.comp.dbaccess.OTextConnectionSettingsDialog") + IMPLEMENT_SERVICE_INFO_SUPPORTS(OTextConnectionSettingsDialog) + IMPLEMENT_SERVICE_INFO_GETSUPPORTED1_STATIC(OTextConnectionSettingsDialog, "com.sun.star.sdb.TextConnectionSettings") + + css::uno::Reference< css::uno::XInterface > + OTextConnectionSettingsDialog::Create(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB) + { + return static_cast< XServiceInfo* >(new OTextConnectionSettingsDialog( comphelper::getComponentContext(_rxORB))); + } + + 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 ); + + aProps[ nProp++ ] = Property( + "HeaderLine", + PROPERTY_ID_HEADER_LINE, + ::cppu::UnoType< sal_Bool >::get(), + PropertyAttribute::TRANSIENT + ); + + aProps[ nProp++ ] = Property( + "FieldDelimiter", + PROPERTY_ID_FIELD_DELIMITER, + ::cppu::UnoType< OUString >::get(), + PropertyAttribute::TRANSIENT + ); + + aProps[ nProp++ ] = Property( + "StringDelimiter", + PROPERTY_ID_STRING_DELIMITER, + ::cppu::UnoType< OUString >::get(), + PropertyAttribute::TRANSIENT + ); + + aProps[ nProp++ ] = Property( + "DecimalDelimiter", + PROPERTY_ID_DECIMAL_DELIMITER, + ::cppu::UnoType< OUString >::get(), + PropertyAttribute::TRANSIENT + ); + + aProps[ nProp++ ] = Property( + "ThousandDelimiter", + PROPERTY_ID_THOUSAND_DELIMITER, + ::cppu::UnoType< OUString >::get(), + PropertyAttribute::TRANSIENT + ); + + aProps[ 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" void createRegistryInfo_OTextConnectionSettingsDialog() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::OTextConnectionSettingsDialog > aAutoRegistration; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/unoDirectSql.cxx b/dbaccess/source/ui/uno/unoDirectSql.cxx new file mode 100644 index 000000000..7abfbdfef --- /dev/null +++ b/dbaccess/source/ui/uno/unoDirectSql.cxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * 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 "unoDirectSql.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" void createRegistryInfo_ODirectSQLDialog() +{ + static ::dbaui::OMultiInstanceAutoRegistration< ::dbaui::ODirectSQLDialog > aAutoRegistration; +} + +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(); + } + + IMPLEMENT_SERVICE_INFO_IMPLNAME_STATIC(ODirectSQLDialog, "com.sun.star.comp.sdb.DirectSQLDialog") + IMPLEMENT_SERVICE_INFO_SUPPORTS(ODirectSQLDialog) + IMPLEMENT_SERVICE_INFO_GETSUPPORTED1_STATIC(ODirectSQLDialog, SERVICE_SDB_DIRECTSQLDIALOG) + + css::uno::Reference< css::uno::XInterface > + ODirectSQLDialog::Create(const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB) + { + return static_cast< XServiceInfo* >(new ODirectSQLDialog( comphelper::getComponentContext(_rxORB))); + } + + IMPLEMENT_PROPERTYCONTAINER_DEFAULTS( ODirectSQLDialog ) + + 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 000000000..afad0d820 --- /dev/null +++ b/dbaccess/source/ui/uno/unoDirectSql.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 . + */ + +#ifndef INCLUDED_DBACCESS_SOURCE_UI_UNO_UNODIRECTSQL_HXX +#define INCLUDED_DBACCESS_SOURCE_UI_UNO_UNODIRECTSQL_HXX + +#include +#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; + protected: + explicit ODirectSQLDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + virtual ~ODirectSQLDialog() override; + + public: + virtual css::uno::Sequence SAL_CALL getImplementationId() override; + + DECLARE_SERVICE_INFO(); + /// @throws css::uno::RuntimeException + static OUString getImplementationName_Static( ); + /// @throws css::uno::RuntimeException + static css::uno::Sequence< OUString > getSupportedServiceNames_Static( ); + static css::uno::Reference< css::uno::XInterface > + Create(const css::uno::Reference< css::lang::XMultiServiceFactory >&); + + DECLARE_PROPERTYCONTAINER_DEFAULTS( ); + + 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 + +#endif // INCLUDED_DBACCESS_SOURCE_UI_UNO_UNODIRECTSQL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/unoadmin.cxx b/dbaccess/source/ui/uno/unoadmin.cxx new file mode 100644 index 000000000..f53df65a9 --- /dev/null +++ b/dbaccess/source/ui/uno/unoadmin.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 + +#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_pItemPool(nullptr) + ,m_pItemPoolDefaults(nullptr) +{ + m_pCollection.reset( new ::dbaccess::ODsnTypeCollection(_rxORB) ); + ODbAdminDialog::createItemSet(m_pDatasourceItems, m_pItemPool, m_pItemPoolDefaults, m_pCollection.get()); +} + +ODatabaseAdministrationDialog::~ODatabaseAdministrationDialog() +{ + if (m_xDialog) + { + ::osl::MutexGuard aGuard(m_aMutex); + if (m_xDialog) + { + destroyDialog(); + ODbAdminDialog::destroyItemSet(m_pDatasourceItems, m_pItemPool, m_pItemPoolDefaults); + } + } +} + +void ODatabaseAdministrationDialog::implInitialize(const Any& _rValue) +{ + PropertyValue aProperty; + if (_rValue >>= aProperty) + { + if (aProperty.Name == "InitialSelection") + { + m_aInitialSelection = aProperty.Value; + } + else if (aProperty.Name == "ActiveConnection") + { + m_xActiveConnection.set(aProperty.Value,UNO_QUERY); + } + else + ODatabaseAdministrationDialogBase::implInitialize(_rValue); + } + else + ODatabaseAdministrationDialogBase::implInitialize(_rValue); +} + +} // namespace dbaui + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/dbaccess/source/ui/uno/unosqlmessage.cxx b/dbaccess/source/ui/uno/unosqlmessage.cxx new file mode 100644 index 000000000..4881a1744 --- /dev/null +++ b/dbaccess/source/ui/uno/unosqlmessage.cxx @@ -0,0 +1,160 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#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" void createRegistryInfo_OSQLMessageDialog() +{ + static OMultiInstanceAutoRegistration< OSQLMessageDialog > aAutoRegistration; +} + +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(); +} + +Reference< XInterface > OSQLMessageDialog::Create(const Reference< XMultiServiceFactory >& _rxFactory) +{ + return *(new OSQLMessageDialog( comphelper::getComponentContext(_rxFactory) )); +} + +OUString SAL_CALL OSQLMessageDialog::getImplementationName() +{ + return getImplementationName_Static(); +} + +OUString OSQLMessageDialog::getImplementationName_Static() +{ + return "org.openoffice.comp.dbu.OSQLMessageDialog"; +} + +css::uno::Sequence SAL_CALL OSQLMessageDialog::getSupportedServiceNames() +{ + return getSupportedServiceNames_Static(); +} + +css::uno::Sequence OSQLMessageDialog::getSupportedServiceNames_Static() +{ + 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: */ diff --git a/dbaccess/uiconfig/dbapp/menubar/menubar.xml b/dbaccess/uiconfig/dbapp/menubar/menubar.xml new file mode 100644 index 000000000..7038a6360 --- /dev/null +++ b/dbaccess/uiconfig/dbapp/menubar/menubar.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbapp/popupmenu/edit.xml b/dbaccess/uiconfig/dbapp/popupmenu/edit.xml new file mode 100644 index 000000000..539b9e74c --- /dev/null +++ b/dbaccess/uiconfig/dbapp/popupmenu/edit.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbapp/popupmenu/new.xml b/dbaccess/uiconfig/dbapp/popupmenu/new.xml new file mode 100644 index 000000000..fd9a23a9d --- /dev/null +++ b/dbaccess/uiconfig/dbapp/popupmenu/new.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbapp/popupmenu/preview.xml b/dbaccess/uiconfig/dbapp/popupmenu/preview.xml new file mode 100644 index 000000000..eb58afdb9 --- /dev/null +++ b/dbaccess/uiconfig/dbapp/popupmenu/preview.xml @@ -0,0 +1,14 @@ + + + + + + + diff --git a/dbaccess/uiconfig/dbapp/statusbar/statusbar.xml b/dbaccess/uiconfig/dbapp/statusbar/statusbar.xml new file mode 100644 index 000000000..8e4801d50 --- /dev/null +++ b/dbaccess/uiconfig/dbapp/statusbar/statusbar.xml @@ -0,0 +1,25 @@ + + + + + + + + + diff --git a/dbaccess/uiconfig/dbapp/toolbar/formobjectbar.xml b/dbaccess/uiconfig/dbapp/toolbar/formobjectbar.xml new file mode 100644 index 000000000..b3c2c9c37 --- /dev/null +++ b/dbaccess/uiconfig/dbapp/toolbar/formobjectbar.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbapp/toolbar/queryobjectbar.xml b/dbaccess/uiconfig/dbapp/toolbar/queryobjectbar.xml new file mode 100644 index 000000000..9733036ea --- /dev/null +++ b/dbaccess/uiconfig/dbapp/toolbar/queryobjectbar.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbapp/toolbar/reportobjectbar.xml b/dbaccess/uiconfig/dbapp/toolbar/reportobjectbar.xml new file mode 100644 index 000000000..a8cd8c834 --- /dev/null +++ b/dbaccess/uiconfig/dbapp/toolbar/reportobjectbar.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbapp/toolbar/tableobjectbar.xml b/dbaccess/uiconfig/dbapp/toolbar/tableobjectbar.xml new file mode 100644 index 000000000..b852d03a2 --- /dev/null +++ b/dbaccess/uiconfig/dbapp/toolbar/tableobjectbar.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbapp/toolbar/toolbar.xml b/dbaccess/uiconfig/dbapp/toolbar/toolbar.xml new file mode 100644 index 000000000..62c48f1c4 --- /dev/null +++ b/dbaccess/uiconfig/dbapp/toolbar/toolbar.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbbrowser/menubar/compat.xml b/dbaccess/uiconfig/dbbrowser/menubar/compat.xml new file mode 100644 index 000000000..1e224627c --- /dev/null +++ b/dbaccess/uiconfig/dbbrowser/menubar/compat.xml @@ -0,0 +1 @@ + diff --git a/dbaccess/uiconfig/dbbrowser/menubar/preserve.txt b/dbaccess/uiconfig/dbbrowser/menubar/preserve.txt new file mode 100644 index 000000000..268db482c --- /dev/null +++ b/dbaccess/uiconfig/dbbrowser/menubar/preserve.txt @@ -0,0 +1 @@ +Needed for compatibility reasons. \ No newline at end of file diff --git a/dbaccess/uiconfig/dbbrowser/popupmenu/explorer.xml b/dbaccess/uiconfig/dbbrowser/popupmenu/explorer.xml new file mode 100644 index 000000000..3be0c047a --- /dev/null +++ b/dbaccess/uiconfig/dbbrowser/popupmenu/explorer.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbbrowser/popupmenu/refreshdata.xml b/dbaccess/uiconfig/dbbrowser/popupmenu/refreshdata.xml new file mode 100644 index 000000000..216c6c53c --- /dev/null +++ b/dbaccess/uiconfig/dbbrowser/popupmenu/refreshdata.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/dbaccess/uiconfig/dbbrowser/toolbar/toolbar.xml b/dbaccess/uiconfig/dbbrowser/toolbar/toolbar.xml new file mode 100644 index 000000000..3f73d9a58 --- /dev/null +++ b/dbaccess/uiconfig/dbbrowser/toolbar/toolbar.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbquery/menubar/menubar.xml b/dbaccess/uiconfig/dbquery/menubar/menubar.xml new file mode 100644 index 000000000..8227446b4 --- /dev/null +++ b/dbaccess/uiconfig/dbquery/menubar/menubar.xml @@ -0,0 +1,119 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbquery/toolbar/designobjectbar.xml b/dbaccess/uiconfig/dbquery/toolbar/designobjectbar.xml new file mode 100644 index 000000000..af8b850d4 --- /dev/null +++ b/dbaccess/uiconfig/dbquery/toolbar/designobjectbar.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbquery/toolbar/sqlobjectbar.xml b/dbaccess/uiconfig/dbquery/toolbar/sqlobjectbar.xml new file mode 100644 index 000000000..c6898fd26 --- /dev/null +++ b/dbaccess/uiconfig/dbquery/toolbar/sqlobjectbar.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/dbaccess/uiconfig/dbquery/toolbar/toolbar.xml b/dbaccess/uiconfig/dbquery/toolbar/toolbar.xml new file mode 100644 index 000000000..55480895c --- /dev/null +++ b/dbaccess/uiconfig/dbquery/toolbar/toolbar.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbrelation/menubar/menubar.xml b/dbaccess/uiconfig/dbrelation/menubar/menubar.xml new file mode 100644 index 000000000..6e3df781e --- /dev/null +++ b/dbaccess/uiconfig/dbrelation/menubar/menubar.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbrelation/toolbar/toolbar.xml b/dbaccess/uiconfig/dbrelation/toolbar/toolbar.xml new file mode 100644 index 000000000..a01cb895c --- /dev/null +++ b/dbaccess/uiconfig/dbrelation/toolbar/toolbar.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbtable/menubar/menubar.xml b/dbaccess/uiconfig/dbtable/menubar/menubar.xml new file mode 100644 index 000000000..bbd4a7428 --- /dev/null +++ b/dbaccess/uiconfig/dbtable/menubar/menubar.xml @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbtable/toolbar/toolbar.xml b/dbaccess/uiconfig/dbtable/toolbar/toolbar.xml new file mode 100644 index 000000000..2d5825cb4 --- /dev/null +++ b/dbaccess/uiconfig/dbtable/toolbar/toolbar.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbtdata/menubar/menubar.xml b/dbaccess/uiconfig/dbtdata/menubar/menubar.xml new file mode 100644 index 000000000..bbf379953 --- /dev/null +++ b/dbaccess/uiconfig/dbtdata/menubar/menubar.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/dbtdata/popupmenu/refreshdata.xml b/dbaccess/uiconfig/dbtdata/popupmenu/refreshdata.xml new file mode 100644 index 000000000..216c6c53c --- /dev/null +++ b/dbaccess/uiconfig/dbtdata/popupmenu/refreshdata.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/dbaccess/uiconfig/dbtdata/toolbar/toolbar.xml b/dbaccess/uiconfig/dbtdata/toolbar/toolbar.xml new file mode 100644 index 000000000..7d925ff89 --- /dev/null +++ b/dbaccess/uiconfig/dbtdata/toolbar/toolbar.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/ui/admindialog.ui b/dbaccess/uiconfig/ui/admindialog.ui new file mode 100644 index 000000000..eae5b543c --- /dev/null +++ b/dbaccess/uiconfig/ui/admindialog.ui @@ -0,0 +1,161 @@ + + + + + + False + 6 + Database Properties + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-revert-to-saved + True + True + True + True + + + False + True + 0 + + + + + gtk-ok + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-cancel + True + True + True + True + + + False + True + 2 + + + + + gtk-help + True + True + True + True + + + False + True + 3 + True + + + + + False + True + end + 0 + + + + + True + True + True + True + True + True + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + False + Advanced Properties + 0.4699999988079071 + + + False + + + + + False + True + 1 + + + + + + reset + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/advancedsettingsdialog.ui b/dbaccess/uiconfig/ui/advancedsettingsdialog.ui new file mode 100644 index 000000000..b2a191797 --- /dev/null +++ b/dbaccess/uiconfig/ui/advancedsettingsdialog.ui @@ -0,0 +1,208 @@ + + + + + + False + 6 + Advanced Settings + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-revert-to-saved + True + True + True + True + + + False + True + 0 + + + + + gtk-ok + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-cancel + True + True + True + True + + + False + True + 2 + + + + + gtk-help + True + True + True + True + + + False + True + 3 + True + + + + + False + True + end + 0 + + + + + True + True + True + True + True + True + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + False + Generated Values + + + False + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + True + False + Special Settings + 0.4699999988079071 + + + 1 + False + + + + + False + True + 1 + + + + + + reset + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/applycolpage.ui b/dbaccess/uiconfig/ui/applycolpage.ui new file mode 100644 index 000000000..84bd80c86 --- /dev/null +++ b/dbaccess/uiconfig/ui/applycolpage.ui @@ -0,0 +1,245 @@ + + + + + + True + False + dbaccess/res/all_right.png + + + True + False + dbaccess/res/one_right.png + + + True + False + dbaccess/res/one_left.png + + + True + False + dbaccess/res/all_left.png + + + + + + + + + + + + + + + + + + + True + False + True + True + 6 + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + 12 + + + True + True + True + True + in + + + True + True + True + True + True + liststore1 + False + 1 + False + + + + + + True + 6 + + + + 0 + + + + + + + + + 0 + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore2 + False + 1 + False + + + + + + True + 6 + + + + 0 + + + + + + + + + 2 + 0 + + + + + True + False + center + vertical + 6 + start + + + True + True + True + image2 + + + False + True + 0 + + + + + True + True + True + image1 + + + False + True + 1 + + + + + True + True + True + image3 + + + False + True + 2 + + + + + True + True + True + image4 + + + False + True + 3 + + + + + 1 + 0 + + + + + + + + + True + False + Existing Columns + + + + + + + + 0 + 0 + + + + + + + + + + diff --git a/dbaccess/uiconfig/ui/authentificationpage.ui b/dbaccess/uiconfig/ui/authentificationpage.ui new file mode 100644 index 000000000..9086e1d41 --- /dev/null +++ b/dbaccess/uiconfig/ui/authentificationpage.ui @@ -0,0 +1,122 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + start + 12 + Set up the user authentication + + + + + + False + True + 0 + + + + + True + False + 6 + Some databases require you to enter a user name. + True + 72 + 72 + 0 + + + False + True + 1 + + + + + True + False + True + 2 + 6 + + + True + False + start + _User name + True + generalUserNameEntry + + + 0 + 0 + + + + + True + True + True + True + + + 1 + 0 + + + + + Password re_quired + True + True + False + True + 0 + True + + + 1 + 1 + + + + + + + + False + True + 2 + + + + + _Test Connection + True + True + True + True + end + True + + + False + True + 3 + + + + diff --git a/dbaccess/uiconfig/ui/autocharsetpage.ui b/dbaccess/uiconfig/ui/autocharsetpage.ui new file mode 100644 index 000000000..b5cbd930a --- /dev/null +++ b/dbaccess/uiconfig/ui/autocharsetpage.ui @@ -0,0 +1,81 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + 12 + + + True + False + _Character set: + True + charset + + + False + True + 0 + + + + + True + True + True + + + False + True + 1 + + + + + + + + + True + False + Data Conversion + + + + + + + + False + True + 0 + + + + diff --git a/dbaccess/uiconfig/ui/choosedatasourcedialog.ui b/dbaccess/uiconfig/ui/choosedatasourcedialog.ui new file mode 100644 index 000000000..23ad6cfaf --- /dev/null +++ b/dbaccess/uiconfig/ui/choosedatasourcedialog.ui @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + False + 6 + Data Source + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + Or_ganize... + True + True + True + True + + + False + True + 3 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + 6 + + + True + False + Choose a data source: + True + treeview + 0 + + + 0 + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore2 + False + 1 + False + + + + + + True + 6 + + + + 0 + + + + + + + + + 0 + 1 + + + + + False + True + 1 + + + + + + ok + cancel + help + organize + + + diff --git a/dbaccess/uiconfig/ui/collectionviewdialog.ui b/dbaccess/uiconfig/ui/collectionviewdialog.ui new file mode 100644 index 000000000..0ffb48584 --- /dev/null +++ b/dbaccess/uiconfig/ui/collectionviewdialog.ui @@ -0,0 +1,269 @@ + + + + + + True + False + res/fp015.png + + + True + False + res/fp010.png + + + + + + + + + + + False + True + True + 6 + Save + True + 0 + 0 + dialog + + + + + + False + True + True + vertical + 12 + + + False + end + + + _Save + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + vertical + 6 + + + True + False + True + 3 + + + True + False + start + start + True + middle + + + False + True + 0 + + + + + True + True + False + True + True + True + Create New Directory + image1 + True + + + False + True + 1 + + + + + True + True + True + True + True + Up One Level + image2 + True + + + False + True + 2 + + + + + False + True + 0 + + + + + True + True + True + in + + + True + True + True + True + liststore1 + False + 1 + False + + + + + + True + Folder Name + + + + 0 + + + + + + + + + False + True + 1 + + + + + True + False + True + 12 + + + True + False + File _name: + True + fileNameEntry + + + False + True + 0 + + + + + True + True + True + True + + + False + True + 1 + + + + + False + True + 2 + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/colwidthdialog.ui b/dbaccess/uiconfig/ui/colwidthdialog.ui new file mode 100644 index 000000000..28b5492ff --- /dev/null +++ b/dbaccess/uiconfig/ui/colwidthdialog.ui @@ -0,0 +1,156 @@ + + + + + + 0.10000000000000001 + 200 + 2.27 + 1 + 10 + + + False + 6 + Column Width + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + start + True + True + 6 + 12 + + + True + False + _Width: + True + value + 1 + + + 0 + 0 + + + + + True + True + True + True + adjustment1 + 2 + + + 1 + 0 + + + + + _Automatic + True + True + False + True + 0 + True + + + 1 + 1 + + + + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/connectionpage.ui b/dbaccess/uiconfig/ui/connectionpage.ui new file mode 100644 index 000000000..7e0faa324 --- /dev/null +++ b/dbaccess/uiconfig/ui/connectionpage.ui @@ -0,0 +1,316 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + start + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + 6 + 12 + + + True + False + start + Path to the dBASE files: + True + browseurl + + + 0 + 0 + + + + + _Create New + True + True + True + True + + + 1 + 0 + + + + + _Browse… + True + True + True + True + + + 1 + 1 + + + + + True + False + + + True + True + True + + + 1 + 0 + + + + + True + False + + + 0 + 0 + + + + + 0 + 1 + + + + + + + + + True + False + General + + + + + + + + False + True + 0 + + + + + True + False + start + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + 6 + 12 + + + True + False + _User name: + True + userNameEntry + 1 + + + 0 + 0 + + + + + True + True + True + + + 1 + 0 + + + + + Password required + True + True + False + True + 0 + True + + + 1 + 1 + + + + + + + + + + + + True + False + User Authentication + + + + + + + + False + True + 1 + + + + + True + False + start + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + 12 + + + True + False + _JDBC driver class: + True + driverEntry + 1 + + + False + True + 0 + + + + + True + True + True + + + False + True + 1 + + + + + Test Class + True + True + True + + + False + True + 2 + + + + + + + + + True + False + JDBC Properties + + + + + + + + False + True + 2 + + + + + Test Connection + True + True + True + end + end + True + + + False + True + 3 + + + + diff --git a/dbaccess/uiconfig/ui/copytablepage.ui b/dbaccess/uiconfig/ui/copytablepage.ui new file mode 100644 index 000000000..4c027a354 --- /dev/null +++ b/dbaccess/uiconfig/ui/copytablepage.ui @@ -0,0 +1,246 @@ + + + + + + True + False + 6 + 6 + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + 6 + + + De_finition and data + True + True + False + True + 0 + True + True + + + 0 + 0 + + + + + Def_inition + True + True + False + True + 0 + True + defdata + + + 0 + 1 + + + + + A_s table view + True + True + False + True + 0 + True + defdata + + + 0 + 2 + + + + + Append _data + True + True + False + True + 0 + True + defdata + + + 0 + 3 + + + + + Use first _line as column names + True + True + False + True + 0 + True + + + 0 + 4 + + + + + Crea_te new field as primary key + True + True + False + True + 0 + True + + + 0 + 5 + + + + + True + False + 12 + + + True + False + True + 12 + + + True + False + Name: + True + keyname + 1 + + + 0 + 0 + + + + + True + True + True + True + + + 1 + 0 + + + + + + + 0 + 6 + + + + + True + False + Existing data fields can be set as primary key on the type formatting step (third page) of the wizard. + True + 72 + 72 + 0 + + + 0 + 7 + + + + + + + + + True + False + Options + + + + + + + + 0 + 1 + + + + + True + False + True + 12 + + + True + False + Ta_ble name: + True + name + 1 + + + 0 + 0 + + + + + True + True + True + True + + + 1 + 0 + + + + + 0 + 0 + + + + diff --git a/dbaccess/uiconfig/ui/dbaseindexdialog.ui b/dbaccess/uiconfig/ui/dbaseindexdialog.ui new file mode 100644 index 000000000..aaf689453 --- /dev/null +++ b/dbaccess/uiconfig/ui/dbaseindexdialog.ui @@ -0,0 +1,391 @@ + + + + + + True + False + dbaccess/res/one_left.png + + + True + False + dbaccess/res/one_left.png + + + True + False + dbaccess/res/one_right.png + + + True + False + dbaccess/res/all_right.png + + + + + + + + + + + + + + + + + + + False + 6 + Indexes + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + 12 + + + True + False + 12 + + + True + False + _Table: + True + table + 0 + + + 0 + 0 + + + + + True + False + True + True + + + True + True + + + + + 1 + 0 + + + + + 0 + 0 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + False + 6 + 12 + + + True + False + T_able indexes + True + tableindex + 0 + + + 0 + 0 + + + + + True + False + _Free indexes + True + freeindex + 0 + + + 2 + 0 + + + + + True + False + True + True + in + + + True + True + True + True + liststore1 + False + False + 0 + False + + + + + + + + + 0 + + + + + + + + + 0 + 1 + + + + + True + False + True + True + in + + + True + True + True + True + liststore2 + False + False + 0 + False + + + + + + + + + 0 + + + + + + + + + 2 + 1 + + + + + True + False + center + True + vertical + 6 + start + + + True + True + True + image1 + + + False + True + 0 + + + + + True + True + True + image2 + + + False + True + 1 + + + + + True + True + True + image3 + + + False + True + 2 + + + + + True + True + True + image4 + + + False + True + 3 + + + + + 1 + 1 + + + + + + + + + + + + True + False + Assignment + + + + + + + + 0 + 1 + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/dbasepage.ui b/dbaccess/uiconfig/ui/dbasepage.ui new file mode 100644 index 000000000..244b754d4 --- /dev/null +++ b/dbaccess/uiconfig/ui/dbasepage.ui @@ -0,0 +1,172 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + 12 + + + True + False + _Character set: + True + charset + + + False + True + 0 + + + + + True + True + True + + + False + True + 1 + + + + + + + + + True + False + Data Conversion + + + + + + + + False + True + 0 + + + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + vertical + 6 + + + Display deleted records as well + True + True + False + True + 0 + True + + + False + True + 0 + + + + + True + False + Note: When deleted, and thus inactive, records are displayed, you will not be able to delete records from the data source. + True + 72 + 72 + 0 + + + False + True + 1 + + + + + + + + + True + False + Optional Settings + + + + + + + + False + True + 1 + + + + + Indexes... + True + True + True + end + end + True + True + + + False + True + 2 + + + + diff --git a/dbaccess/uiconfig/ui/dbwizconnectionpage.ui b/dbaccess/uiconfig/ui/dbwizconnectionpage.ui new file mode 100644 index 000000000..812497948 --- /dev/null +++ b/dbaccess/uiconfig/ui/dbwizconnectionpage.ui @@ -0,0 +1,134 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + start + 12 + + + + + + False + True + 0 + + + + + True + False + 6 + label + True + 72 + 72 + 0 + + + False + True + 1 + + + + + True + False + True + 6 + 12 + + + True + False + start + Path to the dBASE files: + True + browseurl + + + 0 + 0 + + + + + _Create New + True + True + True + True + + + 1 + 0 + + + + + _Browse… + True + True + True + True + + + 1 + 1 + + + + + True + False + True + + + True + True + True + True + + + 1 + 0 + + + + + True + False + + + 0 + 0 + + + + + 0 + 1 + + + + + False + True + 2 + + + + diff --git a/dbaccess/uiconfig/ui/dbwizmysqlintropage.ui b/dbaccess/uiconfig/ui/dbwizmysqlintropage.ui new file mode 100644 index 000000000..224f17189 --- /dev/null +++ b/dbaccess/uiconfig/ui/dbwizmysqlintropage.ui @@ -0,0 +1,157 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + True + 0 + none + + + True + False + 6 + + + True + False + vertical + 6 + + + True + False + You can connect to a MySQL database using either ODBC or JDBC. +Please contact your system administrator if you are unsure about the following settings. + True + 72 + 72 + 0 + + + False + True + 0 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + False + vertical + 6 + + + Connect using ODBC (Open Database Connectivity) + True + True + False + True + 0 + True + jdbc + + + False + True + 0 + + + + + Connect using JDBC (Java Database Connectivity) + True + True + False + True + 0 + True + True + + + False + True + 1 + + + + + Connect directly + True + False + True + 0 + True + jdbc + + + False + True + 2 + + + + + + + + + True + False + How do you want to connect to your MySQL database? + + + + + False + True + 1 + + + + + + + + + True + False + Set Up a Connection to a MySQL Database + + + + + + + + True + True + 0 + + + + diff --git a/dbaccess/uiconfig/ui/dbwizmysqlnativepage.ui b/dbaccess/uiconfig/ui/dbwizmysqlnativepage.ui new file mode 100644 index 000000000..5d2b38c6e --- /dev/null +++ b/dbaccess/uiconfig/ui/dbwizmysqlnativepage.ui @@ -0,0 +1,90 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + + + True + False + vertical + 6 + + + True + False + start + Please enter the required information to connect to a MySQL database. + True + 72 + 72 + 0 + + + False + True + 0 + + + + + True + False + True + True + vertical + + + + + + False + True + 1 + + + + + + + + + True + False + Set Up a Connection to a MySQL Database + + + + + + + + True + True + 0 + + + + diff --git a/dbaccess/uiconfig/ui/dbwizspreadsheetpage.ui b/dbaccess/uiconfig/ui/dbwizspreadsheetpage.ui new file mode 100644 index 000000000..ed65d12b2 --- /dev/null +++ b/dbaccess/uiconfig/ui/dbwizspreadsheetpage.ui @@ -0,0 +1,175 @@ + + + + + + True + False + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + True + 6 + + + True + False + True + True + vertical + 6 + + + True + False + start + True + True + 72 + 72 + 0 + + + False + True + 0 + + + + + True + False + True + 6 + 6 + + + Browse + True + True + True + + + 1 + 1 + + + + + Create New + True + True + True + + + 2 + 1 + + + + + True + False + start + True + True + browseurl + 0 + + + 0 + 0 + 3 + + + + + True + False + True + + + True + True + True + True + + + 1 + 0 + + + + + True + False + + + 0 + 0 + + + + + 0 + 1 + + + + + _Password required + True + True + False + True + 0 + True + + + 0 + 2 + 3 + + + + + True + True + 1 + + + + + + + + + True + False + + + + + + + + False + True + 0 + + + + diff --git a/dbaccess/uiconfig/ui/dbwiztextpage.ui b/dbaccess/uiconfig/ui/dbwiztextpage.ui new file mode 100644 index 000000000..24b4e57a7 --- /dev/null +++ b/dbaccess/uiconfig/ui/dbwiztextpage.ui @@ -0,0 +1,176 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + True + 6 + + + True + False + True + True + vertical + 6 + + + True + False + start + True + True + 72 + 72 + 0 + + + False + True + 0 + + + + + True + False + True + 6 + 6 + + + Browse + True + True + True + + + 1 + 1 + + + + + Create New + True + True + True + + + 2 + 1 + + + + + True + False + start + True + True + browseurl + 0 + + + 0 + 0 + 3 + + + + + True + False + True + + + True + True + True + + + 1 + 0 + + + + + True + False + + + 0 + 0 + + + + + 0 + 1 + + + + + True + True + 1 + + + + + + + + + True + False + + + + + + + + False + True + 0 + + + + + True + False + True + vertical + 12 + + + + + + True + True + 1 + + + + diff --git a/dbaccess/uiconfig/ui/deleteallrowsdialog.ui b/dbaccess/uiconfig/ui/deleteallrowsdialog.ui new file mode 100644 index 000000000..fc299783f --- /dev/null +++ b/dbaccess/uiconfig/ui/deleteallrowsdialog.ui @@ -0,0 +1,81 @@ + + + + + + False + False + True + dialog + True + question + You are trying to delete all the columns in the table. A table cannot exist without columns. Should the table be deleted from the database? If not, the table will remain unchanged. + + + False + vertical + 12 + + + False + + + gtk-no + True + True + True + True + + + False + True + 0 + + + + + gtk-yes + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-cancel + True + True + True + True + + + False + True + 2 + + + + + False + True + end + 0 + + + + + + no + yes + cancel + + + diff --git a/dbaccess/uiconfig/ui/designsavemodifieddialog.ui b/dbaccess/uiconfig/ui/designsavemodifieddialog.ui new file mode 100644 index 000000000..0e41ed4e5 --- /dev/null +++ b/dbaccess/uiconfig/ui/designsavemodifieddialog.ui @@ -0,0 +1,82 @@ + + + + + + False + False + True + dialog + True + question + Do you want to save the changes? + The relation design has been changed. + + + False + vertical + 12 + + + False + + + gtk-no + True + True + True + True + + + False + True + 0 + + + + + gtk-yes + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-cancel + True + True + True + True + + + False + True + 2 + + + + + False + True + end + 0 + + + + + + no + yes + cancel + + + diff --git a/dbaccess/uiconfig/ui/directsqldialog.ui b/dbaccess/uiconfig/ui/directsqldialog.ui new file mode 100644 index 000000000..0947f539d --- /dev/null +++ b/dbaccess/uiconfig/ui/directsqldialog.ui @@ -0,0 +1,309 @@ + + + + + + False + 6 + Execute SQL Statement + False + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-help + True + True + True + True + True + + + False + True + 0 + True + + + + + gtk-close + True + True + True + True + True + + + False + True + 1 + + + + + False + True + end + 0 + + + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + 6 + + + True + True + True + True + 0 + in + + + True + False + + + True + True + GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_FOCUS_CHANGE_MASK | GDK_STRUCTURE_MASK + + + + + + + 0 + 1 + + + + + True + False + _Command to execute: + True + sql + 0 + + + 0 + 0 + + + + + True + False + 12 + + + _Show output of "select" statements + True + True + False + True + 0 + True + + + 0 + 0 + + + + + _Execute + True + True + True + True + True + True + + + 1 + 0 + + + + + 0 + 2 + + + + + True + False + + + 0 + 4 + + + + + True + False + _Previous commands: + True + sqlhistory + 0 + + + 0 + 3 + + + + + + + + + True + False + SQL Command + + + + + + + + False + True + 1 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + True + in + + + True + True + False + + + + + + + + + True + False + Status + + + + + + + + False + True + 2 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + True + in + + + True + True + False + + + + + + + + + True + False + Output + + + + + + + + False + True + 3 + + + + + + help + close + + + diff --git a/dbaccess/uiconfig/ui/emptypage.ui b/dbaccess/uiconfig/ui/emptypage.ui new file mode 100644 index 000000000..79b28524a --- /dev/null +++ b/dbaccess/uiconfig/ui/emptypage.ui @@ -0,0 +1,17 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + + + diff --git a/dbaccess/uiconfig/ui/fielddescpage.ui b/dbaccess/uiconfig/ui/fielddescpage.ui new file mode 100644 index 000000000..d535f4a49 --- /dev/null +++ b/dbaccess/uiconfig/ui/fielddescpage.ui @@ -0,0 +1,419 @@ + + + + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + True + False + True + True + 6 + + + True + True + True + True + in + + + True + False + + + True + False + + + True + False + True + True + 6 + 6 + 12 + + + False + True + Field name + True + ColumnName + 0 + + + 0 + 0 + + + + + True + True + True + + + 1 + 0 + + + + + False + True + A_uto-increment statement + True + AutoIncrementValue + 0 + + + 0 + 3 + + + + + True + True + True + adjustment2 + + + 1 + 3 + + + + + False + True + _Default value + True + DefaultValue + 0 + + + 0 + 9 + + + + + True + True + True + + + 1 + 9 + + + + + False + True + Format example + True + FormatText + 0 + + + 0 + 10 + + + + + True + False + True + 6 + + + True + True + True + + + False + True + 0 + + + + + _... + True + True + True + True + + + False + True + 1 + + + + + 1 + 10 + + + + + False + True + _Length + True + Length + 0 + + + 0 + 7 + + + + + True + True + True + adjustment1 + + + 1 + 7 + + + + + False + True + _Length + True + TextLength + 0 + + + 0 + 6 + + + + + True + True + True + adjustment3 + + + 1 + 6 + + + + + False + True + Decimal _places + True + Scale + 0 + + + 0 + 8 + + + + + True + True + True + adjustment4 + + + 1 + 8 + + + + + False + True + _Entry required + True + Required + 0 + + + 0 + 5 + + + + + False + True + True + + + 1 + 5 + + + + + False + True + _AutoValue + True + AutoIncrement + 0 + + + 0 + 2 + + + + + False + True + True + + + 1 + 2 + + + + + False + True + _Default value + True + BoolDefault + 0 + + + 0 + 11 + + + + + False + True + True + + + 1 + 11 + + + + + False + True + _Type + True + NumType + 0 + + + 0 + 4 + + + + + False + True + True + + + 1 + 4 + + + + + False + True + Field _type + True + Type + 0 + + + 0 + 1 + + + + + False + True + True + + + 1 + 1 + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/ui/fielddialog.ui b/dbaccess/uiconfig/ui/fielddialog.ui new file mode 100644 index 000000000..decc47f16 --- /dev/null +++ b/dbaccess/uiconfig/ui/fielddialog.ui @@ -0,0 +1,233 @@ + + + + + + -1 + False + 6 + Field Format + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-revert-to-saved + True + True + True + True + + + False + True + 0 + + + + + gtk-ok + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-cancel + True + True + True + True + + + False + True + 2 + + + + + gtk-help + True + True + True + True + + + False + True + 3 + True + + + + + False + True + end + 0 + + + + + True + False + vertical + + + True + False + True + True + True + True + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + False + Format + + + False + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + True + False + Alignment + 0.4699999988079071 + + + 1 + False + + + + + True + True + 0 + + + + + False + True + Table Format + + + False + True + 1 + + + + + True + True + 1 + + + + + + reset + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/finalpagewizard.ui b/dbaccess/uiconfig/ui/finalpagewizard.ui new file mode 100644 index 000000000..8e065ea1f --- /dev/null +++ b/dbaccess/uiconfig/ui/finalpagewizard.ui @@ -0,0 +1,171 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + Decide How to Proceed After Saving the Database + True + 0 + + + + + + 0 + 0 + + + + + True + False + 12 + + + True + False + 6 + + + True + False + Do you want the wizard to register the database in %PRODUCTNAME? + True + 72 + 72 + 0 + + + 0 + 0 + + + + + _Yes, register the database for me + True + True + False + 12 + True + 0 + True + True + + + 0 + 1 + + + + + N_o, do not register the database + True + True + False + 12 + True + 0 + True + yesregister + + + 0 + 2 + + + + + 0 + 0 + + + + + True + False + 6 + + + True + False + After the database file has been saved, what do you want to do? + True + 72 + 72 + 0 + + + 0 + 0 + + + + + Open the database for editing + True + True + False + 12 + True + 0 + True + + + 0 + 1 + + + + + Create tables using the table wizard + True + True + False + 12 + True + 0 + True + + + 0 + 2 + + + + + 0 + 1 + + + + + True + False + Click 'Finish' to save the database. + 0 + + + 0 + 2 + + + + + 0 + 1 + + + + diff --git a/dbaccess/uiconfig/ui/generalpagedialog.ui b/dbaccess/uiconfig/ui/generalpagedialog.ui new file mode 100644 index 000000000..31ace519a --- /dev/null +++ b/dbaccess/uiconfig/ui/generalpagedialog.ui @@ -0,0 +1,81 @@ + + + + + + True + False + 16 + 6 + 12 + + + True + False + 0 + 0 + Select the type of database to which you want to establish a connection. + + + 0 + 0 + 2 + + + + + True + False + 48 + 0 + Database _type: + True + datasourceType + + + 0 + 1 + + + + + True + False + start + True + + + 1 + 1 + + + + + True + False + 6 + 0 + 0 + On the following pages, you can make detailed settings for the connection. + +The new settings you make will overwrite your existing settings. + + + 0 + 2 + 2 + + + + + False + 0 + + + 0 + 3 + 2 + + + + diff --git a/dbaccess/uiconfig/ui/generalpagewizard.ui b/dbaccess/uiconfig/ui/generalpagewizard.ui new file mode 100644 index 000000000..029fc1adf --- /dev/null +++ b/dbaccess/uiconfig/ui/generalpagewizard.ui @@ -0,0 +1,226 @@ + + + + + + True + False + True + True + 6 + vertical + 6 + + + True + False + Welcome to the %PRODUCTNAME Database Wizard + True + 0 + + + + + + 0 + 0 + + + + + True + False + True + Use the Database Wizard to create a new database, open an existing database file, or connect to a database stored on a server. + True + 72 + 72 + 0 + + + 0 + 1 + + + + + True + False + What do you want to do? + True + 0 + + + 0 + 2 + + + + + Create a n_ew database + True + True + False + 12 + True + 0 + True + True + + + 0 + 3 + + + + + True + False + 24 + 12 + + + True + False + _Embedded database: + True + embeddeddbList + 0 + + + False + True + 0 + + + + + True + False + + + False + True + 1 + + + + + 0 + 4 + + + + + Open an existing database _file + True + True + False + 12 + True + 0 + True + True + createDatabase + + + 0 + 5 + + + + + True + False + 24 + 12 + + + True + False + _Recently used: + True + documentList + 0 + + + False + True + 0 + + + + + True + False + True + + + False + True + 1 + + + + + 0 + 6 + + + + + Open + True + True + True + start + 24 + True + + + 0 + 7 + + + + + Connect to an e_xisting database + True + True + False + 12 + True + 0 + True + True + createDatabase + + + 0 + 8 + + + + + True + False + start + 24 + + + 0 + 9 + + + + + False + 0 + + + 0 + 10 + + + + diff --git a/dbaccess/uiconfig/ui/generalspecialjdbcdetailspage.ui b/dbaccess/uiconfig/ui/generalspecialjdbcdetailspage.ui new file mode 100644 index 000000000..6280e2cc1 --- /dev/null +++ b/dbaccess/uiconfig/ui/generalspecialjdbcdetailspage.ui @@ -0,0 +1,250 @@ + + + + + + 65535 + 1 + 10 + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + 6 + 12 + + + True + False + _Host name: + True + hostNameEntry + 1 + + + 0 + 0 + + + + + True + False + _Port number: + True + portNumberSpinbutton + 1 + + + 0 + 1 + + + + + True + True + True + True + + + 1 + 0 + + + + + True + False + Socket: + 1 + + + 0 + 2 + + + + + True + False + MySQL JDBC d_river class: + True + jdbcDriverClassEntry + 1 + + + 0 + 3 + + + + + True + True + True + True + + + 1 + 3 + + + + + Test Class + True + True + True + + + 2 + 3 + + + + + True + True + True + True + + + 1 + 2 + + + + + True + True + True + adjustment1 + + + 1 + 1 + + + + + + + + + + + + + + + + + + True + False + Connection Settings + + + + + + + + False + True + 0 + + + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + 12 + + + True + False + _Character set: + True + charset + + + False + True + 0 + + + + + True + True + True + + + False + True + 1 + + + + + + + + + True + False + Data Conversion + + + + + + + + False + True + 1 + + + + diff --git a/dbaccess/uiconfig/ui/generatedvaluespage.ui b/dbaccess/uiconfig/ui/generatedvaluespage.ui new file mode 100644 index 000000000..30e118aaa --- /dev/null +++ b/dbaccess/uiconfig/ui/generatedvaluespage.ui @@ -0,0 +1,155 @@ + + + + + + True + False + True + True + 6 + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + 12 + + + Re_trieve generated values + True + True + False + True + 0 + True + + + 0 + 0 + + + + + True + False + True + 12 + + + True + False + True + 12 + + + True + False + True + 6 + + + True + False + _Auto-increment statement: + True + statement + 0 + + + 0 + 0 + + + + + True + True + True + True + 34 + + + 0 + 1 + + + + + 0 + 0 + + + + + True + False + True + 6 + + + True + False + _Query of generated values: + True + query + 0 + + + 0 + 0 + + + + + True + True + True + True + 34 + + + 0 + 1 + + + + + 0 + 1 + + + + + + + 0 + 1 + + + + + + + + + True + False + Settings + + + + + + + diff --git a/dbaccess/uiconfig/ui/indexdesigndialog.ui b/dbaccess/uiconfig/ui/indexdesigndialog.ui new file mode 100644 index 000000000..96a672bbd --- /dev/null +++ b/dbaccess/uiconfig/ui/indexdesigndialog.ui @@ -0,0 +1,351 @@ + + + + + + + + + + + + + + + + False + 6 + Indexes + False + dialog + + + + + + False + vertical + 2 + + + False + end + + + gtk-close + True + True + True + True + + + False + True + 0 + + + + + gtk-help + True + True + True + True + + + False + True + 1 + True + + + + + False + True + end + 0 + + + + + True + False + vertical + 6 + + + True + False + + + True + False + + + True + False + start + New Index + True + dbaccess/res/sc036.png + + + False + True + + + + + True + False + start + Delete Current Index + True + dbaccess/res/sc037.png + + + False + True + + + + + True + False + start + Rename Current Index + True + dbaccess/res/sc038.png + + + False + True + + + + + True + False + start + Save Current Index + True + dbaccess/res/sc039.png + + + False + True + + + + + True + False + start + Reset Current Index + True + dbaccess/res/sc040.png + + + False + True + + + + + 0 + 0 + + + + + False + True + 0 + + + + + True + False + 6 + 12 + + + True + True + True + True + in + + + -1 + True + True + True + True + True + liststore1 + False + 1 + True + + + + + + 6 + + + + 0 + + + + + True + + + 1 + + + + + + + + + 0 + 0 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + False + 6 + 12 + + + True + False + start + Index identifier: + 0 + + + 0 + 0 + + + + + True + False + start + 0 + + + 1 + 0 + + + + + _Unique + True + True + False + start + True + 0 + True + + + 0 + 1 + 2 + + + + + True + False + start + Fields: + True + 0 + + + 0 + 2 + 2 + + + + + True + True + True + True + + + 0 + 3 + 2 + + + + + + + + + True + False + Index Details + + + + + + + + 1 + 0 + + + + + True + True + 1 + + + + + True + True + 1 + + + + + + close + help + + + diff --git a/dbaccess/uiconfig/ui/jdbcconnectionpage.ui b/dbaccess/uiconfig/ui/jdbcconnectionpage.ui new file mode 100644 index 000000000..9e55d4e0e --- /dev/null +++ b/dbaccess/uiconfig/ui/jdbcconnectionpage.ui @@ -0,0 +1,202 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + start + 6 + Set Up a Connection to a JDBC Database + + + + + + False + True + 0 + + + + + True + False + Please enter the required information to connect to a JDBC database. Please contact your system administrator if you are unsure about the following settings. + True + 72 + 72 + 0 + + + False + True + 1 + + + + + True + False + 6 + 12 + + + True + False + start + Path to the dBASE files: + True + browseurl + + + 0 + 0 + + + + + _Create New + True + True + True + True + + + 1 + 0 + + + + + _Browse… + True + True + True + True + + + 1 + 1 + + + + + True + False + + + True + True + True + True + + + 1 + 0 + + + + + True + False + + + 0 + 0 + + + + + 0 + 1 + + + + + False + True + 2 + + + + + True + False + True + True + vertical + 6 + + + True + False + start + JDBC d_river class: + True + jdbcEntry + + + False + True + 0 + + + + + True + False + True + 12 + + + True + True + True + True + + + False + True + 0 + + + + + _Test Class + True + True + True + True + + + False + True + 1 + + + + + False + True + 1 + + + + + False + True + 3 + + + + diff --git a/dbaccess/uiconfig/ui/joindialog.ui b/dbaccess/uiconfig/ui/joindialog.ui new file mode 100644 index 000000000..078f6452c --- /dev/null +++ b/dbaccess/uiconfig/ui/joindialog.ui @@ -0,0 +1,329 @@ + + + + + + False + 6 + Join Properties + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + top + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + 12 + True + + + True + False + True + + + 0 + 0 + + + + + True + False + True + + + 1 + 0 + + + + + + + + + True + False + Tables Involved + + + + + + + + 0 + 0 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + False + 6 + + + True + False + True + 48 + 48 + 0 + 0 + + + 0 + 1 + + + + + True + False + True + True + + + 0 + 0 + + + + + + + + + True + False + Fields Involved + + + + + + + + 0 + 2 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + False + 6 + 12 + + + True + False + True + _Type: + True + type + 1 + + + 0 + 0 + + + + + True + False + True + + Inner join + Left join + Right join + Full (outer) join + Cross join + + + + 1 + 0 + + + + + Natural + True + True + False + True + 0 + True + + + 1 + 1 + + + + + + + + + + + + True + False + Options + + + + + + + + 0 + 1 + + + + + False + True + 1 + + + + + + ok + cancel + help + + + + + + + + + + + + + + + diff --git a/dbaccess/uiconfig/ui/jointablemenu.ui b/dbaccess/uiconfig/ui/jointablemenu.ui new file mode 100644 index 000000000..4e3271d72 --- /dev/null +++ b/dbaccess/uiconfig/ui/jointablemenu.ui @@ -0,0 +1,17 @@ + + + + + + True + False + + + True + False + _Delete + True + + + + diff --git a/dbaccess/uiconfig/ui/joinviewmenu.ui b/dbaccess/uiconfig/ui/joinviewmenu.ui new file mode 100644 index 000000000..8ea72854f --- /dev/null +++ b/dbaccess/uiconfig/ui/joinviewmenu.ui @@ -0,0 +1,25 @@ + + + + + + True + False + + + True + False + _Delete + True + + + + + True + False + Edit... + True + + + + diff --git a/dbaccess/uiconfig/ui/keymenu.ui b/dbaccess/uiconfig/ui/keymenu.ui new file mode 100644 index 000000000..71dc28355 --- /dev/null +++ b/dbaccess/uiconfig/ui/keymenu.ui @@ -0,0 +1,17 @@ + + + + + + True + False + + + True + False + Primary Key + True + + + + diff --git a/dbaccess/uiconfig/ui/ldapconnectionpage.ui b/dbaccess/uiconfig/ui/ldapconnectionpage.ui new file mode 100644 index 000000000..a64373d9d --- /dev/null +++ b/dbaccess/uiconfig/ui/ldapconnectionpage.ui @@ -0,0 +1,186 @@ + + + + + + 1000000000000 + 1 + 10 + + + True + False + True + 6 + vertical + 6 + + + True + False + start + 6 + Set Up a Connection to an LDAP Directory + + + + + + False + True + 0 + + + + + True + False + Please enter the required information to connect to an LDAP directory. Please contact your system administrator if you are unsure about the following settings. + True + 72 + 72 + 0 + + + False + True + 1 + + + + + True + False + True + True + 6 + 12 + + + True + False + _Server: + True + hostNameEntry + 1 + + + 0 + 0 + + + + + True + False + _Port number: + True + portNumEntry + 1 + + + 0 + 2 + + + + + True + True + True + True + + + 1 + 0 + + + + + True + False + True + 12 + + + True + True + True + True + adjustment1 + + + False + True + 0 + + + + + True + False + Default: 389 + + + False + True + 1 + + + + + 1 + 2 + + + + + True + False + Base _DN: + True + baseDNEntry + 1 + + + 0 + 1 + + + + + True + True + True + True + + + 1 + 1 + + + + + False + True + 2 + + + + + Use _secure connection (SSL) + True + True + False + True + 0 + True + + + False + True + 3 + + + + diff --git a/dbaccess/uiconfig/ui/ldappage.ui b/dbaccess/uiconfig/ui/ldappage.ui new file mode 100644 index 000000000..d98767375 --- /dev/null +++ b/dbaccess/uiconfig/ui/ldappage.ui @@ -0,0 +1,162 @@ + + + + + + 65535 + 1 + 10 + + + 65535 + 1 + 10 + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + 6 + 12 + + + True + False + _Base DN: + True + baseDNEntry + 1 + + + 0 + 0 + + + + + True + True + True + True + + + 1 + 0 + + + + + Use secure connection (SSL) + True + True + False + True + 0 + True + + + 0 + 1 + 2 + + + + + True + False + _Port number: + True + portNumberSpinbutton + 1 + + + 0 + 2 + + + + + True + True + True + True + adjustment1 + + + 1 + 2 + + + + + True + False + Maximum number of _records: + True + LDAPRowCountspinbutton + 1 + + + 0 + 3 + + + + + True + True + True + True + adjustment2 + + + 1 + 3 + + + + + + + + + True + False + Connection Settings + + + + + + + + False + True + 0 + + + + diff --git a/dbaccess/uiconfig/ui/limitbox.ui b/dbaccess/uiconfig/ui/limitbox.ui new file mode 100644 index 000000000..efc0117e0 --- /dev/null +++ b/dbaccess/uiconfig/ui/limitbox.ui @@ -0,0 +1,30 @@ + + + + + + True + False + True + 6 + + + True + False + True + True + True + + + True + + + + + False + True + 0 + + + + diff --git a/dbaccess/uiconfig/ui/migrwarndlg.ui b/dbaccess/uiconfig/ui/migrwarndlg.ui new file mode 100644 index 000000000..97a89cb6f --- /dev/null +++ b/dbaccess/uiconfig/ui/migrwarndlg.ui @@ -0,0 +1,81 @@ + + + + + + False + Confirm Migration + False + True + dialog + The document contains embedded HSQL data, which is deprecated. + Would you like to migrate to Firebird now? + + + False + vertical + 12 + + + False + + + gtk-yes + True + True + True + True + + + True + True + 0 + + + + + _Later + True + True + True + True + True + True + + + True + True + 1 + + + + + False + False + end + 0 + + + + + Click for important information about migration. + True + True + True + none + https://wiki.documentfoundation.org/Documentation/HowTo/MigrateFromHSQLDB + + + False + True + 2 + + + + + + yes + no + + + diff --git a/dbaccess/uiconfig/ui/mysqlnativepage.ui b/dbaccess/uiconfig/ui/mysqlnativepage.ui new file mode 100644 index 000000000..3a098e31d --- /dev/null +++ b/dbaccess/uiconfig/ui/mysqlnativepage.ui @@ -0,0 +1,219 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + vertical + + + + + + + + + + True + False + Connection Settings + + + + + + + + True + True + 0 + + + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + 6 + 12 + + + True + False + _User name: + True + username + 1 + + + 0 + 0 + + + + + True + True + True + True + + + 1 + 0 + + + + + Password required + True + True + False + True + 0 + True + + + 1 + 1 + + + + + + + + + + + + True + False + User Authentication + + + + + + + + True + True + 1 + + + + + True + False + True + 0 + none + + + True + False + start + True + 6 + 12 + + + True + False + True + 12 + + + True + False + _Character set: + True + charset + 1 + + + False + True + 0 + + + + + True + False + True + + + False + True + 1 + + + + + + + + + True + False + Data Conversion + + + + + + + + True + True + 2 + + + + diff --git a/dbaccess/uiconfig/ui/mysqlnativesettings.ui b/dbaccess/uiconfig/ui/mysqlnativesettings.ui new file mode 100644 index 000000000..6b4e20a36 --- /dev/null +++ b/dbaccess/uiconfig/ui/mysqlnativesettings.ui @@ -0,0 +1,263 @@ + + + + + + 65535 + 1 + 10 + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 12 + + + True + False + start + _Database name: + True + dbname + 0 + + + False + True + 0 + + + + + True + True + True + True + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + True + 6 + + + Se_rver/port + True + True + False + True + 0 + True + True + + + 0 + 0 + + + + + True + False + True + 12 + + + True + False + True + 6 + 12 + + + True + False + _Server: + True + server + 1 + + + 0 + 0 + + + + + True + False + _Port: + True + port + 1 + + + 0 + 1 + + + + + True + True + True + True + + + 1 + 0 + 2 + + + + + True + False + start + Default: 3306 + 0 + + + 2 + 1 + + + + + True + True + True + True + adjustment1 + True + + + 1 + 1 + + + + + + + 0 + 1 + + + + + False + True + 1 + + + + + True + False + True + 6 + 12 + + + So_cket: + True + True + False + True + 0 + True + hostport + + + 0 + 0 + + + + + True + True + True + True + + + 1 + 0 + + + + + False + True + 3 + + + + + True + False + True + 6 + 12 + + + Named p_ipe: + True + True + False + True + 0 + True + hostport + + + 0 + 0 + + + + + True + True + True + True + + + 1 + 0 + + + + + False + True + 4 + + + + diff --git a/dbaccess/uiconfig/ui/namematchingpage.ui b/dbaccess/uiconfig/ui/namematchingpage.ui new file mode 100644 index 000000000..543f192c6 --- /dev/null +++ b/dbaccess/uiconfig/ui/namematchingpage.ui @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + False + True + True + 6 + 12 + + + True + False + vertical + 6 + center + + + True + True + True + + + False + True + 0 + + + + + True + True + True + + + False + True + 1 + + + + + _All + True + True + True + True + + + False + True + 2 + + + + + Non_e + True + True + True + True + + + False + True + 3 + + + + + False + True + 0 + + + + + True + False + True + True + vertical + 6 + + + True + False + start + Source table: + True + left + 0 + + + False + True + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore1 + False + 1 + False + + + + + + True + 6 + + + + 3 + 0 + 4 + + + + + + + True + 6 + + + + 1 + + + + + + + + + True + True + 1 + + + + + True + True + 1 + + + + + True + False + True + True + vertical + 6 + + + True + False + start + Destination table: + True + right + 0 + + + False + True + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore2 + False + 0 + False + + + + + + True + 6 + + + + 0 + + + + + + + + + True + True + 1 + + + + + True + True + 2 + + + + + True + False + vertical + 6 + center + + + True + True + True + + + False + True + 0 + + + + + True + True + True + + + False + True + 1 + + + + + + + + + + + False + True + 3 + + + + diff --git a/dbaccess/uiconfig/ui/odbcpage.ui b/dbaccess/uiconfig/ui/odbcpage.ui new file mode 100644 index 000000000..5ea61c2fc --- /dev/null +++ b/dbaccess/uiconfig/ui/odbcpage.ui @@ -0,0 +1,179 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + 12 + + + True + False + _Character set: + True + charset + + + False + True + 0 + + + + + True + True + True + + + False + True + 1 + + + + + + + + + True + False + Data Conversion + + + + + + + + False + True + 0 + + + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + vertical + 6 + + + True + False + True + 12 + + + True + False + ODBC _options: + True + options + + + False + True + 0 + + + + + True + True + True + True + + + False + True + 1 + + + + + False + True + 0 + + + + + Use catalog for file-based databases + True + True + False + True + 0 + True + + + False + True + 1 + + + + + + + + + True + False + Optional Settings + + + + + + + + False + True + 1 + + + + diff --git a/dbaccess/uiconfig/ui/parametersdialog.ui b/dbaccess/uiconfig/ui/parametersdialog.ui new file mode 100644 index 000000000..55f68b612 --- /dev/null +++ b/dbaccess/uiconfig/ui/parametersdialog.ui @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + False + True + True + 6 + Parameter Input + True + 0 + 0 + dialog + north + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + vertical + 6 + + + True + False + True + True + in + + + True + True + True + True + liststore1 + False + False + 0 + False + + + + + + + + + 0 + + + + + + + + + False + True + 0 + + + + + True + False + start + _Value: + True + paramEntry + + + False + True + 1 + + + + + True + False + True + 12 + + + True + True + True + True + + + False + True + 0 + + + + + _Next + True + True + True + True + True + + + False + True + 1 + + + + + False + True + 2 + + + + + + + + + True + False + _Parameters + True + allParamTreeview + + + + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/password.ui b/dbaccess/uiconfig/ui/password.ui new file mode 100644 index 000000000..8e2706835 --- /dev/null +++ b/dbaccess/uiconfig/ui/password.ui @@ -0,0 +1,210 @@ + + + + + + False + 6 + Change Password + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + False + True + 6 + 12 + + + True + True + True + False + True + password + + + 1 + 0 + + + + + True + True + True + False + True + password + + + 1 + 1 + + + + + True + False + Old p_assword: + True + oldpassword + 1 + + + 0 + 0 + + + + + True + False + _Password: + True + newpassword + 1 + + + 0 + 1 + + + + + True + False + _Confirm password: + True + confirmpassword + 1 + + + 0 + 2 + + + + + True + True + True + False + True + password + + + 1 + 2 + + + + + + + + + True + False + User “$name$: $” + + + + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/querycolmenu.ui b/dbaccess/uiconfig/ui/querycolmenu.ui new file mode 100644 index 000000000..0167b8d01 --- /dev/null +++ b/dbaccess/uiconfig/ui/querycolmenu.ui @@ -0,0 +1,31 @@ + + + + + + True + False + + + True + False + Column _Width... + True + + + + + True + False + + + + + True + False + _Delete + True + + + + diff --git a/dbaccess/uiconfig/ui/queryfilterdialog.ui b/dbaccess/uiconfig/ui/queryfilterdialog.ui new file mode 100644 index 000000000..46164e2f5 --- /dev/null +++ b/dbaccess/uiconfig/ui/queryfilterdialog.ui @@ -0,0 +1,330 @@ + + + + + + False + 6 + Standard Filter + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + 0 + none + + + True + False + 6 + 12 + + + True + False + 6 + 12 + + + True + False + Operator + 0 + + + 0 + 0 + + + + + True + False + Field name + + + 1 + 0 + + + + + True + False + Condition + + + 2 + 0 + + + + + True + False + 0 + + - none - + + + + 1 + 1 + + + + + True + False + True + 0 + + = + <> + < + <= + > + >= + like + not like + null + not null + + + + 2 + 1 + + + + + True + False + 0 + + - none - + + + + 1 + 2 + + + + + True + False + 0 + + - none - + + + + 1 + 3 + + + + + True + False + True + 0 + + + 2 + 2 + + + + + True + False + True + 0 + + + 2 + 3 + + + + + True + False + Value + + + 3 + 0 + + + + + True + True + True + True + + + 3 + 1 + + + + + True + True + True + True + + + 3 + 2 + + + + + True + True + True + True + + + 3 + 3 + + + + + True + False + 0 + + AND + OR + + + + 0 + 2 + + + + + True + False + 0 + + AND + OR + + + + 0 + 3 + + + + + + + + + + + + True + False + Criteria + + + + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/queryfuncmenu.ui b/dbaccess/uiconfig/ui/queryfuncmenu.ui new file mode 100644 index 000000000..f220eafb5 --- /dev/null +++ b/dbaccess/uiconfig/ui/queryfuncmenu.ui @@ -0,0 +1,53 @@ + + + + + + True + False + + + True + False + Functions + True + + + + + True + False + + + + + True + False + Table Name + True + + + + + True + False + Alias + True + + + + + True + False + + + + + True + False + Distinct Values + True + + + + diff --git a/dbaccess/uiconfig/ui/querypropertiesdialog.ui b/dbaccess/uiconfig/ui/querypropertiesdialog.ui new file mode 100644 index 000000000..a89852d93 --- /dev/null +++ b/dbaccess/uiconfig/ui/querypropertiesdialog.ui @@ -0,0 +1,187 @@ + + + + + + False + 6 + Query Properties + False + True + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + 6 + 12 + + + True + False + Limit: + 1 + + + 0 + 1 + + + + + True + False + start + + + Yes + True + True + False + True + 0 + True + True + + + False + True + 0 + + + + + No + True + True + False + True + 0 + True + distinct + + + False + True + 1 + + + + + 1 + 0 + + + + + True + False + Distinct values: + 1 + + + 0 + 0 + + + + + True + False + True + True + + + True + True + + + + + 1 + 1 + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/relationdialog.ui b/dbaccess/uiconfig/ui/relationdialog.ui new file mode 100644 index 000000000..4a702a7b3 --- /dev/null +++ b/dbaccess/uiconfig/ui/relationdialog.ui @@ -0,0 +1,460 @@ + + + + + + False + 6 + Relations + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + top + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + 12 + True + + + True + False + True + + + 0 + 0 + + + + + True + False + True + + + 1 + 0 + + + + + + + + + True + False + Tables Involved + + + + + + + + 0 + 0 + + + + + True + False + 0 + none + + + True + False + 6 + 12 + + + True + False + True + True + + + + + + + True + False + Fields Involved + + + + + + + + 0 + 1 + + + + + True + False + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + 6 + + + _No action + True + True + False + True + 0 + True + True + + + 0 + 0 + + + + + _Update cascade + True + True + False + True + 0 + True + addaction + + + 0 + 1 + + + + + _Set NULL + True + True + False + True + 0 + True + addaction + + + 0 + 2 + + + + + Set _default + True + True + False + True + 0 + True + addaction + + + 0 + 3 + + + + + + + + + True + False + Update Options + + + + + + + + 0 + 0 + + + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + 6 + + + _No action + True + True + False + True + 0 + True + True + + + 0 + 0 + + + + + Delete _cascade + True + True + False + True + 0 + True + delaction + + + 0 + 1 + + + + + _Set NULL + True + True + False + True + 0 + True + delaction + + + 0 + 2 + + + + + Set _default + True + True + False + True + 0 + True + delaction + + + 0 + 3 + + + + + + + + + True + False + Delete Options + + + + + + + + 1 + 0 + + + + + 0 + 2 + + + + + False + True + 1 + + + + + + ok + cancel + help + + + + + + + + + + + + + + + + + + + + + + +

Inner join + 1 + + + Left join + 2 + + + Right join + 3 + + + Full (outer) join + 4 + + + Cross join + 5 + + + + diff --git a/dbaccess/uiconfig/ui/rowheightdialog.ui b/dbaccess/uiconfig/ui/rowheightdialog.ui new file mode 100644 index 000000000..a22542014 --- /dev/null +++ b/dbaccess/uiconfig/ui/rowheightdialog.ui @@ -0,0 +1,156 @@ + + + + + + 0.10000000000000001 + 160 + 2.27 + 1 + 10 + + + False + 6 + Row Height + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + start + True + True + 6 + 12 + + + True + False + _Height: + True + value + 1 + + + 0 + 0 + + + + + True + True + True + True + adjustment1 + 2 + + + 1 + 0 + + + + + _Automatic + True + True + False + True + 0 + True + + + 1 + 1 + + + + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/savedialog.ui b/dbaccess/uiconfig/ui/savedialog.ui new file mode 100644 index 000000000..5184395e5 --- /dev/null +++ b/dbaccess/uiconfig/ui/savedialog.ui @@ -0,0 +1,204 @@ + + + + + + False + 6 + Save As + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + 6 + 12 + + + True + False + Please enter a name for the object to be created: + True + 52 + 0 + + + 0 + 0 + 2 + + + + + True + False + _Catalog: + True + catalog + 1 + + + 0 + 1 + + + + + True + False + _Schema: + True + schema + 1 + + + 0 + 2 + + + + + True + False + True + title + 1 + + + 0 + 3 + + + + + True + True + True + True + + + 1 + 3 + + + + + True + False + True + True + + + True + True + + + + + 1 + 1 + + + + + True + False + True + True + + + True + True + + + + + 1 + 2 + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/saveindexdialog.ui b/dbaccess/uiconfig/ui/saveindexdialog.ui new file mode 100644 index 000000000..164c9ec6f --- /dev/null +++ b/dbaccess/uiconfig/ui/saveindexdialog.ui @@ -0,0 +1,82 @@ + + + + + + False + Exit Index Design + False + True + dialog + True + question + Do you want to save the changes made to the current index? + + + False + vertical + 12 + + + False + + + gtk-no + True + True + True + True + + + False + True + 0 + + + + + gtk-yes + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-cancel + True + True + True + True + + + False + True + 2 + + + + + False + True + end + 0 + + + + + + no + yes + cancel + + + diff --git a/dbaccess/uiconfig/ui/savemodifieddialog.ui b/dbaccess/uiconfig/ui/savemodifieddialog.ui new file mode 100644 index 000000000..0eb96ec60 --- /dev/null +++ b/dbaccess/uiconfig/ui/savemodifieddialog.ui @@ -0,0 +1,82 @@ + + + + + + False + False + True + dialog + True + question + Do you want to save the changes? + The current record has been changed. + + + False + vertical + 12 + + + False + + + gtk-no + True + True + True + True + + + False + True + 0 + + + + + gtk-yes + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-cancel + True + True + True + True + + + False + True + 2 + + + + + False + True + end + 0 + + + + + + no + yes + cancel + + + diff --git a/dbaccess/uiconfig/ui/sortdialog.ui b/dbaccess/uiconfig/ui/sortdialog.ui new file mode 100644 index 000000000..9349ef724 --- /dev/null +++ b/dbaccess/uiconfig/ui/sortdialog.ui @@ -0,0 +1,270 @@ + + + + + + False + 6 + Sort Order + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + 0 + none + + + True + False + 6 + 12 + + + True + False + 6 + 12 + + + True + False + Operator + end + + + 0 + 0 + + + + + True + False + and then + end + 1 + + + 0 + 2 + + + + + True + False + and then + end + 1 + + + 0 + 3 + + + + + True + False + Field name + end + + + 1 + 0 + + + + + True + False + Order + end + + + 2 + 0 + + + + + True + False + True + + + 1 + 1 + + + + + True + False + True + + ascending + descending + + + + 2 + 1 + + + + + True + False + True + + + 1 + 2 + + + + + True + False + True + + + 1 + 3 + + + + + True + False + True + + ascending + descending + + + + 2 + 2 + + + + + True + False + True + + ascending + descending + + + + 2 + 3 + + + + + + + + + + + + True + False + Sort Order + + + + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/specialjdbcconnectionpage.ui b/dbaccess/uiconfig/ui/specialjdbcconnectionpage.ui new file mode 100644 index 000000000..c63f6a2c0 --- /dev/null +++ b/dbaccess/uiconfig/ui/specialjdbcconnectionpage.ui @@ -0,0 +1,228 @@ + + + + + + 1000000000000 + 1 + 10 + + + True + False + True + True + 6 + vertical + 12 + + + True + False + start + 6 + Set up connection to a MySQL database using JDBC + + + + + + False + True + 0 + + + + + True + False + Please enter the required information to connect to a MySQL database using JDBC. Note that a JDBC driver class must be installed on your system and registered with %PRODUCTNAME. Please contact your system administrator if you are unsure about the following settings. + True + 72 + 72 + 0 + + + False + True + 1 + + + + + True + False + True + True + 6 + 12 + + + True + False + _Database name: + True + dbNameEntry + 1 + + + 0 + 0 + + + + + True + False + _Server: + True + hostNameEntry + 1 + + + 0 + 1 + + + + + True + False + _Port number: + True + portNumEntry + 1 + + + 0 + 2 + + + + + True + True + True + True + + + 1 + 0 + + + + + True + True + True + True + + + 1 + 1 + + + + + True + False + True + 12 + + + True + True + True + True + adjustment1 + + + False + True + 0 + + + + + True + False + Default: 3306 + + + False + True + 1 + + + + + 1 + 2 + + + + + False + True + 2 + + + + + True + False + True + True + 6 + 12 + + + True + False + start + MySQL JDBC d_river class: + True + jdbcDriverEntry + + + 0 + 0 + + + + + True + True + True + True + + + 0 + 1 + + + + + _Test Class + True + True + True + True + + + 1 + 1 + + + + + + + + False + True + 3 + + + + diff --git a/dbaccess/uiconfig/ui/specialsettingspage.ui b/dbaccess/uiconfig/ui/specialsettingspage.ui new file mode 100644 index 000000000..52f5762fe --- /dev/null +++ b/dbaccess/uiconfig/ui/specialsettingspage.ui @@ -0,0 +1,337 @@ + + + + + + 1000000 + 1 + 10 + + + True + False + True + True + 6 + + + True + False + 6 + + + Use SQL92 naming constraints + True + False + True + True + 0 + True + + + 0 + 0 + + + + + Append the table alias name on SELECT statements + True + False + True + True + 0 + True + + + 0 + 1 + + + + + Use keyword AS before table alias names + True + False + True + True + 0 + True + + + 0 + 2 + + + + + Use Outer Join syntax '{oj }' + True + False + True + True + 0 + True + + + 0 + 3 + + + + + Ignore the privileges from the database driver + True + False + True + True + 0 + True + + + 0 + 4 + + + + + Replace named parameters with '?' + True + False + True + True + 0 + True + + + 0 + 5 + + + + + Display version columns (when available) + True + False + True + True + 0 + True + + + 0 + 6 + + + + + Use catalog name in SELECT statements + True + False + True + True + 0 + True + + + 0 + 7 + + + + + Use schema name in SELECT statements + True + False + True + True + 0 + True + + + 0 + 8 + + + + + Create index with ASC or DESC statement + True + False + True + True + 0 + True + + + 0 + 9 + + + + + End text lines with CR+LF + True + False + True + True + 0 + True + + + 0 + 10 + + + + + Ignore currency field information + True + False + True + True + 0 + True + + + 0 + 11 + + + + + Form data input checks for required fields + True + False + True + True + 0 + True + + + 0 + 12 + + + + + Use ODBC conformant date/time literals + True + False + True + True + 0 + True + + + 0 + 13 + + + + + Supports primary keys + True + False + True + True + 0 + True + + + 0 + 14 + + + + + Respect the result set type from the database driver + True + False + True + True + 0 + True + + + 0 + 15 + + + + + True + False + 6 + 12 + + + False + True + Comparison of Boolean values: + True + comparison + 1 + + + 0 + 0 + + + + + False + True + + Default + SQL + Mixed + MS Access + + + + 1 + 0 + + + + + False + True + Rows to scan column types: + True + rows + 1 + + + 0 + 1 + + + + + True + True + True + adjustment1 + + + 1 + 1 + + + + + 0 + 16 + + + + + False + True + 0 + + + + diff --git a/dbaccess/uiconfig/ui/sqlexception.ui b/dbaccess/uiconfig/ui/sqlexception.ui new file mode 100644 index 000000000..ef392f219 --- /dev/null +++ b/dbaccess/uiconfig/ui/sqlexception.ui @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + False + 6 + Error Details + True + 0 + 0 + dialog + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + False + True + end + 0 + + + + + True + False + True + True + 6 + 12 + + + True + False + Error _list: + True + list + 0 + + + 0 + 0 + + + + + True + False + _Description: + True + description + 0 + + + 1 + 0 + + + + + True + True + True + True + in + + + True + True + True + True + False + + + + + 1 + 1 + + + + + True + True + True + True + in + + + True + True + True + True + liststore1 + False + False + 0 + False + + + + + + + + + 0 + + + + + + + + + + 1 + + + + + + + + + 0 + 1 + + + + + False + True + 1 + + + + + + ok + + + + + + diff --git a/dbaccess/uiconfig/ui/tabledesignrowmenu.ui b/dbaccess/uiconfig/ui/tabledesignrowmenu.ui new file mode 100644 index 000000000..e9cc6cbd8 --- /dev/null +++ b/dbaccess/uiconfig/ui/tabledesignrowmenu.ui @@ -0,0 +1,59 @@ + + + + + + True + False + + + True + False + Cu_t + True + + + + + True + False + _Copy + True + + + + + True + False + _Paste + + + + + True + False + _Delete + + + + + True + False + Insert Rows + + + + + True + False + + + + + True + False + Primary Key + + + + diff --git a/dbaccess/uiconfig/ui/tabledesignsavemodifieddialog.ui b/dbaccess/uiconfig/ui/tabledesignsavemodifieddialog.ui new file mode 100644 index 000000000..cc322aee8 --- /dev/null +++ b/dbaccess/uiconfig/ui/tabledesignsavemodifieddialog.ui @@ -0,0 +1,82 @@ + + + + + + False + False + True + dialog + True + question + Do you want to save the changes? + The table has been changed. + + + False + vertical + 12 + + + False + + + gtk-no + True + True + True + True + + + False + True + 0 + + + + + gtk-yes + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-cancel + True + True + True + True + + + False + True + 2 + + + + + False + True + end + 0 + + + + + + no + yes + cancel + + + diff --git a/dbaccess/uiconfig/ui/tablesfilterdialog.ui b/dbaccess/uiconfig/ui/tablesfilterdialog.ui new file mode 100644 index 000000000..f0f4a9dec --- /dev/null +++ b/dbaccess/uiconfig/ui/tablesfilterdialog.ui @@ -0,0 +1,90 @@ + + + + + + False + 6 + Tables Filter + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/tablesfilterpage.ui b/dbaccess/uiconfig/ui/tablesfilterpage.ui new file mode 100644 index 000000000..85f1b9084 --- /dev/null +++ b/dbaccess/uiconfig/ui/tablesfilterpage.ui @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + 6 + 18 + + + True + False + Mark the tables that should be visible for the applications. + True + 56 + 0 + + + 0 + 1 + + + + + True + True + True + True + in + + + -1 + True + True + True + True + True + liststore2 + False + 2 + True + True + + + + + + 6 + + + + 0 + + + + + + 4 + 1 + 5 + + + + + + + 6 + + + + 2 + 6 + + + + + + + + + 0 + 0 + + + + + + + + + True + False + Tables and Table Filter + + + + + + + diff --git a/dbaccess/uiconfig/ui/tablesjoindialog.ui b/dbaccess/uiconfig/ui/tablesjoindialog.ui new file mode 100644 index 000000000..c727d7348 --- /dev/null +++ b/dbaccess/uiconfig/ui/tablesjoindialog.ui @@ -0,0 +1,272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + 6 + False + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-add + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-close + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + 6 + + + Tables + True + True + False + True + 0 + True + True + + + 0 + 0 + + + + + Queries + True + True + False + True + 0 + True + tables + + + 0 + 1 + + + + + True + True + True + True + in + + + -1 + True + True + True + True + True + liststore2 + False + 1 + True + True + + + + + + 6 + + + + 0 + + + + + + 1 + 3 + + + + + + + + + 0 + 2 + + + + + False + True + Add Tables + + + 0 + 4 + + + + + False + True + Add Table or Query + + + 0 + 5 + + + + + True + True + True + True + in + + + -1 + True + True + True + True + True + liststore1 + False + 1 + False + True + + + + + + 6 + + + + 0 + + + + + + 1 + + + + + + + + + 0 + 3 + + + + + False + True + 1 + + + + + + add + close + help + + + diff --git a/dbaccess/uiconfig/ui/textconnectionsettings.ui b/dbaccess/uiconfig/ui/textconnectionsettings.ui new file mode 100644 index 000000000..10f01e82d --- /dev/null +++ b/dbaccess/uiconfig/ui/textconnectionsettings.ui @@ -0,0 +1,105 @@ + + + + + + False + 6 + Text Connection Settings + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-ok + True + True + True + True + True + True + + + False + True + 0 + + + + + gtk-cancel + True + True + True + True + + + False + True + 1 + + + + + gtk-help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + vertical + 6 + + + + + + True + True + 1 + + + + + + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/textpage.ui b/dbaccess/uiconfig/ui/textpage.ui new file mode 100644 index 000000000..3b4fd3b67 --- /dev/null +++ b/dbaccess/uiconfig/ui/textpage.ui @@ -0,0 +1,404 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + 6 + 12 + + + Plain text files (*.txt) + True + True + False + True + 0 + True + True + + + 0 + 0 + 3 + + + + + Comma-separated value files (*.csv) + True + True + False + True + 0 + True + textfile + + + 0 + 1 + 3 + + + + + Custom: + True + True + False + True + 0 + True + textfile + + + 0 + 2 + + + + + True + False + True + True + True + + + 1 + 2 + + + + + True + False + False + Custom: *.abc + + + 2 + 2 + + + + + + + + + True + False + Specify the Type of Files You Want to Access + + + + + + + + True + True + 0 + + + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + 6 + 12 + + + _Text contains headers + True + True + False + True + True + 0 + True + True + + + 0 + 4 + 2 + + + + + True + False + Field separator: + True + fieldseparator + 1 + + + 0 + 0 + + + + + True + False + Text separator: + True + textseparator + 1 + + + 0 + 1 + + + + + True + False + Decimal separator: + True + decimalseparator + 1 + + + 0 + 2 + + + + + True + False + Thousands separator: + True + thousandsseparator + 1 + + + 0 + 3 + + + + + True + False + True + True + + + True + True + + + + + 1 + 0 + + + + + True + False + True + True + + + True + True + + + + + 1 + 1 + + + + + True + False + True + True + + . + , + ; + : + + + + True + True + + + + + 1 + 2 + + + + + True + False + True + True + + . + , + + + + True + True + + + + + 1 + 3 + + + + + + + + + True + False + Row Format + + + + + + + + True + True + 1 + + + + + True + False + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + 12 + + + True + False + start + _Character set: + True + charset + 0 + + + False + True + 0 + + + + + True + False + True + + + False + True + 1 + + + + + + + + + True + False + Data Conversion + + + + + + + + True + True + 2 + + + + diff --git a/dbaccess/uiconfig/ui/typeselectpage.ui b/dbaccess/uiconfig/ui/typeselectpage.ui new file mode 100644 index 000000000..383e8d546 --- /dev/null +++ b/dbaccess/uiconfig/ui/typeselectpage.ui @@ -0,0 +1,220 @@ + + + + + + 100 + 1 + 10 + + + + + + + + + + + + + True + False + True + True + 6 + 12 + + + 150 + True + True + True + in + + + 150 + True + True + True + True + liststore1 + False + 1 + False + + + + + + True + 6 + + + + 0 + + + + + + 1 + + + + + + + + + False + True + 0 + + + + + True + False + True + True + vertical + 6 + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + 12 + + + True + False + True + True + vertical + + + + + + + + + + True + False + Column Information + + + + + + + + True + True + 0 + + + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + 6 + 12 + + + True + False + start + Lines (ma_x.): + True + auto + 0 + + + 0 + 0 + + + + + _Auto + True + True + True + True + + + 2 + 0 + + + + + True + True + True + True + adjustment1 + + + 1 + 0 + + + + + + + + + True + False + Automatic Type Recognition + + + + + + + + False + True + 1 + + + + + True + True + 1 + + + + diff --git a/dbaccess/uiconfig/ui/useradmindialog.ui b/dbaccess/uiconfig/ui/useradmindialog.ui new file mode 100644 index 000000000..4b470a9b5 --- /dev/null +++ b/dbaccess/uiconfig/ui/useradmindialog.ui @@ -0,0 +1,160 @@ + + + + + + False + 6 + User Administration + False + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + gtk-revert-to-saved + True + True + True + + + False + True + 0 + + + + + gtk-ok + True + True + True + True + True + True + + + False + True + 1 + + + + + gtk-cancel + True + True + True + True + + + False + True + 2 + + + + + gtk-help + True + True + True + True + + + False + True + 3 + True + + + + + False + True + end + 0 + + + + + True + True + True + True + True + True + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + False + User Settings + 0.4699999988079071 + + + False + + + + + False + True + 1 + + + + + + reset + ok + cancel + help + + + diff --git a/dbaccess/uiconfig/ui/useradminpage.ui b/dbaccess/uiconfig/ui/useradminpage.ui new file mode 100644 index 000000000..71addc1e6 --- /dev/null +++ b/dbaccess/uiconfig/ui/useradminpage.ui @@ -0,0 +1,198 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + vertical + 6 + + + True + False + True + 12 + + + True + False + start + True + Us_er: + True + 0 + + + False + True + 0 + + + + + True + False + True + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + True + 12 + + + _Add User... + True + True + True + True + + + False + True + 0 + + + + + Change _Password... + True + True + True + True + + + False + True + 1 + + + + + _Delete User... + True + True + True + True + + + False + True + 2 + + + + + False + True + 1 + + + + + + + + + True + False + User Selection + + + + + + + + False + True + 0 + + + + + True + False + True + True + 0 + none + + + 150 + True + False + True + True + 6 + 12 + + + True + False + vertical + + + + + + + + + + True + False + Access Rights for Selected User + + + + + + + + True + True + 1 + + + + diff --git a/dbaccess/uiconfig/ui/userdetailspage.ui b/dbaccess/uiconfig/ui/userdetailspage.ui new file mode 100644 index 000000000..a40dae743 --- /dev/null +++ b/dbaccess/uiconfig/ui/userdetailspage.ui @@ -0,0 +1,235 @@ + + + + + + 65535 + 1 + 10 + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + 6 + 12 + + + True + False + start + _Host name: + True + hostname + end + 1 + + + 0 + 0 + + + + + True + False + start + _Port number: + True + portnumber + 1 + + + 0 + 1 + + + + + True + True + True + True + + + 1 + 0 + + + + + True + True + True + True + adjustment1 + + + 1 + 1 + + + + + _Use catalog + True + True + False + True + 0 + True + + + 0 + 3 + 2 + + + + + True + False + start + _Driver settings: + True + options + 1 + + + 0 + 2 + + + + + True + True + True + True + + + 1 + 2 + + + + + + + + + True + False + Connection Settings + + + + + + + + False + True + 0 + + + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + + + True + False + True + 12 + + + True + False + _Character set: + True + charset + 1 + + + False + True + 0 + + + + + True + True + True + + + False + True + 1 + + + + + + + + + True + False + Data conversion + + + + + + + + False + True + 1 + + + + + + + + + + + + diff --git a/dbaccess/util/dba.component b/dbaccess/util/dba.component new file mode 100644 index 000000000..90ba9e3ba --- /dev/null +++ b/dbaccess/util/dba.component @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/util/dbu.component b/dbaccess/util/dbu.component new file mode 100644 index 000000000..bd7646a49 --- /dev/null +++ b/dbaccess/util/dbu.component @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dbaccess/util/sdbt.component b/dbaccess/util/sdbt.component new file mode 100644 index 000000000..2cf8b9395 --- /dev/null +++ b/dbaccess/util/sdbt.component @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/dbaccess/win32/source/odbcconfig/odbcconfig.cxx b/dbaccess/win32/source/odbcconfig/odbcconfig.cxx new file mode 100644 index 000000000..0cc48725c --- /dev/null +++ b/dbaccess/win32/source/odbcconfig/odbcconfig.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 . + */ + + +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +// displays the error text for the last error (GetLastError), and returns this error value +static int displayLastError() +{ + DWORD dwError = GetLastError(); + + LPVOID lpMsgBuf = nullptr; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + dwError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + reinterpret_cast(&lpMsgBuf), + 0, + nullptr + ); + + // Display the string. + MessageBoxW( nullptr, static_cast(lpMsgBuf), nullptr, MB_OK | MB_ICONERROR ); + + // Free the buffer. + HeapFree( GetProcessHeap(), 0, lpMsgBuf ); + + return dwError; +} + +/** registers the window class for our application's main window +*/ +static bool registerWindowClass( HINSTANCE _hAppInstance ) +{ + WNDCLASSEXW wcx; + + wcx.cbSize = sizeof(wcx); // size of structure + wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes + wcx.lpfnWndProc = DefWindowProcW; // points to window procedure + wcx.cbClsExtra = 0; // no extra class memory + wcx.cbWndExtra = 0; // no extra window memory + wcx.hInstance = _hAppInstance; // handle to instance + wcx.hIcon = nullptr; // predefined app. icon + wcx.hCursor = nullptr; // predefined arrow + wcx.hbrBackground = nullptr; // no background brush + wcx.lpszMenuName = nullptr; // name of menu resource + wcx.lpszClassName = L"ODBCConfigMainClass"; // name of window class + wcx.hIconSm = nullptr; // small class icon + + return ( !!RegisterClassExW( &wcx ) ); +} + +/// initializes the application instances +static HWND initInstance( HINSTANCE _hAppInstance ) +{ + HWND hWindow = CreateWindowW( + L"ODBCConfigMainClass", // name of window class + L"ODBC Config Wrapper", // title-bar string + WS_OVERLAPPEDWINDOW, // top-level window + CW_USEDEFAULT, // default horizontal position + CW_USEDEFAULT, // default vertical position + CW_USEDEFAULT, // default width + CW_USEDEFAULT, // default height + nullptr, // no owner window + nullptr, // use class menu + _hAppInstance, // handle to application instance + nullptr); // no window-creation data + + // don't show the window, we only need it as parent handle for the + // SQLManageDataSources function + return hWindow; +} + +// main window function +extern "C" int APIENTRY wWinMain( HINSTANCE _hAppInstance, HINSTANCE, LPWSTR, int ) +{ + if ( !registerWindowClass( _hAppInstance ) ) + return FALSE; + + HWND hAppWindow = initInstance( _hAppInstance ); + if ( !IsWindow( hAppWindow ) ) + return displayLastError(); + + if (!SQLManageDataSources(hAppWindow)) + return displayLastError(); + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3