From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- extensions/AllLangMoTarget_pcr.mk | 13 + extensions/Configuration_updchk.mk | 31 + extensions/CppunitTest_extensions_bibliography.mk | 43 + extensions/CppunitTest_extensions_test_update.mk | 66 + extensions/CustomTarget_automationtest.mk | 29 + extensions/CustomTarget_so_activex_idl.mk | 37 + extensions/CustomTarget_so_activex_x64.mk | 25 + extensions/Executable_twain32shim.mk | 46 + extensions/IwyuFilter_extensions.yaml | 88 + extensions/JunitTest_extensions_unoapi.mk | 14 + extensions/Library_OOoSpotlightImporter.mk | 30 + extensions/Library_WinUserInfoBe.mk | 42 + extensions/Library_abp.mk | 58 + extensions/Library_bib.mk | 58 + extensions/Library_dbp.mk | 55 + extensions/Library_ldapbe2.mk | 63 + extensions/Library_log.mk | 40 + extensions/Library_oleautobridge.mk | 65 + extensions/Library_pcr.mk | 102 + extensions/Library_scn.mk | 67 + extensions/Library_so_activex.mk | 53 + extensions/Library_so_activex_x64.mk | 56 + extensions/Library_updatecheckui.mk | 38 + extensions/Library_updatefeed.mk | 31 + extensions/Library_updchk.mk | 57 + extensions/Makefile | 14 + extensions/Module_extensions.mk | 117 + extensions/Package_OOoSpotlightImporter.mk | 14 + extensions/Package_mdibundle.mk | 20 + extensions/README.md | 51 + extensions/UIConfig_sabpilot.mk | 30 + extensions/UIConfig_sbibliography.mk | 27 + extensions/UIConfig_scanner.mk | 17 + extensions/UIConfig_spropctrlr.mk | 37 + extensions/WinResTarget_activex.mk | 31 + extensions/inc/bitmaps.hlst | 50 + extensions/inc/command.hrc | 40 + extensions/inc/helpids.h | 327 ++ extensions/inc/propctrlr.h | 86 + extensions/inc/showhide.hrc | 39 + extensions/inc/stringarrays.hrc | 258 ++ extensions/inc/strings.hrc | 412 +++ extensions/inc/yesno.hrc | 39 + extensions/qa/bibliography/bibliography.cxx | 50 + .../integration/extensions/ComponentFactory.java | 93 + .../qa/integration/extensions/ConsoleWait.java | 120 + extensions/qa/integration/extensions/Frame.java | 215 ++ .../integration/extensions/HelpTextProvider.java | 58 + .../qa/integration/extensions/MethodHandler.java | 217 ++ .../qa/integration/extensions/ObjectInspector.java | 159 + .../qa/integration/extensions/ServicesHandler.java | 212 ++ .../integration/extensions/extensions_complex.sce | 1 + extensions/qa/integration/extensions/makefile.mk | 74 + extensions/qa/ole/automationtest.vbs | 132 + extensions/qa/unoapi/extensions.sce | 5 + extensions/qa/update/simple.xml | 18 + extensions/qa/update/test_update.cxx | 152 + extensions/source/abpilot/abp.component | 26 + extensions/source/abpilot/abpfinalpage.cxx | 227 ++ extensions/source/abpilot/abpfinalpage.hxx | 74 + extensions/source/abpilot/abptypes.hxx | 40 + extensions/source/abpilot/abspage.cxx | 74 + extensions/source/abpilot/abspage.hxx | 56 + extensions/source/abpilot/abspilot.cxx | 449 +++ extensions/source/abpilot/abspilot.hxx | 119 + extensions/source/abpilot/addresssettings.hxx | 56 + extensions/source/abpilot/admininvokationimpl.cxx | 116 + extensions/source/abpilot/admininvokationimpl.hxx | 50 + extensions/source/abpilot/admininvokationpage.cxx | 90 + extensions/source/abpilot/admininvokationpage.hxx | 52 + extensions/source/abpilot/datasourcehandling.cxx | 620 ++++ extensions/source/abpilot/datasourcehandling.hxx | 181 ++ extensions/source/abpilot/fieldmappingimpl.cxx | 317 ++ extensions/source/abpilot/fieldmappingimpl.hxx | 111 + extensions/source/abpilot/fieldmappingpage.cxx | 77 + extensions/source/abpilot/fieldmappingpage.hxx | 46 + extensions/source/abpilot/moduleabp.cxx | 22 + extensions/source/abpilot/tableselectionpage.cxx | 101 + extensions/source/abpilot/tableselectionpage.hxx | 50 + extensions/source/abpilot/typeselectionpage.cxx | 224 ++ extensions/source/abpilot/typeselectionpage.hxx | 81 + extensions/source/abpilot/unodialogabp.cxx | 156 + extensions/source/abpilot/unodialogabp.hxx | 78 + extensions/source/activex/README.txt | 33 + extensions/source/activex/SOActionsApproval.cxx | 58 + extensions/source/activex/SOActionsApproval.h | 105 + extensions/source/activex/SOActionsApproval.rgs | 24 + extensions/source/activex/SOActiveX.cxx | 1162 +++++++ extensions/source/activex/SOActiveX.h | 212 ++ extensions/source/activex/SOActiveX.rgs | 33 + extensions/source/activex/SOComWindowPeer.cxx | 57 + extensions/source/activex/SOComWindowPeer.h | 159 + extensions/source/activex/SOComWindowPeer.rgs | 23 + .../source/activex/SODispatchInterceptor.cxx | 248 ++ extensions/source/activex/SODispatchInterceptor.h | 175 + .../source/activex/SODispatchInterceptor.rgs | 23 + extensions/source/activex/StdAfx2.cxx | 30 + extensions/source/activex/StdAfx2.h | 68 + extensions/source/activex/com_uno_helper.h | 44 + extensions/source/activex/example.html | 43 + extensions/source/activex/resource.h | 46 + extensions/source/activex/so_activex.cxx | 774 +++++ extensions/source/activex/so_activex.def | 13 + extensions/source/activex/so_activex.idl | 230 ++ extensions/source/activex/so_activex.rc | 124 + extensions/source/bibliography/bib.component | 27 + extensions/source/bibliography/bibbeam.cxx | 267 ++ extensions/source/bibliography/bibbeam.hxx | 71 + extensions/source/bibliography/bibconfig.cxx | 297 ++ extensions/source/bibliography/bibconfig.hxx | 153 + extensions/source/bibliography/bibcont.cxx | 241 ++ extensions/source/bibliography/bibcont.hxx | 93 + extensions/source/bibliography/bibload.cxx | 609 ++++ extensions/source/bibliography/bibmod.cxx | 89 + extensions/source/bibliography/bibmod.hxx | 50 + extensions/source/bibliography/bibresid.hxx | 27 + .../source/bibliography/bibshortcuthandler.hxx | 66 + extensions/source/bibliography/bibtools.hxx | 42 + extensions/source/bibliography/bibview.cxx | 189 ++ extensions/source/bibliography/bibview.hxx | 83 + extensions/source/bibliography/datman.cxx | 1390 ++++++++ extensions/source/bibliography/datman.hxx | 169 + .../source/bibliography/formcontrolcontainer.cxx | 136 + .../source/bibliography/formcontrolcontainer.hxx | 65 + extensions/source/bibliography/framectr.cxx | 869 +++++ extensions/source/bibliography/framectr.hxx | 117 + extensions/source/bibliography/general.cxx | 876 +++++ extensions/source/bibliography/general.hxx | 158 + .../source/bibliography/loadlisteneradapter.cxx | 185 ++ .../source/bibliography/loadlisteneradapter.hxx | 151 + extensions/source/bibliography/toolbar.cxx | 620 ++++ extensions/source/bibliography/toolbar.hxx | 217 ++ .../config/WinUserInfo/WinUserInfoBe.component | 16 + .../source/config/WinUserInfo/WinUserInfoBe.cxx | 433 +++ .../source/config/WinUserInfo/WinUserInfoBe.hxx | 101 + extensions/source/config/ldap/ldapaccess.cxx | 289 ++ extensions/source/config/ldap/ldapaccess.hxx | 133 + extensions/source/config/ldap/ldapbe2.component | 26 + .../source/config/ldap/ldapuserprofilebe.cxx | 214 ++ .../source/config/ldap/ldapuserprofilebe.hxx | 113 + extensions/source/dbpilots/commonpagesdbp.cxx | 449 +++ extensions/source/dbpilots/commonpagesdbp.hxx | 120 + extensions/source/dbpilots/controlwizard.cxx | 663 ++++ extensions/source/dbpilots/controlwizard.hxx | 149 + extensions/source/dbpilots/dbp.component | 34 + extensions/source/dbpilots/dbptools.cxx | 62 + extensions/source/dbpilots/dbptools.hxx | 37 + extensions/source/dbpilots/dbptypes.hxx | 36 + extensions/source/dbpilots/gridwizard.cxx | 446 +++ extensions/source/dbpilots/gridwizard.hxx | 103 + extensions/source/dbpilots/groupboxwiz.cxx | 468 +++ extensions/source/dbpilots/groupboxwiz.hxx | 180 + extensions/source/dbpilots/listcombowizard.cxx | 485 +++ extensions/source/dbpilots/listcombowizard.hxx | 178 + extensions/source/dbpilots/moduledbp.cxx | 22 + extensions/source/dbpilots/optiongrouplayouter.cxx | 204 ++ extensions/source/dbpilots/optiongrouplayouter.hxx | 58 + extensions/source/dbpilots/unoautopilot.hxx | 116 + extensions/source/dbpilots/wizardcontext.hxx | 82 + extensions/source/dbpilots/wizardservices.cxx | 65 + extensions/source/inc/componentmodule.cxx | 35 + extensions/source/inc/componentmodule.hxx | 34 + extensions/source/logging/consolehandler.cxx | 264 ++ extensions/source/logging/csvformatter.cxx | 320 ++ extensions/source/logging/filehandler.cxx | 359 ++ extensions/source/logging/log.component | 47 + extensions/source/logging/logger.cxx | 265 ++ extensions/source/logging/loggerconfig.cxx | 283 ++ extensions/source/logging/loggerconfig.hxx | 50 + extensions/source/logging/loghandler.cxx | 183 ++ extensions/source/logging/loghandler.hxx | 142 + extensions/source/logging/logrecord.cxx | 86 + extensions/source/logging/logrecord.hxx | 53 + extensions/source/logging/methodguard.hxx | 55 + extensions/source/logging/plaintextformatter.cxx | 154 + extensions/source/logging/simpletextformatter.cxx | 98 + .../source/macosx/spotlight/GetMetadataForFile.h | 26 + .../source/macosx/spotlight/GetMetadataForFile.m | 64 + .../source/macosx/spotlight/OOoContentDataParser.h | 51 + .../source/macosx/spotlight/OOoContentDataParser.m | 144 + .../source/macosx/spotlight/OOoMetaDataParser.h | 46 + .../source/macosx/spotlight/OOoMetaDataParser.m | 205 ++ .../source/macosx/spotlight/OOoSpotlightImporter.h | 37 + .../source/macosx/spotlight/OOoSpotlightImporter.m | 487 +++ .../SpotlightImporterTester.xcodeproj/.gitignore | 1 + .../project.pbxproj | 308 ++ .../xcschemes/SpotlightImporterTester.xcscheme | 88 + .../SpotlightImporterTester/main.m | 30 + extensions/source/macosx/spotlight/main.m | 211 ++ .../source/macosx/spotlight/mdimporter/Info.plist | 87 + .../spotlight/mdimporter/en.lproj/schema.strings | 1 + .../source/macosx/spotlight/mdimporter/schema.xml | 413 +++ extensions/source/macosx/spotlight/version.plist | 33 + extensions/source/ole/comifaces.hxx | 62 + extensions/source/ole/jscriptclasses.cxx | 312 ++ extensions/source/ole/jscriptclasses.hxx | 147 + extensions/source/ole/ole2uno.cxx | 47 + extensions/source/ole/ole2uno.hxx | 70 + extensions/source/ole/oleautobridge.component | 37 + extensions/source/ole/oledll.cxx | 70 + extensions/source/ole/oleobjw.cxx | 2513 ++++++++++++++ extensions/source/ole/oleobjw.hxx | 244 ++ extensions/source/ole/olethread.cxx | 66 + extensions/source/ole/servprov.cxx | 548 ++++ extensions/source/ole/servprov.hxx | 184 ++ extensions/source/ole/servreg.cxx | 94 + extensions/source/ole/unoconversionutilities.hxx | 2363 ++++++++++++++ extensions/source/ole/unoobjw.cxx | 3437 ++++++++++++++++++++ extensions/source/ole/unoobjw.hxx | 268 ++ extensions/source/ole/unotypewrapper.cxx | 160 + extensions/source/ole/unotypewrapper.hxx | 81 + extensions/source/ole/wincrap.hxx | 64 + extensions/source/ole/windata.hxx | 196 ++ .../source/propctrlr/MasterDetailLinkDialog.cxx | 133 + .../source/propctrlr/MasterDetailLinkDialog.hxx | 67 + extensions/source/propctrlr/browserline.cxx | 405 +++ extensions/source/propctrlr/browserline.hxx | 127 + extensions/source/propctrlr/browserlistbox.cxx | 817 +++++ extensions/source/propctrlr/browserlistbox.hxx | 163 + extensions/source/propctrlr/browserpage.cxx | 41 + extensions/source/propctrlr/browserpage.hxx | 61 + extensions/source/propctrlr/browserview.cxx | 64 + extensions/source/propctrlr/browserview.hxx | 56 + .../source/propctrlr/buttonnavigationhandler.cxx | 268 ++ .../source/propctrlr/buttonnavigationhandler.hxx | 71 + extensions/source/propctrlr/cellbindinghandler.cxx | 487 +++ extensions/source/propctrlr/cellbindinghandler.hxx | 92 + extensions/source/propctrlr/cellbindinghelper.cxx | 540 +++ extensions/source/propctrlr/cellbindinghelper.hxx | 272 ++ extensions/source/propctrlr/commoncontrol.cxx | 134 + extensions/source/propctrlr/commoncontrol.hxx | 208 ++ extensions/source/propctrlr/composeduiupdate.cxx | 786 +++++ extensions/source/propctrlr/composeduiupdate.hxx | 208 ++ extensions/source/propctrlr/controlfontdialog.cxx | 148 + extensions/source/propctrlr/controlfontdialog.hxx | 82 + extensions/source/propctrlr/controltype.hxx | 35 + .../source/propctrlr/defaultforminspection.cxx | 215 ++ .../source/propctrlr/defaultforminspection.hxx | 66 + .../source/propctrlr/defaulthelpprovider.cxx | 184 ++ .../source/propctrlr/defaulthelpprovider.hxx | 78 + .../source/propctrlr/editpropertyhandler.cxx | 308 ++ .../source/propctrlr/editpropertyhandler.hxx | 68 + extensions/source/propctrlr/eformshelper.cxx | 762 +++++ extensions/source/propctrlr/eformshelper.hxx | 255 ++ .../source/propctrlr/eformspropertyhandler.cxx | 598 ++++ .../source/propctrlr/eformspropertyhandler.hxx | 95 + extensions/source/propctrlr/enumrepresentation.hxx | 62 + extensions/source/propctrlr/eventhandler.cxx | 1112 +++++++ extensions/source/propctrlr/eventhandler.hxx | 241 ++ extensions/source/propctrlr/fontdialog.cxx | 572 ++++ extensions/source/propctrlr/fontdialog.hxx | 68 + extensions/source/propctrlr/fontitemids.hxx | 48 + extensions/source/propctrlr/formbrowsertools.cxx | 132 + extensions/source/propctrlr/formbrowsertools.hxx | 89 + .../source/propctrlr/formcomponenthandler.cxx | 3305 +++++++++++++++++++ .../source/propctrlr/formcomponenthandler.hxx | 435 +++ extensions/source/propctrlr/formcontroller.cxx | 241 ++ extensions/source/propctrlr/formcontroller.hxx | 103 + .../source/propctrlr/formgeometryhandler.cxx | 820 +++++ extensions/source/propctrlr/formlinkdialog.cxx | 630 ++++ extensions/source/propctrlr/formlinkdialog.hxx | 127 + extensions/source/propctrlr/formmetadata.cxx | 694 ++++ extensions/source/propctrlr/formmetadata.hxx | 345 ++ extensions/source/propctrlr/formstrings.hxx | 302 ++ .../source/propctrlr/genericpropertyhandler.cxx | 619 ++++ .../source/propctrlr/genericpropertyhandler.hxx | 139 + extensions/source/propctrlr/handlerhelper.cxx | 314 ++ extensions/source/propctrlr/handlerhelper.hxx | 231 ++ .../source/propctrlr/inspectorhelpwindow.cxx | 42 + .../source/propctrlr/inspectorhelpwindow.hxx | 44 + extensions/source/propctrlr/inspectormodelbase.cxx | 246 ++ extensions/source/propctrlr/inspectormodelbase.hxx | 93 + extensions/source/propctrlr/linedescriptor.hxx | 51 + extensions/source/propctrlr/listselectiondlg.cxx | 138 + extensions/source/propctrlr/listselectiondlg.hxx | 60 + extensions/source/propctrlr/modulepcr.cxx | 30 + extensions/source/propctrlr/modulepcr.hxx | 30 + extensions/source/propctrlr/newdatatype.cxx | 79 + extensions/source/propctrlr/newdatatype.hxx | 53 + .../source/propctrlr/objectinspectormodel.cxx | 194 ++ extensions/source/propctrlr/pcr.component | 103 + extensions/source/propctrlr/pcrcommon.cxx | 60 + extensions/source/propctrlr/pcrcommon.hxx | 121 + extensions/source/propctrlr/pcrcommontypes.hxx | 33 + extensions/source/propctrlr/pcrstrings.hxx | 35 + extensions/source/propctrlr/pcrunodialogs.cxx | 143 + extensions/source/propctrlr/pcrunodialogs.hxx | 79 + extensions/source/propctrlr/propcontroller.cxx | 1652 ++++++++++ extensions/source/propctrlr/propcontroller.hxx | 368 +++ .../source/propctrlr/propcontrolobserver.hxx | 46 + extensions/source/propctrlr/propertycomposer.cxx | 484 +++ extensions/source/propctrlr/propertycomposer.hxx | 142 + .../source/propctrlr/propertycontrolextender.cxx | 125 + .../source/propctrlr/propertycontrolextender.hxx | 63 + extensions/source/propctrlr/propertyeditor.cxx | 380 +++ extensions/source/propctrlr/propertyeditor.hxx | 134 + extensions/source/propctrlr/propertyhandler.cxx | 421 +++ extensions/source/propctrlr/propertyhandler.hxx | 369 +++ extensions/source/propctrlr/propertyinfo.hxx | 50 + .../source/propctrlr/propeventtranslation.cxx | 89 + .../source/propctrlr/propeventtranslation.hxx | 70 + extensions/source/propctrlr/proplinelistener.hxx | 43 + .../source/propctrlr/pushbuttonnavigation.cxx | 298 ++ .../source/propctrlr/pushbuttonnavigation.hxx | 98 + extensions/source/propctrlr/selectlabeldialog.cxx | 279 ++ extensions/source/propctrlr/selectlabeldialog.hxx | 62 + extensions/source/propctrlr/sqlcommanddesign.cxx | 355 ++ extensions/source/propctrlr/sqlcommanddesign.hxx | 193 ++ extensions/source/propctrlr/standardcontrol.cxx | 865 +++++ extensions/source/propctrlr/standardcontrol.hxx | 412 +++ .../source/propctrlr/stringrepresentation.cxx | 604 ++++ extensions/source/propctrlr/submissionhandler.cxx | 431 +++ extensions/source/propctrlr/submissionhandler.hxx | 110 + extensions/source/propctrlr/taborder.cxx | 320 ++ extensions/source/propctrlr/taborder.hxx | 74 + extensions/source/propctrlr/unourl.cxx | 65 + extensions/source/propctrlr/unourl.hxx | 50 + extensions/source/propctrlr/usercontrol.cxx | 276 ++ extensions/source/propctrlr/usercontrol.hxx | 148 + extensions/source/propctrlr/xsddatatypes.cxx | 185 ++ extensions/source/propctrlr/xsddatatypes.hxx | 89 + .../source/propctrlr/xsdvalidationhelper.cxx | 406 +++ .../source/propctrlr/xsdvalidationhelper.hxx | 137 + .../propctrlr/xsdvalidationpropertyhandler.cxx | 673 ++++ .../propctrlr/xsdvalidationpropertyhandler.hxx | 88 + extensions/source/scanner/grid.cxx | 700 ++++ extensions/source/scanner/grid.hxx | 51 + extensions/source/scanner/sane.cxx | 996 ++++++ extensions/source/scanner/sane.hxx | 190 ++ extensions/source/scanner/sanedlg.cxx | 1467 +++++++++ extensions/source/scanner/sanedlg.hxx | 111 + extensions/source/scanner/scanner.cxx | 89 + extensions/source/scanner/scanner.hxx | 85 + extensions/source/scanner/scanunx.cxx | 341 ++ extensions/source/scanner/scanwin.cxx | 646 ++++ extensions/source/scanner/scn.component | 26 + extensions/source/scanner/twain32shim.cxx | 604 ++++ extensions/source/scanner/twain32shim.hxx | 68 + extensions/source/update/check/actionlistener.hxx | 39 + extensions/source/update/check/download.cxx | 427 +++ extensions/source/update/check/download.hxx | 80 + extensions/source/update/check/onlinecheck.cxx | 49 + extensions/source/update/check/onlinecheck.hxx | 28 + .../update/check/org/openoffice/Office/Addons.xcu | 42 + .../update/check/org/openoffice/Office/Jobs.xcu | 66 + extensions/source/update/check/updatecheck.cxx | 1617 +++++++++ extensions/source/update/check/updatecheck.hxx | 189 ++ .../source/update/check/updatecheckconfig.cxx | 660 ++++ .../source/update/check/updatecheckconfig.hxx | 205 ++ .../update/check/updatecheckconfiglistener.hxx | 37 + extensions/source/update/check/updatecheckjob.cxx | 322 ++ extensions/source/update/check/updatehdl.cxx | 1281 ++++++++ extensions/source/update/check/updatehdl.hxx | 207 ++ extensions/source/update/check/updateinfo.hxx | 61 + extensions/source/update/check/updateprotocol.cxx | 317 ++ extensions/source/update/check/updateprotocol.hxx | 68 + .../source/update/check/updateprotocoltest.cxx | 76 + .../source/update/check/updchk.uno.component | 30 + .../source/update/feed/test/updatefeedtest.cxx | 86 + extensions/source/update/feed/updatefeed.component | 26 + extensions/source/update/feed/updatefeed.cxx | 755 +++++ extensions/source/update/ui/updatecheckui.cxx | 306 ++ extensions/source/update/ui/updchk.component | 26 + .../test/ole/AxTestComponents/AxTestComponents.cpp | 77 + .../test/ole/AxTestComponents/AxTestComponents.def | 9 + .../test/ole/AxTestComponents/AxTestComponents.dsp | 325 ++ .../test/ole/AxTestComponents/AxTestComponents.idl | 251 ++ .../test/ole/AxTestComponents/AxTestComponents.rc | 155 + .../test/ole/AxTestComponents/AxTestComponents.sln | 31 + .../ole/AxTestComponents/AxTestComponents.vcproj | 819 +++++ extensions/test/ole/AxTestComponents/Basic.cpp | 1356 ++++++++ extensions/test/ole/AxTestComponents/Basic.h | 259 ++ extensions/test/ole/AxTestComponents/Basic.rgs | 50 + extensions/test/ole/AxTestComponents/Foo.cpp | 30 + extensions/test/ole/AxTestComponents/Foo.h | 54 + extensions/test/ole/AxTestComponents/StdAfx.cpp | 26 + extensions/test/ole/AxTestComponents/StdAfx.h | 46 + extensions/test/ole/AxTestComponents/readme.txt | 3 + extensions/test/ole/AxTestComponents/resource.h | 38 + .../test/ole/DCOM/Clients/WriterDemo/Module1.bas | 25 + .../DCOM/Clients/WriterDemo/client_writerdemo.vbp | 33 + .../DCOM/Clients/WriterDemo/client_writerdemo.vbw | 1 + .../test/ole/DCOM/Clients/WriterDemo/readme.txt | 4 + extensions/test/ole/DCOM/dcom_test/Module1.bas | 55 + extensions/test/ole/DCOM/dcom_test/dcom_test.vbp | 37 + extensions/test/ole/DCOM/dcom_test/dcom_test.vbw | 1 + extensions/test/ole/DCOM/dcom_test/readme.txt | 5 + .../test/ole/DCOM/scriptComponents/WriterDemo.wsc | 186 ++ .../test/ole/DCOM/scriptComponents/readme.txt | 12 + .../EventListener/EventListener.cpp | 76 + .../EventListener/EventListener.def | 9 + .../EventListener/EventListener.idl | 60 + .../EventListener/EventListener.rc | 154 + .../EventListener/EventListener.sln | 31 + .../EventListener/EventListener.vcproj | 927 ++++++ .../EventListener/EvtListener.cpp | 38 + .../EventListener/EvtListener.h | 52 + .../EventListener/EvtListener.rgs | 26 + .../EventListenerSample/EventListener/StdAfx.cpp | 32 + .../ole/EventListenerSample/EventListener/StdAfx.h | 44 + .../EventListenerSample/EventListener/resource.h | 37 + .../VBEventListener/Module1.bas | 9 + .../VBEventListener/VBEventListener.cls | 69 + .../VBEventListener/VBasicEventListener.vbp | 38 + .../VBEventListener/VBasicEventListener.vbw | 2 + .../EventListenerSample/VBEventListener/readme.txt | 7 + extensions/test/ole/EventListenerSample/events.htm | 115 + extensions/test/ole/EventListenerSample/readme.txt | 20 + extensions/test/ole/JScriptNewStyle.htm | 1071 ++++++ extensions/test/ole/MfcControl/MfcControl.cpp | 90 + extensions/test/ole/MfcControl/MfcControl.def | 9 + extensions/test/ole/MfcControl/MfcControl.dsp | 265 ++ extensions/test/ole/MfcControl/MfcControl.h | 52 + extensions/test/ole/MfcControl/MfcControl.odl | 82 + extensions/test/ole/MfcControl/MfcControl.rc | 163 + extensions/test/ole/MfcControl/MfcControl.sln | 25 + extensions/test/ole/MfcControl/MfcControl.vcproj | 581 ++++ extensions/test/ole/MfcControl/MfcControlCtl.cpp | 364 +++ extensions/test/ole/MfcControl/MfcControlCtl.h | 116 + extensions/test/ole/MfcControl/MfcControlCtl.png | Bin 0 -> 204 bytes extensions/test/ole/MfcControl/MfcControlPpg.cpp | 96 + extensions/test/ole/MfcControl/MfcControlPpg.h | 66 + extensions/test/ole/MfcControl/Resource.h | 40 + extensions/test/ole/MfcControl/StdAfx.cpp | 25 + extensions/test/ole/MfcControl/StdAfx.h | 50 + extensions/test/ole/OleClient/OleClient.ini | 5 + extensions/test/ole/OleClient/axhost.cxx | 39 + extensions/test/ole/OleClient/axhost.hxx | 51 + extensions/test/ole/OleClient/clientTest.cxx | 1291 ++++++++ extensions/test/ole/OleClient/funcs.cxx | 345 ++ extensions/test/ole/OleClient/readme.txt | 10 + extensions/test/ole/OleConverterVar1/convTest.cxx | 647 ++++ extensions/test/ole/OleConverterVar1/makefile.mk | 57 + extensions/test/ole/OleConverterVar1/readme.txt | 10 + extensions/test/ole/OleConverterVar1/smartarray.h | 222 ++ extensions/test/ole/OleTest.htm | 1080 ++++++ extensions/test/ole/ScriptTest.html | 1555 +++++++++ .../test/ole/StarBasic_OleClient/oleclient.bas | 622 ++++ extensions/test/ole/StarBasic_OleClient/readme.txt | 10 + extensions/test/ole/VisualBasic/AssemblyInfo.vb | 51 + extensions/test/ole/VisualBasic/Module1.vb | 871 +++++ extensions/test/ole/VisualBasic/Project1.sln | 19 + extensions/test/ole/VisualBasic/Project1.vbproj | 90 + extensions/test/ole/VisualBasic/readme.txt | 18 + extensions/test/ole/callUnoToJava.htm | 552 ++++ extensions/test/ole/cpnt/cpnt.cxx | 1955 +++++++++++ extensions/test/ole/cpnt/exports.dxp | 2 + extensions/test/ole/cpnt/makefile.mk | 66 + extensions/test/ole/cpnt/readme.txt | 21 + extensions/test/ole/cppToUno/makefile.mk | 56 + extensions/test/ole/cppToUno/readme.txt | 8 + extensions/test/ole/cppToUno/testcppuno.cxx | 206 ++ extensions/test/ole/cpptest/cpptest.cxx | 101 + extensions/test/ole/cpptest/makefile.mk | 55 + extensions/test/ole/cpptest/readme.txt | 4 + extensions/test/ole/idl/oletest.idl | 301 ++ extensions/test/ole/unloading/makefile.mk | 61 + extensions/test/ole/unloading/readme.txt | 6 + extensions/test/ole/unloading/unloadTest.cxx | 199 ++ extensions/test/ole/unoTocomCalls/Test/StdAfx.cpp | 28 + extensions/test/ole/unoTocomCalls/Test/StdAfx.h | 47 + extensions/test/ole/unoTocomCalls/Test/Test.cpp | 240 ++ extensions/test/ole/unoTocomCalls/Test/Test.dsp | 114 + extensions/test/ole/unoTocomCalls/Test/Test.sln | 19 + extensions/test/ole/unoTocomCalls/Test/Test.vcproj | 247 ++ .../ole/unoTocomCalls/XCallback_Impl/Basic.rgs | 27 + .../ole/unoTocomCalls/XCallback_Impl/BasicTest.rgs | 27 + .../ole/unoTocomCalls/XCallback_Impl/Callback.cpp | 505 +++ .../ole/unoTocomCalls/XCallback_Impl/Callback.h | 126 + .../ole/unoTocomCalls/XCallback_Impl/Callback.rgs | 27 + .../ole/unoTocomCalls/XCallback_Impl/Simple.cpp | 73 + .../test/ole/unoTocomCalls/XCallback_Impl/Simple.h | 55 + .../ole/unoTocomCalls/XCallback_Impl/Simple.rgs | 27 + .../ole/unoTocomCalls/XCallback_Impl/StdAfx.cpp | 32 + .../test/ole/unoTocomCalls/XCallback_Impl/StdAfx.h | 45 + .../XCallback_Impl/XCallback_Impl.cpp | 78 + .../XCallback_Impl/XCallback_Impl.def | 10 + .../XCallback_Impl/XCallback_Impl.dsp | 337 ++ .../XCallback_Impl/XCallback_Impl.idl | 144 + .../unoTocomCalls/XCallback_Impl/XCallback_Impl.rc | 154 + .../XCallback_Impl/XCallback_Impl.sln | 31 + .../XCallback_Impl/XCallback_Impl.vcproj | 816 +++++ .../ole/unoTocomCalls/XCallback_Impl/resource.h | 39 + extensions/test/ole/unoTocomCalls/readme.txt | 9 + extensions/test/pgp/TestPGP.java | 95 + extensions/test/pgp/makefile.mk | 62 + extensions/test/pgp/readme.txt | 33 + .../uiconfig/sabpilot/ui/contentfieldpage.ui | 177 + .../uiconfig/sabpilot/ui/contenttablepage.ui | 242 ++ extensions/uiconfig/sabpilot/ui/datasourcepage.ui | 235 ++ .../sabpilot/ui/defaultfieldselectionpage.ui | 94 + extensions/uiconfig/sabpilot/ui/fieldassignpage.ui | 81 + extensions/uiconfig/sabpilot/ui/fieldlinkpage.ui | 150 + .../sabpilot/ui/gridfieldsselectionpage.ui | 403 +++ .../sabpilot/ui/groupradioselectionpage.ui | 317 ++ extensions/uiconfig/sabpilot/ui/invokeadminpage.ui | 80 + .../uiconfig/sabpilot/ui/optiondbfieldpage.ui | 113 + .../uiconfig/sabpilot/ui/optionsfinalpage.ui | 63 + .../uiconfig/sabpilot/ui/optionvaluespage.ui | 166 + extensions/uiconfig/sabpilot/ui/selecttablepage.ui | 94 + extensions/uiconfig/sabpilot/ui/selecttypepage.ui | 211 ++ .../uiconfig/sabpilot/ui/tableselectionpage.ui | 261 ++ .../uiconfig/sbibliography/menubar/menubar.xml | 77 + .../uiconfig/sbibliography/ui/autofiltermenu.ui | 9 + .../sbibliography/ui/choosedatasourcedialog.ui | 142 + extensions/uiconfig/sbibliography/ui/combobox.ui | 40 + extensions/uiconfig/sbibliography/ui/editbox.ui | 39 + .../uiconfig/sbibliography/ui/generalpage.ui | 1019 ++++++ .../uiconfig/sbibliography/ui/mappingdialog.ui | 1077 ++++++ .../uiconfig/sbibliography/ui/querydialog.ui | 49 + extensions/uiconfig/sbibliography/ui/toolbar.ui | 122 + extensions/uiconfig/scanner/ui/griddialog.ui | 158 + extensions/uiconfig/scanner/ui/sanedialog.ui | 778 +++++ extensions/uiconfig/spropctrlr/ui/browserline.ui | 51 + extensions/uiconfig/spropctrlr/ui/browserpage.ui | 94 + extensions/uiconfig/spropctrlr/ui/colorlistbox.ui | 18 + extensions/uiconfig/spropctrlr/ui/combobox.ui | 17 + .../uiconfig/spropctrlr/ui/controlfontdialog.ui | 205 ++ .../uiconfig/spropctrlr/ui/datatypedialog.ui | 130 + extensions/uiconfig/spropctrlr/ui/datefield.ui | 45 + extensions/uiconfig/spropctrlr/ui/datetimefield.ui | 49 + .../uiconfig/spropctrlr/ui/formattedcontrol.ui | 20 + .../uiconfig/spropctrlr/ui/formattedsample.ui | 45 + .../uiconfig/spropctrlr/ui/formlinksdialog.ui | 384 +++ .../uiconfig/spropctrlr/ui/formproperties.ui | 40 + .../uiconfig/spropctrlr/ui/hyperlinkfield.ui | 38 + .../uiconfig/spropctrlr/ui/labelselectiondialog.ui | 194 ++ extensions/uiconfig/spropctrlr/ui/listbox.ui | 10 + .../uiconfig/spropctrlr/ui/listselectdialog.ui | 154 + extensions/uiconfig/spropctrlr/ui/multiline.ui | 87 + extensions/uiconfig/spropctrlr/ui/numericfield.ui | 17 + extensions/uiconfig/spropctrlr/ui/taborder.ui | 243 ++ extensions/uiconfig/spropctrlr/ui/textfield.ui | 11 + extensions/uiconfig/spropctrlr/ui/timefield.ui | 17 + extensions/uiconfig/spropctrlr/ui/urlcontrol.ui | 17 + 535 files changed, 113691 insertions(+) create mode 100644 extensions/AllLangMoTarget_pcr.mk create mode 100644 extensions/Configuration_updchk.mk create mode 100644 extensions/CppunitTest_extensions_bibliography.mk create mode 100644 extensions/CppunitTest_extensions_test_update.mk create mode 100644 extensions/CustomTarget_automationtest.mk create mode 100644 extensions/CustomTarget_so_activex_idl.mk create mode 100644 extensions/CustomTarget_so_activex_x64.mk create mode 100644 extensions/Executable_twain32shim.mk create mode 100644 extensions/IwyuFilter_extensions.yaml create mode 100644 extensions/JunitTest_extensions_unoapi.mk create mode 100644 extensions/Library_OOoSpotlightImporter.mk create mode 100644 extensions/Library_WinUserInfoBe.mk create mode 100644 extensions/Library_abp.mk create mode 100644 extensions/Library_bib.mk create mode 100644 extensions/Library_dbp.mk create mode 100644 extensions/Library_ldapbe2.mk create mode 100644 extensions/Library_log.mk create mode 100644 extensions/Library_oleautobridge.mk create mode 100644 extensions/Library_pcr.mk create mode 100644 extensions/Library_scn.mk create mode 100644 extensions/Library_so_activex.mk create mode 100644 extensions/Library_so_activex_x64.mk create mode 100644 extensions/Library_updatecheckui.mk create mode 100644 extensions/Library_updatefeed.mk create mode 100644 extensions/Library_updchk.mk create mode 100644 extensions/Makefile create mode 100644 extensions/Module_extensions.mk create mode 100644 extensions/Package_OOoSpotlightImporter.mk create mode 100644 extensions/Package_mdibundle.mk create mode 100644 extensions/README.md create mode 100644 extensions/UIConfig_sabpilot.mk create mode 100644 extensions/UIConfig_sbibliography.mk create mode 100644 extensions/UIConfig_scanner.mk create mode 100644 extensions/UIConfig_spropctrlr.mk create mode 100644 extensions/WinResTarget_activex.mk create mode 100644 extensions/inc/bitmaps.hlst create mode 100644 extensions/inc/command.hrc create mode 100644 extensions/inc/helpids.h create mode 100644 extensions/inc/propctrlr.h create mode 100644 extensions/inc/showhide.hrc create mode 100644 extensions/inc/stringarrays.hrc create mode 100644 extensions/inc/strings.hrc create mode 100644 extensions/inc/yesno.hrc create mode 100644 extensions/qa/bibliography/bibliography.cxx create mode 100644 extensions/qa/integration/extensions/ComponentFactory.java create mode 100644 extensions/qa/integration/extensions/ConsoleWait.java create mode 100644 extensions/qa/integration/extensions/Frame.java create mode 100644 extensions/qa/integration/extensions/HelpTextProvider.java create mode 100644 extensions/qa/integration/extensions/MethodHandler.java create mode 100644 extensions/qa/integration/extensions/ObjectInspector.java create mode 100644 extensions/qa/integration/extensions/ServicesHandler.java create mode 100644 extensions/qa/integration/extensions/extensions_complex.sce create mode 100644 extensions/qa/integration/extensions/makefile.mk create mode 100644 extensions/qa/ole/automationtest.vbs create mode 100644 extensions/qa/unoapi/extensions.sce create mode 100644 extensions/qa/update/simple.xml create mode 100644 extensions/qa/update/test_update.cxx create mode 100644 extensions/source/abpilot/abp.component create mode 100644 extensions/source/abpilot/abpfinalpage.cxx create mode 100644 extensions/source/abpilot/abpfinalpage.hxx create mode 100644 extensions/source/abpilot/abptypes.hxx create mode 100644 extensions/source/abpilot/abspage.cxx create mode 100644 extensions/source/abpilot/abspage.hxx create mode 100644 extensions/source/abpilot/abspilot.cxx create mode 100644 extensions/source/abpilot/abspilot.hxx create mode 100644 extensions/source/abpilot/addresssettings.hxx create mode 100644 extensions/source/abpilot/admininvokationimpl.cxx create mode 100644 extensions/source/abpilot/admininvokationimpl.hxx create mode 100644 extensions/source/abpilot/admininvokationpage.cxx create mode 100644 extensions/source/abpilot/admininvokationpage.hxx create mode 100644 extensions/source/abpilot/datasourcehandling.cxx create mode 100644 extensions/source/abpilot/datasourcehandling.hxx create mode 100644 extensions/source/abpilot/fieldmappingimpl.cxx create mode 100644 extensions/source/abpilot/fieldmappingimpl.hxx create mode 100644 extensions/source/abpilot/fieldmappingpage.cxx create mode 100644 extensions/source/abpilot/fieldmappingpage.hxx create mode 100644 extensions/source/abpilot/moduleabp.cxx create mode 100644 extensions/source/abpilot/tableselectionpage.cxx create mode 100644 extensions/source/abpilot/tableselectionpage.hxx create mode 100644 extensions/source/abpilot/typeselectionpage.cxx create mode 100644 extensions/source/abpilot/typeselectionpage.hxx create mode 100644 extensions/source/abpilot/unodialogabp.cxx create mode 100644 extensions/source/abpilot/unodialogabp.hxx create mode 100644 extensions/source/activex/README.txt create mode 100644 extensions/source/activex/SOActionsApproval.cxx create mode 100644 extensions/source/activex/SOActionsApproval.h create mode 100644 extensions/source/activex/SOActionsApproval.rgs create mode 100644 extensions/source/activex/SOActiveX.cxx create mode 100644 extensions/source/activex/SOActiveX.h create mode 100644 extensions/source/activex/SOActiveX.rgs create mode 100644 extensions/source/activex/SOComWindowPeer.cxx create mode 100644 extensions/source/activex/SOComWindowPeer.h create mode 100644 extensions/source/activex/SOComWindowPeer.rgs create mode 100644 extensions/source/activex/SODispatchInterceptor.cxx create mode 100644 extensions/source/activex/SODispatchInterceptor.h create mode 100644 extensions/source/activex/SODispatchInterceptor.rgs create mode 100644 extensions/source/activex/StdAfx2.cxx create mode 100644 extensions/source/activex/StdAfx2.h create mode 100644 extensions/source/activex/com_uno_helper.h create mode 100644 extensions/source/activex/example.html create mode 100644 extensions/source/activex/resource.h create mode 100644 extensions/source/activex/so_activex.cxx create mode 100644 extensions/source/activex/so_activex.def create mode 100644 extensions/source/activex/so_activex.idl create mode 100644 extensions/source/activex/so_activex.rc create mode 100644 extensions/source/bibliography/bib.component create mode 100644 extensions/source/bibliography/bibbeam.cxx create mode 100644 extensions/source/bibliography/bibbeam.hxx create mode 100644 extensions/source/bibliography/bibconfig.cxx create mode 100644 extensions/source/bibliography/bibconfig.hxx create mode 100644 extensions/source/bibliography/bibcont.cxx create mode 100644 extensions/source/bibliography/bibcont.hxx create mode 100644 extensions/source/bibliography/bibload.cxx create mode 100644 extensions/source/bibliography/bibmod.cxx create mode 100644 extensions/source/bibliography/bibmod.hxx create mode 100644 extensions/source/bibliography/bibresid.hxx create mode 100644 extensions/source/bibliography/bibshortcuthandler.hxx create mode 100644 extensions/source/bibliography/bibtools.hxx create mode 100644 extensions/source/bibliography/bibview.cxx create mode 100644 extensions/source/bibliography/bibview.hxx create mode 100644 extensions/source/bibliography/datman.cxx create mode 100644 extensions/source/bibliography/datman.hxx create mode 100644 extensions/source/bibliography/formcontrolcontainer.cxx create mode 100644 extensions/source/bibliography/formcontrolcontainer.hxx create mode 100644 extensions/source/bibliography/framectr.cxx create mode 100644 extensions/source/bibliography/framectr.hxx create mode 100644 extensions/source/bibliography/general.cxx create mode 100644 extensions/source/bibliography/general.hxx create mode 100644 extensions/source/bibliography/loadlisteneradapter.cxx create mode 100644 extensions/source/bibliography/loadlisteneradapter.hxx create mode 100644 extensions/source/bibliography/toolbar.cxx create mode 100644 extensions/source/bibliography/toolbar.hxx create mode 100644 extensions/source/config/WinUserInfo/WinUserInfoBe.component create mode 100644 extensions/source/config/WinUserInfo/WinUserInfoBe.cxx create mode 100644 extensions/source/config/WinUserInfo/WinUserInfoBe.hxx create mode 100644 extensions/source/config/ldap/ldapaccess.cxx create mode 100644 extensions/source/config/ldap/ldapaccess.hxx create mode 100644 extensions/source/config/ldap/ldapbe2.component create mode 100644 extensions/source/config/ldap/ldapuserprofilebe.cxx create mode 100644 extensions/source/config/ldap/ldapuserprofilebe.hxx create mode 100644 extensions/source/dbpilots/commonpagesdbp.cxx create mode 100644 extensions/source/dbpilots/commonpagesdbp.hxx create mode 100644 extensions/source/dbpilots/controlwizard.cxx create mode 100644 extensions/source/dbpilots/controlwizard.hxx create mode 100644 extensions/source/dbpilots/dbp.component create mode 100644 extensions/source/dbpilots/dbptools.cxx create mode 100644 extensions/source/dbpilots/dbptools.hxx create mode 100644 extensions/source/dbpilots/dbptypes.hxx create mode 100644 extensions/source/dbpilots/gridwizard.cxx create mode 100644 extensions/source/dbpilots/gridwizard.hxx create mode 100644 extensions/source/dbpilots/groupboxwiz.cxx create mode 100644 extensions/source/dbpilots/groupboxwiz.hxx create mode 100644 extensions/source/dbpilots/listcombowizard.cxx create mode 100644 extensions/source/dbpilots/listcombowizard.hxx create mode 100644 extensions/source/dbpilots/moduledbp.cxx create mode 100644 extensions/source/dbpilots/optiongrouplayouter.cxx create mode 100644 extensions/source/dbpilots/optiongrouplayouter.hxx create mode 100644 extensions/source/dbpilots/unoautopilot.hxx create mode 100644 extensions/source/dbpilots/wizardcontext.hxx create mode 100644 extensions/source/dbpilots/wizardservices.cxx create mode 100644 extensions/source/inc/componentmodule.cxx create mode 100644 extensions/source/inc/componentmodule.hxx create mode 100644 extensions/source/logging/consolehandler.cxx create mode 100644 extensions/source/logging/csvformatter.cxx create mode 100644 extensions/source/logging/filehandler.cxx create mode 100644 extensions/source/logging/log.component create mode 100644 extensions/source/logging/logger.cxx create mode 100644 extensions/source/logging/loggerconfig.cxx create mode 100644 extensions/source/logging/loggerconfig.hxx create mode 100644 extensions/source/logging/loghandler.cxx create mode 100644 extensions/source/logging/loghandler.hxx create mode 100644 extensions/source/logging/logrecord.cxx create mode 100644 extensions/source/logging/logrecord.hxx create mode 100644 extensions/source/logging/methodguard.hxx create mode 100644 extensions/source/logging/plaintextformatter.cxx create mode 100644 extensions/source/logging/simpletextformatter.cxx create mode 100644 extensions/source/macosx/spotlight/GetMetadataForFile.h create mode 100644 extensions/source/macosx/spotlight/GetMetadataForFile.m create mode 100644 extensions/source/macosx/spotlight/OOoContentDataParser.h create mode 100644 extensions/source/macosx/spotlight/OOoContentDataParser.m create mode 100644 extensions/source/macosx/spotlight/OOoMetaDataParser.h create mode 100644 extensions/source/macosx/spotlight/OOoMetaDataParser.m create mode 100644 extensions/source/macosx/spotlight/OOoSpotlightImporter.h create mode 100644 extensions/source/macosx/spotlight/OOoSpotlightImporter.m create mode 100644 extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/.gitignore create mode 100644 extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/project.pbxproj create mode 100644 extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/xcshareddata/xcschemes/SpotlightImporterTester.xcscheme create mode 100644 extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester/main.m create mode 100644 extensions/source/macosx/spotlight/main.m create mode 100644 extensions/source/macosx/spotlight/mdimporter/Info.plist create mode 100644 extensions/source/macosx/spotlight/mdimporter/en.lproj/schema.strings create mode 100644 extensions/source/macosx/spotlight/mdimporter/schema.xml create mode 100644 extensions/source/macosx/spotlight/version.plist create mode 100644 extensions/source/ole/comifaces.hxx create mode 100644 extensions/source/ole/jscriptclasses.cxx create mode 100644 extensions/source/ole/jscriptclasses.hxx create mode 100644 extensions/source/ole/ole2uno.cxx create mode 100644 extensions/source/ole/ole2uno.hxx create mode 100644 extensions/source/ole/oleautobridge.component create mode 100644 extensions/source/ole/oledll.cxx create mode 100644 extensions/source/ole/oleobjw.cxx create mode 100644 extensions/source/ole/oleobjw.hxx create mode 100644 extensions/source/ole/olethread.cxx create mode 100644 extensions/source/ole/servprov.cxx create mode 100644 extensions/source/ole/servprov.hxx create mode 100644 extensions/source/ole/servreg.cxx create mode 100644 extensions/source/ole/unoconversionutilities.hxx create mode 100644 extensions/source/ole/unoobjw.cxx create mode 100644 extensions/source/ole/unoobjw.hxx create mode 100644 extensions/source/ole/unotypewrapper.cxx create mode 100644 extensions/source/ole/unotypewrapper.hxx create mode 100644 extensions/source/ole/wincrap.hxx create mode 100644 extensions/source/ole/windata.hxx create mode 100644 extensions/source/propctrlr/MasterDetailLinkDialog.cxx create mode 100644 extensions/source/propctrlr/MasterDetailLinkDialog.hxx create mode 100644 extensions/source/propctrlr/browserline.cxx create mode 100644 extensions/source/propctrlr/browserline.hxx create mode 100644 extensions/source/propctrlr/browserlistbox.cxx create mode 100644 extensions/source/propctrlr/browserlistbox.hxx create mode 100644 extensions/source/propctrlr/browserpage.cxx create mode 100644 extensions/source/propctrlr/browserpage.hxx create mode 100644 extensions/source/propctrlr/browserview.cxx create mode 100644 extensions/source/propctrlr/browserview.hxx create mode 100644 extensions/source/propctrlr/buttonnavigationhandler.cxx create mode 100644 extensions/source/propctrlr/buttonnavigationhandler.hxx create mode 100644 extensions/source/propctrlr/cellbindinghandler.cxx create mode 100644 extensions/source/propctrlr/cellbindinghandler.hxx create mode 100644 extensions/source/propctrlr/cellbindinghelper.cxx create mode 100644 extensions/source/propctrlr/cellbindinghelper.hxx create mode 100644 extensions/source/propctrlr/commoncontrol.cxx create mode 100644 extensions/source/propctrlr/commoncontrol.hxx create mode 100644 extensions/source/propctrlr/composeduiupdate.cxx create mode 100644 extensions/source/propctrlr/composeduiupdate.hxx create mode 100644 extensions/source/propctrlr/controlfontdialog.cxx create mode 100644 extensions/source/propctrlr/controlfontdialog.hxx create mode 100644 extensions/source/propctrlr/controltype.hxx create mode 100644 extensions/source/propctrlr/defaultforminspection.cxx create mode 100644 extensions/source/propctrlr/defaultforminspection.hxx create mode 100644 extensions/source/propctrlr/defaulthelpprovider.cxx create mode 100644 extensions/source/propctrlr/defaulthelpprovider.hxx create mode 100644 extensions/source/propctrlr/editpropertyhandler.cxx create mode 100644 extensions/source/propctrlr/editpropertyhandler.hxx create mode 100644 extensions/source/propctrlr/eformshelper.cxx create mode 100644 extensions/source/propctrlr/eformshelper.hxx create mode 100644 extensions/source/propctrlr/eformspropertyhandler.cxx create mode 100644 extensions/source/propctrlr/eformspropertyhandler.hxx create mode 100644 extensions/source/propctrlr/enumrepresentation.hxx create mode 100644 extensions/source/propctrlr/eventhandler.cxx create mode 100644 extensions/source/propctrlr/eventhandler.hxx create mode 100644 extensions/source/propctrlr/fontdialog.cxx create mode 100644 extensions/source/propctrlr/fontdialog.hxx create mode 100644 extensions/source/propctrlr/fontitemids.hxx create mode 100644 extensions/source/propctrlr/formbrowsertools.cxx create mode 100644 extensions/source/propctrlr/formbrowsertools.hxx create mode 100644 extensions/source/propctrlr/formcomponenthandler.cxx create mode 100644 extensions/source/propctrlr/formcomponenthandler.hxx create mode 100644 extensions/source/propctrlr/formcontroller.cxx create mode 100644 extensions/source/propctrlr/formcontroller.hxx create mode 100644 extensions/source/propctrlr/formgeometryhandler.cxx create mode 100644 extensions/source/propctrlr/formlinkdialog.cxx create mode 100644 extensions/source/propctrlr/formlinkdialog.hxx create mode 100644 extensions/source/propctrlr/formmetadata.cxx create mode 100644 extensions/source/propctrlr/formmetadata.hxx create mode 100644 extensions/source/propctrlr/formstrings.hxx create mode 100644 extensions/source/propctrlr/genericpropertyhandler.cxx create mode 100644 extensions/source/propctrlr/genericpropertyhandler.hxx create mode 100644 extensions/source/propctrlr/handlerhelper.cxx create mode 100644 extensions/source/propctrlr/handlerhelper.hxx create mode 100644 extensions/source/propctrlr/inspectorhelpwindow.cxx create mode 100644 extensions/source/propctrlr/inspectorhelpwindow.hxx create mode 100644 extensions/source/propctrlr/inspectormodelbase.cxx create mode 100644 extensions/source/propctrlr/inspectormodelbase.hxx create mode 100644 extensions/source/propctrlr/linedescriptor.hxx create mode 100644 extensions/source/propctrlr/listselectiondlg.cxx create mode 100644 extensions/source/propctrlr/listselectiondlg.hxx create mode 100644 extensions/source/propctrlr/modulepcr.cxx create mode 100644 extensions/source/propctrlr/modulepcr.hxx create mode 100644 extensions/source/propctrlr/newdatatype.cxx create mode 100644 extensions/source/propctrlr/newdatatype.hxx create mode 100644 extensions/source/propctrlr/objectinspectormodel.cxx create mode 100644 extensions/source/propctrlr/pcr.component create mode 100644 extensions/source/propctrlr/pcrcommon.cxx create mode 100644 extensions/source/propctrlr/pcrcommon.hxx create mode 100644 extensions/source/propctrlr/pcrcommontypes.hxx create mode 100644 extensions/source/propctrlr/pcrstrings.hxx create mode 100644 extensions/source/propctrlr/pcrunodialogs.cxx create mode 100644 extensions/source/propctrlr/pcrunodialogs.hxx create mode 100644 extensions/source/propctrlr/propcontroller.cxx create mode 100644 extensions/source/propctrlr/propcontroller.hxx create mode 100644 extensions/source/propctrlr/propcontrolobserver.hxx create mode 100644 extensions/source/propctrlr/propertycomposer.cxx create mode 100644 extensions/source/propctrlr/propertycomposer.hxx create mode 100644 extensions/source/propctrlr/propertycontrolextender.cxx create mode 100644 extensions/source/propctrlr/propertycontrolextender.hxx create mode 100644 extensions/source/propctrlr/propertyeditor.cxx create mode 100644 extensions/source/propctrlr/propertyeditor.hxx create mode 100644 extensions/source/propctrlr/propertyhandler.cxx create mode 100644 extensions/source/propctrlr/propertyhandler.hxx create mode 100644 extensions/source/propctrlr/propertyinfo.hxx create mode 100644 extensions/source/propctrlr/propeventtranslation.cxx create mode 100644 extensions/source/propctrlr/propeventtranslation.hxx create mode 100644 extensions/source/propctrlr/proplinelistener.hxx create mode 100644 extensions/source/propctrlr/pushbuttonnavigation.cxx create mode 100644 extensions/source/propctrlr/pushbuttonnavigation.hxx create mode 100644 extensions/source/propctrlr/selectlabeldialog.cxx create mode 100644 extensions/source/propctrlr/selectlabeldialog.hxx create mode 100644 extensions/source/propctrlr/sqlcommanddesign.cxx create mode 100644 extensions/source/propctrlr/sqlcommanddesign.hxx create mode 100644 extensions/source/propctrlr/standardcontrol.cxx create mode 100644 extensions/source/propctrlr/standardcontrol.hxx create mode 100644 extensions/source/propctrlr/stringrepresentation.cxx create mode 100644 extensions/source/propctrlr/submissionhandler.cxx create mode 100644 extensions/source/propctrlr/submissionhandler.hxx create mode 100644 extensions/source/propctrlr/taborder.cxx create mode 100644 extensions/source/propctrlr/taborder.hxx create mode 100644 extensions/source/propctrlr/unourl.cxx create mode 100644 extensions/source/propctrlr/unourl.hxx create mode 100644 extensions/source/propctrlr/usercontrol.cxx create mode 100644 extensions/source/propctrlr/usercontrol.hxx create mode 100644 extensions/source/propctrlr/xsddatatypes.cxx create mode 100644 extensions/source/propctrlr/xsddatatypes.hxx create mode 100644 extensions/source/propctrlr/xsdvalidationhelper.cxx create mode 100644 extensions/source/propctrlr/xsdvalidationhelper.hxx create mode 100644 extensions/source/propctrlr/xsdvalidationpropertyhandler.cxx create mode 100644 extensions/source/propctrlr/xsdvalidationpropertyhandler.hxx create mode 100644 extensions/source/scanner/grid.cxx create mode 100644 extensions/source/scanner/grid.hxx create mode 100644 extensions/source/scanner/sane.cxx create mode 100644 extensions/source/scanner/sane.hxx create mode 100644 extensions/source/scanner/sanedlg.cxx create mode 100644 extensions/source/scanner/sanedlg.hxx create mode 100644 extensions/source/scanner/scanner.cxx create mode 100644 extensions/source/scanner/scanner.hxx create mode 100644 extensions/source/scanner/scanunx.cxx create mode 100644 extensions/source/scanner/scanwin.cxx create mode 100644 extensions/source/scanner/scn.component create mode 100644 extensions/source/scanner/twain32shim.cxx create mode 100644 extensions/source/scanner/twain32shim.hxx create mode 100644 extensions/source/update/check/actionlistener.hxx create mode 100644 extensions/source/update/check/download.cxx create mode 100644 extensions/source/update/check/download.hxx create mode 100644 extensions/source/update/check/onlinecheck.cxx create mode 100644 extensions/source/update/check/onlinecheck.hxx create mode 100644 extensions/source/update/check/org/openoffice/Office/Addons.xcu create mode 100644 extensions/source/update/check/org/openoffice/Office/Jobs.xcu create mode 100644 extensions/source/update/check/updatecheck.cxx create mode 100644 extensions/source/update/check/updatecheck.hxx create mode 100644 extensions/source/update/check/updatecheckconfig.cxx create mode 100644 extensions/source/update/check/updatecheckconfig.hxx create mode 100644 extensions/source/update/check/updatecheckconfiglistener.hxx create mode 100644 extensions/source/update/check/updatecheckjob.cxx create mode 100644 extensions/source/update/check/updatehdl.cxx create mode 100644 extensions/source/update/check/updatehdl.hxx create mode 100644 extensions/source/update/check/updateinfo.hxx create mode 100644 extensions/source/update/check/updateprotocol.cxx create mode 100644 extensions/source/update/check/updateprotocol.hxx create mode 100644 extensions/source/update/check/updateprotocoltest.cxx create mode 100644 extensions/source/update/check/updchk.uno.component create mode 100644 extensions/source/update/feed/test/updatefeedtest.cxx create mode 100644 extensions/source/update/feed/updatefeed.component create mode 100644 extensions/source/update/feed/updatefeed.cxx create mode 100644 extensions/source/update/ui/updatecheckui.cxx create mode 100644 extensions/source/update/ui/updchk.component create mode 100644 extensions/test/ole/AxTestComponents/AxTestComponents.cpp create mode 100644 extensions/test/ole/AxTestComponents/AxTestComponents.def create mode 100644 extensions/test/ole/AxTestComponents/AxTestComponents.dsp create mode 100644 extensions/test/ole/AxTestComponents/AxTestComponents.idl create mode 100644 extensions/test/ole/AxTestComponents/AxTestComponents.rc create mode 100644 extensions/test/ole/AxTestComponents/AxTestComponents.sln create mode 100644 extensions/test/ole/AxTestComponents/AxTestComponents.vcproj create mode 100644 extensions/test/ole/AxTestComponents/Basic.cpp create mode 100644 extensions/test/ole/AxTestComponents/Basic.h create mode 100644 extensions/test/ole/AxTestComponents/Basic.rgs create mode 100644 extensions/test/ole/AxTestComponents/Foo.cpp create mode 100644 extensions/test/ole/AxTestComponents/Foo.h create mode 100644 extensions/test/ole/AxTestComponents/StdAfx.cpp create mode 100644 extensions/test/ole/AxTestComponents/StdAfx.h create mode 100644 extensions/test/ole/AxTestComponents/readme.txt create mode 100644 extensions/test/ole/AxTestComponents/resource.h create mode 100644 extensions/test/ole/DCOM/Clients/WriterDemo/Module1.bas create mode 100644 extensions/test/ole/DCOM/Clients/WriterDemo/client_writerdemo.vbp create mode 100644 extensions/test/ole/DCOM/Clients/WriterDemo/client_writerdemo.vbw create mode 100644 extensions/test/ole/DCOM/Clients/WriterDemo/readme.txt create mode 100644 extensions/test/ole/DCOM/dcom_test/Module1.bas create mode 100644 extensions/test/ole/DCOM/dcom_test/dcom_test.vbp create mode 100644 extensions/test/ole/DCOM/dcom_test/dcom_test.vbw create mode 100644 extensions/test/ole/DCOM/dcom_test/readme.txt create mode 100644 extensions/test/ole/DCOM/scriptComponents/WriterDemo.wsc create mode 100644 extensions/test/ole/DCOM/scriptComponents/readme.txt create mode 100644 extensions/test/ole/EventListenerSample/EventListener/EventListener.cpp create mode 100644 extensions/test/ole/EventListenerSample/EventListener/EventListener.def create mode 100644 extensions/test/ole/EventListenerSample/EventListener/EventListener.idl create mode 100644 extensions/test/ole/EventListenerSample/EventListener/EventListener.rc create mode 100644 extensions/test/ole/EventListenerSample/EventListener/EventListener.sln create mode 100644 extensions/test/ole/EventListenerSample/EventListener/EventListener.vcproj create mode 100644 extensions/test/ole/EventListenerSample/EventListener/EvtListener.cpp create mode 100644 extensions/test/ole/EventListenerSample/EventListener/EvtListener.h create mode 100644 extensions/test/ole/EventListenerSample/EventListener/EvtListener.rgs create mode 100644 extensions/test/ole/EventListenerSample/EventListener/StdAfx.cpp create mode 100644 extensions/test/ole/EventListenerSample/EventListener/StdAfx.h create mode 100644 extensions/test/ole/EventListenerSample/EventListener/resource.h create mode 100644 extensions/test/ole/EventListenerSample/VBEventListener/Module1.bas create mode 100644 extensions/test/ole/EventListenerSample/VBEventListener/VBEventListener.cls create mode 100644 extensions/test/ole/EventListenerSample/VBEventListener/VBasicEventListener.vbp create mode 100644 extensions/test/ole/EventListenerSample/VBEventListener/VBasicEventListener.vbw create mode 100644 extensions/test/ole/EventListenerSample/VBEventListener/readme.txt create mode 100644 extensions/test/ole/EventListenerSample/events.htm create mode 100644 extensions/test/ole/EventListenerSample/readme.txt create mode 100644 extensions/test/ole/JScriptNewStyle.htm create mode 100644 extensions/test/ole/MfcControl/MfcControl.cpp create mode 100644 extensions/test/ole/MfcControl/MfcControl.def create mode 100644 extensions/test/ole/MfcControl/MfcControl.dsp create mode 100644 extensions/test/ole/MfcControl/MfcControl.h create mode 100644 extensions/test/ole/MfcControl/MfcControl.odl create mode 100644 extensions/test/ole/MfcControl/MfcControl.rc create mode 100644 extensions/test/ole/MfcControl/MfcControl.sln create mode 100644 extensions/test/ole/MfcControl/MfcControl.vcproj create mode 100644 extensions/test/ole/MfcControl/MfcControlCtl.cpp create mode 100644 extensions/test/ole/MfcControl/MfcControlCtl.h create mode 100644 extensions/test/ole/MfcControl/MfcControlCtl.png create mode 100644 extensions/test/ole/MfcControl/MfcControlPpg.cpp create mode 100644 extensions/test/ole/MfcControl/MfcControlPpg.h create mode 100644 extensions/test/ole/MfcControl/Resource.h create mode 100644 extensions/test/ole/MfcControl/StdAfx.cpp create mode 100644 extensions/test/ole/MfcControl/StdAfx.h create mode 100644 extensions/test/ole/OleClient/OleClient.ini create mode 100644 extensions/test/ole/OleClient/axhost.cxx create mode 100644 extensions/test/ole/OleClient/axhost.hxx create mode 100644 extensions/test/ole/OleClient/clientTest.cxx create mode 100644 extensions/test/ole/OleClient/funcs.cxx create mode 100644 extensions/test/ole/OleClient/readme.txt create mode 100644 extensions/test/ole/OleConverterVar1/convTest.cxx create mode 100644 extensions/test/ole/OleConverterVar1/makefile.mk create mode 100644 extensions/test/ole/OleConverterVar1/readme.txt create mode 100644 extensions/test/ole/OleConverterVar1/smartarray.h create mode 100644 extensions/test/ole/OleTest.htm create mode 100644 extensions/test/ole/ScriptTest.html create mode 100644 extensions/test/ole/StarBasic_OleClient/oleclient.bas create mode 100644 extensions/test/ole/StarBasic_OleClient/readme.txt create mode 100644 extensions/test/ole/VisualBasic/AssemblyInfo.vb create mode 100644 extensions/test/ole/VisualBasic/Module1.vb create mode 100644 extensions/test/ole/VisualBasic/Project1.sln create mode 100644 extensions/test/ole/VisualBasic/Project1.vbproj create mode 100644 extensions/test/ole/VisualBasic/readme.txt create mode 100644 extensions/test/ole/callUnoToJava.htm create mode 100644 extensions/test/ole/cpnt/cpnt.cxx create mode 100644 extensions/test/ole/cpnt/exports.dxp create mode 100644 extensions/test/ole/cpnt/makefile.mk create mode 100644 extensions/test/ole/cpnt/readme.txt create mode 100644 extensions/test/ole/cppToUno/makefile.mk create mode 100644 extensions/test/ole/cppToUno/readme.txt create mode 100644 extensions/test/ole/cppToUno/testcppuno.cxx create mode 100644 extensions/test/ole/cpptest/cpptest.cxx create mode 100644 extensions/test/ole/cpptest/makefile.mk create mode 100644 extensions/test/ole/cpptest/readme.txt create mode 100644 extensions/test/ole/idl/oletest.idl create mode 100644 extensions/test/ole/unloading/makefile.mk create mode 100644 extensions/test/ole/unloading/readme.txt create mode 100644 extensions/test/ole/unloading/unloadTest.cxx create mode 100644 extensions/test/ole/unoTocomCalls/Test/StdAfx.cpp create mode 100644 extensions/test/ole/unoTocomCalls/Test/StdAfx.h create mode 100644 extensions/test/ole/unoTocomCalls/Test/Test.cpp create mode 100644 extensions/test/ole/unoTocomCalls/Test/Test.dsp create mode 100644 extensions/test/ole/unoTocomCalls/Test/Test.sln create mode 100644 extensions/test/ole/unoTocomCalls/Test/Test.vcproj create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/Basic.rgs create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/BasicTest.rgs create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.cpp create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.h create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.rgs create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.cpp create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.h create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.rgs create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/StdAfx.cpp create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/StdAfx.h create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.cpp create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.def create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.dsp create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.idl create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.rc create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.sln create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.vcproj create mode 100644 extensions/test/ole/unoTocomCalls/XCallback_Impl/resource.h create mode 100644 extensions/test/ole/unoTocomCalls/readme.txt create mode 100644 extensions/test/pgp/TestPGP.java create mode 100644 extensions/test/pgp/makefile.mk create mode 100644 extensions/test/pgp/readme.txt create mode 100644 extensions/uiconfig/sabpilot/ui/contentfieldpage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/contenttablepage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/datasourcepage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/defaultfieldselectionpage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/fieldassignpage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/fieldlinkpage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/gridfieldsselectionpage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/groupradioselectionpage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/invokeadminpage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/optiondbfieldpage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/optionsfinalpage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/optionvaluespage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/selecttablepage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/selecttypepage.ui create mode 100644 extensions/uiconfig/sabpilot/ui/tableselectionpage.ui create mode 100644 extensions/uiconfig/sbibliography/menubar/menubar.xml create mode 100644 extensions/uiconfig/sbibliography/ui/autofiltermenu.ui create mode 100644 extensions/uiconfig/sbibliography/ui/choosedatasourcedialog.ui create mode 100644 extensions/uiconfig/sbibliography/ui/combobox.ui create mode 100644 extensions/uiconfig/sbibliography/ui/editbox.ui create mode 100644 extensions/uiconfig/sbibliography/ui/generalpage.ui create mode 100644 extensions/uiconfig/sbibliography/ui/mappingdialog.ui create mode 100644 extensions/uiconfig/sbibliography/ui/querydialog.ui create mode 100644 extensions/uiconfig/sbibliography/ui/toolbar.ui create mode 100644 extensions/uiconfig/scanner/ui/griddialog.ui create mode 100644 extensions/uiconfig/scanner/ui/sanedialog.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/browserline.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/browserpage.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/colorlistbox.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/combobox.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/controlfontdialog.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/datatypedialog.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/datefield.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/datetimefield.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/formattedcontrol.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/formattedsample.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/formlinksdialog.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/formproperties.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/hyperlinkfield.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/labelselectiondialog.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/listbox.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/listselectdialog.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/multiline.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/numericfield.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/taborder.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/textfield.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/timefield.ui create mode 100644 extensions/uiconfig/spropctrlr/ui/urlcontrol.ui (limited to 'extensions') diff --git a/extensions/AllLangMoTarget_pcr.mk b/extensions/AllLangMoTarget_pcr.mk new file mode 100644 index 000000000..d826748f7 --- /dev/null +++ b/extensions/AllLangMoTarget_pcr.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,pcr)) + +$(eval $(call gb_AllLangMoTarget_set_polocation,pcr,extensions)) + +# vim: set noet sw=4 ts=4: diff --git a/extensions/Configuration_updchk.mk b/extensions/Configuration_updchk.mk new file mode 100644 index 000000000..394a1ae6c --- /dev/null +++ b/extensions/Configuration_updchk.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/. +# +# + +# TODO is this really supposed to be delivered to the officecfg registry? +$(eval $(call gb_Configuration_Configuration,updchk)) + +$(eval $(call gb_Configuration_add_spool_modules,updchk,extensions/source/update/check,\ + org/openoffice/Office/Jobs-onlineupdate.xcu \ + org/openoffice/Office/Addons-onlineupdate.xcu \ +)) + +# The resulting solver/*/pck/updchk_*.zip are merged into registry_*.xcd in +# postprocess/packregistry/makefile.mk (in principle, localizations of an +# install:module should go into their own per-lang xcd files, but they are +# currently all merged into a global per-lang registry_*.xcd, see e.g. how +# localized "Title" property values of +# /org.openoffice.Office.Common/Menus/New/m0 (install:module="writer") end up in +# registry_*.xcd instead of a, say, writer_*.xcd): +$(eval $(call gb_Configuration_add_localized_datas,updchk,extensions/source/update/check,\ + org/openoffice/Office/Addons.xcu \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/CppunitTest_extensions_bibliography.mk b/extensions/CppunitTest_extensions_bibliography.mk new file mode 100644 index 000000000..c5503a468 --- /dev/null +++ b/extensions/CppunitTest_extensions_bibliography.mk @@ -0,0 +1,43 @@ +# -*- 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,extensions_bibliography)) + +$(eval $(call gb_CppunitTest_use_externals,extensions_bibliography,\ + boost_headers \ +)) + +$(eval $(call gb_CppunitTest_add_exception_objects,extensions_bibliography, \ + extensions/qa/bibliography/bibliography \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,extensions_bibliography, \ + comphelper \ + cppu \ + sal \ + test \ + unotest \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,extensions_bibliography)) + +$(eval $(call gb_CppunitTest_use_ure,extensions_bibliography)) +$(eval $(call gb_CppunitTest_use_vcl,extensions_bibliography)) + +$(eval $(call gb_CppunitTest_use_rdb,extensions_bibliography,services)) + +$(eval $(call gb_CppunitTest_use_custom_headers,extensions_bibliography,\ + officecfg/registry \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,extensions_bibliography)) + +# vim: set noet sw=4 ts=4: diff --git a/extensions/CppunitTest_extensions_test_update.mk b/extensions/CppunitTest_extensions_test_update.mk new file mode 100644 index 000000000..02876aab7 --- /dev/null +++ b/extensions/CppunitTest_extensions_test_update.mk @@ -0,0 +1,66 @@ +# -*- 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,extensions_test_update)) + +$(eval $(call gb_CppunitTest_add_exception_objects,extensions_test_update, \ + extensions/qa/update/test_update \ +)) + +$(eval $(call gb_CppunitTest_use_external,extensions_test_update,boost_headers)) + +$(eval $(call gb_CppunitTest_use_libraries,extensions_test_update, \ + cppu \ + cppuhelper \ + sal \ + salhelper \ + test \ + tl \ + utl \ + unotest \ + vcl \ +)) + +$(eval $(call gb_CppunitTest_use_library_objects,extensions_test_update, \ + updchk \ +)) + +ifeq ($(OS),WNT) +$(eval $(call gb_CppunitTest_use_system_win32_libs,extensions_test_update,\ + shell32 \ + ole32 \ + wininet \ +)) +endif + +$(eval $(call gb_CppunitTest_use_external,extensions_test_update,curl)) + +$(eval $(call gb_CppunitTest_set_include,extensions_test_update,\ + $$(INCLUDE) \ + -I$(SRCDIR)/extensions/inc \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,extensions_test_update)) + +$(eval $(call gb_CppunitTest_use_ure,extensions_test_update)) +$(eval $(call gb_CppunitTest_use_vcl,extensions_test_update)) + +$(eval $(call gb_CppunitTest_use_components,extensions_test_update,\ + configmgr/source/configmgr \ + extensions/source/update/feed/updatefeed \ + ucb/source/core/ucb1 \ + ucb/source/ucp/file/ucpfile1 \ + unoxml/source/service/unoxml \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,extensions_test_update)) + +# vim:set shiftwidth=4 softtabstop=4 noexpandtab: diff --git a/extensions/CustomTarget_automationtest.mk b/extensions/CustomTarget_automationtest.mk new file mode 100644 index 000000000..e895c0b2a --- /dev/null +++ b/extensions/CustomTarget_automationtest.mk @@ -0,0 +1,29 @@ +# -*- 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_CustomTarget_CustomTarget,extensions/automationtest)) + +extensions_AUTOMATIONTESTDIR := $(call gb_CustomTarget_get_workdir,extensions/automationtest) + +extensions_AUTOMATIONTESTLOG1 := $(extensions_AUTOMATIONTESTDIR)/automationtest.1.log +extensions_AUTOMATIONTESTLOG2 := $(extensions_AUTOMATIONTESTDIR)/automationtest.2.log + +$(call gb_CustomTarget_get_target,extensions/automationtest) : \ + $(SRCDIR)/extensions/qa/ole/automationtest.vbs \ + | $(extensions_AUTOMATIONTESTDIR)/.dir + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),VBS,1) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),VBS) + SAL_LOG=+INFO.extensions.olebridge+WARN $(INSTDIR)/program/soffice 2>$(extensions_AUTOMATIONTESTLOG1) & + sleep 10 + $(call gb_Helper_abbreviate_dirs, \ + cscript -nologo $(SRCDIR)/extensions/qa/ole/automationtest.vbs $(SRCDIR)) >$(extensions_AUTOMATIONTESTLOG2) || \ + (cat $(extensions_AUTOMATIONTESTLOG1) $(extensions_AUTOMATIONTESTLOG2) && exit 1) + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),VBS) + +# vim:set shiftwidth=4 tabstop=4 noexpandtab: diff --git a/extensions/CustomTarget_so_activex_idl.mk b/extensions/CustomTarget_so_activex_idl.mk new file mode 100644 index 000000000..b4d841aec --- /dev/null +++ b/extensions/CustomTarget_so_activex_idl.mk @@ -0,0 +1,37 @@ +# -*- 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_CustomTarget_CustomTarget,extensions/source/activex/idl)) + +extensions_AXIDLDIR := $(call gb_CustomTarget_get_workdir,extensions/source/activex/idl) + +$(call gb_CustomTarget_get_target,extensions/source/activex/idl) : \ + $(extensions_AXIDLDIR)/so_activex.tlb + +# XXX: I presume that the "$(COM)"=="GCC" case in the original +# extensions/source/activex/msidl/makefile.mk was for the +# use-mingw-on-windows case and thus is not interesting for us. +$(extensions_AXIDLDIR)/so_activex.tlb : \ + $(SRCDIR)/extensions/source/activex/so_activex.idl \ + | $(extensions_AXIDLDIR)/.dir + $(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),IDL,1) + $(call gb_Trace_StartRange,$(subst $(WORKDIR)/,,$@),IDL) + $(call gb_Helper_abbreviate_dirs, \ + midl.exe \ + -tlb $@ \ + -h $(extensions_AXIDLDIR)/so_activex.h \ + -iid $(extensions_AXIDLDIR)/so_activex_i.c \ + -dlldata $(extensions_AXIDLDIR)/so_activex_dll.c \ + -proxy $(extensions_AXIDLDIR)/so_activex_p.c \ + -Oicf \ + $(INCLUDE) \ + $<) + $(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),IDL) + +# vim:set shiftwidth=4 tabstop=4 noexpandtab: diff --git a/extensions/CustomTarget_so_activex_x64.mk b/extensions/CustomTarget_so_activex_x64.mk new file mode 100644 index 000000000..6b1b35d94 --- /dev/null +++ b/extensions/CustomTarget_so_activex_x64.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_CustomTarget_CustomTarget,extensions/source/activex)) + +$(call gb_CustomTarget_get_target,extensions/source/activex) : \ + $(call gb_CustomTarget_get_workdir,extensions/source/activex)/SOActionsApproval.cxx \ + $(call gb_CustomTarget_get_workdir,extensions/source/activex)/SOActiveX.cxx \ + $(call gb_CustomTarget_get_workdir,extensions/source/activex)/SOComWindowPeer.cxx \ + $(call gb_CustomTarget_get_workdir,extensions/source/activex)/SODispatchInterceptor.cxx \ + $(call gb_CustomTarget_get_workdir,extensions/source/activex)/StdAfx2.cxx \ + $(call gb_CustomTarget_get_workdir,extensions/source/activex)/so_activex.cxx \ + +$(call gb_CustomTarget_get_workdir,extensions/source/activex)/% : \ + $(SRCDIR)/extensions/source/activex/% \ + | $(call gb_CustomTarget_get_workdir,extensions/source/activex)/.dir + cp $< $@ + +# vim:set shiftwidth=4 tabstop=4 noexpandtab: diff --git a/extensions/Executable_twain32shim.mk b/extensions/Executable_twain32shim.mk new file mode 100644 index 000000000..f063f7d6e --- /dev/null +++ b/extensions/Executable_twain32shim.mk @@ -0,0 +1,46 @@ +# -*- 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,twain32shim)) + +$(eval $(call gb_Executable_set_targettype_gui,twain32shim,YES)) + +$(eval $(call gb_Executable_set_x86,twain32shim,YES)) + +# when building with link-time optimisation on, we need to turn it off for the helper +ifeq ($(ENABLE_LTO),TRUE) +$(eval $(call gb_Executable_add_cxxflags,twain32shim,\ + -GL- \ +)) +$(eval $(call gb_Executable_add_ldflags,twain32shim,\ + -LTCG:OFF \ +)) +endif + +$(eval $(call gb_Executable_use_externals,twain32shim,\ + sane_headers \ +)) + +$(eval $(call gb_Executable_set_include,twain32shim,\ + -I$(SRCDIR)/extensions/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Executable_add_exception_objects,twain32shim,\ + extensions/source/scanner/twain32shim \ +)) + +$(eval $(call gb_Executable_use_system_win32_libs,twain32shim,\ + Ole32 \ + shell32 \ +)) + +$(eval $(call gb_Executable_add_default_nativeres,twain32shim)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/IwyuFilter_extensions.yaml b/extensions/IwyuFilter_extensions.yaml new file mode 100644 index 000000000..0e0ba4c9c --- /dev/null +++ b/extensions/IwyuFilter_extensions.yaml @@ -0,0 +1,88 @@ +--- +assumeFilename: extensions/source/propctrlr/formcomponenthandler.cxx +excludelist: + extensions/inc/strings.hrc: + # Needed for TranslateId macro + - unotools/resmgr.hxx + extensions/source/logging/loghandler.hxx: + # Don't propose hxx -> h change in URE libs + - cppuhelper/interfacecontainer.hxx + extensions/source/abpilot/admininvokationimpl.cxx: + # Needed for direct member access + - com/sun/star/awt/XWindow.hpp + extensions/source/abpilot/unodialogabp.cxx: + # Needed for direct member access + - com/sun/star/awt/XWindow.hpp + extensions/source/bibliography/framectr.cxx: + # Don't propose hxx -> h change in URE libs + - cppuhelper/interfacecontainer.hxx + # Actually used + - com/sun/star/form/runtime/XFormController.hpp + - com/sun/star/beans/PropertyValue.hpp + extensions/source/config/ldap/ldapaccess.cxx: + # Needed on WIN32 + - o3tl/char16_t2wchar_t.hxx + extensions/source/config/ldap/ldapuserprofilebe.cxx: + # Actually used + - comphelper/scopeguard.hxx + extensions/source/dbpilots/listcombowizard.cxx: + # Actually used + - com/sun/star/container/XNameAccess.hpp + extensions/source/dbpilots/commonpagesdbp.cxx: + # Actually used + - com/sun/star/sdbc/XConnection.hpp + extensions/source/update/check/updatecheck.cxx: + # Needed on WIN32 for WNT_hasInternetConnection + - onlinecheck.hxx + # Actually used + - comphelper/scopeguard.hxx + extensions/source/update/check/updatecheckconfig.cxx: + # Needed on WIN32 + - o3tl/char16_t2wchar_t.hxx + extensions/source/propctrlr/editpropertyhandler.cxx: + # Actually used + - com/sun/star/inspection/XObjectInspectorUI.hpp + extensions/source/propctrlr/cellbindinghandler.cxx: + # Actually used + - com/sun/star/inspection/XObjectInspectorUI.hpp + extensions/source/propctrlr/eformspropertyhandler.cxx: + # Actually used + - com/sun/star/inspection/XObjectInspectorUI.hpp + extensions/source/propctrlr/formcomponenthandler.cxx: + # Actually used + - com/sun/star/inspection/XObjectInspectorUI.hpp + # Needed for template + - com/sun/star/ui/dialogs/XFilePicker3.hpp + extensions/source/propctrlr/formlinkdialog.cxx: + # Needed for template + - com/sun/star/sdb/XSingleSelectQueryComposer.hpp + extensions/source/propctrlr/formgeometryhandler.cxx: + # Don't propose hxx -> h change in URE libs + - cppuhelper/interfacecontainer.hxx + extensions/source/propctrlr/handlerhelper.cxx: + # Actually used + - com/sun/star/inspection/LineDescriptor.hpp + extensions/source/propctrlr/pcrunodialogs.cxx: + # Actually used + - com/sun/star/awt/XWindow.hpp + extensions/source/propctrlr/sqlcommanddesign.cxx: + # Actually used + - com/sun/star/sdbc/XConnection.hpp + extensions/source/propctrlr/xsddatatypes.cxx: + # Actually used + - com/sun/star/xsd/XDataType.hpp + extensions/source/propctrlr/submissionhandler.cxx: + # Actually used + - com/sun/star/inspection/XObjectInspectorUI.hpp + extensions/source/propctrlr/selectlabeldialog.cxx: + # Actually used + - com/sun/star/beans/XPropertySet.hpp + extensions/source/propctrlr/xsdvalidationhelper.cxx: + # Actually used + - com/sun/star/xforms/XDataTypeRepository.hpp + extensions/source/propctrlr/xsdvalidationpropertyhandler.cxx: + # Actually used + - com/sun/star/inspection/XObjectInspectorUI.hpp + extensions/source/scanner/grid.cxx: + # Needed for rtl::math::expm1 + - rtl/math.hxx diff --git a/extensions/JunitTest_extensions_unoapi.mk b/extensions/JunitTest_extensions_unoapi.mk new file mode 100644 index 000000000..1320bf56d --- /dev/null +++ b/extensions/JunitTest_extensions_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,extensions_unoapi)) + +$(eval $(call gb_JunitTest_set_unoapi_test_defaults,extensions_unoapi)) + +# vim: set noet sw=4 ts=4: diff --git a/extensions/Library_OOoSpotlightImporter.mk b/extensions/Library_OOoSpotlightImporter.mk new file mode 100644 index 000000000..ac55f1eac --- /dev/null +++ b/extensions/Library_OOoSpotlightImporter.mk @@ -0,0 +1,30 @@ +# -*- 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_Bundle,OOoSpotlightImporter)) + +$(eval $(call gb_Library_add_objcobjects,OOoSpotlightImporter,\ + extensions/source/macosx/spotlight/GetMetadataForFile \ + extensions/source/macosx/spotlight/OOoContentDataParser \ + extensions/source/macosx/spotlight/OOoMetaDataParser \ + extensions/source/macosx/spotlight/OOoSpotlightImporter \ + extensions/source/macosx/spotlight/main \ +)) + +$(eval $(call gb_Library_use_system_darwin_frameworks,OOoSpotlightImporter,\ + CoreFoundation \ + Foundation \ + CoreServices \ +)) + +$(eval $(call gb_Library_use_external,OOoSpotlightImporter,zlib)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_WinUserInfoBe.mk b/extensions/Library_WinUserInfoBe.mk new file mode 100644 index 000000000..3e20e0941 --- /dev/null +++ b/extensions/Library_WinUserInfoBe.mk @@ -0,0 +1,42 @@ +# -*- 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,WinUserInfoBe)) + +$(eval $(call gb_Library_set_componentfile,WinUserInfoBe,extensions/source/config/WinUserInfo/WinUserInfoBe,services)) + +$(eval $(call gb_Library_use_custom_headers,WinUserInfoBe,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_use_sdk_api,WinUserInfoBe)) + +$(eval $(call gb_Library_add_exception_objects,WinUserInfoBe,\ + extensions/source/config/WinUserInfo/WinUserInfoBe \ +)) + +$(eval $(call gb_Library_use_libraries,WinUserInfoBe,\ + comphelper \ + cppuhelper \ + cppu \ + sal \ + tl \ +)) + +$(eval $(call gb_Library_use_system_win32_libs,WinUserInfoBe,\ + Ole32 \ + OleAut32 \ + Activeds \ + Adsiid \ + Secur32 \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_abp.mk b/extensions/Library_abp.mk new file mode 100644 index 000000000..85d0942ef --- /dev/null +++ b/extensions/Library_abp.mk @@ -0,0 +1,58 @@ +# -*- 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,abp)) + +$(eval $(call gb_Library_set_componentfile,abp,extensions/source/abpilot/abp,services)) + +$(eval $(call gb_Library_set_include,abp,\ + $$(INCLUDE) \ + -I$(SRCDIR)/extensions/inc \ + -I$(SRCDIR)/extensions/source/inc \ +)) + +$(eval $(call gb_Library_use_external,abp,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,abp)) + +$(eval $(call gb_Library_add_exception_objects,abp,\ + extensions/source/abpilot/abpfinalpage \ + extensions/source/abpilot/abspage \ + extensions/source/abpilot/abspilot \ + extensions/source/abpilot/admininvokationimpl \ + extensions/source/abpilot/admininvokationpage \ + extensions/source/abpilot/datasourcehandling \ + extensions/source/abpilot/fieldmappingimpl \ + extensions/source/abpilot/fieldmappingpage \ + extensions/source/abpilot/moduleabp \ + extensions/source/abpilot/tableselectionpage \ + extensions/source/abpilot/typeselectionpage \ + extensions/source/abpilot/unodialogabp \ +)) + +$(eval $(call gb_Library_use_libraries,abp,\ + comphelper \ + cppuhelper \ + cppu \ + sal \ + sfx \ + svl \ + svt \ + svxcore \ + svx \ + tk \ + tl \ + utl \ + vcl \ + i18nlangtag \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_bib.mk b/extensions/Library_bib.mk new file mode 100644 index 000000000..147b8034f --- /dev/null +++ b/extensions/Library_bib.mk @@ -0,0 +1,58 @@ +# -*- 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,bib)) + +$(eval $(call gb_Library_set_componentfile,bib,extensions/source/bibliography/bib,services)) + +$(eval $(call gb_Library_set_include,bib,\ + $$(INCLUDE) \ + -I$(SRCDIR)/extensions/inc \ +)) + +$(eval $(call gb_Library_use_external,bib,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,bib)) + +$(eval $(call gb_Library_add_exception_objects,bib,\ + extensions/source/bibliography/bibbeam \ + extensions/source/bibliography/bibconfig \ + extensions/source/bibliography/bibcont \ + extensions/source/bibliography/bibload \ + extensions/source/bibliography/bibmod \ + extensions/source/bibliography/bibview \ + extensions/source/bibliography/datman \ + extensions/source/bibliography/formcontrolcontainer \ + extensions/source/bibliography/framectr \ + extensions/source/bibliography/general \ + extensions/source/bibliography/loadlisteneradapter \ + extensions/source/bibliography/toolbar \ +)) + +$(eval $(call gb_Library_use_libraries,bib,\ + dbtools \ + sfx \ + sot \ + svt \ + svl \ + tk \ + vcl \ + utl \ + tl \ + comphelper \ + cppuhelper \ + cppu \ + sal \ + salhelper \ + i18nlangtag \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_dbp.mk b/extensions/Library_dbp.mk new file mode 100644 index 000000000..ec5f75c12 --- /dev/null +++ b/extensions/Library_dbp.mk @@ -0,0 +1,55 @@ +# -*- 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,dbp)) + +$(eval $(call gb_Library_set_componentfile,dbp,extensions/source/dbpilots/dbp,services)) + +$(eval $(call gb_Library_set_include,dbp,\ + $$(INCLUDE) \ + -I$(SRCDIR)/extensions/inc \ + -I$(SRCDIR)/extensions/source/inc \ +)) + +$(eval $(call gb_Library_use_external,dbp,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,dbp)) + +$(eval $(call gb_Library_add_exception_objects,dbp,\ + extensions/source/dbpilots/commonpagesdbp \ + extensions/source/dbpilots/controlwizard \ + extensions/source/dbpilots/dbptools \ + extensions/source/dbpilots/gridwizard \ + extensions/source/dbpilots/groupboxwiz \ + extensions/source/dbpilots/listcombowizard \ + extensions/source/dbpilots/moduledbp \ + extensions/source/dbpilots/optiongrouplayouter \ + extensions/source/dbpilots/wizardservices \ +)) + +$(eval $(call gb_Library_use_libraries,dbp,\ + svt \ + vcl \ + tl \ + tk \ + svl \ + sfx \ + dbtools \ + utl \ + comphelper \ + cppuhelper \ + cppu \ + sal \ + salhelper \ + i18nlangtag \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_ldapbe2.mk b/extensions/Library_ldapbe2.mk new file mode 100644 index 000000000..58ea11b2d --- /dev/null +++ b/extensions/Library_ldapbe2.mk @@ -0,0 +1,63 @@ +# -*- 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,ldapbe2)) + +$(eval $(call gb_Library_set_componentfile,ldapbe2,extensions/source/config/ldap/ldapbe2,services)) + +$(eval $(call gb_Library_use_sdk_api,ldapbe2)) + +ifneq ($(OS),WNT) +$(eval $(call gb_Library_add_defs,ldapbe2,\ + -DLDAP_DEPRECATED \ +)) +endif + +$(eval $(call gb_Library_add_exception_objects,ldapbe2,\ + extensions/source/config/ldap/ldapaccess \ + extensions/source/config/ldap/ldapuserprofilebe \ +)) + +$(eval $(call gb_Library_use_libraries,ldapbe2,\ + comphelper \ + cppuhelper \ + cppu \ + salhelper \ + sal \ + tl \ +)) + +ifeq ($(OS),WNT) +$(eval $(call gb_Library_use_externals,ldapbe2,\ + boost_headers \ +)) +$(eval $(call gb_Library_use_system_win32_libs,ldapbe2,\ + wldap32 \ +)) +else # 0S!=WNT +$(eval $(call gb_Library_use_externals,ldapbe2,\ + boost_headers \ + openldap \ + nss3 \ + plc4 \ + ssl3 \ +)) +endif + + + +ifeq ($(OS),FREEBSD) +$(eval $(call gb_Library_add_libs,ldapbe2,\ + -lcompat \ +)) +endif # OS=FREEBSD + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_log.mk b/extensions/Library_log.mk new file mode 100644 index 000000000..edf42d35e --- /dev/null +++ b/extensions/Library_log.mk @@ -0,0 +1,40 @@ +# -*- 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,log)) + +$(eval $(call gb_Library_set_componentfile,log,extensions/source/logging/log,services)) + +$(eval $(call gb_Library_use_external,log,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,log)) + +$(eval $(call gb_Library_add_exception_objects,log,\ + extensions/source/logging/consolehandler \ + extensions/source/logging/csvformatter \ + extensions/source/logging/filehandler \ + extensions/source/logging/logger \ + extensions/source/logging/loggerconfig \ + extensions/source/logging/loghandler \ + extensions/source/logging/logrecord \ + extensions/source/logging/plaintextformatter \ + extensions/source/logging/simpletextformatter \ +)) + +$(eval $(call gb_Library_use_libraries,log,\ + comphelper \ + cppuhelper \ + cppu \ + sal \ + tl \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_oleautobridge.mk b/extensions/Library_oleautobridge.mk new file mode 100644 index 000000000..aa6c6d0cf --- /dev/null +++ b/extensions/Library_oleautobridge.mk @@ -0,0 +1,65 @@ +# -*- 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,oleautobridge)) + +$(eval $(call gb_Library_set_componentfile,oleautobridge,extensions/source/ole/oleautobridge,services)) + +$(eval $(call gb_Library_use_api,oleautobridge,\ + offapi \ + oovbaapi \ + udkapi \ +)) + +$(eval $(call gb_Library_set_include,oleautobridge,\ + $(foreach inc,$(ATL_INCLUDE),-I$(inc)) \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Library_add_ldflags,oleautobridge,\ + -LIBPATH:$(ATL_LIB) \ +)) + +$(eval $(call gb_Library_use_external,oleautobridge,boost_headers)) + +$(eval $(call gb_Library_use_libraries,oleautobridge,\ + comphelper \ + cppuhelper \ + cppu \ + sal \ +)) + +$(eval $(call gb_Library_use_system_win32_libs,oleautobridge,\ + advapi32 \ + ole32 \ + oleaut32 \ + uuid \ +)) + +ifeq ($(COM),MSC) +$(eval $(call gb_Library_add_libs,oleautobridge,\ + $(ATL_LIB)/atls.lib \ +)) +endif + +$(eval $(call gb_Library_add_exception_objects,oleautobridge,\ + extensions/source/ole/jscriptclasses \ + extensions/source/ole/ole2uno \ + extensions/source/ole/oledll \ + extensions/source/ole/oleobjw \ + extensions/source/ole/olethread \ + extensions/source/ole/servprov \ + extensions/source/ole/servreg \ + extensions/source/ole/unoobjw \ + extensions/source/ole/unotypewrapper \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_pcr.mk b/extensions/Library_pcr.mk new file mode 100644 index 000000000..14187b960 --- /dev/null +++ b/extensions/Library_pcr.mk @@ -0,0 +1,102 @@ +# -*- 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,pcr)) + +$(eval $(call gb_Library_set_componentfile,pcr,extensions/source/propctrlr/pcr,services)) + +$(eval $(call gb_Library_use_sdk_api,pcr)) + +$(eval $(call gb_Library_set_include,pcr,\ + -I$(SRCDIR)/extensions/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Library_use_common_precompiled_header,pcr)) + +$(eval $(call gb_Library_use_external,pcr,boost_headers)) + +$(eval $(call gb_Library_use_libraries,pcr,\ + svx \ + svxcore \ + editeng \ + sfx \ + svt \ + tk \ + vcl \ + svl \ + utl \ + tl \ + dbtools \ + i18nlangtag \ + comphelper \ + cppuhelper \ + cppu \ + sal \ + salhelper \ +)) + +$(eval $(call gb_Library_add_exception_objects,pcr,\ + extensions/source/propctrlr/MasterDetailLinkDialog \ + extensions/source/propctrlr/browserline \ + extensions/source/propctrlr/browserlistbox \ + extensions/source/propctrlr/browserpage \ + extensions/source/propctrlr/browserview \ + extensions/source/propctrlr/buttonnavigationhandler \ + extensions/source/propctrlr/cellbindinghandler \ + extensions/source/propctrlr/cellbindinghelper \ + extensions/source/propctrlr/commoncontrol \ + extensions/source/propctrlr/composeduiupdate \ + extensions/source/propctrlr/controlfontdialog \ + extensions/source/propctrlr/defaultforminspection \ + extensions/source/propctrlr/defaulthelpprovider \ + extensions/source/propctrlr/editpropertyhandler \ + extensions/source/propctrlr/eformshelper \ + extensions/source/propctrlr/eformspropertyhandler \ + extensions/source/propctrlr/eventhandler \ + extensions/source/propctrlr/fontdialog \ + extensions/source/propctrlr/formbrowsertools \ + extensions/source/propctrlr/formcomponenthandler \ + extensions/source/propctrlr/formcontroller \ + extensions/source/propctrlr/formgeometryhandler \ + extensions/source/propctrlr/formlinkdialog \ + extensions/source/propctrlr/formmetadata \ + extensions/source/propctrlr/genericpropertyhandler \ + extensions/source/propctrlr/handlerhelper \ + extensions/source/propctrlr/inspectorhelpwindow \ + extensions/source/propctrlr/inspectormodelbase \ + extensions/source/propctrlr/listselectiondlg \ + extensions/source/propctrlr/modulepcr \ + extensions/source/propctrlr/newdatatype \ + extensions/source/propctrlr/objectinspectormodel \ + extensions/source/propctrlr/pcrcommon \ + extensions/source/propctrlr/pcrunodialogs \ + extensions/source/propctrlr/propcontroller \ + extensions/source/propctrlr/propertycomposer \ + extensions/source/propctrlr/propertycontrolextender \ + extensions/source/propctrlr/propertyeditor \ + extensions/source/propctrlr/propertyhandler \ + extensions/source/propctrlr/propeventtranslation \ + extensions/source/propctrlr/pushbuttonnavigation \ + extensions/source/propctrlr/selectlabeldialog \ + extensions/source/propctrlr/sqlcommanddesign \ + extensions/source/propctrlr/standardcontrol \ + extensions/source/propctrlr/stringrepresentation \ + extensions/source/propctrlr/submissionhandler \ + extensions/source/propctrlr/taborder \ + extensions/source/propctrlr/unourl \ + extensions/source/propctrlr/usercontrol \ + extensions/source/propctrlr/xsddatatypes \ + extensions/source/propctrlr/xsdvalidationhelper \ + extensions/source/propctrlr/xsdvalidationpropertyhandler \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_scn.mk b/extensions/Library_scn.mk new file mode 100644 index 000000000..51c48fbfd --- /dev/null +++ b/extensions/Library_scn.mk @@ -0,0 +1,67 @@ +# -*- 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,scn)) + +$(eval $(call gb_Library_use_externals,scn,\ + boost_headers \ + $(if $(filter-out WNT,$(OS)),sane_headers) \ +)) + +$(eval $(call gb_Library_set_include,scn,\ + -I$(SRCDIR)/extensions/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Library_set_componentfile,scn,extensions/source/scanner/scn,services)) + +$(eval $(call gb_Library_use_sdk_api,scn)) + +$(eval $(call gb_Library_use_libraries,scn,\ + comphelper \ + cppu \ + cppuhelper \ + i18nlangtag \ + sal \ + $(if $(filter WNT,$(OS)),salhelper) \ + svt \ + $(if $(filter WNT,$(OS)),tk) \ + tl \ + utl \ + vcl \ +)) + +$(eval $(call gb_Library_add_exception_objects,scn,\ + extensions/source/scanner/scanner \ +)) + +ifeq ($(OS),WNT) +$(eval $(call gb_Library_add_exception_objects,scn,\ + extensions/source/scanner/scanwin \ +)) +else +ifneq ($(OS),WNT) + +$(eval $(call gb_Library_add_exception_objects,scn,\ + extensions/source/scanner/grid \ + extensions/source/scanner/sane \ + extensions/source/scanner/sanedlg \ + extensions/source/scanner/scanunx \ +)) +ifeq ($(OS),LINUX) +$(eval $(call gb_Library_add_libs,scn,\ + -ldl \ +)) +endif +endif +endif + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_so_activex.mk b/extensions/Library_so_activex.mk new file mode 100644 index 000000000..5fc012a0f --- /dev/null +++ b/extensions/Library_so_activex.mk @@ -0,0 +1,53 @@ +# -*- 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,so_activex)) + +$(eval $(call gb_Library_use_custom_headers,so_activex,extensions/source/activex/idl)) + +$(eval $(call gb_Library_set_include,so_activex,\ + $$(INCLUDE) \ + $(foreach i,$(ATL_INCLUDE), -I$(i)) \ +)) + +$(eval $(call gb_Library_use_sdk_api,so_activex)) + +$(eval $(call gb_Library_add_nativeres,so_activex,so_activex)) + +$(eval $(call gb_Library_add_exception_objects,so_activex,\ + extensions/source/activex/so_activex \ + extensions/source/activex/SOActiveX \ + extensions/source/activex/SOComWindowPeer \ + extensions/source/activex/SODispatchInterceptor \ + extensions/source/activex/SOActionsApproval \ + extensions/source/activex/StdAfx2 \ +)) + +$(eval $(call gb_Library_add_ldflags,so_activex,\ + /DEF:$(SRCDIR)/extensions/source/activex/so_activex.def \ + -LIBPATH:$(ATL_LIB) \ +)) + +$(eval $(call gb_Library_use_system_win32_libs,so_activex,\ + advapi32 \ + gdi32 \ + ole32 \ + oleaut32 \ + shlwapi \ + urlmon \ + uuid \ +)) + +$(eval $(call gb_Library_add_libs,so_activex,\ + $(ATL_LIB)/atls.lib \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_so_activex_x64.mk b/extensions/Library_so_activex_x64.mk new file mode 100644 index 000000000..047c1044f --- /dev/null +++ b/extensions/Library_so_activex_x64.mk @@ -0,0 +1,56 @@ +# -*- 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,so_activex_x64)) + +$(eval $(call gb_Library_set_x64,so_activex_x64,YES)) + +$(eval $(call gb_Library_use_custom_headers,so_activex_x64,extensions/source/activex/idl)) + +$(eval $(call gb_Library_set_include,so_activex_x64,\ + $$(INCLUDE) \ + -I$(SRCDIR)/extensions/source/activex \ + $(foreach i,$(ATL_INCLUDE), -I$(i)) \ +)) + +$(eval $(call gb_Library_use_sdk_api,so_activex_x64)) + +$(eval $(call gb_Library_add_nativeres,so_activex_x64,so_activex)) + +$(eval $(call gb_Library_add_x64_generated_exception_objects,so_activex_x64,\ + CustomTarget/extensions/source/activex/so_activex \ + CustomTarget/extensions/source/activex/SOActiveX \ + CustomTarget/extensions/source/activex/SOComWindowPeer \ + CustomTarget/extensions/source/activex/SODispatchInterceptor \ + CustomTarget/extensions/source/activex/SOActionsApproval \ + CustomTarget/extensions/source/activex/StdAfx2 \ +)) + +$(eval $(call gb_Library_add_ldflags,so_activex_x64,\ + /DEF:$(SRCDIR)/extensions/source/activex/so_activex.def \ + -LIBPATH:$(ATL_LIB)/amd64 \ +)) + +$(eval $(call gb_Library_use_system_win32_libs,so_activex_x64,\ + advapi32 \ + gdi32 \ + ole32 \ + oleaut32 \ + shlwapi \ + urlmon \ + uuid \ +)) + +$(eval $(call gb_Library_add_libs,so_activex_x64,\ + $(subst /x86,/x64,$(ATL_LIB)/atls.lib)) \ +) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_updatecheckui.mk b/extensions/Library_updatecheckui.mk new file mode 100644 index 000000000..d889defa8 --- /dev/null +++ b/extensions/Library_updatecheckui.mk @@ -0,0 +1,38 @@ +# -*- 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,updatecheckui)) + +$(eval $(call gb_Library_set_include,updatecheckui,\ + -I$(SRCDIR)/extensions/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_Library_set_componentfile,updatecheckui,extensions/source/update/ui/updchk,services)) + +$(eval $(call gb_Library_use_external,updatecheckui,boost_headers)) + +$(eval $(call gb_Library_use_sdk_api,updatecheckui)) + +$(eval $(call gb_Library_use_libraries,updatecheckui,\ + vcl \ + tl \ + utl \ + comphelper \ + cppuhelper \ + cppu \ + sal \ + i18nlangtag \ +)) + +$(eval $(call gb_Library_add_exception_objects,updatecheckui,\ + extensions/source/update/ui/updatecheckui \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_updatefeed.mk b/extensions/Library_updatefeed.mk new file mode 100644 index 000000000..5b9baa7b1 --- /dev/null +++ b/extensions/Library_updatefeed.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_Library_Library,updatefeed)) + +$(eval $(call gb_Library_set_componentfile,updatefeed,extensions/source/update/feed/updatefeed,services)) + +$(eval $(call gb_Library_use_externals,updatefeed, \ + boost_headers \ +)) + +$(eval $(call gb_Library_use_sdk_api,updatefeed)) + +$(eval $(call gb_Library_use_libraries,updatefeed,\ + cppuhelper \ + cppu \ + sal \ + vcl \ +)) + +$(eval $(call gb_Library_add_exception_objects,updatefeed,\ + extensions/source/update/feed/updatefeed \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Library_updchk.mk b/extensions/Library_updchk.mk new file mode 100644 index 000000000..bd05a3a26 --- /dev/null +++ b/extensions/Library_updchk.mk @@ -0,0 +1,57 @@ +# -*- 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,updchk)) + +$(eval $(call gb_Library_set_componentfile,updchk,extensions/source/update/check/updchk.uno,services)) + +$(eval $(call gb_Library_set_include,updchk,\ + $$(INCLUDE) \ + -I$(SRCDIR)/extensions/inc \ +)) + +$(eval $(call gb_Library_use_sdk_api,updchk)) + +$(eval $(call gb_Library_use_libraries,updchk,\ + cppuhelper \ + cppu \ + sal \ + salhelper \ + tl \ + utl \ + vcl \ +)) + +ifeq ($(OS),WNT) +$(eval $(call gb_Library_use_system_win32_libs,updchk,\ + ole32 \ + shell32 \ + wininet \ +)) + +$(eval $(call gb_Library_add_exception_objects,updchk,\ + extensions/source/update/check/onlinecheck \ +)) +endif # OS WNT + +$(eval $(call gb_Library_use_externals,updchk,\ + boost_headers \ + curl \ +)) + +$(eval $(call gb_Library_add_exception_objects,updchk,\ + extensions/source/update/check/download \ + extensions/source/update/check/updatecheck \ + extensions/source/update/check/updatecheckconfig \ + extensions/source/update/check/updatecheckjob \ + extensions/source/update/check/updatehdl \ + extensions/source/update/check/updateprotocol \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/Makefile b/extensions/Makefile new file mode 100644 index 000000000..0997e6284 --- /dev/null +++ b/extensions/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/extensions/Module_extensions.mk b/extensions/Module_extensions.mk new file mode 100644 index 000000000..8b3a20127 --- /dev/null +++ b/extensions/Module_extensions.mk @@ -0,0 +1,117 @@ +# -*- 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,extensions)) + +$(eval $(call gb_Module_add_l10n_targets,extensions,\ + AllLangMoTarget_pcr \ +)) + +ifeq (,$(DISABLE_DYNLOADING)) +$(eval $(call gb_Module_add_targets,extensions,\ + Library_abp \ + Library_scn \ + $(if $(filter WNT,$(OS)), \ + Library_WinUserInfoBe \ + $(if $(filter TRUE,$(BUILD_X86)),Executable_twain32shim) \ + ) \ + UIConfig_sabpilot \ + UIConfig_scanner \ +)) +endif + +ifneq ($(filter-out iOS,$(OS)),) +$(eval $(call gb_Module_add_targets,extensions,\ + Library_log \ +)) +endif + +ifeq ($(ENABLE_LDAP),TRUE) +$(eval $(call gb_Module_add_targets,extensions,\ + Library_ldapbe2 \ +)) +endif + +$(eval $(call gb_Module_add_targets,extensions,\ + Library_bib \ +)) + +$(eval $(call gb_Module_add_check_targets,extensions,\ + CppunitTest_extensions_bibliography \ +)) + +ifneq (,$(filter DBCONNECTIVITY,$(BUILD_TYPE))) +$(eval $(call gb_Module_add_targets,extensions,\ + Library_dbp \ + Library_pcr \ + UIConfig_sbibliography \ + UIConfig_spropctrlr \ +)) +endif + +ifneq (,$(filter DESKTOP,$(BUILD_TYPE))) +ifeq (,$(ENABLE_WASM_STRIP_BASIC_CALC_DRAW_MATH_IMPRESS)) +$(eval $(call gb_Module_add_targets,extensions,\ + Library_updatefeed \ +)) + +ifeq ($(ENABLE_ONLINE_UPDATE),TRUE) +$(eval $(call gb_Module_add_targets,extensions,\ + Configuration_updchk \ + Library_updatecheckui \ + Library_updchk \ +)) + +$(eval $(call gb_Module_add_check_targets,extensions,\ + CppunitTest_extensions_test_update \ +)) +endif +endif # !ENABLE_WASM_STRIP_BASIC_CALC_DRAW_MATH_IMPRESS +endif + +ifeq ($(OS),WNT) + +ifeq ($(COM),MSC) +$(eval $(call gb_Module_add_targets,extensions,\ + WinResTarget_activex \ + Library_so_activex \ + CustomTarget_so_activex_idl \ +)) + +ifeq ($(BUILD_X64),TRUE) +$(eval $(call gb_Module_add_targets,extensions,\ + CustomTarget_so_activex_x64 \ + Library_so_activex_x64 \ +)) +endif # BUILD_X64 +endif # COM=MSC + +$(eval $(call gb_Module_add_targets,extensions,\ + Library_oleautobridge \ +)) + +# $(eval $(call gb_Module_add_subsequentcheck_targets,extensions,\ +# CustomTarget_automationtest \ +# )) + +endif # WNT + +ifeq ($(OS),MACOSX) +$(eval $(call gb_Module_add_targets,extensions,\ + Library_OOoSpotlightImporter \ + Package_mdibundle \ + Package_OOoSpotlightImporter \ +)) +endif # OS=MACOSX + +$(eval $(call gb_Module_add_subsequentcheck_targets,extensions,\ + JunitTest_extensions_unoapi \ +)) + +# vim:set shiftwidth=4 softtabstop=4 noexpandtab: diff --git a/extensions/Package_OOoSpotlightImporter.mk b/extensions/Package_OOoSpotlightImporter.mk new file mode 100644 index 000000000..35cfa24dd --- /dev/null +++ b/extensions/Package_OOoSpotlightImporter.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_Package_Package,extensions_OOoSpotlightImporter,$(gb_Library_DLLDIR))) + +$(eval $(call gb_Package_add_file,extensions_OOoSpotlightImporter,Library/Spotlight/OOoSpotlightImporter.mdimporter/Contents/MacOS/OOoSpotlightImporter,$(call gb_Library_get_runtime_filename,OOoSpotlightImporter))) + +# vim: set noet sw=4 ts=4: diff --git a/extensions/Package_mdibundle.mk b/extensions/Package_mdibundle.mk new file mode 100644 index 000000000..88f70f211 --- /dev/null +++ b/extensions/Package_mdibundle.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_Package_Package,extensions_mdibundle,$(SRCDIR)/extensions/source/macosx/spotlight/mdimporter)) + +$(eval $(call gb_Package_add_files,extensions_mdibundle,Library/Spotlight/OOoSpotlightImporter.mdimporter/Contents,\ + Info.plist \ +)) + +$(eval $(call gb_Package_add_files,extensions_mdibundle,Library/Spotlight/OOoSpotlightImporter.mdimporter/Contents/Resources,\ + schema.xml \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/extensions/README.md b/extensions/README.md new file mode 100644 index 000000000..94cf2acbe --- /dev/null +++ b/extensions/README.md @@ -0,0 +1,51 @@ +# Miscellaneous Modules + +This module contains a grab-bag of unrelated miscellaneous libraries, *none* of +which is an extension. + +## Application Online Update Checking + +When we start LO, first `InitUpdateCheckJobThread` is created, via +`UpdateCheckJob::execute()` (from `extensions/source/update/check/updatecheckjob.cxx`), +as a reaction to a `onFirstVisibleTask` event. It waits 25 seconds (so that it +does not interfere with the startup itself), and then calls +`UpdateCheck::initialize()` (from `extensions/source/update/check/updatecheck.cxx`). + +This creates one more thread, `UpdateCheckThread`, that regularly checks whether +we have reached the time when we should ask for the update. If yes, asks for +that, and shows the download button in the menu (if the new update is +available). + +## OLE Automation Bridge + +A bridge between "OLE automation" and UNO, so you can use UNO services +from JScript, VBScript, etc. + + + +See `udkapi/com/sun/star/bridge/oleautomation/ApplicationRegistration.idl` + +This is initialized in `Desktop::Main()` in `Desktop::OpenClients_Impl()` +by creating the service `com.sun.star.bridge.OleApplicationRegistration`, +which is implemented by `OleServer_Impl`. + +See `extensions/source/ole/` + +## ActiveX Control + +This allows embedding LO into a Win32 application as an ActiveX control. + +See `extensions/source/activex/` + +## Spotlight Provider + +On macOS, this allows indexing ODF documents with Spotlight. + +See `extensions/source/macosx/spotlight/` + +## Scanner Support + +You can scan from LibreOffice, using platform specific backends like TWAIN/SANE. + +See `extensions/source/scanner/` + diff --git a/extensions/UIConfig_sabpilot.mk b/extensions/UIConfig_sabpilot.mk new file mode 100644 index 000000000..8dfe1462c --- /dev/null +++ b/extensions/UIConfig_sabpilot.mk @@ -0,0 +1,30 @@ +# -*- 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/sabpilot)) + +$(eval $(call gb_UIConfig_add_uifiles,modules/sabpilot,\ + extensions/uiconfig/sabpilot/ui/contentfieldpage \ + extensions/uiconfig/sabpilot/ui/contenttablepage \ + extensions/uiconfig/sabpilot/ui/datasourcepage \ + extensions/uiconfig/sabpilot/ui/defaultfieldselectionpage \ + extensions/uiconfig/sabpilot/ui/fieldassignpage \ + extensions/uiconfig/sabpilot/ui/fieldlinkpage \ + extensions/uiconfig/sabpilot/ui/gridfieldsselectionpage \ + extensions/uiconfig/sabpilot/ui/groupradioselectionpage \ + extensions/uiconfig/sabpilot/ui/invokeadminpage \ + extensions/uiconfig/sabpilot/ui/optiondbfieldpage \ + extensions/uiconfig/sabpilot/ui/optionsfinalpage \ + extensions/uiconfig/sabpilot/ui/optionvaluespage \ + extensions/uiconfig/sabpilot/ui/selecttablepage \ + extensions/uiconfig/sabpilot/ui/selecttypepage \ + extensions/uiconfig/sabpilot/ui/tableselectionpage \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/extensions/UIConfig_sbibliography.mk b/extensions/UIConfig_sbibliography.mk new file mode 100644 index 000000000..7b4056380 --- /dev/null +++ b/extensions/UIConfig_sbibliography.mk @@ -0,0 +1,27 @@ +# -*- 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/sbibliography)) + +$(eval $(call gb_UIConfig_add_menubarfiles,modules/sbibliography,\ + extensions/uiconfig/sbibliography/menubar/menubar \ +)) + +$(eval $(call gb_UIConfig_add_uifiles,modules/sbibliography,\ + extensions/uiconfig/sbibliography/ui/autofiltermenu \ + extensions/uiconfig/sbibliography/ui/choosedatasourcedialog \ + extensions/uiconfig/sbibliography/ui/combobox \ + extensions/uiconfig/sbibliography/ui/editbox \ + extensions/uiconfig/sbibliography/ui/generalpage \ + extensions/uiconfig/sbibliography/ui/querydialog \ + extensions/uiconfig/sbibliography/ui/mappingdialog \ + extensions/uiconfig/sbibliography/ui/toolbar \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/extensions/UIConfig_scanner.mk b/extensions/UIConfig_scanner.mk new file mode 100644 index 000000000..15ce9a4be --- /dev/null +++ b/extensions/UIConfig_scanner.mk @@ -0,0 +1,17 @@ +# -*- 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/scanner)) + +$(eval $(call gb_UIConfig_add_uifiles,modules/scanner,\ + extensions/uiconfig/scanner/ui/sanedialog \ + extensions/uiconfig/scanner/ui/griddialog \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/extensions/UIConfig_spropctrlr.mk b/extensions/UIConfig_spropctrlr.mk new file mode 100644 index 000000000..a07d7737d --- /dev/null +++ b/extensions/UIConfig_spropctrlr.mk @@ -0,0 +1,37 @@ +# -*- 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/spropctrlr)) + +$(eval $(call gb_UIConfig_add_uifiles,modules/spropctrlr,\ + extensions/uiconfig/spropctrlr/ui/browserline \ + extensions/uiconfig/spropctrlr/ui/browserpage \ + extensions/uiconfig/spropctrlr/ui/colorlistbox \ + extensions/uiconfig/spropctrlr/ui/combobox \ + extensions/uiconfig/spropctrlr/ui/controlfontdialog \ + extensions/uiconfig/spropctrlr/ui/datefield \ + extensions/uiconfig/spropctrlr/ui/datatypedialog \ + extensions/uiconfig/spropctrlr/ui/datetimefield \ + extensions/uiconfig/spropctrlr/ui/formlinksdialog \ + extensions/uiconfig/spropctrlr/ui/formattedcontrol \ + extensions/uiconfig/spropctrlr/ui/formattedsample \ + extensions/uiconfig/spropctrlr/ui/formproperties \ + extensions/uiconfig/spropctrlr/ui/hyperlinkfield \ + extensions/uiconfig/spropctrlr/ui/labelselectiondialog \ + extensions/uiconfig/spropctrlr/ui/listbox \ + extensions/uiconfig/spropctrlr/ui/listselectdialog \ + extensions/uiconfig/spropctrlr/ui/multiline \ + extensions/uiconfig/spropctrlr/ui/numericfield \ + extensions/uiconfig/spropctrlr/ui/taborder \ + extensions/uiconfig/spropctrlr/ui/textfield \ + extensions/uiconfig/spropctrlr/ui/timefield \ + extensions/uiconfig/spropctrlr/ui/urlcontrol \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/extensions/WinResTarget_activex.mk b/extensions/WinResTarget_activex.mk new file mode 100644 index 000000000..67980b877 --- /dev/null +++ b/extensions/WinResTarget_activex.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_WinResTarget_WinResTarget,so_activex)) + +$(eval $(call gb_WinResTarget_use_custom_headers,so_activex,\ + extensions/source/activex/idl \ +)) + +ifneq ($(ENABLE_DBGUTIL),TRUE) +$(eval $(call gb_WinResTarget_add_defs,so_activex,\ + -DPRODUCT \ +)) +endif + +$(eval $(call gb_WinResTarget_set_rcfile,so_activex,extensions/source/activex/so_activex)) + +$(eval $(call gb_WinResTarget_add_defs,so_activex,\ + $$(DEFS) \ + -DSO_ACTIVEX_TLB=\"$(subst /,"\\\\",$(WORKDIR)/CustomTarget/extensions/source/activex/idl/so_activex.tlb\") \ +)) + +# vim:set noet sw=4 ts=4: diff --git a/extensions/inc/bitmaps.hlst b/extensions/inc/bitmaps.hlst new file mode 100644 index 000000000..c282df088 --- /dev/null +++ b/extensions/inc/bitmaps.hlst @@ -0,0 +1,50 @@ +/* -*- 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_EXTENSIONS_INC_BITMAPS_HRC +#define INCLUDED_EXTENSIONS_INC_BITMAPS_HRC + +inline constexpr OUStringLiteral RID_EXTBMP_CONTROL = u"res/sx10144.png"; +inline constexpr OUStringLiteral RID_EXTBMP_BUTTON = u"res/sx10594.png"; +inline constexpr OUStringLiteral RID_EXTBMP_RADIOBUTTON = u"res/sx10595.png"; +inline constexpr OUStringLiteral RID_EXTBMP_CHECKBOX = u"res/sx10596.png"; +inline constexpr OUStringLiteral RID_EXTBMP_FIXEDTEXT = u"res/sx10597.png"; +inline constexpr OUStringLiteral RID_EXTBMP_GROUPBOX = u"res/sx10598.png"; +inline constexpr OUStringLiteral RID_EXTBMP_EDITBOX = u"res/sx10599.png"; +inline constexpr OUStringLiteral RID_EXTBMP_LISTBOX = u"res/sx10600.png"; +inline constexpr OUStringLiteral RID_EXTBMP_COMBOBOX = u"res/sx10601.png"; +inline constexpr OUStringLiteral RID_EXTBMP_GRID = u"res/sx10603.png"; +inline constexpr OUStringLiteral RID_EXTBMP_IMAGEBUTTON = u"res/sx10604.png"; +inline constexpr OUStringLiteral RID_EXTBMP_FILECONTROL = u"res/sx10605.png"; +inline constexpr OUStringLiteral RID_EXTBMP_DATEFIELD = u"res/sx10704.png"; +inline constexpr OUStringLiteral RID_EXTBMP_TIMEFIELD = u"res/sx10705.png"; +inline constexpr OUStringLiteral RID_EXTBMP_NUMERICFIELD = u"res/sx10706.png"; +inline constexpr OUStringLiteral RID_EXTBMP_CURRENCYFIELD = u"res/sx10707.png"; +inline constexpr OUStringLiteral RID_EXTBMP_PATTERNFIELD = u"res/sx10708.png"; +inline constexpr OUStringLiteral RID_EXTBMP_IMAGECONTROL = u"res/sx10710.png"; +inline constexpr OUStringLiteral RID_EXTBMP_HIDDEN = u"res/sx18022.png"; +inline constexpr OUStringLiteral RID_EXTBMP_FORMS = u"res/sx18013.png"; +inline constexpr OUStringLiteral RID_EXTBMP_FORM = u"res/sx10593.png"; +inline constexpr OUStringLiteral RID_EXTBMP_SCROLLBAR = u"res/sx10768.png"; +inline constexpr OUStringLiteral RID_EXTBMP_SPINBUTTON = u"res/sx10769.png"; +inline constexpr OUStringLiteral RID_EXTBMP_NAVIGATIONBAR = u"res/sx10607.png"; +inline constexpr OUStringLiteral RID_SCANNER_HANDLE = u"extensions/res/scanner/handle.png"; +inline constexpr OUStringLiteral BMP_TABLE = u"res/sx03188.png"; +inline constexpr OUStringLiteral BMP_QUERY = u"res/sx03202.png"; +inline constexpr OUStringLiteral RID_EXTBMP_AUTOFILTER_SC = u"res/sc10716.png"; +inline constexpr OUStringLiteral RID_EXTBMP_FILTERCRIT_SC = u"res/sc10715.png"; +inline constexpr OUStringLiteral RID_EXTBMP_REMOVE_FILTER_SORT_SC = u"res/sc10711.png"; +inline constexpr OUStringLiteral RID_EXTBMP_AUTOFILTER_LC = u"res/lc10716.png"; +inline constexpr OUStringLiteral RID_EXTBMP_FILTERCRIT_LC = u"res/lc10715.png"; +inline constexpr OUStringLiteral RID_EXTBMP_REMOVE_FILTER_SORT_LC = u"res/lc10711.png"; +#define SV_RESID_BITMAP_INFOBOX "vcl/res/infobox.png" + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/extensions/inc/command.hrc b/extensions/inc/command.hrc new file mode 100644 index 000000000..ca05f1c4e --- /dev/null +++ b/extensions/inc/command.hrc @@ -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_EXTENSIONS_INC_COMMAND_HRC +#define INCLUDED_EXTENSIONS_INC_COMMAND_HRC + +#include + +#define NC_(Context, String) TranslateId(Context, reinterpret_cast(u8##String)) + +namespace { + +const TranslateId RID_RSC_ENUM_COMMAND_TYPE[] = +{ + NC_("RID_RSC_ENUM_COMMAND_TYPE", "Table"), + NC_("RID_RSC_ENUM_COMMAND_TYPE", "Query"), + NC_("RID_RSC_ENUM_COMMAND_TYPE", "SQL command") +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/inc/helpids.h b/extensions/inc/helpids.h new file mode 100644 index 000000000..48a623dd1 --- /dev/null +++ b/extensions/inc/helpids.h @@ -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 EXTENSIONS_HELPIDS_H +#define EXTENSIONS_HELPIDS_H + +#include + +inline constexpr OStringLiteral HID_ABSPILOT_PREVIOUS = "EXTENSIONS_HID_ABSPILOT_PREVIOUS"; +inline constexpr OStringLiteral HID_ABSPILOT_NEXT = "EXTENSIONS_HID_ABSPILOT_NEXT"; +inline constexpr OStringLiteral HID_ABSPILOT_CANCEL = "EXTENSIONS_HID_ABSPILOT_CANCEL"; +inline constexpr OStringLiteral HID_ABSPILOT_FINISH = "EXTENSIONS_HID_ABSPILOT_FINISH"; +inline constexpr OStringLiteral UID_ABSPILOT_HELP = "EXTENSIONS_UID_ABSPILOT_HELP"; +inline constexpr OStringLiteral HID_ABSPILOT = "EXTENSIONS_HID_ABSPILOT"; + +inline constexpr OStringLiteral HID_BIB_IDENTIFIER_POS = "EXTENSIONS_HID_BIB_IDENTIFIER_POS"; +inline constexpr OStringLiteral HID_BIB_AUTHORITYTYPE_POS = "EXTENSIONS_HID_BIB_AUTHORITYTYPE_POS"; +inline constexpr OStringLiteral HID_BIB_AUTHOR_POS = "EXTENSIONS_HID_BIB_AUTHOR_POS"; +inline constexpr OStringLiteral HID_BIB_TITLE_POS = "EXTENSIONS_HID_BIB_TITLE_POS"; +inline constexpr OStringLiteral HID_BIB_YEAR_POS = "EXTENSIONS_HID_BIB_YEAR_POS"; +inline constexpr OStringLiteral HID_BIB_ISBN_POS = "EXTENSIONS_HID_BIB_ISBN_POS"; +inline constexpr OStringLiteral HID_BIB_BOOKTITLE_POS = "EXTENSIONS_HID_BIB_BOOKTITLE_POS"; +inline constexpr OStringLiteral HID_BIB_CHAPTER_POS = "EXTENSIONS_HID_BIB_CHAPTER_POS"; +inline constexpr OStringLiteral HID_BIB_EDITION_POS = "EXTENSIONS_HID_BIB_EDITION_POS"; +inline constexpr OStringLiteral HID_BIB_EDITOR_POS = "EXTENSIONS_HID_BIB_EDITOR_POS"; +inline constexpr OStringLiteral HID_BIB_HOWPUBLISHED_POS = "EXTENSIONS_HID_BIB_HOWPUBLISHED_POS"; +inline constexpr OStringLiteral HID_BIB_INSTITUTION_POS = "EXTENSIONS_HID_BIB_INSTITUTION_POS"; +inline constexpr OStringLiteral HID_BIB_JOURNAL_POS = "EXTENSIONS_HID_BIB_JOURNAL_POS"; +inline constexpr OStringLiteral HID_BIB_MONTH_POS = "EXTENSIONS_HID_BIB_MONTH_POS"; +inline constexpr OStringLiteral HID_BIB_NOTE_POS = "EXTENSIONS_HID_BIB_NOTE_POS"; +inline constexpr OStringLiteral HID_BIB_ANNOTE_POS = "EXTENSIONS_HID_BIB_ANNOTE_POS"; +inline constexpr OStringLiteral HID_BIB_NUMBER_POS = "EXTENSIONS_HID_BIB_NUMBER_POS"; +inline constexpr OStringLiteral HID_BIB_ORGANIZATIONS_POS = "EXTENSIONS_HID_BIB_ORGANIZATIONS_POS"; +inline constexpr OStringLiteral HID_BIB_PAGES_POS = "EXTENSIONS_HID_BIB_PAGES_POS"; +inline constexpr OStringLiteral HID_BIB_PUBLISHER_POS = "EXTENSIONS_HID_BIB_PUBLISHER_POS"; +inline constexpr OStringLiteral HID_BIB_ADDRESS_POS = "EXTENSIONS_HID_BIB_ADDRESS_POS"; +inline constexpr OStringLiteral HID_BIB_SCHOOL_POS = "EXTENSIONS_HID_BIB_SCHOOL_POS"; +inline constexpr OStringLiteral HID_BIB_SERIES_POS = "EXTENSIONS_HID_BIB_SERIES_POS"; +inline constexpr OStringLiteral HID_BIB_REPORTTYPE_POS = "EXTENSIONS_HID_BIB_REPORTTYPE_POS"; +inline constexpr OStringLiteral HID_BIB_VOLUME_POS = "EXTENSIONS_HID_BIB_VOLUME_POS"; +inline constexpr OStringLiteral HID_BIB_URL_POS = "EXTENSIONS_HID_BIB_URL_POS"; +inline constexpr OStringLiteral HID_BIB_CUSTOM1_POS = "EXTENSIONS_HID_BIB_CUSTOM1_POS"; +inline constexpr OStringLiteral HID_BIB_CUSTOM2_POS = "EXTENSIONS_HID_BIB_CUSTOM2_POS"; +inline constexpr OStringLiteral HID_BIB_CUSTOM3_POS = "EXTENSIONS_HID_BIB_CUSTOM3_POS"; +inline constexpr OStringLiteral HID_BIB_CUSTOM4_POS = "EXTENSIONS_HID_BIB_CUSTOM4_POS"; +inline constexpr OStringLiteral HID_BIB_CUSTOM5_POS = "EXTENSIONS_HID_BIB_CUSTOM5_POS"; +inline constexpr OStringLiteral HID_BIB_LOCAL_URL_POS = "EXTENSIONS_HID_BIB_LOCAL_URL_POS"; +#define HID_BIB_DB_GRIDCTRL "EXTENSIONS_HID_BIB_DB_GRIDCTRL" + +inline constexpr OStringLiteral HID_GROUPWIZARD_PREVIOUS = "EXTENSIONS_HID_GROUPWIZARD_PREVIOUS"; +inline constexpr OStringLiteral HID_GROUPWIZARD_NEXT = "EXTENSIONS_HID_GROUPWIZARD_NEXT"; +inline constexpr OStringLiteral HID_GROUPWIZARD_CANCEL = "EXTENSIONS_HID_GROUPWIZARD_CANCEL"; +inline constexpr OStringLiteral HID_GROUPWIZARD_FINISH = "EXTENSIONS_HID_GROUPWIZARD_FINISH"; +inline constexpr OStringLiteral HID_LISTWIZARD_PREVIOUS = "EXTENSIONS_HID_LISTWIZARD_PREVIOUS"; +inline constexpr OStringLiteral HID_LISTWIZARD_NEXT = "EXTENSIONS_HID_LISTWIZARD_NEXT"; +inline constexpr OStringLiteral HID_LISTWIZARD_CANCEL = "EXTENSIONS_HID_LISTWIZARD_CANCEL"; +inline constexpr OStringLiteral HID_LISTWIZARD_FINISH = "EXTENSIONS_HID_LISTWIZARD_FINISH"; +inline constexpr OStringLiteral HID_GRIDWIZARD_PREVIOUS = "EXTENSIONS_HID_GRIDWIZARD_PREVIOUS"; +inline constexpr OStringLiteral HID_GRIDWIZARD_NEXT = "EXTENSIONS_HID_GRIDWIZARD_NEXT"; +inline constexpr OStringLiteral HID_GRIDWIZARD_CANCEL = "EXTENSIONS_HID_GRIDWIZARD_CANCEL"; +inline constexpr OStringLiteral HID_GRIDWIZARD_FINISH = "EXTENSIONS_HID_GRIDWIZARD_FINISH"; + +inline constexpr OUStringLiteral HID_PROP_INPUT_REQUIRED = u"EXTENSIONS_HID_PROP_INPUT_REQUIRED"; +inline constexpr OUStringLiteral HID_PROP_CONTROLSOURCE = u"EXTENSIONS_HID_PROP_CONTROLSOURCE"; +inline constexpr OUStringLiteral HID_PROP_NAME = u"EXTENSIONS_HID_PROP_NAME"; +inline constexpr OUStringLiteral HID_PROP_TABINDEX = u"EXTENSIONS_HID_PROP_TABINDEX"; +inline constexpr OUStringLiteral HID_PROP_MASTERFIELDS = u"EXTENSIONS_HID_PROP_MASTERFIELDS"; +inline constexpr OUStringLiteral HID_PROP_SLAVEFIELDS = u"EXTENSIONS_HID_PROP_SLAVEFIELDS"; +inline constexpr OUStringLiteral HID_PROP_DATASOURCE = u"EXTENSIONS_HID_PROP_DATASOURCE"; +inline constexpr OUStringLiteral HID_PROP_CURSORSOURCE = u"EXTENSIONS_HID_PROP_CURSORSOURCE"; +inline constexpr OUStringLiteral HID_PROP_CURSORSOURCETYPE = u"EXTENSIONS_HID_PROP_CURSORSOURCETYPE"; +inline constexpr OUStringLiteral HID_PROP_READONLY = u"EXTENSIONS_HID_PROP_READONLY"; +inline constexpr OUStringLiteral HID_PROP_DATAENTRY = u"EXTENSIONS_HID_PROP_DATAENTRY"; +inline constexpr OUStringLiteral HID_PROP_NAVIGATION = u"EXTENSIONS_HID_PROP_NAVIGATION"; +inline constexpr OUStringLiteral HID_PROP_CYCLE = u"EXTENSIONS_HID_PROP_CYCLE"; +inline constexpr OUStringLiteral HID_PROP_ALLOW_ADDITIONS = u"EXTENSIONS_HID_PROP_ALLOW_ADDITIONS"; +inline constexpr OUStringLiteral HID_PROP_ALLOW_EDITS = u"EXTENSIONS_HID_PROP_ALLOW_EDITS"; +inline constexpr OUStringLiteral HID_PROP_ALLOW_DELETIONS = u"EXTENSIONS_HID_PROP_ALLOW_DELETIONS"; +inline constexpr OUStringLiteral HID_PROP_VALUE = u"EXTENSIONS_HID_PROP_VALUE"; +inline constexpr OUStringLiteral HID_PROP_FORMATKEY = u"EXTENSIONS_HID_PROP_FORMATKEY"; +inline constexpr OUStringLiteral HID_PROP_WHEEL_BEHAVIOR = u"EXTENSIONS_HID_PROP_WHEEL_BEHAVIOR"; +inline constexpr OUStringLiteral HID_PROP_HEIGHT = u"EXTENSIONS_HID_PROP_HEIGHT"; +inline constexpr OUStringLiteral HID_PROP_WIDTH = u"EXTENSIONS_HID_PROP_WIDTH"; +inline constexpr OUStringLiteral HID_PROP_AUTOGROW = u"EXTENSIONS_HID_PROP_AUTOGROW"; +inline constexpr OUStringLiteral HID_PROP_BOUNDCOLUMN = u"EXTENSIONS_HID_PROP_BOUNDCOLUMN"; +inline constexpr OUStringLiteral HID_PROP_LISTSOURCETYPE = u"EXTENSIONS_HID_PROP_LISTSOURCETYPE"; +inline constexpr OUStringLiteral HID_PROP_LISTSOURCE = u"EXTENSIONS_HID_PROP_LISTSOURCE"; +inline constexpr OUStringLiteral HID_PROP_LISTINDEX = u"EXTENSIONS_HID_PROP_LISTINDEX"; +inline constexpr OUStringLiteral HID_PROP_TEXT = u"EXTENSIONS_HID_PROP_TEXT"; +inline constexpr OUStringLiteral HID_PROP_LABEL = u"EXTENSIONS_HID_PROP_LABEL"; +inline constexpr OUStringLiteral HID_PROP_STRINGITEMLIST = u"EXTENSIONS_HID_PROP_STRINGITEMLIST"; +inline constexpr OUStringLiteral HID_PROP_FONT = u"EXTENSIONS_HID_PROP_FONT"; +inline constexpr OUStringLiteral HID_PROP_ROWHEIGHT = u"EXTENSIONS_HID_PROP_ROWHEIGHT"; +inline constexpr OUStringLiteral HID_PROP_BACKGROUNDCOLOR = u"EXTENSIONS_HID_PROP_BACKGROUNDCOLOR"; +inline constexpr OUStringLiteral HID_PROP_FILLCOLOR = u"EXTENSIONS_HID_PROP_FILLCOLOR"; +inline constexpr OUStringLiteral HID_PROP_LINECOLOR = u"EXTENSIONS_HID_PROP_LINECOLOR"; +inline constexpr OUStringLiteral HID_PROP_BORDER = u"EXTENSIONS_HID_PROP_BORDER"; +inline constexpr OUStringLiteral HID_PROP_ALIGN = u"EXTENSIONS_HID_PROP_ALIGN"; +inline constexpr OUStringLiteral HID_PROP_VERTICAL_ALIGN = u"EXTENSIONS_HID_PROP_VERTICAL_ALIGN"; +inline constexpr OUStringLiteral HID_PROP_DROPDOWN = u"EXTENSIONS_HID_PROP_DROPDOWN"; +inline constexpr OUStringLiteral HID_PROP_MULTILINE = u"EXTENSIONS_HID_PROP_MULTILINE"; +inline constexpr OUStringLiteral HID_PROP_HSCROLL = u"EXTENSIONS_HID_PROP_HSCROLL"; +inline constexpr OUStringLiteral HID_PROP_VSCROLL = u"EXTENSIONS_HID_PROP_VSCROLL"; +inline constexpr OUStringLiteral HID_PROP_TABSTOP = u"EXTENSIONS_HID_PROP_TABSTOP"; +inline constexpr OUStringLiteral HID_PROP_REFVALUE = u"EXTENSIONS_HID_PROP_REFVALUE"; +inline constexpr OUStringLiteral HID_PROP_BUTTONTYPE = u"EXTENSIONS_HID_PROP_BUTTONTYPE"; +inline constexpr OUStringLiteral HID_PROP_SUBMIT_ACTION = u"EXTENSIONS_HID_PROP_SUBMIT_ACTION"; +inline constexpr OUStringLiteral HID_PROP_SUBMIT_METHOD = u"EXTENSIONS_HID_PROP_SUBMIT_METHOD"; +inline constexpr OUStringLiteral HID_PROP_SUBMIT_ENCODING = u"EXTENSIONS_HID_PROP_SUBMIT_ENCODING"; +inline constexpr OUStringLiteral HID_PROP_DEFAULTVALUE = u"EXTENSIONS_HID_PROP_DEFAULTVALUE"; +inline constexpr OUStringLiteral HID_PROP_SUBMIT_TARGET = u"EXTENSIONS_HID_PROP_SUBMIT_TARGET"; +inline constexpr OUStringLiteral HID_PROP_DEFAULT_STATE = u"EXTENSIONS_HID_PROP_DEFAULT_STATE"; +inline constexpr OUStringLiteral HID_PROP_IMAGE_URL = u"EXTENSIONS_HID_PROP_IMAGE_URL"; +inline constexpr OUStringLiteral HID_PROP_DEFAULT_SELECT_SEQ = u"EXTENSIONS_HID_PROP_DEFAULT_SELECT_SEQ"; +inline constexpr OUStringLiteral HID_PROP_MULTISELECTION = u"EXTENSIONS_HID_PROP_MULTISELECTION"; +inline constexpr OUStringLiteral HID_PROP_DATE = u"EXTENSIONS_HID_PROP_DATE"; +inline constexpr OUStringLiteral HID_PROP_DATEMIN = u"EXTENSIONS_HID_PROP_DATEMIN"; +inline constexpr OUStringLiteral HID_PROP_DATEMAX = u"EXTENSIONS_HID_PROP_DATEMAX"; +inline constexpr OUStringLiteral HID_PROP_DATEFORMAT = u"EXTENSIONS_HID_PROP_DATEFORMAT"; +inline constexpr OUStringLiteral HID_PROP_TIME = u"EXTENSIONS_HID_PROP_TIME"; +inline constexpr OUStringLiteral HID_PROP_TIMEMIN = u"EXTENSIONS_HID_PROP_TIMEMIN"; +inline constexpr OUStringLiteral HID_PROP_TIMEMAX = u"EXTENSIONS_HID_PROP_TIMEMAX"; +inline constexpr OUStringLiteral HID_PROP_TIMEFORMAT = u"EXTENSIONS_HID_PROP_TIMEFORMAT"; +inline constexpr OUStringLiteral HID_PROP_VALUEMIN = u"EXTENSIONS_HID_PROP_VALUEMIN"; +inline constexpr OUStringLiteral HID_PROP_VALUEMAX = u"EXTENSIONS_HID_PROP_VALUEMAX"; +inline constexpr OUStringLiteral HID_PROP_VALUESTEP = u"EXTENSIONS_HID_PROP_VALUESTEP"; +inline constexpr OUStringLiteral HID_PROP_CURRENCYSYMBOL = u"EXTENSIONS_HID_PROP_CURRENCYSYMBOL"; +inline constexpr OUStringLiteral HID_PROP_EDITMASK = u"EXTENSIONS_HID_PROP_EDITMASK"; +inline constexpr OUStringLiteral HID_PROP_LITERALMASK = u"EXTENSIONS_HID_PROP_LITERALMASK"; +inline constexpr OUStringLiteral HID_PROP_ENABLED = u"EXTENSIONS_HID_PROP_ENABLED"; +inline constexpr OUStringLiteral HID_PROP_AUTOCOMPLETE = u"EXTENSIONS_HID_PROP_AUTOCOMPLETE"; +inline constexpr OUStringLiteral HID_PROP_LINECOUNT = u"EXTENSIONS_HID_PROP_LINECOUNT"; +inline constexpr OUStringLiteral HID_PROP_MAXTEXTLEN = u"EXTENSIONS_HID_PROP_MAXTEXTLEN"; +inline constexpr OUStringLiteral HID_PROP_SPIN = u"EXTENSIONS_HID_PROP_SPIN"; +inline constexpr OUStringLiteral HID_PROP_STRICTFORMAT = u"EXTENSIONS_HID_PROP_STRICTFORMAT"; +inline constexpr OUStringLiteral HID_PROP_SHOWTHOUSANDSEP = u"EXTENSIONS_HID_PROP_SHOWTHOUSANDSEP"; +inline constexpr OUStringLiteral HID_PROP_PRINTABLE = u"EXTENSIONS_HID_PROP_PRINTABLE"; +inline constexpr OUStringLiteral HID_PROP_TARGET_URL = u"EXTENSIONS_HID_PROP_TARGET_URL"; +inline constexpr OUStringLiteral HID_PROP_TARGET_FRAME = u"EXTENSIONS_HID_PROP_TARGET_FRAME"; +inline constexpr OUStringLiteral HID_PROP_TAG = u"EXTENSIONS_HID_PROP_TAG"; +inline constexpr OUStringLiteral HID_PROP_ECHO_CHAR = u"EXTENSIONS_HID_PROP_ECHO_CHAR"; +inline constexpr OUStringLiteral HID_PROP_EMPTY_IS_NULL = u"EXTENSIONS_HID_PROP_EMPTY_IS_NULL"; +inline constexpr OUStringLiteral HID_PROP_DECIMAL_ACCURACY = u"EXTENSIONS_HID_PROP_DECIMAL_ACCURACY"; +inline constexpr OUStringLiteral HID_PROP_ENABLE_VISIBLE = u"EXTENSIONS_HID_PROP_ENABLE_VISIBLE"; +inline constexpr OUStringLiteral HID_PROP_DEFAULT_BUTTON = u"EXTENSIONS_HID_PROP_DEFAULT_BUTTON"; +inline constexpr OUStringLiteral HID_PROP_HIDDEN_VALUE = u"EXTENSIONS_HID_PROP_HIDDEN_VALUE"; +inline constexpr OUStringLiteral HID_PROP_TRISTATE = u"EXTENSIONS_HID_PROP_TRISTATE"; +inline constexpr OUStringLiteral HID_PROP_NAVIGATIONBAR = u"EXTENSIONS_HID_PROP_NAVIGATIONBAR"; +inline constexpr OUStringLiteral HID_PROP_FILTER = u"EXTENSIONS_HID_PROP_FILTER"; +inline constexpr OUStringLiteral HID_PROP_SORT_CRITERIA = u"EXTENSIONS_HID_PROP_SORT_CRITERIA"; +inline constexpr OUStringLiteral HID_PROP_DEFAULT_LONG_VALUE = u"EXTENSIONS_HID_PROP_DEFAULT_LONG_VALUE"; +inline constexpr OUStringLiteral HID_PROP_DEFAULT_TIME = u"EXTENSIONS_HID_PROP_DEFAULT_TIME"; +inline constexpr OUStringLiteral HID_PROP_DEFAULT_DATE = u"EXTENSIONS_HID_PROP_DEFAULT_DATE"; +inline constexpr OUStringLiteral HID_PROP_HELPTEXT = u"EXTENSIONS_HID_PROP_HELPTEXT"; +inline constexpr OUStringLiteral HID_PROP_HELPURL = u"EXTENSIONS_HID_PROP_HELPURL"; +inline constexpr OUStringLiteral HID_PROP_RECORDMARKER = u"EXTENSIONS_HID_PROP_RECORDMARKER"; +inline constexpr OUStringLiteral HID_PROP_FILTERPROPOSAL = u"EXTENSIONS_HID_PROP_FILTERPROPOSAL"; +inline constexpr OUStringLiteral HID_PROP_EFFECTIVEMIN = u"EXTENSIONS_HID_PROP_EFFECTIVEMIN"; +inline constexpr OUStringLiteral HID_PROP_EFFECTIVEMAX = u"EXTENSIONS_HID_PROP_EFFECTIVEMAX"; +inline constexpr OUStringLiteral HID_PROP_EFFECTIVEDEFAULT = u"EXTENSIONS_HID_PROP_EFFECTIVEDEFAULT"; +inline constexpr OUStringLiteral HID_PROP_CONTROLLABEL = u"EXTENSIONS_HID_PROP_CONTROLLABEL"; +inline constexpr OUStringLiteral HID_PROP_CURRSYM_POSITION = u"EXTENSIONS_HID_PROP_CURRSYM_POSITION"; +inline constexpr OUStringLiteral HID_PROP_ESCAPE_PROCESSING = u"EXTENSIONS_HID_PROP_ESCAPE_PROCESSING"; +inline constexpr OUStringLiteral HID_PROP_TITLE = u"EXTENSIONS_HID_PROP_TITLE"; +inline constexpr OUStringLiteral HID_PROP_STEP = u"EXTENSIONS_HID_PROP_STEP"; +inline constexpr OUStringLiteral HID_PROP_PROGRESSVALUE = u"EXTENSIONS_HID_PROP_PROGRESSVALUE"; +inline constexpr OUStringLiteral HID_PROP_PROGRESSVALUE_MIN = u"EXTENSIONS_HID_PROP_PROGRESSVALUE_MIN"; +inline constexpr OUStringLiteral HID_PROP_PROGRESSVALUE_MAX = u"EXTENSIONS_HID_PROP_PROGRESSVALUE_MAX"; +inline constexpr OUStringLiteral HID_PROP_SCROLLVALUE = u"EXTENSIONS_HID_PROP_SCROLLVALUE"; +inline constexpr OUStringLiteral HID_PROP_SCROLLVALUE_MAX = u"EXTENSIONS_HID_PROP_SCROLLVALUE_MAX"; +inline constexpr OUStringLiteral HID_PROP_SCROLL_WIDTH = u"EXTENSIONS_HID_PROP_SCROLL_WIDTH"; +inline constexpr OUStringLiteral HID_PROP_SCROLL_HEIGHT = u"EXTENSIONS_HID_PROP_SCROLL_HEIGHT"; +inline constexpr OUStringLiteral HID_PROP_SCROLL_TOP = u"EXTENSIONS_HID_PROP_SCROLL_TOP"; +inline constexpr OUStringLiteral HID_PROP_SCROLL_LEFT = u"EXTENSIONS_HID_PROP_SCROLL_LEFT"; +inline constexpr OUStringLiteral HID_PROP_LINEINCREMENT = u"EXTENSIONS_HID_PROP_LINEINCREMENT"; +inline constexpr OUStringLiteral HID_PROP_BLOCKINCREMENT = u"EXTENSIONS_HID_PROP_BLOCKINCREMENT"; +inline constexpr OUStringLiteral HID_PROP_VISIBLESIZE = u"EXTENSIONS_HID_PROP_VISIBLESIZE"; +inline constexpr OUStringLiteral HID_PROP_ORIENTATION = u"EXTENSIONS_HID_PROP_ORIENTATION"; +inline constexpr OUStringLiteral HID_PROP_POSITIONX = u"EXTENSIONS_HID_PROP_POSITIONX"; +inline constexpr OUStringLiteral HID_PROP_POSITIONY = u"EXTENSIONS_HID_PROP_POSITIONY"; +inline constexpr OUStringLiteral HID_PROP_PUSHBUTTONTYPE = u"EXTENSIONS_HID_PROP_PUSHBUTTONTYPE"; +inline constexpr OUStringLiteral HID_PROP_STATE = u"EXTENSIONS_HID_PROP_STATE"; +inline constexpr OUStringLiteral HID_PROP_SCALEIMAGE = u"EXTENSIONS_HID_PROP_SCALEIMAGE"; +inline constexpr OUStringLiteral HID_PROP_BOUND_CELL = u"EXTENSIONS_HID_PROP_BOUND_CELL"; +inline constexpr OUStringLiteral HID_PROP_LIST_CELL_RANGE = u"EXTENSIONS_HID_PROP_LIST_CELL_RANGE"; +inline constexpr OUStringLiteral HID_PROP_CELL_EXCHANGE_TYPE = u"EXTENSIONS_HID_PROP_CELL_EXCHANGE_TYPE"; +inline constexpr OUStringLiteral HID_PROP_SELECTEDITEMS = u"EXTENSIONS_HID_PROP_SELECTEDITEMS"; +inline constexpr OUStringLiteral HID_PROP_SCROLLVALUE_MIN = u"EXTENSIONS_HID_PROP_SCROLLVALUE_MIN"; +inline constexpr OUStringLiteral HID_PROP_DEFAULT_SCROLLVALUE = u"EXTENSIONS_HID_PROP_DEFAULT_SCROLLVALUE"; +inline constexpr OUStringLiteral HID_PROP_REPEAT_DELAY = u"EXTENSIONS_HID_PROP_REPEAT_DELAY"; +inline constexpr OUStringLiteral HID_PROP_SYMBOLCOLOR = u"EXTENSIONS_HID_PROP_SYMBOLCOLOR"; +inline constexpr OUStringLiteral HID_PROP_SPINVALUE = u"EXTENSIONS_HID_PROP_SPINVALUE"; +inline constexpr OUStringLiteral HID_PROP_SPINVALUE_MIN = u"EXTENSIONS_HID_PROP_SPINVALUE_MIN"; +inline constexpr OUStringLiteral HID_PROP_SPINVALUE_MAX = u"EXTENSIONS_HID_PROP_SPINVALUE_MAX"; +inline constexpr OUStringLiteral HID_PROP_DEFAULT_SPINVALUE = u"EXTENSIONS_HID_PROP_DEFAULT_SPINVALUE"; +inline constexpr OUStringLiteral HID_PROP_SPININCREMENT = u"EXTENSIONS_HID_PROP_SPININCREMENT"; +inline constexpr OUStringLiteral HID_PROP_REPEAT = u"EXTENSIONS_HID_PROP_REPEAT"; +inline constexpr OUStringLiteral HID_PROP_WORDBREAK = u"EXTENSIONS_HID_PROP_WORDBREAK"; +inline constexpr OUStringLiteral HID_PROP_SHOW_SCROLLBARS = u"EXTENSIONS_HID_PROP_SHOW_SCROLLBARS"; +inline constexpr OUStringLiteral HID_PROP_ICONSIZE = u"EXTENSIONS_HID_PROP_ICONSIZE"; +inline constexpr OUStringLiteral HID_PROP_SHOW_POSITION = u"EXTENSIONS_HID_PROP_SHOW_POSITION"; +inline constexpr OUStringLiteral HID_PROP_SHOW_NAVIGATION = u"EXTENSIONS_HID_PROP_SHOW_NAVIGATION"; +inline constexpr OUStringLiteral HID_PROP_SHOW_RECORDACTIONS = u"EXTENSIONS_HID_PROP_SHOW_RECORDACTIONS"; +inline constexpr OUStringLiteral HID_PROP_SHOW_FILTERSORT = u"EXTENSIONS_HID_PROP_SHOW_FILTERSORT"; +inline constexpr OUStringLiteral HID_PROP_TEXTTYPE = u"EXTENSIONS_HID_PROP_TEXTTYPE"; +inline constexpr OUStringLiteral HID_PROP_LINEEND_FORMAT = u"EXTENSIONS_HID_PROP_LINEEND_FORMAT"; +inline constexpr OUStringLiteral HID_PROP_XSD_TOTAL_DIGITS = u"EXTENSIONS_HID_PROP_XSD_TOTAL_DIGITS"; +inline constexpr OUStringLiteral HID_PROP_XSD_FRACTION_DIGITS = u"EXTENSIONS_HID_PROP_XSD_FRACTION_DIGITS"; +inline constexpr OUStringLiteral HID_PROP_XSD_MAX_INCLUSIVE = u"EXTENSIONS_HID_PROP_XSD_MAX_INCLUSIVE"; +inline constexpr OUStringLiteral HID_PROP_XSD_MAX_EXCLUSIVE = u"EXTENSIONS_HID_PROP_XSD_MAX_EXCLUSIVE"; +inline constexpr OUStringLiteral HID_PROP_XSD_MIN_INCLUSIVE = u"EXTENSIONS_HID_PROP_XSD_MIN_INCLUSIVE"; +inline constexpr OUStringLiteral HID_PROP_XSD_MIN_EXCLUSIVE = u"EXTENSIONS_HID_PROP_XSD_MIN_EXCLUSIVE"; +inline constexpr OUStringLiteral HID_PROP_UNCHECKEDREFVALUE = u"EXTENSIONS_HID_PROP_UNCHECKEDREFVALUE"; +inline constexpr OUStringLiteral HID_PROP_SUBMISSION_ID = u"EXTENSIONS_HID_PROP_SUBMISSION_ID"; +inline constexpr OUStringLiteral HID_PROP_XML_DATA_MODEL = u"EXTENSIONS_HID_PROP_XML_DATA_MODEL"; +inline constexpr OUStringLiteral HID_PROP_BIND_EXPRESSION = u"EXTENSIONS_HID_PROP_BIND_EXPRESSION"; +inline constexpr OUStringLiteral HID_PROP_XSD_REQUIRED = u"EXTENSIONS_HID_PROP_XSD_REQUIRED"; +inline constexpr OUStringLiteral HID_PROP_XSD_RELEVANT = u"EXTENSIONS_HID_PROP_XSD_RELEVANT"; +inline constexpr OUStringLiteral HID_PROP_XSD_READONLY = u"EXTENSIONS_HID_PROP_XSD_READONLY"; +inline constexpr OUStringLiteral HID_PROP_XSD_CONSTRAINT = u"EXTENSIONS_HID_PROP_XSD_CONSTRAINT"; +inline constexpr OUStringLiteral HID_PROP_XSD_CALCULATION = u"EXTENSIONS_HID_PROP_XSD_CALCULATION"; +inline constexpr OUStringLiteral HID_PROP_XSD_DATA_TYPE = u"EXTENSIONS_HID_PROP_XSD_DATA_TYPE"; +inline constexpr OUStringLiteral HID_PROP_XSD_WHITESPACES = u"EXTENSIONS_HID_PROP_XSD_WHITESPACES"; +inline constexpr OUStringLiteral HID_PROP_URL = u"EXTENSIONS_HID_PROP_URL"; +inline constexpr OUStringLiteral HID_PROP_XSD_PATTERN = u"EXTENSIONS_HID_PROP_XSD_PATTERN"; +inline constexpr OUStringLiteral HID_PROP_XSD_LENGTH = u"EXTENSIONS_HID_PROP_XSD_LENGTH"; +inline constexpr OUStringLiteral HID_PROP_XSD_MIN_LENGTH = u"EXTENSIONS_HID_PROP_XSD_MIN_LENGTH"; +inline constexpr OUStringLiteral HID_PROP_XSD_MAX_LENGTH = u"EXTENSIONS_HID_PROP_XSD_MAX_LENGTH"; +inline constexpr OUStringLiteral HID_PROP_LIST_BINDING = u"EXTENSIONS_HID_PROP_LIST_BINDING"; +inline constexpr OUStringLiteral HID_PROP_BINDING_NAME = u"EXTENSIONS_HID_PROP_BINDING_NAME"; +inline constexpr OUStringLiteral HID_PROP_SELECTION_TYPE = u"EXTENSIONS_HID_PROP_SELECTION_TYPE"; +inline constexpr OUStringLiteral HID_PROP_ROOT_DISPLAYED = u"EXTENSIONS_HID_PROP_ROOT_DISPLAYED"; +inline constexpr OUStringLiteral HID_PROP_SHOWS_HANDLES = u"EXTENSIONS_HID_PROP_SHOWS_HANDLES"; +inline constexpr OUStringLiteral HID_PROP_SHOWS_ROOT_HANDLES = u"EXTENSIONS_HID_PROP_SHOWS_ROOT_HANDLES"; +inline constexpr OUStringLiteral HID_PROP_EDITABLE = u"EXTENSIONS_HID_PROP_EDITABLE"; +inline constexpr OUStringLiteral HID_PROP_INVOKES_STOP_NOT_EDITING = u"EXTENSIONS_HID_PROP_INVOKES_STOP_NOT_EDITING"; +inline constexpr OUStringLiteral HID_PROP_DECORATION = u"EXTENSIONS_HID_PROP_DECORATION"; +inline constexpr OUStringLiteral HID_EVT_ACTIONPERFORMED = u"EXTENSIONS_HID_EVT_ACTIONPERFORMED"; +inline constexpr OUStringLiteral HID_EVT_AFTERUPDATE = u"EXTENSIONS_HID_EVT_AFTERUPDATE"; +inline constexpr OUStringLiteral HID_EVT_BEFOREUPDATE = u"EXTENSIONS_HID_EVT_BEFOREUPDATE"; +inline constexpr OUStringLiteral HID_EVT_CONFIRMDELETE = u"EXTENSIONS_HID_EVT_CONFIRMDELETE"; +inline constexpr OUStringLiteral HID_EVT_ERROROCCURRED = u"EXTENSIONS_HID_EVT_ERROROCCURRED"; +inline constexpr OUStringLiteral HID_EVT_FOCUSGAINED = u"EXTENSIONS_HID_EVT_FOCUSGAINED"; +inline constexpr OUStringLiteral HID_EVT_FOCUSLOST = u"EXTENSIONS_HID_EVT_FOCUSLOST"; +inline constexpr OUStringLiteral HID_EVT_ITEMSTATECHANGED = u"EXTENSIONS_HID_EVT_ITEMSTATECHANGED"; +inline constexpr OUStringLiteral HID_EVT_KEYTYPED = u"EXTENSIONS_HID_EVT_KEYTYPED"; +inline constexpr OUStringLiteral HID_EVT_LOADED = u"EXTENSIONS_HID_EVT_LOADED"; +inline constexpr OUStringLiteral HID_EVT_MOUSEDRAGGED = u"EXTENSIONS_HID_EVT_MOUSEDRAGGED"; +inline constexpr OUStringLiteral HID_EVT_MOUSEENTERED = u"EXTENSIONS_HID_EVT_MOUSEENTERED"; +inline constexpr OUStringLiteral HID_EVT_MOUSEEXITED = u"EXTENSIONS_HID_EVT_MOUSEEXITED"; +inline constexpr OUStringLiteral HID_EVT_MOUSEMOVED = u"EXTENSIONS_HID_EVT_MOUSEMOVED"; +inline constexpr OUStringLiteral HID_EVT_MOUSEPRESSED = u"EXTENSIONS_HID_EVT_MOUSEPRESSED"; +inline constexpr OUStringLiteral HID_EVT_MOUSERELEASED = u"EXTENSIONS_HID_EVT_MOUSERELEASED"; +inline constexpr OUStringLiteral HID_EVT_POSITIONED = u"EXTENSIONS_HID_EVT_POSITIONED"; +inline constexpr OUStringLiteral HID_EVT_RESETTED = u"EXTENSIONS_HID_EVT_RESETTED"; +inline constexpr OUStringLiteral HID_EVT_SUBMITTED = u"EXTENSIONS_HID_EVT_SUBMITTED"; +inline constexpr OUStringLiteral HID_EVT_TEXTCHANGED = u"EXTENSIONS_HID_EVT_TEXTCHANGED"; +inline constexpr OUStringLiteral HID_EVT_UNLOADED = u"EXTENSIONS_HID_EVT_UNLOADED"; +inline constexpr OUStringLiteral HID_EVT_CHANGED = u"EXTENSIONS_HID_EVT_CHANGED"; +inline constexpr OUStringLiteral HID_EVT_APPROVEACTIONPERFORMED = u"EXTENSIONS_HID_EVT_APPROVEACTIONPERFORMED"; +inline constexpr OUStringLiteral HID_EVT_APPROVERESETTED = u"EXTENSIONS_HID_EVT_APPROVERESETTED"; +inline constexpr OUStringLiteral HID_EVT_KEYUP = u"EXTENSIONS_HID_EVT_KEYUP"; +inline constexpr OUStringLiteral HID_EVT_APPROVEPARAMETER = u"EXTENSIONS_HID_EVT_APPROVEPARAMETER"; +inline constexpr OUStringLiteral HID_EVT_POSITIONING = u"EXTENSIONS_HID_EVT_POSITIONING"; +inline constexpr OUStringLiteral HID_EVT_RELOADED = u"EXTENSIONS_HID_EVT_RELOADED"; +inline constexpr OUStringLiteral HID_EVT_APPROVEROWCHANGE = u"EXTENSIONS_HID_EVT_APPROVEROWCHANGE"; +inline constexpr OUStringLiteral HID_EVT_ROWCHANGE = u"EXTENSIONS_HID_EVT_ROWCHANGE"; +inline constexpr OUStringLiteral HID_EVT_RELOADING = u"EXTENSIONS_HID_EVT_RELOADING"; +inline constexpr OUStringLiteral HID_EVT_UNLOADING = u"EXTENSIONS_HID_EVT_UNLOADING"; +inline constexpr OUStringLiteral HID_EVT_ADJUSTMENTVALUECHANGED = u"EXTENSIONS_HID_EVT_ADJUSTMENTVALUECHANGED"; +inline constexpr OUStringLiteral HID_PROP_TOGGLE = u"EXTENSIONS_HID_PROP_TOGGLE"; +inline constexpr OUStringLiteral HID_PROP_FOCUSONCLICK = u"EXTENSIONS_HID_PROP_FOCUSONCLICK"; +inline constexpr OUStringLiteral HID_PROP_HIDEINACTIVESELECTION = u"EXTENSIONS_HID_PROP_HIDEINACTIVESELECTION"; +inline constexpr OUStringLiteral HID_PROP_VISUALEFFECT = u"EXTENSIONS_HID_PROP_VISUALEFFECT"; +inline constexpr OUStringLiteral HID_PROP_BORDERCOLOR = u"EXTENSIONS_HID_PROP_BORDERCOLOR"; +inline constexpr OUStringLiteral HID_PROP_IMAGEPOSITION = u"EXTENSIONS_HID_PROP_IMAGEPOSITION"; +inline constexpr OUStringLiteral HID_PROP_NOLABEL = u"EXTENSIONS_HID_PROP_NOLABEL"; +inline constexpr OUStringLiteral HID_PROP_WRITING_MODE = u"EXTENSIONS_HID_PROP_WRITING_MODE"; +inline constexpr OUStringLiteral HID_PROP_ANCHOR_TYPE = u"EXTENSIONS_HID_PROP_ANCHOR_TYPE"; +inline constexpr OStringLiteral HID_FM_PROPDLG_TABCTR = "EXTENSIONS_HID_FM_PROPDLG_TABCTR"; +inline constexpr OUStringLiteral HID_FM_PROPDLG_TAB_GENERAL = u"EXTENSIONS_HID_FM_PROPDLG_TAB_GENERAL"; +inline constexpr OUStringLiteral HID_FM_PROPDLG_TAB_DATA = u"EXTENSIONS_HID_FM_PROPDLG_TAB_DATA"; +inline constexpr OUStringLiteral HID_FM_PROPDLG_TAB_EVT = u"EXTENSIONS_HID_FM_PROPDLG_TAB_EVT"; +inline constexpr OUStringLiteral HID_PROP_GROUP_NAME = u"EXTENSIONS_HID_PROP_GROUP_NAME"; + +inline constexpr OUStringLiteral HID_PROP_SELECTIONMODEL = u"EXTENSIONS_HID_PROP_SELECTIONMODEL"; +inline constexpr OUStringLiteral HID_PROP_USEGRIDLINE = u"EXTENSIONS_HID_PROP_USEGRIDLINE"; +inline constexpr OUStringLiteral HID_PROP_GRIDLINECOLOR = u"EXTENSIONS_HID_PROP_GRIDLINECOLOR"; +inline constexpr OUStringLiteral HID_PROP_SHOWCOLUMNHEADER = u"EXTENSIONS_HID_PROP_SHOWCOLUMNHEADER"; +inline constexpr OUStringLiteral HID_PROP_SHOWROWHEADER = u"EXTENSIONS_HID_PROP_SHOWROWHEADER"; +inline constexpr OUStringLiteral HID_PROP_HEADERBACKGROUNDCOLOR = u"EXTENSIONS_HID_PROP_HEADERBACKGROUNDCOLOR"; +inline constexpr OUStringLiteral HID_PROP_HEADERTEXTCOLOR = u"EXTENSIONS_HID_PROP_HEADERTEXTCOLOR"; +inline constexpr OUStringLiteral HID_PROP_ACTIVESELECTIONBACKGROUNDCOLOR = u"EXTENSIONS_HID_PROP_ACTIVESELECTIONBACKGROUNDCOLOR"; +inline constexpr OUStringLiteral HID_PROP_ACTIVESELECTIONTEXTCOLOR = u"EXTENSIONS_HID_PROP_ACTIVESELECTIONTEXTCOLOR"; +inline constexpr OUStringLiteral HID_PROP_INACTIVESELECTIONBACKGROUNDCOLOR = u"EXTENSIONS_HID_PROP_INACTIVESELECTIONBACKGROUNDCOLOR"; +inline constexpr OUStringLiteral HID_PROP_INACTIVESELECTIONTEXTCOLOR = u"EXTENSIONS_HID_PROP_INACTIVESELECTIONTEXTCOLOR"; + +#define HID_CHECK_FOR_UPD_DLG "EXTENSIONS_HID_CHECK_FOR_UPD_DLG" +#define HID_CHECK_FOR_UPD_CLOSE "EXTENSIONS_HID_CHECK_FOR_UPD_CLOSE" +#define HID_CHECK_FOR_UPD_PAUSE "EXTENSIONS_HID_CHECK_FOR_UPD_PAUSE" +#define HID_CHECK_FOR_UPD_RESUME "EXTENSIONS_HID_CHECK_FOR_UPD_RESUME" +#define HID_CHECK_FOR_UPD_DOWNLOAD "EXTENSIONS_HID_CHECK_FOR_UPD_DOWNLOAD" +#define HID_CHECK_FOR_UPD_DOWNLOAD2 "EXTENSIONS_HID_CHECK_FOR_UPD_DOWNLOAD2" +#define HID_CHECK_FOR_UPD_INSTALL "EXTENSIONS_HID_CHECK_FOR_UPD_INSTALL" +#define HID_CHECK_FOR_UPD_STATUS "EXTENSIONS_HID_CHECK_FOR_UPD_STATUS" +#define HID_CHECK_FOR_UPD_DESCRIPTION "EXTENSIONS_HID_CHECK_FOR_UPD_DESCRIPTION" +#define HID_CHECK_FOR_UPD_CANCEL "EXTENSIONS_HID_CHECK_FOR_UPD_CANCEL" + +#endif // EXTENSIONS_ABPILOT_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/inc/propctrlr.h b/extensions/inc/propctrlr.h new file mode 100644 index 000000000..bad3d082d --- /dev/null +++ b/extensions/inc/propctrlr.h @@ -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 EXTENSIONS_PROPCTRLR_H +#define EXTENSIONS_PROPCTRLR_H + +#include + +inline constexpr OUStringLiteral UID_PROP_DLG_FONT_TYPE = u"EXTENSIONS_UID_PROP_DLG_FONT_TYPE"; +inline constexpr OUStringLiteral UID_PROP_DLG_IMAGE_URL = u"EXTENSIONS_UID_PROP_DLG_IMAGE_URL"; +inline constexpr OUStringLiteral UID_PROP_DLG_BACKGROUNDCOLOR = u"EXTENSIONS_UID_PROP_DLG_BACKGROUNDCOLOR"; +inline constexpr OUStringLiteral UID_PROP_DLG_SYMBOLCOLOR = u"EXTENSIONS_UID_PROP_DLG_SYMBOLCOLOR"; +inline constexpr OUStringLiteral UID_PROP_DLG_ATTR_DATASOURCE = u"EXTENSIONS_UID_PROP_DLG_ATTR_DATASOURCE"; +inline constexpr OUStringLiteral UID_PROP_DLG_ATTR_TARGET_URL = u"EXTENSIONS_UID_PROP_DLG_ATTR_TARGET_URL"; +inline constexpr OUStringLiteral UID_PROP_DLG_NUMBER_FORMAT = u"EXTENSIONS_UID_PROP_DLG_NUMBER_FORMAT"; +inline constexpr OUStringLiteral UID_PROP_DLG_CONTROLLABEL = u"EXTENSIONS_UID_PROP_DLG_CONTROLLABEL"; +inline constexpr OUStringLiteral UID_PROP_DLG_FILLCOLOR = u"EXTENSIONS_UID_PROP_DLG_FILLCOLOR"; +inline constexpr OUStringLiteral UID_PROP_DLG_TABINDEX = u"EXTENSIONS_UID_PROP_DLG_TABINDEX"; +inline constexpr OUStringLiteral UID_PROP_DLG_SQLCOMMAND = u"EXTENSIONS_UID_PROP_DLG_SQLCOMMAND"; +inline constexpr OUStringLiteral UID_PROP_DLG_FORMLINKFIELDS = u"EXTENSIONS_UID_PROP_DLG_FORMLINKFIELDS"; +inline constexpr OUStringLiteral UID_PROP_DLG_FILTER = u"EXTENSIONS_UID_PROP_DLG_FILTER"; +inline constexpr OUStringLiteral UID_PROP_DLG_ORDER = u"EXTENSIONS_UID_PROP_DLG_ORDER"; +inline constexpr OUStringLiteral UID_PROP_DLG_SELECTION = u"EXTENSIONS_UID_PROP_DLG_SELECTION"; +inline constexpr OUStringLiteral UID_PROP_DLG_BIND_EXPRESSION = u"EXTENSIONS_UID_PROP_DLG_BIND_EXPRESSION"; +inline constexpr OUStringLiteral UID_PROP_DLG_XSD_REQUIRED = u"EXTENSIONS_UID_PROP_DLG_XSD_REQUIRED"; +inline constexpr OUStringLiteral UID_PROP_DLG_XSD_RELEVANT = u"EXTENSIONS_UID_PROP_DLG_XSD_RELEVANT"; +inline constexpr OUStringLiteral UID_PROP_DLG_XSD_READONLY = u"EXTENSIONS_UID_PROP_DLG_XSD_READONLY"; +inline constexpr OUStringLiteral UID_PROP_DLG_XSD_CONSTRAINT = u"EXTENSIONS_UID_PROP_DLG_XSD_CONSTRAINT"; +inline constexpr OUStringLiteral UID_PROP_DLG_XSD_CALCULATION = u"EXTENSIONS_UID_PROP_DLG_XSD_CALCULATION"; +inline constexpr OUStringLiteral UID_PROP_ADD_DATA_TYPE = u"EXTENSIONS_UID_PROP_ADD_DATA_TYPE"; +inline constexpr OUStringLiteral UID_PROP_REMOVE_DATA_TYPE = u"EXTENSIONS_UID_PROP_REMOVE_DATA_TYPE"; +inline constexpr OUStringLiteral UID_PROP_DLG_BORDERCOLOR = u"EXTENSIONS_UID_PROP_DLG_BORDERCOLOR"; + +inline constexpr OStringLiteral UID_BRWEVT_APPROVEACTIONPERFORMED = "EXTENSIONS_UID_BRWEVT_APPROVEACTIONPERFORMED"; +inline constexpr OStringLiteral UID_BRWEVT_ACTIONPERFORMED = "EXTENSIONS_UID_BRWEVT_ACTIONPERFORMED"; +inline constexpr OStringLiteral UID_BRWEVT_CHANGED = "EXTENSIONS_UID_BRWEVT_CHANGED"; +inline constexpr OStringLiteral UID_BRWEVT_TEXTCHANGED = "EXTENSIONS_UID_BRWEVT_TEXTCHANGED"; +inline constexpr OStringLiteral UID_BRWEVT_ITEMSTATECHANGED = "EXTENSIONS_UID_BRWEVT_ITEMSTATECHANGED"; +inline constexpr OStringLiteral UID_BRWEVT_FOCUSGAINED = "EXTENSIONS_UID_BRWEVT_FOCUSGAINED"; +inline constexpr OStringLiteral UID_BRWEVT_FOCUSLOST = "EXTENSIONS_UID_BRWEVT_FOCUSLOST"; +inline constexpr OStringLiteral UID_BRWEVT_KEYTYPED = "EXTENSIONS_UID_BRWEVT_KEYTYPED"; +inline constexpr OStringLiteral UID_BRWEVT_KEYUP = "EXTENSIONS_UID_BRWEVT_KEYUP"; +inline constexpr OStringLiteral UID_BRWEVT_MOUSEENTERED = "EXTENSIONS_UID_BRWEVT_MOUSEENTERED"; +inline constexpr OStringLiteral UID_BRWEVT_MOUSEDRAGGED = "EXTENSIONS_UID_BRWEVT_MOUSEDRAGGED"; +inline constexpr OStringLiteral UID_BRWEVT_MOUSEMOVED = "EXTENSIONS_UID_BRWEVT_MOUSEMOVED"; +inline constexpr OStringLiteral UID_BRWEVT_MOUSEPRESSED = "EXTENSIONS_UID_BRWEVT_MOUSEPRESSED"; +inline constexpr OStringLiteral UID_BRWEVT_MOUSERELEASED = "EXTENSIONS_UID_BRWEVT_MOUSERELEASED"; +inline constexpr OStringLiteral UID_BRWEVT_MOUSEEXITED = "EXTENSIONS_UID_BRWEVT_MOUSEEXITED"; +inline constexpr OStringLiteral UID_BRWEVT_APPROVERESETTED = "EXTENSIONS_UID_BRWEVT_APPROVERESETTED"; +inline constexpr OStringLiteral UID_BRWEVT_RESETTED = "EXTENSIONS_UID_BRWEVT_RESETTED"; +inline constexpr OStringLiteral UID_BRWEVT_SUBMITTED = "EXTENSIONS_UID_BRWEVT_SUBMITTED"; +inline constexpr OStringLiteral UID_BRWEVT_BEFOREUPDATE = "EXTENSIONS_UID_BRWEVT_BEFOREUPDATE"; +inline constexpr OStringLiteral UID_BRWEVT_AFTERUPDATE = "EXTENSIONS_UID_BRWEVT_AFTERUPDATE"; +inline constexpr OStringLiteral UID_BRWEVT_LOADED = "EXTENSIONS_UID_BRWEVT_LOADED"; +inline constexpr OStringLiteral UID_BRWEVT_RELOADING = "EXTENSIONS_UID_BRWEVT_RELOADING"; +inline constexpr OStringLiteral UID_BRWEVT_RELOADED = "EXTENSIONS_UID_BRWEVT_RELOADED"; +inline constexpr OStringLiteral UID_BRWEVT_UNLOADING = "EXTENSIONS_UID_BRWEVT_UNLOADING"; +inline constexpr OStringLiteral UID_BRWEVT_UNLOADED = "EXTENSIONS_UID_BRWEVT_UNLOADED"; +inline constexpr OStringLiteral UID_BRWEVT_CONFIRMDELETE = "EXTENSIONS_UID_BRWEVT_CONFIRMDELETE"; +inline constexpr OStringLiteral UID_BRWEVT_APPROVEROWCHANGE = "EXTENSIONS_UID_BRWEVT_APPROVEROWCHANGE"; +inline constexpr OStringLiteral UID_BRWEVT_ROWCHANGE = "EXTENSIONS_UID_BRWEVT_ROWCHANGE"; +inline constexpr OStringLiteral UID_BRWEVT_POSITIONING = "EXTENSIONS_UID_BRWEVT_POSITIONING"; +inline constexpr OStringLiteral UID_BRWEVT_POSITIONED = "EXTENSIONS_UID_BRWEVT_POSITIONED"; +inline constexpr OStringLiteral UID_BRWEVT_APPROVEPARAMETER = "EXTENSIONS_UID_BRWEVT_APPROVEPARAMETER"; +inline constexpr OStringLiteral UID_BRWEVT_ERROROCCURRED = "EXTENSIONS_UID_BRWEVT_ERROROCCURRED"; +inline constexpr OStringLiteral UID_BRWEVT_ADJUSTMENTVALUECHANGED = "EXTENSIONS_UID_BRWEVT_ADJUSTMENTVALUECHANGED"; + +#endif // EXTENSIONS_PROPCTRLR_HRC + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/inc/showhide.hrc b/extensions/inc/showhide.hrc new file mode 100644 index 000000000..226f8b48e --- /dev/null +++ b/extensions/inc/showhide.hrc @@ -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_EXTENSIONS_INC_SHOWHIDE_HRC +#define INCLUDED_EXTENSIONS_INC_SHOWHIDE_HRC + +#include + +#define NC_(Context, String) TranslateId(Context, reinterpret_cast(u8##String)) + +namespace { + +const TranslateId RID_RSC_ENUM_SHOWHIDE[] = +{ + NC_("RID_RSC_ENUM_SHOWHIDE", "Hide"), + NC_("RID_RSC_ENUM_SHOWHIDE", "Show") +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/inc/stringarrays.hrc b/extensions/inc/stringarrays.hrc new file mode 100644 index 000000000..e567e28fe --- /dev/null +++ b/extensions/inc/stringarrays.hrc @@ -0,0 +1,258 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_EXTENSIONS_INC_STRINGARRAYS_HRC +#define INCLUDED_EXTENSIONS_INC_STRINGARRAYS_HRC + +#include + +#define NC_(Context, String) TranslateId(Context, reinterpret_cast(u8##String)) + +const TranslateId RID_RSC_ENUM_VERTICAL_ALIGN[] = +{ + NC_("RID_RSC_ENUM_VERTICAL_ALIGN", "Top"), + NC_("RID_RSC_ENUM_VERTICAL_ALIGN", "Middle"), + NC_("RID_RSC_ENUM_VERTICAL_ALIGN", "Bottom") +}; + +const TranslateId RID_RSC_ENUM_ICONSIZE_TYPE[] = +{ + NC_("RID_RSC_ENUM_ICONSIZE_TYPE", "Small"), + NC_("RID_RSC_ENUM_ICONSIZE_TYPE", "Large") +}; + +const TranslateId RID_RSC_ENUM_BORDER_TYPE[] = +{ + NC_("RID_RSC_ENUM_BORDER_TYPE", "Without frame"), + NC_("RID_RSC_ENUM_BORDER_TYPE", "3D look"), + NC_("RID_RSC_ENUM_BORDER_TYPE", "Flat") +}; + +const TranslateId RID_RSC_ENUM_LISTSOURCE_TYPE[] = +{ + NC_("RID_RSC_ENUM_LISTSOURCE_TYPE", "Valuelist"), + NC_("RID_RSC_ENUM_LISTSOURCE_TYPE", "Table"), + NC_("RID_RSC_ENUM_LISTSOURCE_TYPE", "Query"), + NC_("RID_RSC_ENUM_LISTSOURCE_TYPE", "Sql"), + NC_("RID_RSC_ENUM_LISTSOURCE_TYPE", "Sql [Native]"), + NC_("RID_RSC_ENUM_LISTSOURCE_TYPE", "Tablefields" ) +}; + +const TranslateId RID_RSC_ENUM_ALIGNMENT[] = +{ + NC_("RID_RSC_ENUM_ALIGNMENT", "Left"), + NC_("RID_RSC_ENUM_ALIGNMENT", "Center"), + NC_("RID_RSC_ENUM_ALIGNMENT", "Right" ) +}; + +const TranslateId RID_RSC_ENUM_BUTTONTYPE[] = +{ + NC_("RID_RSC_ENUM_BUTTONTYPE", "None"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Submit form"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Reset form"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Open document/web page"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "First record"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Previous record"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Next record"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Last record"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Save record"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Undo data entry"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "New record"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Delete record"), + NC_("RID_RSC_ENUM_BUTTONTYPE", "Refresh form") +}; + +const TranslateId RID_RSC_ENUM_SUBMIT_ENCODING[] = +{ + NC_("RID_RSC_ENUM_SUBMIT_ENCODING", "URL"), + NC_("RID_RSC_ENUM_SUBMIT_ENCODING", "Multipart"), + NC_("RID_RSC_ENUM_SUBMIT_ENCODING", "Text" ) +}; + +const TranslateId RID_RSC_ENUM_DATEFORMAT_LIST[] = +{ + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "Standard (short)"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "Standard (short YY)"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "Standard (short YYYY)"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "Standard (long)"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "DD/MM/YY"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "MM/DD/YY"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "YY/MM/DD"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "DD/MM/YYYY"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "MM/DD/YYYY"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "YYYY/MM/DD"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "YY-MM-DD"), + NC_("RID_RSC_ENUM_DATEFORMAT_LIST", "YYYY-MM-DD" ), +}; + +const TranslateId RID_RSC_ENUM_TIMEFORMAT_LIST[] = +{ + NC_("RID_RSC_ENUM_TIMEFORMAT_LIST", "13:45"), + NC_("RID_RSC_ENUM_TIMEFORMAT_LIST", "13:45:00"), + NC_("RID_RSC_ENUM_TIMEFORMAT_LIST", "01:45 PM"), + NC_("RID_RSC_ENUM_TIMEFORMAT_LIST", "01:45:00 PM" ), +}; + +const TranslateId RID_RSC_ENUM_CHECKED[] = +{ + NC_("RID_RSC_ENUM_CHECKED", "Not Selected"), + NC_("RID_RSC_ENUM_CHECKED", "Selected"), + NC_("RID_RSC_ENUM_CHECKED", "Not Defined" ) +}; + +const TranslateId RID_RSC_ENUM_CYCLE[] = +{ + NC_("RID_RSC_ENUM_CYCLE", "All records"), + NC_("RID_RSC_ENUM_CYCLE", "Active record"), + NC_("RID_RSC_ENUM_CYCLE", "Current page" ) +}; + +const TranslateId RID_RSC_ENUM_NAVIGATION[] = +{ + NC_("RID_RSC_ENUM_NAVIGATION", "No"), + NC_("RID_RSC_ENUM_NAVIGATION", "Yes"), + NC_("RID_RSC_ENUM_NAVIGATION", "Parent Form") +}; + +const TranslateId RID_RSC_ENUM_SUBMIT_TARGET[] = +{ + NC_("RID_RSC_ENUM_SUBMIT_TARGET", "_blank"), + NC_("RID_RSC_ENUM_SUBMIT_TARGET", "_parent"), + NC_("RID_RSC_ENUM_SUBMIT_TARGET", "_self"), + NC_("RID_RSC_ENUM_SUBMIT_TARGET", "_top") +}; + +const TranslateId RID_RSC_ENUM_SELECTION_TYPE[] = +{ + NC_("RID_RSC_ENUM_SELECTION_TYPE", "None" ), + NC_("RID_RSC_ENUM_SELECTION_TYPE", "Single" ), + NC_("RID_RSC_ENUM_SELECTION_TYPE", "Multi" ), + NC_("RID_RSC_ENUM_SELECTION_TYPE", "Range" ) +}; + +const TranslateId RID_RSC_ENUM_ORIENTATION[] = +{ + NC_("RID_RSC_ENUM_ORIENTATION", "Horizontal"), + NC_("RID_RSC_ENUM_ORIENTATION", "Vertical") +}; + +const TranslateId RID_RSC_ENUM_PUSHBUTTONTYPE[] = +{ + NC_("RID_RSC_ENUM_PUSHBUTTONTYPE", "Default"), + NC_("RID_RSC_ENUM_PUSHBUTTONTYPE", "OK"), + NC_("RID_RSC_ENUM_PUSHBUTTONTYPE", "Cancel"), + NC_("RID_RSC_ENUM_PUSHBUTTONTYPE", "Help") +}; + +const TranslateId RID_RSC_ENUM_CELL_EXCHANGE_TYPE[] = +{ + NC_("RID_RSC_ENUM_CELL_EXCHANGE_TYPE", "The selected entry"), + NC_("RID_RSC_ENUM_CELL_EXCHANGE_TYPE", "Position of the selected entry") +}; + +const TranslateId RID_RSC_ENUM_TEXTTYPE[] = +{ + NC_("RID_RSC_ENUM_TEXTTYPE", "Single-line"), + NC_("RID_RSC_ENUM_TEXTTYPE", "Multi-line"), + NC_("RID_RSC_ENUM_TEXTTYPE", "Multi-line with formatting") +}; + +const TranslateId RID_RSC_ENUM_LINEEND_FORMAT[] = +{ + NC_("RID_RSC_ENUM_LINEEND_FORMAT", "LF (Unix)"), + NC_("RID_RSC_ENUM_LINEEND_FORMAT", "CR+LF (Windows)") +}; + +const TranslateId RID_RSC_ENUM_SCROLLBARS[] = +{ + NC_("RID_RSC_ENUM_SCROLLBARS", "None"), + NC_("RID_RSC_ENUM_SCROLLBARS", "Horizontal"), + NC_("RID_RSC_ENUM_SCROLLBARS", "Vertical"), + NC_("RID_RSC_ENUM_SCROLLBARS", "Both") +}; + +const TranslateId RID_RSC_ENUM_VISUALEFFECT[] = +{ + NC_("RID_RSC_ENUM_VISUALEFFECT", "3D"), + NC_("RID_RSC_ENUM_VISUALEFFECT", "Flat"), +}; + +const TranslateId RID_RSC_ENUM_IMAGE_POSITION[] = +{ + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Left top"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Left centered"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Left bottom"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Right top"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Right centered"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Right bottom"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Above left"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Above centered"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Above right"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Below left"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Below centered"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Below right"), + NC_("RID_RSC_ENUM_IMAGE_POSITION", "Centered"), +}; + +const TranslateId RID_RSC_ENUM_WHITESPACE_HANDLING[] = +{ + NC_("RID_RSC_ENUM_WHITESPACE_HANDLING", "Preserve"), + NC_("RID_RSC_ENUM_WHITESPACE_HANDLING", "Replace"), + NC_("RID_RSC_ENUM_WHITESPACE_HANDLING", "Collapse") +}; + +const TranslateId RID_RSC_ENUM_SCALE_MODE[] = +{ + NC_("RID_RSC_ENUM_SCALE_MODE", "No"), + NC_("RID_RSC_ENUM_SCALE_MODE", "Keep Ratio"), + NC_("RID_RSC_ENUM_SCALE_MODE", "Fit to Size") +}; + +const TranslateId RID_RSC_ENUM_WRITING_MODE[] = +{ + NC_("RID_RSC_ENUM_WRITING_MODE", "Left-to-right"), + NC_("RID_RSC_ENUM_WRITING_MODE", "Right-to-left"), + NC_("RID_RSC_ENUM_WRITING_MODE", "Use superordinate object settings") +}; + +const TranslateId RID_RSC_ENUM_WHEEL_BEHAVIOR[] = +{ + NC_("RID_RSC_ENUM_WHEEL_BEHAVIOR", "Never"), + NC_("RID_RSC_ENUM_WHEEL_BEHAVIOR", "When focused"), + NC_("RID_RSC_ENUM_WHEEL_BEHAVIOR", "Always") +}; + +const TranslateId RID_RSC_ENUM_TEXT_ANCHOR_TYPE[] = +{ + NC_("RID_RSC_ENUM_TEXT_ANCHOR_TYPE", "To Paragraph"), + NC_("RID_RSC_ENUM_TEXT_ANCHOR_TYPE", "As Character"), + NC_("RID_RSC_ENUM_TEXT_ANCHOR_TYPE", "To Page"), + NC_("RID_RSC_ENUM_TEXT_ANCHOR_TYPE", "To Frame"), + NC_("RID_RSC_ENUM_TEXT_ANCHOR_TYPE", "To Character") +}; + +const TranslateId RID_RSC_ENUM_SHEET_ANCHOR_TYPE[] = +{ + NC_("RID_RSC_ENUM_SHEET_ANCHOR_TYPE", "To Page"), + NC_("RID_RSC_ENUM_SHEET_ANCHOR_TYPE", "To Cell") +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/inc/strings.hrc b/extensions/inc/strings.hrc new file mode 100644 index 000000000..8d6ed0580 --- /dev/null +++ b/extensions/inc/strings.hrc @@ -0,0 +1,412 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_EXTENSIONS_INC_STRINGS_HRC +#define INCLUDED_EXTENSIONS_INC_STRINGS_HRC + +#include + +#define NC_(Context, String) TranslateId(Context, reinterpret_cast(u8##String)) + +#define RID_STR_EDITMASK NC_("RID_STR_EDITMASK", "Edit mask") +#define RID_STR_LITERALMASK NC_("RID_STR_LITERALMASK", "Literal mask") +#define RID_STR_READONLY NC_("RID_STR_READONLY", "Read-only") +#define RID_STR_ENABLED NC_("RID_STR_ENABLED", "Enabled") +#define RID_STR_ENABLE_VISIBLE NC_("RID_STR_ENABLE_VISIBLE", "Visible") +#define RID_STR_AUTOCOMPLETE NC_("RID_STR_AUTOCOMPLETE", "AutoFill") +#define RID_STR_LINECOUNT NC_("RID_STR_LINECOUNT", "Line count") +#define RID_STR_MAXTEXTLEN NC_("RID_STR_MAXTEXTLEN", "Max. text length") +#define RID_STR_SPIN NC_("RID_STR_SPIN", "Spin Button") +#define RID_STR_STRICTFORMAT NC_("RID_STR_STRICTFORMAT", "Strict format") +#define RID_STR_SHOWTHOUSANDSEP NC_("RID_STR_SHOWTHOUSANDSEP", "Thousands separator") +#define RID_STR_PRINTABLE NC_("RID_STR_PRINTABLE", "Printable") +#define RID_STR_TARGET_URL NC_("RID_STR_TARGET_URL", "URL") +#define RID_STR_TARGET_FRAME NC_("RID_STR_TARGET_FRAME", "Frame") +#define RID_STR_HELPTEXT NC_("RID_STR_HELPTEXT", "Help text") +#define RID_STR_HELPURL NC_("RID_STR_HELPURL", "Help URL") +#define RID_STR_TAG NC_("RID_STR_TAG", "Additional information") +#define RID_STR_ECHO_CHAR NC_("RID_STR_ECHO_CHAR", "Password character") +#define RID_STR_TRISTATE NC_("RID_STR_TRISTATE", "Tristate") +#define RID_STR_EMPTY_IS_NULL NC_("RID_STR_EMPTY_IS_NULL", "Empty string is NULL") +#define RID_STR_DECIMAL_ACCURACY NC_("RID_STR_DECIMAL_ACCURACY", "Decimal accuracy") +#define RID_STR_IMAGE_URL NC_("RID_STR_IMAGE_URL", "Graphics") +#define RID_STR_DEFAULT_SELECT_SEQ NC_("RID_STR_DEFAULT_SELECT_SEQ", "Default selection") +#define RID_STR_DEFAULT_BUTTON NC_("RID_STR_DEFAULT_BUTTON", "Default button") +#define RID_STR_LABELCONTROL NC_("RID_STR_LABELCONTROL", "Label Field") +#define RID_STR_LABEL NC_("RID_STR_LABEL", "Label") +#define RID_STR_ALIGN NC_("RID_STR_ALIGN", "Alignment") +#define RID_STR_VERTICAL_ALIGN NC_("RID_STR_VERTICAL_ALIGN", "Vert. Alignment") +#define RID_STR_IMAGEPOSITION NC_("RID_STR_IMAGEPOSITION", "Graphics alignment") +#define RID_STR_FONT NC_("RID_STR_FONT", "Font") +#define RID_STR_BACKGROUNDCOLOR NC_("RID_STR_BACKGROUNDCOLOR", "Background color") +#define RID_STR_BORDER NC_("RID_STR_BORDER", "Border") +#define RID_STR_ICONSIZE NC_("RID_STR_ICONSIZE", "Icon size") +#define RID_STR_SHOW_POSITION NC_("RID_STR_SHOW_POSITION", "Positioning") +#define RID_STR_SHOW_NAVIGATION NC_("RID_STR_SHOW_NAVIGATION", "Navigation") +#define RID_STR_SHOW_RECORDACTIONS NC_("RID_STR_SHOW_RECORDACTIONS", "Acting on a record") +#define RID_STR_SHOW_FILTERSORT NC_("RID_STR_SHOW_FILTERSORT", "Filtering / Sorting") +#define RID_STR_HSCROLL NC_("RID_STR_HSCROLL", "Horizontal scroll bar") +#define RID_STR_VSCROLL NC_("RID_STR_VSCROLL", "Vertical scroll bar") +#define RID_STR_WORDBREAK NC_("RID_STR_WORDBREAK", "Word break") +#define RID_STR_MULTILINE NC_("RID_STR_MULTILINE", "Multiline input") +#define RID_STR_MULTISELECTION NC_("RID_STR_MULTISELECTION", "Multiselection") +#define RID_STR_NAME NC_("RID_STR_NAME", "Name") +#define RID_STR_GROUP_NAME NC_("RID_STR_GROUP_NAME", "Group name") +#define RID_STR_TABINDEX NC_("RID_STR_TABINDEX", "Tab order") +#define RID_STR_WHEEL_BEHAVIOR NC_("RID_STR_WHEEL_BEHAVIOR", "Mouse wheel scroll") +#define RID_STR_FILTER NC_("RID_STR_FILTER", "Filter") +#define RID_STR_SORT_CRITERIA NC_("RID_STR_SORT_CRITERIA", "Sort") +#define RID_STR_RECORDMARKER NC_("RID_STR_RECORDMARKER", "Record marker") +#define RID_STR_FILTERPROPOSAL NC_("RID_STR_FILTERPROPOSAL", "Filter proposal") +#define RID_STR_NAVIGATION NC_("RID_STR_NAVIGATION", "Navigation bar") +#define RID_STR_CYCLE NC_("RID_STR_CYCLE", "Cycle") +#define RID_STR_TABSTOP NC_("RID_STR_TABSTOP", "Tabstop") +#define RID_STR_CONTROLSOURCE NC_("RID_STR_CONTROLSOURCE", "Data field") +#define RID_STR_DROPDOWN NC_("RID_STR_DROPDOWN", "Dropdown") +#define RID_STR_BOUNDCOLUMN NC_("RID_STR_BOUNDCOLUMN", "Bound field") +#define RID_STR_LISTSOURCE NC_("RID_STR_LISTSOURCE", "List content") +#define RID_STR_LISTSOURCETYPE NC_("RID_STR_LISTSOURCETYPE", "Type of list contents") +#define RID_STR_CURSORSOURCE NC_("RID_STR_CURSORSOURCE", "Content") +#define RID_STR_CURSORSOURCETYPE NC_("RID_STR_CURSORSOURCETYPE", "Content type") +#define RID_STR_ALLOW_ADDITIONS NC_("RID_STR_ALLOW_ADDITIONS", "Allow additions") +#define RID_STR_ALLOW_DELETIONS NC_("RID_STR_ALLOW_DELETIONS", "Allow deletions") +#define RID_STR_ALLOW_EDITS NC_("RID_STR_ALLOW_EDITS", "Allow modifications") +#define RID_STR_DATAENTRY NC_("RID_STR_DATAENTRY", "Add data only") +#define RID_STR_DATASOURCE NC_("RID_STR_DATASOURCE", "Data source") +#define RID_STR_MASTERFIELDS NC_("RID_STR_MASTERFIELDS", "Link master fields") +#define RID_STR_SLAVEFIELDS NC_("RID_STR_SLAVEFIELDS", "Link slave fields") +#define RID_STR_VALUEMIN NC_("RID_STR_VALUEMIN", "Value min.") +#define RID_STR_VALUEMAX NC_("RID_STR_VALUEMAX", "Value max.") +#define RID_STR_VALUESTEP NC_("RID_STR_VALUESTEP", "Incr./decrement value") +#define RID_STR_CURRENCYSYMBOL NC_("RID_STR_CURRENCYSYMBOL", "Currency symbol") +#define RID_STR_DATEMIN NC_("RID_STR_DATEMIN", "Date min.") +#define RID_STR_DATEMAX NC_("RID_STR_DATEMAX", "Date max.") +#define RID_STR_DATEFORMAT NC_("RID_STR_DATEFORMAT", "Date format") +#define RID_STR_SELECTEDITEMS NC_("RID_STR_SELECTEDITEMS", "Selection") +#define RID_STR_TIMEMIN NC_("RID_STR_TIMEMIN", "Time min.") +#define RID_STR_TIMEMAX NC_("RID_STR_TIMEMAX", "Time max.") +#define RID_STR_TIMEFORMAT NC_("RID_STR_TIMEFORMAT", "Time format") +#define RID_STR_CURRSYM_POSITION NC_("RID_STR_CURRSYM_POSITION", "Prefix symbol") +#define RID_STR_VALUE NC_("RID_STR_VALUE", "Value") +#define RID_STR_FORMATKEY NC_("RID_STR_FORMATKEY", "Formatting") +#define RID_STR_CLASSID NC_("RID_STR_CLASSID", "Class ID") +#define RID_STR_HEIGHT NC_("RID_STR_HEIGHT", "Height") +#define RID_STR_WIDTH NC_("RID_STR_WIDTH", "Width") +#define RID_STR_AUTOGROW NC_("RID_STR_AUTOGROW", "Auto grow") +#define RID_STR_LISTINDEX NC_("RID_STR_LISTINDEX", "List index") +#define RID_STR_ROWHEIGHT NC_("RID_STR_ROWHEIGHT", "Row height") +#define RID_STR_FILLCOLOR NC_("RID_STR_FILLCOLOR", "Fill color") +#define RID_STR_LINECOLOR NC_("RID_STR_LINECOLOR", "Line color") +#define RID_STR_REFVALUE NC_("RID_STR_REFVALUE", "Reference value (on)") +#define RID_STR_UNCHECKEDREFVALUE NC_("RID_STR_UNCHECKEDREFVALUE", "Reference value (off)") +#define RID_STR_STRINGITEMLIST NC_("RID_STR_STRINGITEMLIST", "List entries") +#define RID_STR_BUTTONTYPE NC_("RID_STR_BUTTONTYPE", "Action") +#define RID_STR_SUBMIT_ACTION NC_("RID_STR_SUBMIT_ACTION", "URL") +#define RID_STR_SUBMIT_METHOD NC_("RID_STR_SUBMIT_METHOD", "Type of submission") +#define RID_STR_DEFAULT_STATE NC_("RID_STR_DEFAULT_STATE", "Default status") +#define RID_STR_SUBMIT_ENCODING NC_("RID_STR_SUBMIT_ENCODING", "Submission encoding") +#define RID_STR_DEFAULTVALUE NC_("RID_STR_DEFAULTVALUE", "Default value") +#define RID_STR_DEFAULTTEXT NC_("RID_STR_DEFAULTTEXT", "Default text") +#define RID_STR_DEFAULTDATE NC_("RID_STR_DEFAULTDATE", "Default date") +#define RID_STR_DEFAULTTIME NC_("RID_STR_DEFAULTTIME", "Default time") +#define RID_STR_SUBMIT_TARGET NC_("RID_STR_SUBMIT_TARGET", "Frame") +#define RID_STR_EVT_APPROVEPARAMETER NC_("RID_STR_EVT_APPROVEPARAMETER", "Fill parameters") +#define RID_STR_EVT_ACTIONPERFORMED NC_("RID_STR_EVT_ACTIONPERFORMED", "Execute action") +#define RID_STR_EVT_AFTERUPDATE NC_("RID_STR_EVT_AFTERUPDATE", "After updating") +#define RID_STR_EVT_BEFOREUPDATE NC_("RID_STR_EVT_BEFOREUPDATE", "Before updating") +#define RID_STR_EVT_APPROVEROWCHANGE NC_("RID_STR_EVT_APPROVEROWCHANGE", "Before record action") +#define RID_STR_EVT_ROWCHANGE NC_("RID_STR_EVT_ROWCHANGE", "After record action") +#define RID_STR_EVT_CONFIRMDELETE NC_("RID_STR_EVT_CONFIRMDELETE", "Confirm deletion") +#define RID_STR_EVT_ERROROCCURRED NC_("RID_STR_EVT_ERROROCCURRED", "Error occurred") +#define RID_STR_EVT_FOCUSGAINED NC_("RID_STR_EVT_FOCUSGAINED", "When receiving focus") +#define RID_STR_EVT_FOCUSLOST NC_("RID_STR_EVT_FOCUSLOST", "When losing focus") +#define RID_STR_EVT_ITEMSTATECHANGED NC_("RID_STR_EVT_ITEMSTATECHANGED", "Item status changed") +#define RID_STR_EVT_KEYTYPED NC_("RID_STR_EVT_KEYTYPED", "Key pressed") +#define RID_STR_EVT_KEYUP NC_("RID_STR_EVT_KEYUP", "Key released") +#define RID_STR_EVT_LOADED NC_("RID_STR_EVT_LOADED", "When loading") +#define RID_STR_EVT_RELOADING NC_("RID_STR_EVT_RELOADING", "Before reloading") +#define RID_STR_EVT_RELOADED NC_("RID_STR_EVT_RELOADED", "When reloading") +#define RID_STR_EVT_MOUSEDRAGGED NC_("RID_STR_EVT_MOUSEDRAGGED", "Mouse moved while key pressed") +#define RID_STR_EVT_MOUSEENTERED NC_("RID_STR_EVT_MOUSEENTERED", "Mouse inside") +#define RID_STR_EVT_MOUSEEXITED NC_("RID_STR_EVT_MOUSEEXITED", "Mouse outside") +#define RID_STR_EVT_MOUSEMOVED NC_("RID_STR_EVT_MOUSEMOVED", "Mouse moved") +#define RID_STR_EVT_MOUSEPRESSED NC_("RID_STR_EVT_MOUSEPRESSED", "Mouse button pressed") +#define RID_STR_EVT_MOUSERELEASED NC_("RID_STR_EVT_MOUSERELEASED", "Mouse button released") +#define RID_STR_EVT_POSITIONING NC_("RID_STR_EVT_POSITIONING", "Before record change") +#define RID_STR_EVT_POSITIONED NC_("RID_STR_EVT_POSITIONED", "After record change") +#define RID_STR_EVT_RESETTED NC_("RID_STR_EVT_RESETTED", "After resetting") +#define RID_STR_EVT_APPROVERESETTED NC_("RID_STR_EVT_APPROVERESETTED", "Prior to reset") +#define RID_STR_EVT_APPROVEACTIONPERFORMED NC_("RID_STR_EVT_APPROVEACTIONPERFORMED", "Approve action") +#define RID_STR_EVT_SUBMITTED NC_("RID_STR_EVT_SUBMITTED", "Before submitting") +#define RID_STR_EVT_TEXTCHANGED NC_("RID_STR_EVT_TEXTCHANGED", "Text modified") +#define RID_STR_EVT_UNLOADING NC_("RID_STR_EVT_UNLOADING", "Before unloading") +#define RID_STR_EVT_UNLOADED NC_("RID_STR_EVT_UNLOADED", "When unloading") +#define RID_STR_EVT_CHANGED NC_("RID_STR_EVT_CHANGED", "Changed") +#define RID_STR_EVENTS NC_("RID_STR_EVENTS", "Events") +#define RID_STR_ESCAPE_PROCESSING NC_("RID_STR_ESCAPE_PROCESSING", "Analyze SQL command") +#define RID_STR_POSITIONX NC_("RID_STR_POSITIONX", "PositionX") +#define RID_STR_POSITIONY NC_("RID_STR_POSITIONY", "PositionY") +#define RID_STR_TITLE NC_("RID_STR_TITLE", "Title") +#define RID_STR_STEP NC_("RID_STR_STEP", "Page (step)") +#define RID_STR_PROGRESSVALUE NC_("RID_STR_PROGRESSVALUE", "Progress value") +#define RID_STR_PROGRESSVALUE_MIN NC_("RID_STR_PROGRESSVALUE_MIN", "Progress value min.") +#define RID_STR_PROGRESSVALUE_MAX NC_("RID_STR_PROGRESSVALUE_MAX", "Progress value max.") +#define RID_STR_SCROLLVALUE NC_("RID_STR_SCROLLVALUE", "Scroll value") +#define RID_STR_SCROLLVALUE_MAX NC_("RID_STR_SCROLLVALUE_MAX", "Scroll value max.") +#define RID_STR_SCROLLVALUE_MIN NC_("RID_STR_SCROLLVALUE_MIN", "Scroll value min.") +#define RID_STR_SCROLL_WIDTH NC_("RID_STR_SCROLL_WIDTH", "Scroll width") +#define RID_STR_SCROLL_HEIGHT NC_("RID_STR_SCROLL_HEIGHT", "Scroll height") +#define RID_STR_SCROLL_TOP NC_("RID_STR_SCROLL_TOP", "Scroll top") +#define RID_STR_SCROLL_LEFT NC_("RID_STR_SCROLL_LEFT", "Scroll left") +#define RID_STR_DEFAULT_SCROLLVALUE NC_("RID_STR_DEFAULT_SCROLLVALUE", "Default scroll value") +#define RID_STR_LINEINCREMENT NC_("RID_STR_LINEINCREMENT", "Small change") +#define RID_STR_BLOCKINCREMENT NC_("RID_STR_BLOCKINCREMENT", "Large change") +#define RID_STR_REPEAT_DELAY NC_("RID_STR_REPEAT_DELAY", "Delay") +#define RID_STR_REPEAT NC_("RID_STR_REPEAT", "Repeat") +#define RID_STR_VISIBLESIZE NC_("RID_STR_VISIBLESIZE", "Visible size") +#define RID_STR_ORIENTATION NC_("RID_STR_ORIENTATION", "Orientation") +#define RID_STR_EVT_ADJUSTMENTVALUECHANGED NC_("RID_STR_EVT_ADJUSTMENTVALUECHANGED", "While adjusting") +#define RID_STR_DATE NC_("RID_STR_DATE", "Date") +#define RID_STR_STATE NC_("RID_STR_STATE", "State") +#define RID_STR_TIME NC_("RID_STR_TIME", "Time") +#define RID_STR_SCALEIMAGE NC_("RID_STR_SCALEIMAGE", "Scale") +#define RID_STR_PUSHBUTTONTYPE NC_("RID_STR_PUSHBUTTONTYPE", "Button type") +#define RID_STR_UNABLETOCONNECT NC_("RID_STR_UNABLETOCONNECT", "The connection to the data source \"$name$\" could not be established.") +#define RID_STR_TEXT NC_("RID_STR_TEXT", "Text") +#define RID_STR_BOUND_CELL NC_("RID_STR_BOUND_CELL", "Linked cell") +#define RID_STR_LIST_CELL_RANGE NC_("RID_STR_LIST_CELL_RANGE", "Source cell range") +#define RID_STR_CELL_EXCHANGE_TYPE NC_("RID_STR_CELL_EXCHANGE_TYPE", "Contents of the linked cell") +#define RID_STR_SYMBOLCOLOR NC_("RID_STR_SYMBOLCOLOR", "Symbol color") +#define RID_STR_LINEEND_FORMAT NC_("RID_STR_LINEEND_FORMAT", "Text lines end with") +#define RID_STR_TOGGLE NC_("RID_STR_TOGGLE", "Toggle") +#define RID_STR_FOCUSONCLICK NC_("RID_STR_FOCUSONCLICK", "Take Focus on Click") +#define RID_STR_HIDEINACTIVESELECTION NC_("RID_STR_HIDEINACTIVESELECTION", "Hide selection") +#define RID_STR_VISUALEFFECT NC_("RID_STR_VISUALEFFECT", "Style") +#define RID_STR_AUTOLINEBREAK NC_("RID_STR_AUTOLINEBREAK", "Wrap text automatically") +#define RID_STR_TEXTTYPE NC_("RID_STR_TEXTTYPE", "Text type") +#define RID_STR_XML_DATA_MODEL NC_("RID_STR_XML_DATA_MODEL", "XML data model") +#define RID_STR_BIND_EXPRESSION NC_("RID_STR_BIND_EXPRESSION", "Binding expression") +#define RID_STR_XSD_REQUIRED NC_("RID_STR_XSD_REQUIRED", "Required") +#define RID_STR_LIST_BINDING NC_("RID_STR_LIST_BINDING", "List entry source") +#define RID_STR_XSD_RELEVANT NC_("RID_STR_XSD_RELEVANT", "Relevant") +#define RID_STR_XSD_READONLY NC_("RID_STR_XSD_READONLY", "Read-only") +#define RID_STR_XSD_CONSTRAINT NC_("RID_STR_XSD_CONSTRAINT", "Constraint") +#define RID_STR_XSD_CALCULATION NC_("RID_STR_XSD_CALCULATION", "Calculation") +#define RID_STR_XSD_DATA_TYPE NC_("RID_STR_XSD_DATA_TYPE", "Data type") +#define RID_STR_XSD_WHITESPACES NC_("RID_STR_XSD_WHITESPACES", "Whitespaces") +#define RID_STR_SHOW_SCROLLBARS NC_("RID_STR_SHOW_SCROLLBARS", "Scrollbars") +#define RID_STR_XSD_PATTERN NC_("RID_STR_XSD_PATTERN", "Pattern") +#define RID_STR_XSD_LENGTH NC_("RID_STR_XSD_LENGTH", "Length") +#define RID_STR_XSD_MIN_LENGTH NC_("RID_STR_XSD_MIN_LENGTH", "Length (at least)") +#define RID_STR_XSD_MAX_LENGTH NC_("RID_STR_XSD_MAX_LENGTH", "Length (at most)") +#define RID_STR_XSD_TOTAL_DIGITS NC_("RID_STR_XSD_TOTAL_DIGITS", "Digits (total)") +#define RID_STR_XSD_FRACTION_DIGITS NC_("RID_STR_XSD_FRACTION_DIGITS", "Digits (fraction)") +#define RID_STR_XSD_MAX_INCLUSIVE NC_("RID_STR_XSD_MAX_INCLUSIVE", "Max. (inclusive)") +#define RID_STR_XSD_MAX_EXCLUSIVE NC_("RID_STR_XSD_MAX_EXCLUSIVE", "Max. (exclusive)") +#define RID_STR_XSD_MIN_INCLUSIVE NC_("RID_STR_XSD_MIN_INCLUSIVE", "Min. (inclusive)") +#define RID_STR_XSD_MIN_EXCLUSIVE NC_("RID_STR_XSD_MIN_EXCLUSIVE", "Min. (exclusive)") +#define RID_STR_SUBMISSION_ID NC_("RID_STR_SUBMISSION_ID", "Submission") +#define RID_STR_BINDING_NAME NC_("RID_STR_BINDING_NAME", "Binding") +#define RID_STR_SELECTION_TYPE NC_("RID_STR_SELECTION_TYPE", "Selection type") +#define RID_STR_ROOT_DISPLAYED NC_("RID_STR_ROOT_DISPLAYED", "Root displayed") +#define RID_STR_SHOWS_HANDLES NC_("RID_STR_SHOWS_HANDLES", "Show handles") +#define RID_STR_SHOWS_ROOT_HANDLES NC_("RID_STR_SHOWS_ROOT_HANDLES", "Show root handles") +#define RID_STR_EDITABLE NC_("RID_STR_EDITABLE", "Editable") +#define RID_STR_INVOKES_STOP_NOT_EDITING NC_("RID_STR_INVOKES_STOP_NOT_EDITING", "Invokes stop node editing") +#define RID_STR_DECORATION NC_("RID_STR_DECORATION", "With title bar") +#define RID_STR_NOLABEL NC_("RID_STR_NOLABEL", "No Label") +#define RID_STR_BORDERCOLOR NC_("RID_STR_BORDERCOLOR", "Border color") +#define RID_STR_INPUT_REQUIRED NC_("RID_STR_INPUT_REQUIRED", "Input required") +#define RID_STR_WRITING_MODE NC_("RID_STR_WRITING_MODE", "Text direction") +#define RID_STR_ANCHOR_TYPE NC_("RID_STR_ANCHOR_TYPE", "Anchor") +// To translators: That's the 'Regular' as used for a font style (as opposed to 'italic' and 'bold'), so please use a consistent translation. +#define RID_STR_FONTSTYLE_REGULAR NC_("RID_STR_FONTSTYLE_REGULAR", "Regular") +// To translators: That's the 'Bold Italic' as used for a font style, so please use a consistent translation. +#define RID_STR_FONTSTYLE_BOLD_ITALIC NC_("RID_STR_FONTSTYLE_BOLD_ITALIC", "Bold Italic") +// To translators: That's the 'Italic' as used for a font style, so please use a consistent translation. +#define RID_STR_FONTSTYLE_ITALIC NC_("RID_STR_FONTSTYLE_ITALIC", "Italic") +// To translators: That's the 'Bold' as used for a font style, so please use a consistent translation." +#define RID_STR_FONTSTYLE_BOLD NC_("RID_STR_FONTSTYLE_BOLD", "Bold") +#define RID_STR_FONT_DEFAULT NC_("RID_STR_FONT_DEFAULT", "(Default)") +#define RID_STR_URL NC_("RID_STR_URL", "URL") +#define RID_STR_SELECTIONMODEL NC_("RID_STR_SELECTIONMODEL", "Selection Type") +#define RID_STR_USEGRIDLINE NC_("RID_STR_USEGRIDLINE", "Use grid line") +#define RID_STR_GRIDLINECOLOR NC_("RID_STR_GRIDLINECOLOR", "Grid line color") +#define RID_STR_SHOWCOLUMNHEADER NC_("RID_STR_SHOWCOLUMNHEADER", "Show column header") +#define RID_STR_SHOWROWHEADER NC_("RID_STR_SHOWROWHEADER", "Show row header") +#define RID_STR_HEADERBACKGROUNDCOLOR NC_("RID_STR_HEADERBACKGROUNDCOLOR", "Header background color") +#define RID_STR_HEADERTEXTCOLOR NC_("RID_STR_HEADERTEXTCOLOR", "Header text color") +#define RID_STR_ACTIVESELECTIONBACKGROUNDCOLOR NC_("RID_STR_ACTIVESELECTIONBACKGROUNDCOLOR", "Active selection background color") +#define RID_STR_ACTIVESELECTIONTEXTCOLOR NC_("ID_STR_ACTIVESELECTIONTEXTCOLOR", "Active selection text color") +#define RID_STR_INACTIVESELECTIONBACKGROUNDCOLOR NC_("RID_STR_INACTIVESELECTIONBACKGROUNDCOLOR", "Inactive selection background color") +#define RID_STR_INACTIVESELECTIONTEXTCOLOR NC_("RID_STR_INACTIVESELECTIONTEXTCOLOR", "Inactive selection text color") +#define RID_STR_STANDARD NC_("RID_STR_STANDARD", "Default") +#define RID_STR_PROPPAGE_DEFAULT NC_("RID_STR_PROPPAGE_DEFAULT", "General") +#define RID_STR_PROPPAGE_DATA NC_("RID_STR_PROPPAGE_DATA", "Data") +#define RID_EMBED_IMAGE_PLACEHOLDER NC_("RID_EMBED_IMAGE_PLACEHOLDER", "") +#define RID_STR_TEXT_FORMAT NC_("RID_STR_TEXT_FORMAT", "Text") + +#define RID_STR_CONFIRM_DELETE_DATA_TYPE NC_("RID_STR_CONFIRM_DELETE_DATA_TYPE", "Do you want to delete the data type '#type#' from the model?\n" \ + "Please note that this will affect all controls which are bound to this data type.") +#define RID_STR_PROPTITLE_PUSHBUTTON NC_("RID_STR_PROPTITLE_PUSHBUTTON", "Button") +#define RID_STR_PROPTITLE_RADIOBUTTON NC_("RID_STR_PROPTITLE_RADIOBUTTON", "Option Button") +#define RID_STR_PROPTITLE_CHECKBOX NC_("RID_STR_PROPTITLE_CHECKBOX", "Check Box") +#define RID_STR_PROPTITLE_FIXEDTEXT NC_("RID_STR_PROPTITLE_FIXEDTEXT", "Label Field") +#define RID_STR_PROPTITLE_GROUPBOX NC_("RID_STR_PROPTITLE_GROUPBOX", "Group Box") +#define RID_STR_PROPTITLE_EDIT NC_("RID_STR_PROPTITLE_EDIT", "Text Box") +#define RID_STR_PROPTITLE_FORMATTED NC_("RID_STR_PROPTITLE_FORMATTED", "Formatted Field") +#define RID_STR_PROPTITLE_LISTBOX NC_("RID_STR_PROPTITLE_LISTBOX", "List Box") +#define RID_STR_PROPTITLE_COMBOBOX NC_("RID_STR_PROPTITLE_COMBOBOX", "Combo Box") +#define RID_STR_PROPTITLE_IMAGEBUTTON NC_("RID_STR_PROPTITLE_IMAGEBUTTON", "Image Button") +#define RID_STR_PROPTITLE_HIDDENCONTROL NC_("RID_STR_PROPTITLE_HIDDENCONTROL", "Hidden Control") +#define RID_STR_PROPTITLE_UNKNOWNCONTROL NC_("RID_STR_PROPTITLE_UNKNOWNCONTROL", "Control (unknown type)") +#define RID_STR_PROPTITLE_IMAGECONTROL NC_("RID_STR_PROPTITLE_IMAGECONTROL", "Image Control") +#define RID_STR_PROPTITLE_FILECONTROL NC_("RID_STR_PROPTITLE_FILECONTROL", "File Selection") +#define RID_STR_PROPTITLE_DATEFIELD NC_("RID_STR_PROPTITLE_DATEFIELD", "Date Field") +#define RID_STR_PROPTITLE_TIMEFIELD NC_("RID_STR_PROPTITLE_TIMEFIELD", "Time Field") +#define RID_STR_PROPTITLE_NUMERICFIELD NC_("RID_STR_PROPTITLE_NUMERICFIELD", "Numeric Field") +#define RID_STR_PROPTITLE_CURRENCYFIELD NC_("RID_STR_PROPTITLE_CURRENCYFIELD", "Currency Field") +#define RID_STR_PROPTITLE_PATTERNFIELD NC_("RID_STR_PROPTITLE_PATTERNFIELD", "Pattern Field") +#define RID_STR_PROPTITLE_DBGRID NC_("RID_STR_PROPTITLE_DBGRID", "Table Control ") + +#define STR_DETAIL_FORM NC_("STR_DETAIL_FORM", "Sub Form") +#define STR_MASTER_FORM NC_("STR_MASTER_FORM", "Master Form") +// To translators: # will be replace with a name. +#define STR_ERROR_RETRIEVING_COLUMNS NC_("STR_ERROR_RETRIEVING_COLUMNS", "The columns of '#' could not be retrieved.") + +#define RID_STR_FORMS NC_("RID_STR_FORMS", "Forms") + +#define RID_UPDATE_STR_CHECKING NC_("RID_UPDATE_STR_CHECKING", "Checking...") +#define RID_UPDATE_STR_CHECKING_ERR NC_("RID_UPDATE_STR_CHECKING_ERR", "Checking for an update failed.") +#define RID_UPDATE_STR_NO_UPD_FOUND NC_("RID_UPDATE_STR_NO_UPD_FOUND", "%PRODUCTNAME %PRODUCTVERSION is up to date.") +#define RID_UPDATE_STR_UPD_FOUND NC_("RID_UPDATE_STR_UPD_FOUND", "%PRODUCTNAME %NEXTVERSION is available.\n\nThe installed version is %PRODUCTNAME %PRODUCTVERSION.\n\nNote: Before downloading an update, please ensure that you have sufficient access rights to install it.\nA password, usually the administrator's or root password, may be required.") +#define RID_UPDATE_STR_DLG_TITLE NC_("RID_UPDATE_STR_DLG_TITLE", "Check for Updates") +#define RID_UPDATE_STR_DOWNLOAD_PAUSE NC_("RID_UPDATE_STR_DOWNLOAD_PAUSE", "Downloading %PRODUCTNAME %NEXTVERSION paused at...") +#define RID_UPDATE_STR_DOWNLOAD_ERR NC_("RID_UPDATE_STR_DOWNLOAD_ERR", "Downloading %PRODUCTNAME %NEXTVERSION stalled at") +#define RID_UPDATE_STR_DOWNLOAD_WARN NC_("RID_UPDATE_STR_DOWNLOAD_WARN", "The download location is: %DOWNLOAD_PATH.\n\nUnder Tools – Options... - %PRODUCTNAME – Online Update you can change the download location.") +#define RID_UPDATE_STR_DOWNLOAD_DESCR NC_("RID_UPDATE_STR_DOWNLOAD_DESCR", "%FILE_NAME has been downloaded to %DOWNLOAD_PATH.") +#define RID_UPDATE_STR_DOWNLOAD_UNAVAIL NC_("RID_UPDATE_STR_DOWNLOAD_UNAVAIL", "The automatic download of the update is currently not available.\n\nClick 'Download...' to download %PRODUCTNAME %NEXTVERSION manually from the web site.") +#define RID_UPDATE_STR_DOWNLOADING NC_("RID_UPDATE_STR_DOWNLOADING", "Downloading %PRODUCTNAME %NEXTVERSION...") +#define RID_UPDATE_STR_READY_INSTALL NC_("RID_UPDATE_STR_READY_INSTALL", "Download of %PRODUCTNAME %NEXTVERSION completed. Ready for installation.") +#define RID_UPDATE_STR_CANCEL_DOWNLOAD NC_("RID_UPDATE_STR_CANCEL_DOWNLOAD", "Do you really want to cancel the download?") +#define RID_UPDATE_STR_BEGIN_INSTALL NC_("RID_UPDATE_STR_BEGIN_INSTALL", "To install the update, %PRODUCTNAME %PRODUCTVERSION needs to be closed. Do you want to install the update now?") +#define RID_UPDATE_STR_INSTALL_ERROR NC_("RID_UPDATE_STR_INSTALL_ERROR", "Could not run the installer application, please run %FILE_NAME in %DOWNLOAD_PATH manually.") +#define RID_UPDATE_STR_OVERWRITE_WARNING NC_("RID_UPDATE_STR_OVERWRITE_WARNING", "A file with that name already exists! Do you want to overwrite the existing file?") +#define RID_UPDATE_STR_RELOAD_WARNING NC_("RID_UPDATE_STR_RELOAD_WARNING", "A file with the name '%FILENAME' already exists in '%DOWNLOAD_PATH'! Do you want to continue with the download or delete and reload the file?") +#define RID_UPDATE_STR_RELOAD_RELOAD NC_("RID_UPDATE_STR_RELOAD_RELOAD", "Reload File") +#define RID_UPDATE_STR_RELOAD_CONTINUE NC_("RID_UPDATE_STR_RELOAD_CONTINUE", "Continue") +#define RID_UPDATE_STR_PERCENT NC_("RID_UPDATE_STR_PERCENT", "%PERCENT%") +#define RID_UPDATE_FT_STATUS NC_("RID_UPDATE_FT_STATUS", "Status") +#define RID_UPDATE_FT_DESCRIPTION NC_("RID_UPDATE_FT_DESCRIPTION", "Description") +#define RID_UPDATE_BTN_CLOSE NC_("RID_UPDATE_BTN_CLOSE", "Close") +#define RID_UPDATE_BTN_DOWNLOAD NC_("RID_UPDATE_BTN_DOWNLOAD", "~Download") +#define RID_UPDATE_BTN_INSTALL NC_("RID_UPDATE_BTN_INSTALL", "~Install") +#define RID_UPDATE_BTN_PAUSE NC_("RID_UPDATE_BTN_PAUSE", "~Pause") +#define RID_UPDATE_BTN_RESUME NC_("RID_UPDATE_BTN_RESUME", "~Resume") +#define RID_UPDATE_BTN_CANCEL NC_("RID_UPDATE_BTN_CANCEL", "Cancel") +#define RID_UPDATE_BUBBLE_T_UPDATE_AVAIL NC_("RID_UPDATE_BUBBLE_T_UPDATE_AVAIL", "%PRODUCTNAME update available") +#define RID_UPDATE_BUBBLE_UPDATE_AVAIL NC_("RID_UPDATE_BUBBLE_UPDATE_AVAIL", "Click the icon to start the download.") +#define RID_UPDATE_BUBBLE_T_UPDATE_NO_DOWN NC_("RID_UPDATE_BUBBLE_T_UPDATE_NO_DOWN", "%PRODUCTNAME update available") +#define RID_UPDATE_BUBBLE_UPDATE_NO_DOWN NC_("RID_UPDATE_BUBBLE_UPDATE_NO_DOWN", "Click the icon for more information.") +#define RID_UPDATE_BUBBLE_T_AUTO_START NC_("RID_UPDATE_BUBBLE_T_AUTO_START", "%PRODUCTNAME update available") +#define RID_UPDATE_BUBBLE_AUTO_START NC_("RID_UPDATE_BUBBLE_AUTO_START", "Download of update begins.") +#define RID_UPDATE_BUBBLE_T_DOWNLOADING NC_("RID_UPDATE_BUBBLE_T_DOWNLOADING", "Download of update in progress") +#define RID_UPDATE_BUBBLE_DOWNLOADING NC_("RID_UPDATE_BUBBLE_DOWNLOADING", "Click the icon to pause.") +#define RID_UPDATE_BUBBLE_T_DOWNLOAD_PAUSED NC_("RID_UPDATE_BUBBLE_T_DOWNLOAD_PAUSED", "Download of update paused") +#define RID_UPDATE_BUBBLE_DOWNLOAD_PAUSED NC_("RID_UPDATE_BUBBLE_DOWNLOAD_PAUSED", "Click the icon to resume.") +#define RID_UPDATE_BUBBLE_T_ERROR_DOWNLOADING NC_("RID_UPDATE_BUBBLE_T_ERROR_DOWNLOADING", "Download of update stalled") +#define RID_UPDATE_BUBBLE_ERROR_DOWNLOADING NC_("RID_UPDATE_BUBBLE_ERROR_DOWNLOADING", "Click the icon for more information.") +#define RID_UPDATE_BUBBLE_T_DOWNLOAD_AVAIL NC_("RID_UPDATE_BUBBLE_T_DOWNLOAD_AVAIL", "Download of update completed") +#define RID_UPDATE_BUBBLE_DOWNLOAD_AVAIL NC_("RID_UPDATE_BUBBLE_DOWNLOAD_AVAIL", "Click the icon to start the installation.") +#define RID_UPDATE_BUBBLE_T_EXT_UPD_AVAIL NC_("RID_UPDATE_BUBBLE_T_EXT_UPD_AVAIL", "Updates for extensions available") +#define RID_UPDATE_BUBBLE_EXT_UPD_AVAIL NC_("RID_UPDATE_BUBBLE_EXT_UPD_AVAIL", "Click the icon for more information.") + +#define STR_COULD_NOT_BE_INIT NC_("STR_COULD_NOT_BE_INIT", "The SANE interface could not be initialized. Scanning is not possible.") +#define STR_SLOW_PREVIEW NC_("STR_SLOW_PREVIEW", "The device does not offer a preview option. Therefore, a normal scan will be used as a preview instead. This may take a considerable amount of time.") +#define STR_ERROR_SCAN NC_("STR_ERROR_SCAN", "An error occurred while scanning.") +#define STR_DEVICE_DESC NC_("STR_DEVICE_DESC", "Device: %s\nVendor: %s\nModel: %s\nType: %s") + +#define RID_BIB_STR_FRAME_TITLE NC_("RID_BIB_STR_FRAME_TITLE", "Bibliography Database") +#define RID_MAP_QUESTION NC_("RID_MAP_QUESTION", "Do you want to edit the column arrangement?") +#define RID_BIB_STR_NONE NC_("RID_BIB_STR_NONE", "") + +#define ST_ERROR_PREFIX NC_("ST_ERROR_PREFIX", "The following column names could not be assigned:\n") +#define ST_TYPE_ARTICLE NC_("ST_TYPE_ARTICLE", "Article") +#define ST_TYPE_BOOK NC_("ST_TYPE_BOOK", "Book") +#define ST_TYPE_BOOKLET NC_("ST_TYPE_BOOKLET", "Brochures") +#define ST_TYPE_CONFERENCE NC_("ST_TYPE_CONFERENCE", "Conference proceedings article (BiBTeX)") +#define ST_TYPE_INBOOK NC_("ST_TYPE_INBOOK", "Book excerpt") +#define ST_TYPE_INCOLLECTION NC_("ST_TYPE_INCOLLECTION", "Book excerpt with title") +#define ST_TYPE_INPROCEEDINGS NC_("ST_TYPE_INPROCEEDINGS", "Conference proceedings article") +#define ST_TYPE_JOURNAL NC_("ST_TYPE_JOURNAL", "Journal") +#define ST_TYPE_MANUAL NC_("ST_TYPE_MANUAL", "Techn. documentation") +#define ST_TYPE_MASTERSTHESIS NC_("ST_TYPE_MASTERSTHESIS", "Thesis") +#define ST_TYPE_MISC NC_("ST_TYPE_MISC", "Miscellaneous") +#define ST_TYPE_PHDTHESIS NC_("ST_TYPE_PHDTHESIS", "Dissertation") +#define ST_TYPE_PROCEEDINGS NC_("ST_TYPE_PROCEEDINGS", "Conference proceedings") +#define ST_TYPE_TECHREPORT NC_("ST_TYPE_TECHREPORT", "Research report") +#define ST_TYPE_UNPUBLISHED NC_("ST_TYPE_UNPUBLISHED", "Unpublished") +#define ST_TYPE_EMAIL NC_("ST_TYPE_EMAIL", "Email") +#define ST_TYPE_WWW NC_("ST_TYPE_WWW", "WWW document") +#define ST_TYPE_CUSTOM1 NC_("ST_TYPE_CUSTOM1", "User-defined1") +#define ST_TYPE_CUSTOM2 NC_("ST_TYPE_CUSTOM2", "User-defined2") +#define ST_TYPE_CUSTOM3 NC_("ST_TYPE_CUSTOM3", "User-defined3") +#define ST_TYPE_CUSTOM4 NC_("ST_TYPE_CUSTOM4", "User-defined4") +#define ST_TYPE_CUSTOM5 NC_("ST_TYPE_CUSTOM5", "User-defined5") +#define ST_TYPE_TITLE NC_("ST_TYPE_TITLE", "General") + +#define RID_STR_ABSOURCEDIALOGTITLE NC_("RID_STR_ABSOURCEDIALOGTITLE", "Address Book Data Source Wizard") +#define RID_STR_SELECT_ABTYPE NC_("RID_STR_SELECT_ABTYPE", "Address Book Type") +#define RID_STR_INVOKE_ADMIN_DIALOG NC_("RID_STR_INVOKE_ADMIN_DIALOG", "Connection Settings") +#define RID_STR_TABLE_SELECTION NC_("RID_STR_TABLE_SELECTION", "Table Selection") +#define RID_STR_MANUAL_FIELD_MAPPING NC_("RID_STR_MANUAL_FIELD_MAPPING", "Field Assignment") +#define RID_STR_FINAL_CONFIRM NC_("RID_STR_FINAL_CONFIRM", "Data Source Title") +#define RID_STR_NEEDTYPESELECTION NC_("RID_STR_NEEDTYPESELECTION", "Please select a type of address book.") +#define RID_STR_QRY_NOTABLES NC_("RID_STR_QRY_NOTABLES", "The data source does not contain any tables.\nDo you want to set it up as an address data source, anyway?") +#define RID_STR_QRY_NO_EVO_GW NC_("RID_STR_QRY_NO_EVO_GW", "You don't seem to have any GroupWise account configured in Evolution.\nDo you want to set it up as an address data source, anyway?") +#define RID_STR_DEFAULT_NAME NC_("RID_STR_DEFAULT_NAME", "Addresses") +#define RID_STR_ADMINDIALOGTITLE NC_("RID_STR_ADMINDIALOGTITLE", "Create Address Data Source") +#define RID_STR_NOCONNECTION NC_("RID_STR_NOCONNECTION", "The connection could not be established.") +#define RID_STR_PLEASECHECKSETTINGS NC_("RID_STR_PLEASECHECKSETTINGS", "Please check the settings made for the data source.") +#define RID_STR_FIELDDIALOGTITLE NC_("RID_STR_FIELDDIALOGTITLE", "Address Data - Field Assignment") +#define RID_STR_NOFIELDSASSIGNED NC_("RID_STR_NOFIELDSASSIGNED", "There are no fields assigned at this time.\nYou can either assign fields now or do so later by first choosing:\n\"File - Template - Address Book Source...\"") + +#define RID_STR_OPTION_DB_FIELD_TITLE NC_("RID_STR_OPTION_DB_FIELD_TITLE", "Database Field") +#define RID_STR_TYPE_TABLE NC_("RID_STR_TYPE_TABLE", "Table") +#define RID_STR_TYPE_QUERY NC_("RID_STR_TYPE_QUERY", "Query") +#define RID_STR_TYPE_COMMAND NC_("RID_STR_TYPE_COMMAND", "SQL command") + +#define RID_STR_GROUPWIZARD_TITLE NC_("RID_STR_GROUPWIZARD_TITLE", "Group Element Wizard") +#define RID_STR_GRIDWIZARD_TITLE NC_("RID_STR_GRIDWIZARD_TITLE", "Table Element Wizard") +#define RID_STR_LISTWIZARD_TITLE NC_("RID_STR_LISTWIZARD_TITLE", "List Box Wizard") +#define RID_STR_COMBOWIZARD_TITLE NC_("RID_STR_COMBOWIZARD_TITLE", "Combo Box Wizard") +#define RID_STR_COULDNOTOPENTABLE NC_("RID_STR_COULDNOTOPENTABLE", "The table connection to the data source could not be established.") + +#define RID_STR_DATEPOSTFIX NC_("RID_STR_DATEPOSTFIX", " (Date)") +#define RID_STR_TIMEPOSTFIX NC_("RID_STR_TIMEPOSTFIX", " (Time)") + +#define RID_STR_FIELDINFO_COMBOBOX NC_("RID_STR_FIELDINFO_COMBOBOX", "The contents of the field selected will be shown in the combo box list.") +#define RID_STR_FIELDINFO_LISTBOX NC_("RID_STR_FIELDINFO_LISTBOX", "The contents of the selected field will be shown in the list box if the linked fields are identical.") +#define RID_STR_COMBOWIZ_DBFIELD NC_("RID_STR_COMBOWIZ_DBFIELD", "You can either save the value of the combo box in a database field or use it for display purposes.") + +#define RID_STR_GROUPWIZ_DBFIELD NC_("RID_STR_GROUPWIZ_DBFIELD", "You can either save the value of the option group in a database field or use it for a later action.") + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/inc/yesno.hrc b/extensions/inc/yesno.hrc new file mode 100644 index 000000000..32792bb81 --- /dev/null +++ b/extensions/inc/yesno.hrc @@ -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_EXTENSIONS_INC_YESNO_HRC +#define INCLUDED_EXTENSIONS_INC_YESNO_HRC + +#include + +#define NC_(Context, String) TranslateId(Context, reinterpret_cast(u8##String)) + +namespace { + +const TranslateId RID_RSC_ENUM_YESNO[] = +{ + NC_("RID_RSC_ENUM_YESNO", "No" ), + NC_("RID_RSC_ENUM_YESNO", "Yes" ) +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/qa/bibliography/bibliography.cxx b/extensions/qa/bibliography/bibliography.cxx new file mode 100644 index 000000000..af68ee95e --- /dev/null +++ b/extensions/qa/bibliography/bibliography.cxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +namespace +{ +/// Covers extensions/source/bibliography/ fixes. +class Test : public test::BootstrapFixture, public unotest::MacrosTest +{ +}; +} + +CPPUNIT_TEST_FIXTURE(Test, testBibliographyLoader) +{ + // Given a bibliography provider: + uno::Reference xBibAccess + = frame::Bibliography::create(mxComponentContext); + uno::Reference xPropSet(xBibAccess, uno::UNO_QUERY); + uno::Sequence aSeq; + + // When getting the column names: + xPropSet->getPropertyValue("BibliographyDataFieldNames") >>= aSeq; + + // Then make sure we have columns and all have non-empty names: + CPPUNIT_ASSERT(aSeq.hasElements()); + + // Without the accompanying fix in place, this test would have failed, as the last column + // (LOCAL_URL) had an empty field name: + for (const auto& rPair : std::as_const(aSeq)) + { + CPPUNIT_ASSERT(!rPair.Name.isEmpty()); + } +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/qa/integration/extensions/ComponentFactory.java b/extensions/qa/integration/extensions/ComponentFactory.java new file mode 100644 index 000000000..ec848c4df --- /dev/null +++ b/extensions/qa/integration/extensions/ComponentFactory.java @@ -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 . + */ + +package integration.extensions; + +import com.sun.star.uno.XComponentContext; +import com.sun.star.lang.XSingleComponentFactory; +import java.lang.reflect.Constructor; + +public class ComponentFactory implements XSingleComponentFactory +{ + private final Class m_handlerClass; + private Constructor m_defaultConstructor; + private Constructor m_initConstructor; + + public ComponentFactory( Class _handlerClass ) + { + m_handlerClass = _handlerClass; + + Class objectArrayClass = null; + try + { + objectArrayClass = Class.forName("[Ljava.lang.Object;"); + } + catch ( java.lang.ClassNotFoundException e ) { } + + Constructor ctors[] = _handlerClass.getConstructors(); + for ( int i = 0; i < ctors.length; ++i) + { + Class ctorParams[] = ctors[i].getParameterTypes(); + if ( ( ctorParams.length == 1 ) && ( ctorParams[0].equals( XComponentContext.class ) ) ) + m_defaultConstructor = ctors[i]; + if ( ( ctorParams.length == 2 ) + && ( ctorParams[0].equals( XComponentContext.class ) ) + && ( ctorParams[1].equals( objectArrayClass ) ) + ) + m_initConstructor = ctors[i]; + } + if ( m_defaultConstructor == null ) + throw new java.lang.IllegalArgumentException(); + } + + private Object ipml_createInstance( Constructor _ctor, Object[] _arguments ) + { + Object newInstance = null; + try + { + newInstance = _ctor.newInstance( _arguments ); + } + catch( InstantiationException e ) + { + System.err.println( "InstantiationException: Could not instantiate an instance of " + m_handlerClass.getName() ); + } + catch( IllegalAccessException e ) + { + System.err.println( "IllegalAccessException: Could not instantiate an instance of " + m_handlerClass.getName() ); + } + catch( java.lang.reflect.InvocationTargetException e ) + { + System.err.println( "InvocationTargetException: Could not instantiate an instance of " + m_handlerClass.getName() ); + } + return newInstance; + } + + public Object createInstanceWithArgumentsAndContext(Object[] _arguments, XComponentContext _componentContext) throws com.sun.star.uno.Exception + { + if ( m_initConstructor != null ) + return ipml_createInstance( m_initConstructor, new Object[] { _componentContext, _arguments } ); + else + return createInstanceWithContext( _componentContext ); + } + + public Object createInstanceWithContext(XComponentContext _componentContext) throws com.sun.star.uno.Exception + { + return ipml_createInstance( m_defaultConstructor, new Object[] { _componentContext } ); + } +} + diff --git a/extensions/qa/integration/extensions/ConsoleWait.java b/extensions/qa/integration/extensions/ConsoleWait.java new file mode 100644 index 000000000..34fdaa7c0 --- /dev/null +++ b/extensions/qa/integration/extensions/ConsoleWait.java @@ -0,0 +1,120 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 integration.extensions; + +import com.sun.star.uno.*; +import com.sun.star.lang.XComponent; + +public class ConsoleWait implements com.sun.star.lang.XEventListener +{ + private final Object m_disposable; + + /** a helper class which waits for a console ENTER key event in a dedicated thread, + and notifies a ConsoleWait object if this event happened + */ + private class WaitForEnter extends java.lang.Thread + { + private final ConsoleWait m_toNotify; + private boolean m_done; + + public WaitForEnter( ConsoleWait _toNotify ) + { + m_toNotify = _toNotify; + m_done = false; + } + + public boolean isDone() + { + return m_done; + } + + @Override + public void run() + { + try + { + System.out.println( "\npress enter to exit" ); + System.in.read(); + + m_done = true; + // notify that the user pressed the key + synchronized ( m_toNotify ) + { + m_toNotify.notify(); + } + } + catch( java.lang.Exception e ) + { + // not really interested in + System.err.println( e ); + } + } + } + + /** creates a ConsoleWait instance + * @param _disposable + * a component whose disposal should be monitored. When this component dies, + * the ConsoleWait also returns from a waitForConsole call, even if the user + * did not yet press the enter key + */ + public ConsoleWait( Object _disposable ) + { + m_disposable = _disposable; + XComponent component = UnoRuntime.queryInterface( XComponent.class, _disposable ); + if ( component != null ) + component.addEventListener( this ); + } + + /** waits for the user to press the ENTER key (on the console where she started the java program) + or the disposable component to be closed by the user. + @return + TRUE if the user pressed a key on the console, FALSE if she closed the document + */ + public boolean waitForUserInput() throws java.lang.Exception + { + synchronized (this) + { + WaitForEnter keyWaiter = new WaitForEnter( this ); + keyWaiter.start(); + wait(); + + // if the waiter thread is done, the user pressed enter + boolean bKeyPressed = keyWaiter.isDone(); + if ( !bKeyPressed ) + keyWaiter.interrupt(); + + return bKeyPressed; + } + } + + /* ------------------------------------------------------------------ */ + /* XEventListener overridables */ + /* ------------------------------------------------------------------ */ + public void disposing( com.sun.star.lang.EventObject eventObject ) + { + if ( eventObject.Source.equals( m_disposable ) ) + { + // notify ourself that we can stop waiting for user input + synchronized (this) + { + notify(); + } + } + } +} diff --git a/extensions/qa/integration/extensions/Frame.java b/extensions/qa/integration/extensions/Frame.java new file mode 100644 index 000000000..15f26de74 --- /dev/null +++ b/extensions/qa/integration/extensions/Frame.java @@ -0,0 +1,215 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 integration.extensions; + +import com.sun.star.uno.*; +import com.sun.star.frame.*; +import com.sun.star.task.XStatusIndicatorFactory; +import com.sun.star.util.XCloseable; + +/** + * wraps the com.sun.star.frame.Frame service + */ +public class Frame implements XDispatchProvider, + XDispatchProviderInterception, + XFramesSupplier, + XStatusIndicatorFactory, + XCloseable +{ + private XFrame m_frame; + private XDispatchProvider m_dispatchProvider; + private XDispatchProviderInterception m_dispatchProviderInterception; + private XFramesSupplier m_framesSupplier; + private XStatusIndicatorFactory m_statusIndicatorFactory; + private XCloseable m_closeable; + + /** Creates a new instance of Frame */ + public Frame( Object _frameComponent ) + { + if ( _frameComponent != null ) + { + m_frame = UnoRuntime.queryInterface( XFrame.class, _frameComponent ); + m_dispatchProvider = UnoRuntime.queryInterface( XDispatchProvider.class, _frameComponent ); + m_dispatchProviderInterception = UnoRuntime.queryInterface( XDispatchProviderInterception.class, _frameComponent ); + m_framesSupplier = UnoRuntime.queryInterface( XFramesSupplier.class, _frameComponent ); + m_statusIndicatorFactory = UnoRuntime.queryInterface( XStatusIndicatorFactory.class, _frameComponent ); + m_closeable = UnoRuntime.queryInterface( XCloseable.class, _frameComponent ); + } + } + + public XFrame getXFrame() + { + return m_frame; + } + + public void activate() + { + m_frame.activate(); + } + + public void addEventListener(com.sun.star.lang.XEventListener _eventListener) + { + m_frame.addEventListener( _eventListener ); + } + + public void addFrameActionListener(XFrameActionListener _frameActionListener) + { + m_frame.addFrameActionListener( _frameActionListener ); + } + + public void contextChanged() + { + m_frame.contextChanged(); + } + + public com.sun.star.task.XStatusIndicator createStatusIndicator() + { + return m_statusIndicatorFactory.createStatusIndicator(); + } + + public void deactivate() + { + m_frame.deactivate(); + } + + public void dispose() + { + m_frame.dispose(); + } + + public XFrame findFrame(String str, int param) + { + return m_frame.findFrame( str, param ); + } + + public XFrame getActiveFrame() + { + return m_framesSupplier.getActiveFrame(); + } + + public com.sun.star.awt.XWindow getComponentWindow() + { + return m_frame.getComponentWindow(); + } + + public com.sun.star.awt.XWindow getContainerWindow() + { + return m_frame.getContainerWindow(); + } + + public XController getController() + { + return m_frame.getController(); + } + + public XFramesSupplier getCreator() + { + return m_frame.getCreator(); + } + + public XFrames getFrames() + { + return m_framesSupplier.getFrames(); + } + + public String getName() + { + return m_frame.getName(); + } + + public void initialize(com.sun.star.awt.XWindow _window) + { + m_frame.initialize( _window ); + } + + public boolean isActive() + { + return m_frame.isActive(); + } + + public boolean isTop() + { + return m_frame.isTop(); + } + + public XDispatch queryDispatch(com.sun.star.util.URL _url, String _str, int _param) + { + return m_dispatchProvider.queryDispatch( _url, _str, _param ); + } + + public XDispatch[] queryDispatches(DispatchDescriptor[] dispatchDescriptor) + { + return m_dispatchProvider.queryDispatches( dispatchDescriptor ); + } + + public void registerDispatchProviderInterceptor(XDispatchProviderInterceptor _dispatchProviderInterceptor) + { + m_dispatchProviderInterception.registerDispatchProviderInterceptor( _dispatchProviderInterceptor ); + } + + public void releaseDispatchProviderInterceptor(XDispatchProviderInterceptor _dispatchProviderInterceptor) + { + m_dispatchProviderInterception.releaseDispatchProviderInterceptor( _dispatchProviderInterceptor ); + } + + public void removeEventListener(com.sun.star.lang.XEventListener _eventListener) + { + m_frame.removeEventListener( _eventListener ); + } + + public void removeFrameActionListener(XFrameActionListener _frameActionListener) + { + m_frame.removeFrameActionListener( _frameActionListener ); + } + + public void setActiveFrame(XFrame _frame) + { + m_framesSupplier.setActiveFrame( _frame ); + } + + public boolean setComponent(com.sun.star.awt.XWindow _window, XController _controller) + { + return m_frame.setComponent( _window, _controller ); + } + + public void setCreator(XFramesSupplier _framesSupplier) + { + m_frame.setCreator( _framesSupplier ); + } + + public void setName(String str) + { + m_frame.setName( str ); + } + + public void close(boolean _deliverOwnership) throws com.sun.star.util.CloseVetoException + { + m_closeable.close( _deliverOwnership ); + } + + public void removeCloseListener(com.sun.star.util.XCloseListener _closeListener) + { + m_closeable.removeCloseListener( _closeListener ); + } + + public void addCloseListener(com.sun.star.util.XCloseListener _closeListener) + { + m_closeable.addCloseListener( _closeListener ); + } +} diff --git a/extensions/qa/integration/extensions/HelpTextProvider.java b/extensions/qa/integration/extensions/HelpTextProvider.java new file mode 100644 index 000000000..8bd6596bc --- /dev/null +++ b/extensions/qa/integration/extensions/HelpTextProvider.java @@ -0,0 +1,58 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 integration.extensions; + +import com.sun.star.inspection.XObjectInspectorUI; +import com.sun.star.inspection.XPropertyControl; +import com.sun.star.inspection.XPropertyControlObserver; +import com.sun.star.lang.NoSupportException; + +/** displays help text for the currently selected method + */ +public class HelpTextProvider implements XPropertyControlObserver +{ + private final XObjectInspectorUI m_inspectorUI; + + /** + * Creates a new instance of HelpTextProvider + */ + public HelpTextProvider( XObjectInspectorUI _inspectorUI ) + { + m_inspectorUI = _inspectorUI; + m_inspectorUI.registerControlObserver( this ); + } + + public void focusGained( XPropertyControl _propertyControl ) + { + try + { + String helpText = "here could be the help for:\n"; + helpText += _propertyControl.getValue().toString(); + m_inspectorUI.setHelpSectionText( helpText ); + } + catch (NoSupportException ex) + { + ex.printStackTrace(); + } + } + + public void valueChanged( XPropertyControl _propertyControl ) + { + // not interested in + } +} diff --git a/extensions/qa/integration/extensions/MethodHandler.java b/extensions/qa/integration/extensions/MethodHandler.java new file mode 100644 index 000000000..ffc81c5f5 --- /dev/null +++ b/extensions/qa/integration/extensions/MethodHandler.java @@ -0,0 +1,217 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 integration.extensions; + +import com.sun.star.uno.*; +import com.sun.star.beans.*; +import com.sun.star.reflection.*; +import com.sun.star.inspection.*; + +public class MethodHandler implements XPropertyHandler +{ + private XIntrospection m_introspection; + private XIdlMethod[] m_methods; + private java.util.HashMap m_methodsHash; + + /** Creates a new instance of MethodHandler */ + public MethodHandler( XComponentContext _context ) + { + m_methodsHash = new java.util.HashMap(); + + try + { + m_introspection = UnoRuntime.queryInterface( XIntrospection.class, + _context.getServiceManager().createInstanceWithContext( "com.sun.star.beans.Introspection", _context ) + ); + } + catch( com.sun.star.uno.Exception e ) + { + System.err.println( "MethodHandler: could not create an Introspection service, not much functionality will be available." ); + } + } + + + + public void actuatingPropertyChanged(String _propertyName, Object _newValue, Object _oldValue, com.sun.star.inspection.XObjectInspectorUI _objectInspectorUI, boolean _firstTimeInit) throws com.sun.star.lang.NullPointerException + { + // not interested in + } + + public void addEventListener(com.sun.star.lang.XEventListener _eventListener) + { + // ignoring this + } + + public void addPropertyChangeListener(com.sun.star.beans.XPropertyChangeListener _propertyChangeListener) throws com.sun.star.lang.NullPointerException + { + // ignoring this + } + + public Object convertToControlValue(String _propertyName, Object _propertyValue, com.sun.star.uno.Type type) throws com.sun.star.beans.UnknownPropertyException + { + return _propertyValue; + } + + public Object convertToPropertyValue(String _propertyName, Object _controlValue) throws com.sun.star.beans.UnknownPropertyException + { + return _controlValue; + } + + public com.sun.star.inspection.LineDescriptor describePropertyLine(String _propertyName, com.sun.star.inspection.XPropertyControlFactory _propertyControlFactory) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.NullPointerException + { + com.sun.star.inspection.LineDescriptor descriptor = new com.sun.star.inspection.LineDescriptor(); + + descriptor = new LineDescriptor(); + descriptor.Category = "Methods"; + descriptor.DisplayName = "has method"; + descriptor.HasPrimaryButton = descriptor.HasSecondaryButton = false; + descriptor.IndentLevel = 0; + try + { + XPropertyControl control = UnoRuntime.queryInterface( + XPropertyControl.class, _propertyControlFactory.createPropertyControl( + PropertyControlType.TextField, true ) ); + + descriptor.Control = control; + } + catch( com.sun.star.lang.IllegalArgumentException e ) + { + } + return descriptor; + } + + public void dispose() + { + // nothing to do + } + + public String[] getActuatingProperties() + { + // none + return new String[] { }; + } + + public com.sun.star.beans.PropertyState getPropertyState(String _propertyName) throws com.sun.star.beans.UnknownPropertyException + { + return com.sun.star.beans.PropertyState.DIRECT_VALUE; + } + + public Object getPropertyValue(String _propertyName) throws com.sun.star.beans.UnknownPropertyException + { + XIdlMethod method = impl_getMethod( _propertyName ); + + String signature = ""; + signature += method.getReturnType().getName(); + signature += " "; + signature += method.getName(); + + signature += "("; + + XIdlClass[] parameterTypes = method.getParameterTypes(); + for ( int param = 0; param(); + + XIntrospectionAccess introspectionAccess = m_introspection.inspect( _component ); + if ( introspectionAccess == null ) + return; + + m_methods = introspectionAccess.getMethods( MethodConcept.ALL ); + } + + public boolean isComposable(String _propertyName) throws com.sun.star.beans.UnknownPropertyException + { + return true; + } + + public com.sun.star.inspection.InteractiveSelectionResult onInteractivePropertySelection(String str, boolean param, Object[] obj, com.sun.star.inspection.XObjectInspectorUI xObjectInspectorUI) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.NullPointerException + { + return InteractiveSelectionResult.Cancelled; + } + + public void removeEventListener(com.sun.star.lang.XEventListener _eventListener) + { + // ignoring this + } + + public void removePropertyChangeListener(com.sun.star.beans.XPropertyChangeListener _propertyChangeListener) + { + // ignoring this + } + + public void setPropertyValue(String str, Object obj) throws com.sun.star.beans.UnknownPropertyException + { + // we declared our properties as readonly + throw new java.lang.RuntimeException(); + } + + public boolean suspend(boolean param) + { + return true; + } + + /** returns the descriptor for the method with the given name + * @param _propertyName + * the name of the method whose descriptor should be obtained + * @throws com.sun.star.beans.UnknownPropertyException + * if we don't have a method hash, or the given property name does not denote a method of our inspectee + */ + private XIdlMethod impl_getMethod( String _methodName ) throws UnknownPropertyException + { + XIdlMethod method = m_methodsHash.get( _methodName ); + if ( method == null ) + throw new com.sun.star.beans.UnknownPropertyException(); + + return method; + } +} diff --git a/extensions/qa/integration/extensions/ObjectInspector.java b/extensions/qa/integration/extensions/ObjectInspector.java new file mode 100644 index 000000000..2b2fa4e0a --- /dev/null +++ b/extensions/qa/integration/extensions/ObjectInspector.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 integration.extensions; + +import com.sun.star.uno.XComponentContext; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.lang.XMultiServiceFactory; + +import com.sun.star.frame.*; +import com.sun.star.inspection.*; +import com.sun.star.beans.*; + +public class ObjectInspector extends complexlib.ComplexTestCase +{ + private XComponentContext m_context; + private XMultiServiceFactory m_orb; + private Frame m_desktop; + + static final private String m_inspectorFrameName = "ObjectInspector"; + + /* ------------------------------------------------------------------ */ + @Override + public String[] getTestMethodNames() + { + return new String[] { + "interactiveObjectInspector" + }; + } + + /* ------------------------------------------------------------------ */ + @Override + public String getTestObjectName() + { + return "Test Skeleton"; + } + + /* ------------------------------------------------------------------ */ + public void before() throws com.sun.star.uno.Exception, java.lang.Exception + { + m_orb = param.getMSF(); + m_context = UnoRuntime.queryInterface( XComponentContext.class, + UnoRuntime.queryInterface( XPropertySet.class, m_orb ).getPropertyValue( "DefaultContext" ) ); + m_desktop = new Frame( m_orb.createInstance( "com.sun.star.frame.Desktop" ) ); + } + + /* ------------------------------------------------------------------ */ + public void after() throws java.lang.Exception + { + closeExistentInspector(); + } + + /* ------------------------------------------------------------------ */ + public void interactiveObjectInspector() throws com.sun.star.uno.Exception, java.lang.Exception + { + closeExistentInspector(); + + // the to-be-inspected object + XFrame inspectee = m_desktop.getActiveFrame(); + + // the inspector + XObjectInspector inspector = createObjectInspector(); + + // do inspect + inspector.inspect( new Object[] { inspectee } ); + + ConsoleWait keyWaiter = new ConsoleWait( inspector ); + keyWaiter.waitForUserInput(); + } + + /* ------------------------------------------------------------------ */ + private XObjectInspector createObjectInspector() throws com.sun.star.uno.Exception + { + com.sun.star.awt.XWindow floatingWindow = createFloatingWindow(); + + Frame inspectorFrame = new Frame( m_orb.createInstance( "com.sun.star.frame.Frame" ) ); + inspectorFrame.setName( m_inspectorFrameName ); + inspectorFrame.initialize( floatingWindow ); + m_desktop.getFrames().append( inspectorFrame.getXFrame() ); + + // handler factories: + Object[] handlerFactories = new Object[] { + "com.sun.star.inspection.GenericPropertyHandler", + new ComponentFactory( ServicesHandler.class ), + new ComponentFactory( MethodHandler.class ) + }; + // a model + XObjectInspectorModel model = ObjectInspectorModel.createWithHandlerFactoriesAndHelpSection( + m_context, handlerFactories, 4, 4 ); + + // create the ObjectInspector + XObjectInspector inspector = com.sun.star.inspection.ObjectInspector.createWithModel( + m_context, model ); + + // add an observer which will emit help texts + new HelpTextProvider( inspector.getInspectorUI() ); + + // plug it into the frame + inspector.attachFrame( inspectorFrame.getXFrame() ); + + // make the window visible + floatingWindow.setVisible( true ); + + // outta here + return inspector; + } + + /* ------------------------------------------------------------------ */ + private void closeExistentInspector() + { + Frame existentInspectorFrame = new Frame( m_desktop.findFrame( m_inspectorFrameName, 255 ) ); + try + { + existentInspectorFrame.close( true ); + } + catch( com.sun.star.util.CloseVetoException e ) + { + failed( "could not close the existent inspector frame" ); + } + } + + /* ------------------------------------------------------------------ */ + private com.sun.star.awt.XWindow createFloatingWindow() throws com.sun.star.uno.Exception + { + com.sun.star.awt.XToolkit toolkit = UnoRuntime.queryInterface( + com.sun.star.awt.XToolkit.class, m_orb.createInstance( "com.sun.star.awt.Toolkit" ) ); + + com.sun.star.awt.WindowDescriptor windowDescriptor = new com.sun.star.awt.WindowDescriptor(); + windowDescriptor.Type = com.sun.star.awt.WindowClass.TOP; + windowDescriptor.WindowServiceName = "modelessdialog"; // "floatingwindow" would need a parent + windowDescriptor.ParentIndex = -1; + //windowDescriptor.Parent = null; + + windowDescriptor.Bounds = new com.sun.star.awt.Rectangle( 500, 100, 400, 600 ); + windowDescriptor.WindowAttributes = com.sun.star.awt.WindowAttribute.BORDER + + com.sun.star.awt.WindowAttribute.MOVEABLE + + com.sun.star.awt.WindowAttribute.SIZEABLE + + com.sun.star.awt.WindowAttribute.CLOSEABLE + + com.sun.star.awt.VclWindowPeerAttribute.CLIPCHILDREN; + + return UnoRuntime.queryInterface( com.sun.star.awt.XWindow.class, + toolkit.createWindow( windowDescriptor ) ); + } +} diff --git a/extensions/qa/integration/extensions/ServicesHandler.java b/extensions/qa/integration/extensions/ServicesHandler.java new file mode 100644 index 000000000..c84e128e8 --- /dev/null +++ b/extensions/qa/integration/extensions/ServicesHandler.java @@ -0,0 +1,212 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 integration.extensions; + +import com.sun.star.uno.*; +import com.sun.star.beans.*; +import com.sun.star.inspection.*; +import com.sun.star.frame.*; +import com.sun.star.lang.XServiceInfo; + +public class ServicesHandler implements XPropertyHandler +{ + private final XComponentContext m_context; + private String[] m_supportedServices; + + private static class ClickHandler implements com.sun.star.awt.XActionListener + { + XComponentContext m_context; + private final String m_serviceName; + + public ClickHandler( XComponentContext _context, String _serviceName ) + { + m_context = _context; + m_serviceName = _serviceName; + } + + public void disposing(com.sun.star.lang.EventObject eventObject) + { + // not interested in + } + + public void actionPerformed(com.sun.star.awt.ActionEvent actionEvent) + { + try + { + // translate the service name into a URL to dispatch + String documentationURL = "https://api.libreoffice.org/docs/common/ref/" + m_serviceName.replace('.','/') + ".html"; + System.out.println( documentationURL ); + + // the OpenHyperlink command, to be dispatched to the Desktop + com.sun.star.util.URL dispatchURL[] = { new com.sun.star.util.URL() }; + dispatchURL[0].Complete = ".uno:OpenHyperlink"; + com.sun.star.util.XURLTransformer transformer = UnoRuntime.queryInterface( + com.sun.star.util.XURLTransformer.class, + m_context.getServiceManager().createInstanceWithContext( "com.sun.star.util.URLTransformer", m_context ) ); + transformer.parseStrict( dispatchURL ); + + // the dispatcher for the OpenHyperlink command + Frame desktop = new Frame( + m_context.getServiceManager().createInstanceWithContext( "com.sun.star.frame.Desktop", m_context ) ); + XDispatch dispatcher = desktop.queryDispatch(dispatchURL[0],"",0); + + // the arguments for the OpenHyperlink command + PropertyValue dispatchArgs[] = new PropertyValue[] { new PropertyValue() }; + dispatchArgs[0].Name = "URL"; + dispatchArgs[0].Value = documentationURL; + + dispatcher.dispatch(dispatchURL[0], dispatchArgs ); + } + catch( com.sun.star.uno.Exception e ) + { + e.printStackTrace( System.err ); + } + } + } + + /** Creates a new instance of ServicesHandler */ + public ServicesHandler( XComponentContext _context ) + { + m_context = _context; + m_supportedServices = new String[] { }; + } + + public void actuatingPropertyChanged(String _propertyName, Object _newValue, Object _oldValue, com.sun.star.inspection.XObjectInspectorUI _objectInspectorUI, boolean _firstTimeInit) throws com.sun.star.lang.NullPointerException + { + // not interested in + } + + public void addEventListener(com.sun.star.lang.XEventListener _eventListener) + { + // ignoring this + } + + public void addPropertyChangeListener(com.sun.star.beans.XPropertyChangeListener _propertyChangeListener) throws com.sun.star.lang.NullPointerException + { + // ignoring this + } + + public Object convertToControlValue(String _propertyName, Object _propertyValue, com.sun.star.uno.Type type) throws com.sun.star.beans.UnknownPropertyException + { + return _propertyValue; + } + + public Object convertToPropertyValue(String _propertyName, Object _controlValue) throws com.sun.star.beans.UnknownPropertyException + { + return _controlValue; + } + + public com.sun.star.inspection.LineDescriptor describePropertyLine(String _propertyName, com.sun.star.inspection.XPropertyControlFactory _propertyControlFactory) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.NullPointerException + { + com.sun.star.inspection.LineDescriptor descriptor = new com.sun.star.inspection.LineDescriptor(); + + descriptor = new LineDescriptor(); + descriptor.Category = "Services"; + descriptor.DisplayName = "supports service"; + descriptor.HasPrimaryButton = descriptor.HasSecondaryButton = false; + descriptor.IndentLevel = 0; + try + { + XHyperlinkControl hyperlinkControl = UnoRuntime.queryInterface( + XHyperlinkControl.class, _propertyControlFactory.createPropertyControl( PropertyControlType.HyperlinkField, true ) ); + hyperlinkControl.addActionListener( new ClickHandler( m_context, _propertyName ) ); + + descriptor.Control = hyperlinkControl; + } + catch( com.sun.star.lang.IllegalArgumentException e ) + { + } + return descriptor; + } + + public void dispose() + { + // nothing to do + } + + public String[] getActuatingProperties() + { + // none + return new String[] { }; + } + + public com.sun.star.beans.PropertyState getPropertyState(String _propertyName) throws com.sun.star.beans.UnknownPropertyException + { + return com.sun.star.beans.PropertyState.DIRECT_VALUE; + } + + public Object getPropertyValue(String _propertyName) throws com.sun.star.beans.UnknownPropertyException + { + return _propertyName; + } + + public String[] getSupersededProperties() + { + return new String[] { "SupportedServiceNames" }; + // we're used in conjunction with a GenericPropertyHandler, which (via inspection) finds + // a property SupportedServiceNames, resulting from the XServiceInfo.getSupportedServiceNames + // method. Since we handle those ourself, we supersede them. + } + + public com.sun.star.beans.Property[] getSupportedProperties() + { + Property[] properties = new Property[ m_supportedServices.length ]; + for ( int i=0; i 1 Then + WScript.Echo "Pass $(SRCDIR) as parameter" + WScript.Quit(1) +End If + +srcdir = WScript.Arguments.Item(0) + +exitStatus = 0 + +testCounter = 0 +okCounter = 0 + +Sub ExitWithReport + If okCounter <> testCounter Then + exitStatus = 1 + End If + WScript.Echo "OK (" + CStr(okCounter) + ")" + WScript.Quit(exitstatus) +End Sub + +Sub CheckFatal(expr) + testCounter = testCounter + 1 + If Not Eval(expr) Then + WScript.Echo "FAIL: " & expr + ExitWithReport + Else + WScript.Echo "PASS: " & expr + okCounter = okCounter + 1 + End If +End Sub + +Sub Check(expr) + testCounter = testCounter + 1 + If Not Eval(expr) Then + WScript.Echo "FAIL: " & expr + Else + WScript.Echo "PASS: " & expr + okCounter = okCounter + 1 + End If +End Sub + +Sub CheckIfExpected(expr, expected) + testCounter = testCounter + 1 + actual = Eval(expr) + If actual <> expected Then + WScript.Echo "FAIL: Value of '" & expr & "' was expected to be '" & CStr(expected) & "', but was " & CStr(actual) + Else + WScript.Echo "PASS: " & expr & " == " & CStr(expected) + okCounter = okCounter + 1 + End If +End Sub + +Sub CheckErrorFatal(test) + testCounter = testCounter + 1 + Execute(test) + If Err.Number <> 0 Then + WScript.Echo "FAIL: " & test + WScript.Echo "ERROR: " & Err.Description + ExitWithReport + Else + WScript.Echo "PASS: " & test + okCounter = okCounter + 1 + End If +End Sub + +Sub CheckError(test) + testCounter = testCounter + 1 + Execute(test) + If Err.Number <> 0 Then + WScript.Echo "FAIL: " & test + WScript.Echo "ERROR: " & Err.Description + Else + WScript.Echo "PASS: " & test + okCounter = okCounter + 1 + End If +End Sub + +WScript.Echo "Running Automation client tests" + +On Error Resume Next + +' FIXME: How can we ever make this work specifically with the +' LibreOffice in instdir, when WScript.CreateObject() wants the +' symbolic name that it then looks up from the Registry to find the +' CLSID of the class? + +CheckErrorFatal "Set writer = WScript.CreateObject(""Writer.Application"")" +CheckErrorFatal "writer.Visible = True" +CheckErrorFatal "writer.Caption = ""=== This is Writer ===""" +CheckErrorFatal "writer.ShowMe" + +CheckErrorFatal "Set documents = writer.Documents" + +' Open two randomly chosen documents +CheckErrorFatal "Set d1 = documents.Open(""" & srcdir & "/sw/qa/extras/ww8export/data/n325936.doc"")" +CheckErrorFatal "Set d2 = documents.Open(""" & srcdir & "/sw/qa/extras/ww8export/data/bnc636128.doc"")" + +CheckErrorFatal "n1 = d1.FullName" +CheckErrorFatal "n2 = d2.FullName" + +CheckIfExpected "n1", "n325936.doc" +CheckIfExpected "n2", "bnc636128.doc" + +CheckErrorFatal "Set c1 = d1.Content" +CheckErrorFatal "Set c2 = d2.Content" + +' The range of characters in these documents +CheckIfExpected "c1.Start", 0 +CheckIfExpected "c1.End", 4 +CheckIfExpected "c2.Start", 0 +CheckIfExpected "c2.End", 42 + +' Check number of paragraphs in each document +CheckErrorFatal "Set p1 = d1.Paragraphs" +nparas = 0 +For Each i in p1 + nparas = nparas + 1 +Next +CheckIfExpected "nparas", 1 + +CheckErrorFatal "Set p2 = d2.Paragraphs" +nparas = 0 +For Each i in p2 + nparas = nparas + 1 +Next +CheckIfExpected "nparas", 1 + +CheckErrorFatal "writer.Quit" + +ExitWithReport diff --git a/extensions/qa/unoapi/extensions.sce b/extensions/qa/unoapi/extensions.sce new file mode 100644 index 000000000..b63a954b7 --- /dev/null +++ b/extensions/qa/unoapi/extensions.sce @@ -0,0 +1,5 @@ +-o pcr.ObjectInspector +# this object must be tested twice, because it is the only one in this module +# The runner only prints "[0-9]+? of [0-9]+? tests failed" +# if more than one tests is executed. This is needed by cwscheckapi. +-o pcr.ObjectInspector diff --git a/extensions/qa/update/simple.xml b/extensions/qa/update/simple.xml new file mode 100644 index 000000000..f2694700a --- /dev/null +++ b/extensions/qa/update/simple.xml @@ -0,0 +1,18 @@ + + + + LibreOffice 3.5.0 Beta2 + 3.5.0 Beta2 + 123456-abcdef-1a2b3c-4d5e6f + Linux + x86 + + + diff --git a/extensions/qa/update/test_update.cxx b/extensions/qa/update/test_update.cxx new file mode 100644 index 000000000..27d634b3b --- /dev/null +++ b/extensions/qa/update/test_update.cxx @@ -0,0 +1,152 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.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 "../../source/update/check/updatecheck.hxx" +#include "../../source/update/check/updateprotocol.hxx" + +using namespace com::sun::star; +using namespace com::sun::star::xml; + +namespace testupdate { + +class Test : public test::BootstrapFixture +{ +public: + virtual void setUp() override + { + // so that comphelper::getProcessServiceFactory() works, m_xContext is + // set up, etc. + test::BootstrapFixture::setUp(); + + if ( !m_xProvider.is() ) + m_xProvider = deployment::UpdateInformationProvider::create( m_xContext ); + + // repositories that we will be checking + m_aRepositoryList = { m_directories.getURLFromSrc( u"/extensions/qa/update/simple.xml" ) }; + } + + virtual void tearDown() override + { + m_xProvider.clear(); + m_aRepositoryList.realloc( 0 ); + test::BootstrapFixture::tearDown(); + } + +protected: + // test the getUpdateInformationEnumeration() method + void testGetUpdateInformationEnumeration() + { + uno::Reference< container::XEnumeration > aUpdateInfoEnumeration = + m_xProvider->getUpdateInformationEnumeration( + m_aRepositoryList, + "TODO" ); // unused when we do not have a 'feed' + + if ( !aUpdateInfoEnumeration.is() ) + CPPUNIT_FAIL( "Calling getUpdateInformationEnumeration() with TODO failed." ); + + if ( !aUpdateInfoEnumeration->hasMoreElements() ) + CPPUNIT_FAIL( "Should have more elements (this one is 1st)." ); + + deployment::UpdateInformationEntry aEntry; + if ( aUpdateInfoEnumeration->nextElement() >>= aEntry ) + { + CPPUNIT_ASSERT_EQUAL( OUString("description"), aEntry.UpdateDocument->getNodeName() ); + + uno::Reference< dom::XNodeList> xChildNodes = aEntry.UpdateDocument->getChildNodes(); + CPPUNIT_ASSERT( xChildNodes.is() ); +#if 0 + for ( int i = 0; i < xChildNodes->getLength(); ++i ) + { + fprintf( stderr, "node == %d\n", i ); + uno::Reference< dom::XElement > xChildId( xChildNodes->item( i ), uno::UNO_QUERY ); + if ( xChildId.is() ) + { + fprintf( stderr, "Name == %s\n", OUStringToOString( xChildId->getNodeName(), RTL_TEXTENCODING_UTF8 ).getStr() ); + fprintf( stderr, "Value == %s\n", OUStringToOString( xChildId->getNodeValue(), RTL_TEXTENCODING_UTF8 ).getStr() ); + } + } +#endif + CPPUNIT_ASSERT_EQUAL( sal_Int32(13), xChildNodes->getLength() ); + + //uno::Reference< dom::XElement > xChildId( xChildNodes->item( 0 ), uno::UNO_QUERY ); + //CPPUNIT_ASSERT( xChildId.is() ); + //CPPUNIT_ASSERT( xChildId->getNodeValue() == "LibreOffice_3.4" ); + //fprintf( stderr, "Attribute == %s\n", OUStringToOString( aEntry.UpdateDocument->getAttribute( OUString( "test" ) ), RTL_TEXTENCODING_UTF8 ).getStr() ); + //fprintf( stderr, "Value == %s\n", OUStringToOString( xChildId->getNodeValue(), RTL_TEXTENCODING_UTF8 ).getStr() ); + // TODO check more deeply + } + else + CPPUNIT_FAIL( "Wrong type of the entry." ); + } + + // test the checkForUpdates() method - update is available + void testCheckUpdateAvailable() + { + UpdateInfo aInfo; + rtl::Reference< UpdateCheck > aController( UpdateCheck::get() ); + + if ( checkForUpdates( aInfo, m_xContext, aController->getInteractionHandler(), m_xProvider, + u"Linux", + u"x86", + m_aRepositoryList, + u"111111-222222-333333-444444", + "InstallSetID" ) ) + { + CPPUNIT_ASSERT_EQUAL( std::size_t(1), aInfo.Sources.size() ); + CPPUNIT_ASSERT_EQUAL( OUString("http://www.libreoffice.org/download/"), aInfo.Sources[0].URL ); + } + else + CPPUNIT_FAIL( "Calling checkForUpdates() failed." ); + } + + // test the checkForUpdates() method - we are up-to-date + void testCheckUpToDate() + { + UpdateInfo aInfo; + rtl::Reference< UpdateCheck > aController( UpdateCheck::get() ); + + if ( checkForUpdates( aInfo, m_xContext, aController->getInteractionHandler(), m_xProvider, + u"Linux", + u"x86", + m_aRepositoryList, + u"123456-abcdef-1a2b3c-4d5e6f", + "InstallSetID" ) ) + { + CPPUNIT_ASSERT( aInfo.Sources.empty() ); + } + else + CPPUNIT_FAIL( "Calling checkForUpdates() failed." ); + } + + CPPUNIT_TEST_SUITE(Test); + CPPUNIT_TEST(testGetUpdateInformationEnumeration); + CPPUNIT_TEST(testCheckUpdateAvailable); + CPPUNIT_TEST(testCheckUpToDate); + CPPUNIT_TEST_SUITE_END(); + +private: + uno::Reference< deployment::XUpdateInformationProvider > m_xProvider; + uno::Sequence< OUString > m_aRepositoryList; +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(testupdate::Test); +} // namespace testupdate + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/abp.component b/extensions/source/abpilot/abp.component new file mode 100644 index 000000000..91b9638c4 --- /dev/null +++ b/extensions/source/abpilot/abp.component @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/extensions/source/abpilot/abpfinalpage.cxx b/extensions/source/abpilot/abpfinalpage.cxx new file mode 100644 index 000000000..045a66d3f --- /dev/null +++ b/extensions/source/abpilot/abpfinalpage.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 "abpfinalpage.hxx" +#include "addresssettings.hxx" +#include "abspilot.hxx" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace abp +{ + + using namespace ::svt; + using namespace ::utl; + + static std::shared_ptr lcl_getBaseFilter() + { + std::shared_ptr pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)"); + OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!"); + return pFilter; + } + + FinalPage::FinalPage(weld::Container* pPage, OAddressBookSourcePilot* pWizard) + : AddressBookSourcePage(pPage, pWizard, "modules/sabpilot/ui/datasourcepage.ui", + "DataSourcePage") + , m_xLocation(new SvtURLBox(m_xBuilder->weld_combo_box("location"))) + , m_xBrowse(m_xBuilder->weld_button("browse")) + , m_xRegisterName(m_xBuilder->weld_check_button("available")) + , m_xEmbed(m_xBuilder->weld_check_button("embed")) + , m_xNameLabel(m_xBuilder->weld_label("nameft")) + , m_xLocationLabel(m_xBuilder->weld_label("locationft")) + , m_xName(m_xBuilder->weld_entry("name")) + , m_xDuplicateNameError(m_xBuilder->weld_label("warning")) + { + m_xLocation->SetSmartProtocol(INetProtocol::File); + m_xLocation->DisableHistory(); + + m_xLocationController.reset( new svx::DatabaseLocationInputController(pWizard->getORB(), + *m_xLocation, *m_xBrowse, *pWizard->getDialog()) ); + + m_xName->connect_changed( LINK(this, FinalPage, OnEntryNameModified) ); + m_xLocation->connect_changed( LINK(this, FinalPage, OnComboNameModified) ); + m_xRegisterName->connect_toggled( LINK( this, FinalPage, OnRegister ) ); + m_xRegisterName->set_active(true); + m_xEmbed->connect_toggled( LINK( this, FinalPage, OnEmbed ) ); + m_xEmbed->set_active(true); + } + + FinalPage::~FinalPage() + { + m_xLocationController.reset(); + } + + bool FinalPage::isValidName() const + { + OUString sCurrentName(m_xName->get_text()); + + if (sCurrentName.isEmpty()) + // the name must not be empty + return false; + + if ( m_aInvalidDataSourceNames.find( sCurrentName ) != m_aInvalidDataSourceNames.end() ) + // there already is a data source with this name + return false; + + return true; + } + + void FinalPage::setFields() + { + AddressSettings& rSettings = getSettings(); + + INetURLObject aURL( rSettings.sDataSourceName ); + if( aURL.GetProtocol() == INetProtocol::NotValid ) + { + OUString sPath = SvtPathOptions().GetWorkPath(); + sPath += "/" + rSettings.sDataSourceName; + + std::shared_ptr pFilter = lcl_getBaseFilter(); + if ( pFilter ) + { + OUString sExt = pFilter->GetDefaultExtension(); + sPath += o3tl::getToken(sExt,1,'*'); + } + + aURL.SetURL(sPath); + } + OSL_ENSURE( aURL.GetProtocol() != INetProtocol::NotValid ,"No valid file name!"); + rSettings.sDataSourceName = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + m_xLocationController->setURL( rSettings.sDataSourceName ); + OUString sName = aURL.getName( ); + sal_Int32 nPos = sName.indexOf(aURL.GetFileExtension()); + if ( nPos != -1 ) + { + sName = sName.replaceAt(nPos-1, 4, u""); + } + m_xName->set_text(sName); + + OnRegister(*m_xRegisterName); + } + + + void FinalPage::initializePage() + { + AddressBookSourcePage::initializePage(); + + setFields(); + } + + bool FinalPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!AddressBookSourcePage::commitPage(_eReason)) + return false; + + if ( ( ::vcl::WizardTypes::eTravelBackward != _eReason ) + && ( !m_xLocationController->prepareCommit() ) + ) + return false; + + AddressSettings& rSettings = getSettings(); + rSettings.sDataSourceName = m_xLocationController->getURL(); + rSettings.bRegisterDataSource = m_xRegisterName->get_active(); + if ( rSettings.bRegisterDataSource ) + rSettings.sRegisteredDataSourceName = m_xName->get_text(); + rSettings.bEmbedDataSource = m_xEmbed->get_active(); + + return true; + } + + void FinalPage::Activate() + { + AddressBookSourcePage::Activate(); + + // get the names of all data sources + ODataSourceContext aContext( getORB() ); + aContext.getDataSourceNames( m_aInvalidDataSourceNames ); + + // give the name edit the focus + m_xLocation->grab_focus(); + + // default the finish button + getDialog()->defaultButton( WizardButtonFlags::FINISH ); + + OnEmbed(*m_xEmbed); + } + + void FinalPage::Deactivate() + { + AddressBookSourcePage::Deactivate(); + + // default the "next" button, again + getDialog()->defaultButton( WizardButtonFlags::NEXT ); + // disable the finish button + getDialog()->enableButtons( WizardButtonFlags::FINISH, false ); + } + + + bool FinalPage::canAdvance() const + { + return false; + } + + void FinalPage::implCheckName() + { + bool bValidName = isValidName(); + bool bEmptyName = m_xName->get_text().isEmpty(); + bool bEmptyLocation = m_xLocation->get_active_text().isEmpty(); + + // enable or disable the finish button + getDialog()->enableButtons( WizardButtonFlags::FINISH, !bEmptyLocation && (!m_xRegisterName->get_active() || bValidName) ); + + // show the error message for an invalid name + m_xDuplicateNameError->set_visible(!bValidName && !bEmptyName); + } + + IMPL_LINK_NOARG( FinalPage, OnEntryNameModified, weld::Entry&, void ) + { + implCheckName(); + } + + IMPL_LINK_NOARG( FinalPage, OnComboNameModified, weld::ComboBox&, void ) + { + implCheckName(); + } + + IMPL_LINK_NOARG(FinalPage, OnRegister, weld::Toggleable&, void) + { + bool bEnable = m_xRegisterName->get_active(); + m_xNameLabel->set_sensitive(bEnable); + m_xName->set_sensitive(bEnable); + implCheckName(); + } + + IMPL_LINK_NOARG(FinalPage, OnEmbed, weld::Toggleable&, void) + { + bool bEmbed = m_xEmbed->get_active(); + m_xLocationLabel->set_sensitive(!bEmbed); + m_xLocation->set_sensitive(!bEmbed); + m_xBrowse->set_sensitive(!bEmbed); + } + +} // namespace abp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/abpfinalpage.hxx b/extensions/source/abpilot/abpfinalpage.hxx new file mode 100644 index 000000000..6c6c5d69d --- /dev/null +++ b/extensions/source/abpilot/abpfinalpage.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 "abspage.hxx" +#include "abptypes.hxx" + +#include +#include + +namespace abp +{ + + class FinalPage final : public AddressBookSourcePage + { + std::unique_ptr m_xLocation; + std::unique_ptr m_xBrowse; + std::unique_ptr m_xRegisterName; + std::unique_ptr m_xEmbed; + std::unique_ptr m_xNameLabel; + std::unique_ptr m_xLocationLabel; + std::unique_ptr m_xName; + std::unique_ptr m_xDuplicateNameError; + + std::unique_ptr + m_xLocationController; + + StringBag m_aInvalidDataSourceNames; + + public: + explicit FinalPage(weld::Container* pPage, OAddressBookSourcePilot* pController); + virtual ~FinalPage() override; + + private: + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + // BuilderPage overridables + virtual void Activate() override; + virtual void Deactivate() override; + + // OImportPage overridables + virtual bool canAdvance() const override; + + DECL_LINK(OnEntryNameModified, weld::Entry&, void); + DECL_LINK(OnComboNameModified, weld::ComboBox&, void); + DECL_LINK(OnRegister, weld::Toggleable&, void); + DECL_LINK(OnEmbed, weld::Toggleable&, void); + + bool isValidName() const; + void implCheckName(); + void setFields(); + }; + +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/abptypes.hxx b/extensions/source/abpilot/abptypes.hxx new file mode 100644 index 000000000..0339253ff --- /dev/null +++ b/extensions/source/abpilot/abptypes.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include +#include + +#include + + +namespace abp +{ + + + typedef std::set StringBag; + + typedef std::map MapString2String; + + +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/abspage.cxx b/extensions/source/abpilot/abspage.cxx new file mode 100644 index 000000000..ee36cee27 --- /dev/null +++ b/extensions/source/abpilot/abspage.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 "abspage.hxx" +#include "abspilot.hxx" + +namespace abp +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + AddressBookSourcePage::AddressBookSourcePage(weld::Container* pPage, OAddressBookSourcePilot* pDialog, const OUString& rUIXMLDescription, const OString& rID) + : AddressBookSourcePage_Base(pPage, pDialog, rUIXMLDescription, rID) + , m_pDialog(pDialog) + { + } + + void AddressBookSourcePage::Activate() + { + AddressBookSourcePage_Base::Activate(); + m_pDialog->updateTravelUI(); + } + + void AddressBookSourcePage::Deactivate() + { + AddressBookSourcePage_Base::Deactivate(); + m_pDialog->enableButtons(WizardButtonFlags::NEXT, true); + } + + OAddressBookSourcePilot* AddressBookSourcePage::getDialog() + { + return m_pDialog; + } + + const OAddressBookSourcePilot* AddressBookSourcePage::getDialog() const + { + return m_pDialog; + } + + AddressSettings& AddressBookSourcePage::getSettings() + { + return m_pDialog->getSettings(); + } + + const AddressSettings& AddressBookSourcePage::getSettings() const + { + return m_pDialog->getSettings(); + } + + const Reference< XComponentContext > & AddressBookSourcePage::getORB() const + { + return m_pDialog->getORB(); + } + +} // namespace abp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/abspage.hxx b/extensions/source/abpilot/abspage.hxx new file mode 100644 index 000000000..4d78533ad --- /dev/null +++ b/extensions/source/abpilot/abspage.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace abp +{ + class OAddressBookSourcePilot; + struct AddressSettings; + + typedef ::vcl::OWizardPage AddressBookSourcePage_Base; + /// the base class for all tab pages in the address book source wizard + class AddressBookSourcePage : public AddressBookSourcePage_Base + { + OAddressBookSourcePilot* m_pDialog; + + protected: + AddressBookSourcePage(weld::Container* pPage, OAddressBookSourcePilot* pController, const OUString& rUIXMLDescription, const OString& rID); + + protected: + // helper + OAddressBookSourcePilot* getDialog(); + const OAddressBookSourcePilot* getDialog() const; + const css::uno::Reference< css::uno::XComponentContext > & + getORB() const; + AddressSettings& getSettings(); + const AddressSettings& getSettings() const; + + // BuilderPage overridables + virtual void Activate() override; + virtual void Deactivate() override; + }; +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/abspilot.cxx b/extensions/source/abpilot/abspilot.cxx new file mode 100644 index 000000000..0a5cba073 --- /dev/null +++ b/extensions/source/abpilot/abspilot.cxx @@ -0,0 +1,449 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "abspilot.hxx" +#include +#include +#include +#include +#include "typeselectionpage.hxx" +#include "admininvokationpage.hxx" +#include "tableselectionpage.hxx" +#include +#include +#include +#include "abpfinalpage.hxx" +#include "fieldmappingpage.hxx" +#include "fieldmappingimpl.hxx" + +using vcl::RoadmapWizardTypes::PathId; + +namespace abp +{ + + +#define STATE_SELECT_ABTYPE 0 +#define STATE_INVOKE_ADMIN_DIALOG 1 +#define STATE_TABLE_SELECTION 2 +#define STATE_MANUAL_FIELD_MAPPING 3 +#define STATE_FINAL_CONFIRM 4 + +#define PATH_COMPLETE 1 +#define PATH_NO_SETTINGS 2 +#define PATH_NO_FIELDS 3 +#define PATH_NO_SETTINGS_NO_FIELDS 4 + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + OAddressBookSourcePilot::OAddressBookSourcePilot(weld::Window* _pParent, const Reference< XComponentContext >& _rxORB) + :OAddressBookSourcePilot_Base( _pParent ) + ,m_xORB(_rxORB) + ,m_aNewDataSource(_rxORB) + ,m_eNewDataSourceType( AST_INVALID ) + { + declarePath( PATH_COMPLETE, + {STATE_SELECT_ABTYPE, + STATE_INVOKE_ADMIN_DIALOG, + STATE_TABLE_SELECTION, + STATE_MANUAL_FIELD_MAPPING, + STATE_FINAL_CONFIRM} + ); + declarePath( PATH_NO_SETTINGS, + {STATE_SELECT_ABTYPE, + STATE_TABLE_SELECTION, + STATE_MANUAL_FIELD_MAPPING, + STATE_FINAL_CONFIRM} + ); + declarePath( PATH_NO_FIELDS, + {STATE_SELECT_ABTYPE, + STATE_INVOKE_ADMIN_DIALOG, + STATE_TABLE_SELECTION, + STATE_FINAL_CONFIRM} + ); + declarePath( PATH_NO_SETTINGS_NO_FIELDS, + {STATE_SELECT_ABTYPE, + STATE_TABLE_SELECTION, + STATE_FINAL_CONFIRM} + ); + + m_xPrevPage->set_help_id(HID_ABSPILOT_PREVIOUS); + m_xNextPage->set_help_id(HID_ABSPILOT_NEXT); + m_xCancel->set_help_id(HID_ABSPILOT_CANCEL); + m_xFinish->set_help_id(HID_ABSPILOT_FINISH); + m_xHelp->set_help_id(UID_ABSPILOT_HELP); + + // some initial settings +#ifdef UNX +#ifdef MACOSX + m_aSettings.eType = AST_MACAB; +#else +// FIXME: if KDE use KAB instead + m_aSettings.eType = AST_EVOLUTION; +#endif +#else + m_aSettings.eType = AST_OTHER; +#endif + m_aSettings.sDataSourceName = compmodule::ModuleRes(RID_STR_DEFAULT_NAME); + m_aSettings.bRegisterDataSource = false; + m_aSettings.bEmbedDataSource = false; + m_aSettings.bIgnoreNoTable = false; + + defaultButton(WizardButtonFlags::NEXT); + enableButtons(WizardButtonFlags::FINISH, false); + ActivatePage(); + m_xAssistant->set_current_page(0); + + typeSelectionChanged( m_aSettings.eType ); + + OUString sDialogTitle = compmodule::ModuleRes(RID_STR_ABSOURCEDIALOGTITLE); + setTitleBase(sDialogTitle); + m_xAssistant->set_help_id(HID_ABSPILOT); + } + + OUString OAddressBookSourcePilot::getStateDisplayName( WizardState _nState ) const + { + TranslateId pResId; + switch ( _nState ) + { + case STATE_SELECT_ABTYPE: pResId = RID_STR_SELECT_ABTYPE; break; + case STATE_INVOKE_ADMIN_DIALOG: pResId = RID_STR_INVOKE_ADMIN_DIALOG; break; + case STATE_TABLE_SELECTION: pResId = RID_STR_TABLE_SELECTION; break; + case STATE_MANUAL_FIELD_MAPPING: pResId = RID_STR_MANUAL_FIELD_MAPPING; break; + case STATE_FINAL_CONFIRM: pResId = RID_STR_FINAL_CONFIRM; break; + } + DBG_ASSERT( pResId, "OAddressBookSourcePilot::getStateDisplayName: don't know this state!" ); + + OUString sDisplayName; + if (pResId) + { + sDisplayName = compmodule::ModuleRes(pResId); + } + + return sDisplayName; + } + + void OAddressBookSourcePilot::implCommitAll() + { + // in real, the data source already exists in the data source context + // Thus, if the user changed the name, we have to rename the data source + if ( m_aSettings.sDataSourceName != m_aNewDataSource.getName() ) + m_aNewDataSource.rename( m_aSettings.sDataSourceName ); + + // 1. the data source + m_aNewDataSource.store(m_aSettings); + + // 2. check if we need to register the data source + if ( m_aSettings.bRegisterDataSource ) + m_aNewDataSource.registerDataSource(m_aSettings.sRegisteredDataSourceName); + + // 3. write the data source / table names into the configuration + addressconfig::writeTemplateAddressSource( getORB(), m_aSettings.bRegisterDataSource ? m_aSettings.sRegisteredDataSourceName : m_aSettings.sDataSourceName, m_aSettings.sSelectedTable ); + + // 4. write the field mapping + fieldmapping::writeTemplateAddressFieldMapping( getORB(), std::map(m_aSettings.aFieldMapping) ); + } + + void OAddressBookSourcePilot::implCleanup() + { + if ( m_aNewDataSource.isValid() ) + m_aNewDataSource.remove(); + } + + short OAddressBookSourcePilot::run() + { + short nRet = OAddressBookSourcePilot_Base::run(); + + implCleanup(); + + return nRet; + } + + bool OAddressBookSourcePilot::onFinish() + { + if ( !OAddressBookSourcePilot_Base::onFinish() ) + return false; + + implCommitAll(); + + addressconfig::markPilotSuccess( getORB() ); + + return true; + } + + void OAddressBookSourcePilot::enterState( WizardState _nState ) + { + switch ( _nState ) + { + case STATE_SELECT_ABTYPE: + impl_updateRoadmap( static_cast< TypeSelectionPage* >( GetPage( STATE_SELECT_ABTYPE ) )->getSelectedType() ); + break; + + case STATE_FINAL_CONFIRM: + if ( !needManualFieldMapping( ) ) + implDoAutoFieldMapping(); + break; + + case STATE_TABLE_SELECTION: + implDefaultTableName(); + break; + } + + OAddressBookSourcePilot_Base::enterState(_nState); + } + + + bool OAddressBookSourcePilot::prepareLeaveCurrentState( CommitPageReason _eReason ) + { + if ( !OAddressBookSourcePilot_Base::prepareLeaveCurrentState( _eReason ) ) + return false; + + if ( _eReason == vcl::WizardTypes::eTravelBackward ) + return true; + + bool bAllow = true; + + switch ( getCurrentState() ) + { + case STATE_SELECT_ABTYPE: + implCreateDataSource(); + if ( needAdminInvokationPage() ) + break; + [[fallthrough]]; + + case STATE_INVOKE_ADMIN_DIALOG: + if ( !connectToDataSource( false ) ) + { + // connecting did not succeed -> do not allow proceeding + bAllow = false; + break; + } + + + // now that we connected to the data source, check whether we need the "table selection" page + const StringBag& aTables = m_aNewDataSource.getTableNames(); + + if ( aTables.empty() ) + { + std::unique_ptr xBox(Application::CreateMessageDialog(m_xAssistant.get(), + VclMessageType::Question, VclButtonsType::YesNo, + compmodule::ModuleRes(getSettings().eType == AST_EVOLUTION_GROUPWISE ? RID_STR_QRY_NO_EVO_GW : RID_STR_QRY_NOTABLES))); + + if (RET_YES != xBox->run()) + { + // cannot ask the user, or the user chose to use this data source, though there are no tables + bAllow = false; + break; + } + + m_aSettings.bIgnoreNoTable = true; + } + + if ( aTables.size() == 1 ) + // remember the one and only table we have + m_aSettings.sSelectedTable = *aTables.begin(); + + break; + } + + impl_updateRoadmap( m_aSettings.eType ); + return bAllow; + } + + void OAddressBookSourcePilot::implDefaultTableName() + { + const StringBag& rTableNames = getDataSource().getTableNames(); + if ( rTableNames.end() != rTableNames.find( getSettings().sSelectedTable ) ) + // already a valid table selected + return; + + const char* pGuess = nullptr; + switch ( getSettings().eType ) + { + case AST_THUNDERBIRD : pGuess = "Personal Address book"; break; + case AST_EVOLUTION : + case AST_EVOLUTION_GROUPWISE: + case AST_EVOLUTION_LDAP : pGuess = "Personal"; break; + default: + OSL_FAIL( "OAddressBookSourcePilot::implDefaultTableName: unhandled case!" ); + return; + } + const OUString sGuess = OUString::createFromAscii( pGuess ); + if ( rTableNames.end() != rTableNames.find( sGuess ) ) + getSettings().sSelectedTable = sGuess; + } + + void OAddressBookSourcePilot::implDoAutoFieldMapping() + { + DBG_ASSERT( !needManualFieldMapping( ), "OAddressBookSourcePilot::implDoAutoFieldMapping: invalid call!" ); + + fieldmapping::defaultMapping( getORB(), m_aSettings.aFieldMapping ); + } + + void OAddressBookSourcePilot::implCreateDataSource() + { + if (m_aNewDataSource.isValid()) + { // we already have a data source object + if ( m_aSettings.eType == m_eNewDataSourceType ) + // and it already has the correct type + return; + + // it has a wrong type -> remove it + m_aNewDataSource.remove(); + } + + ODataSourceContext aContext( getORB() ); + aContext.disambiguate( m_aSettings.sDataSourceName ); + + switch (m_aSettings.eType) + { + case AST_THUNDERBIRD: + m_aNewDataSource = aContext.createNewThunderbird( m_aSettings.sDataSourceName ); + break; + + case AST_EVOLUTION: + m_aNewDataSource = aContext.createNewEvolution( m_aSettings.sDataSourceName ); + break; + + case AST_EVOLUTION_GROUPWISE: + m_aNewDataSource = aContext.createNewEvolutionGroupwise( m_aSettings.sDataSourceName ); + break; + + case AST_EVOLUTION_LDAP: + m_aNewDataSource = aContext.createNewEvolutionLdap( m_aSettings.sDataSourceName ); + break; + + case AST_KAB: + m_aNewDataSource = aContext.createNewKab( m_aSettings.sDataSourceName ); + break; + + case AST_MACAB: + m_aNewDataSource = aContext.createNewMacab( m_aSettings.sDataSourceName ); + break; + + case AST_OTHER: + m_aNewDataSource = aContext.createNewOther( m_aSettings.sDataSourceName ); + break; + + case AST_INVALID: + OSL_FAIL( "OAddressBookSourcePilot::implCreateDataSource: illegal data source type!" ); + break; + } + m_eNewDataSourceType = m_aSettings.eType; + } + + bool OAddressBookSourcePilot::connectToDataSource( bool _bForceReConnect ) + { + DBG_ASSERT( m_aNewDataSource.isValid(), "OAddressBookSourcePilot::implConnect: invalid current data source!" ); + + weld::WaitObject aWaitCursor(m_xAssistant.get()); + if ( _bForceReConnect && m_aNewDataSource.isConnected( ) ) + m_aNewDataSource.disconnect( ); + + return m_aNewDataSource.connect(m_xAssistant.get()); + } + + std::unique_ptr OAddressBookSourcePilot::createPage(WizardState _nState) + { + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + std::unique_ptr xRet; + + switch (_nState) + { + case STATE_SELECT_ABTYPE: + xRet = std::make_unique(pPageContainer, this); + break; + case STATE_INVOKE_ADMIN_DIALOG: + xRet = std::make_unique(pPageContainer, this); + break; + case STATE_TABLE_SELECTION: + xRet = std::make_unique(pPageContainer, this); + break; + case STATE_MANUAL_FIELD_MAPPING: + xRet = std::make_unique(pPageContainer, this); + break; + case STATE_FINAL_CONFIRM: + xRet = std::make_unique(pPageContainer, this); + break; + default: + assert(false && "OAddressBookSourcePilot::createPage: invalid state!"); + break; + } + + m_xAssistant->set_page_title(sIdent, getStateDisplayName(_nState)); + + return xRet; + } + + void OAddressBookSourcePilot::impl_updateRoadmap( AddressSourceType _eType ) + { + bool bSettingsPage = needAdminInvokationPage( _eType ); + bool bTablesPage = needTableSelection( _eType ); + bool bFieldsPage = needManualFieldMapping( _eType ); + + bool bConnected = m_aNewDataSource.isConnected(); + bool bCanSkipTables = + ( m_aNewDataSource.hasTable( m_aSettings.sSelectedTable ) + || m_aSettings.bIgnoreNoTable + ); + + enableState( STATE_INVOKE_ADMIN_DIALOG, bSettingsPage ); + + enableState( STATE_TABLE_SELECTION, + bTablesPage && ( bConnected ? !bCanSkipTables : !bSettingsPage ) + // if we do not need a settings page, we connect upon "Next" on the first page + ); + + enableState( STATE_MANUAL_FIELD_MAPPING, + bFieldsPage && bConnected && m_aNewDataSource.hasTable( m_aSettings.sSelectedTable ) + ); + + enableState( STATE_FINAL_CONFIRM, + bConnected && bCanSkipTables + ); + } + + void OAddressBookSourcePilot::typeSelectionChanged( AddressSourceType _eType ) + { + PathId nCurrentPathID( PATH_COMPLETE ); + bool bSettingsPage = needAdminInvokationPage( _eType ); + bool bFieldsPage = needManualFieldMapping( _eType ); + if ( !bSettingsPage ) + if ( !bFieldsPage ) + nCurrentPathID = PATH_NO_SETTINGS_NO_FIELDS; + else + nCurrentPathID = PATH_NO_SETTINGS; + else + if ( !bFieldsPage ) + nCurrentPathID = PATH_NO_FIELDS; + else + nCurrentPathID = PATH_COMPLETE; + activatePath( nCurrentPathID, true ); + + m_aNewDataSource.disconnect(); + m_aSettings.bIgnoreNoTable = false; + impl_updateRoadmap( _eType ); + } + +} // namespace abp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/abspilot.hxx b/extensions/source/abpilot/abspilot.hxx new file mode 100644 index 000000000..45c965d2b --- /dev/null +++ b/extensions/source/abpilot/abspilot.hxx @@ -0,0 +1,119 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include "addresssettings.hxx" +#include "datasourcehandling.hxx" + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace abp +{ + typedef ::vcl::RoadmapWizardMachine OAddressBookSourcePilot_Base; + class OAddressBookSourcePilot final : public OAddressBookSourcePilot_Base + { + css::uno::Reference< css::uno::XComponentContext > + m_xORB; + AddressSettings m_aSettings; + + ODataSource m_aNewDataSource; + AddressSourceType m_eNewDataSourceType; + + public: + /// ctor + OAddressBookSourcePilot( + weld::Window* _pParent, + const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + virtual short run() override; + + /// get the service factory which was used to create the dialog + const css::uno::Reference< css::uno::XComponentContext >& + getORB() const { return m_xORB; } + AddressSettings& getSettings() { return m_aSettings; } + const AddressSettings& getSettings() const { return m_aSettings; } + + const ODataSource& getDataSource() const { return m_aNewDataSource; } + + bool connectToDataSource( bool _bForceReConnect ); + + void travelNext( ) { OAddressBookSourcePilot_Base::travelNext(); } + + /// to be called when the selected type changed + void typeSelectionChanged( AddressSourceType _eType ); + + private: + // OWizardMachine overridables + virtual std::unique_ptr createPage( WizardState _nState ) override; + virtual void enterState( WizardState _nState ) override; + virtual bool prepareLeaveCurrentState( CommitPageReason _eReason ) override; + virtual bool onFinish() override; + + // RoadmapWizard + virtual OUString getStateDisplayName( WizardState _nState ) const override; + + /** creates a new data source of the type indicated by m_aSettings +

If another data source has been created before, this one is deleted.

+ */ + void implCreateDataSource(); + + /// does an automatic field mapping (possible for all types except AST_OTHER) + void implDoAutoFieldMapping(); + + /// guesses a default for the table name, if no valid table is selected + void implDefaultTableName(); + + static bool needAdminInvokationPage( AddressSourceType _eType ) + { + return ( AST_OTHER == _eType ); + } + /// check if with the current settings, we would need to invoke he administration dialog for more details about the data source + bool needAdminInvokationPage() const + { + return needAdminInvokationPage( m_aSettings.eType ); + } + + static bool needManualFieldMapping( AddressSourceType _eType ) + { + return ( AST_OTHER == _eType ) || ( AST_KAB == _eType ) || + ( AST_EVOLUTION == _eType ) || ( AST_EVOLUTION_GROUPWISE == _eType ) || + ( AST_EVOLUTION_LDAP == _eType ); + } + /// checks if we need a manual (user-guided) field mapping + bool needManualFieldMapping() const + { + return needManualFieldMapping( m_aSettings.eType ); + } + + /// determines whether the given address book type does provide one table only + static bool needTableSelection( AddressSourceType _eType ) + { + return ( AST_KAB != _eType ); + } + + void implCleanup(); + void implCommitAll(); + + void impl_updateRoadmap( AddressSourceType _eType ); + }; +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/addresssettings.hxx b/extensions/source/abpilot/addresssettings.hxx new file mode 100644 index 000000000..542a2fe67 --- /dev/null +++ b/extensions/source/abpilot/addresssettings.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include "abptypes.hxx" + + +namespace abp +{ + + enum AddressSourceType + { + AST_THUNDERBIRD, + AST_EVOLUTION, + AST_EVOLUTION_GROUPWISE, + AST_EVOLUTION_LDAP, + AST_KAB, + AST_MACAB, + AST_OTHER, + + AST_INVALID + }; + + struct AddressSettings + { + AddressSourceType eType; + OUString sDataSourceName; + OUString sRegisteredDataSourceName; + OUString sSelectedTable; + bool bIgnoreNoTable; + MapString2String aFieldMapping; + bool bRegisterDataSource; + bool bEmbedDataSource; + }; + + +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/admininvokationimpl.cxx b/extensions/source/abpilot/admininvokationimpl.cxx new file mode 100644 index 000000000..c8ec00b68 --- /dev/null +++ b/extensions/source/abpilot/admininvokationimpl.cxx @@ -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 . + */ + +#include "admininvokationimpl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace abp +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::ui::dialogs; + using namespace ::com::sun::star::sdbc; + + OAdminDialogInvokation::OAdminDialogInvokation(const Reference< XComponentContext >& _rxContext, + const css::uno::Reference< css::beans::XPropertySet >& _rxDataSource, + weld::Window* _pMessageParent) + :m_xContext(_rxContext) + ,m_xDataSource(_rxDataSource) + ,m_pMessageParent(_pMessageParent) + { + DBG_ASSERT(m_xContext.is(), "OAdminDialogInvokation::OAdminDialogInvokation: invalid service factory!"); + DBG_ASSERT(m_xDataSource.is(), "OAdminDialogInvokation::OAdminDialogInvokation: invalid preferred name!"); + assert(m_pMessageParent && "OAdminDialogInvokation::OAdminDialogInvokation: invalid message parent!"); + } + + + bool OAdminDialogInvokation::invokeAdministration() + { + if (!m_xContext.is()) + return false; + + try + { + // the service name of the administration dialog + static const char16_t s_sAdministrationServiceName[] = u"com.sun.star.sdb.DatasourceAdministrationDialog"; + static constexpr OUStringLiteral s_sDataSourceTypeChangeDialog = u"com.sun.star.sdb.DataSourceTypeChangeDialog"; + + // the parameters for the call + Sequence aArguments(comphelper::InitAnyPropertySequence( + { + {"ParentWindow", Any(m_pMessageParent->GetXWindow())}, + {"Title", Any(compmodule::ModuleRes(RID_STR_ADMINDIALOGTITLE))}, + {"InitialSelection", Any(m_xDataSource)}, // the name of the new data source + })); + + + // create the dialog + Reference< XExecutableDialog > xDialog; + { + // creating the dialog service is potentially expensive (if all the libraries invoked need to be loaded) + // so we display a wait cursor + weld::WaitObject aWaitCursor(m_pMessageParent); + Reference x = m_xContext->getServiceManager()->createInstanceWithArgumentsAndContext(s_sDataSourceTypeChangeDialog, aArguments, m_xContext); + xDialog.set( x, UNO_QUERY ); + + // just for a smoother UI: What the dialog does upon execution, is (amongst other things) creating + // the DriverManager service + // If this context has never been accessed before, this may be expensive (it includes loading of + // at least one library). + // As this wizard is intended to run on the first office start, it is very likely that the + // context needs to be freshly created + // Thus, we access the context here (within the WaitCursor), which means the user sees a waitcursor + // while his/her office blocks a few seconds... + DriverManager::create( m_xContext ); + } + + if (xDialog.is()) + { // execute it + if (xDialog->execute()) + return true; + } + else + ShowServiceNotAvailableError(m_pMessageParent, s_sAdministrationServiceName, true); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", + "caught an exception while executing the dialog!"); + } + return false; + } + + +} // namespace abp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/admininvokationimpl.hxx b/extensions/source/abpilot/admininvokationimpl.hxx new file mode 100644 index 000000000..2003809c8 --- /dev/null +++ b/extensions/source/abpilot/admininvokationimpl.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace weld { class Window; } + +namespace abp +{ + /** outsourced from AdminDialogInvokationPage, 'cause this class here, in opposite to + the page, needs exception handling to be enabled. + */ + class OAdminDialogInvokation + { + private: + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + css::uno::Reference< css::beans::XPropertySet > m_xDataSource; + weld::Window* m_pMessageParent; + + public: + OAdminDialogInvokation( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const css::uno::Reference< css::beans::XPropertySet >& _rDataSource, + weld::Window* _pMessageParent + ); + + bool invokeAdministration(); + }; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/admininvokationpage.cxx b/extensions/source/abpilot/admininvokationpage.cxx new file mode 100644 index 000000000..2f51d8639 --- /dev/null +++ b/extensions/source/abpilot/admininvokationpage.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 "admininvokationpage.hxx" +#include "abspilot.hxx" +#include "admininvokationimpl.hxx" + +namespace abp +{ + AdminDialogInvokationPage::AdminDialogInvokationPage(weld::Container* pPage, OAddressBookSourcePilot* pController) + : AddressBookSourcePage(pPage, pController, "modules/sabpilot/ui/invokeadminpage.ui", "InvokeAdminPage") + , m_xInvokeAdminDialog(m_xBuilder->weld_button("settings")) + , m_xErrorMessage(m_xBuilder->weld_label("warning")) + { + m_xInvokeAdminDialog->connect_clicked(LINK(this, AdminDialogInvokationPage, OnInvokeAdminDialog)); + } + + AdminDialogInvokationPage::~AdminDialogInvokationPage() + { + } + + void AdminDialogInvokationPage::Activate() + { + AddressBookSourcePage::Activate(); + m_xInvokeAdminDialog->grab_focus(); + } + + void AdminDialogInvokationPage::implUpdateErrorMessage() + { + const bool bIsConnected = getDialog()->getDataSource().isConnected(); + m_xErrorMessage->set_visible( !bIsConnected ); + } + + void AdminDialogInvokationPage::initializePage() + { + AddressBookSourcePage::initializePage(); + m_xErrorMessage->hide(); + // if we're entering this page, we assume we had no connection trial with this data source + } + + void AdminDialogInvokationPage::implTryConnect() + { + getDialog()->connectToDataSource( true ); + + // show our error message if and only if we could not connect + implUpdateErrorMessage(); + + // the status of the next button may have changed + updateDialogTravelUI(); + + // automatically go to the next page (if successfully connected) + if ( canAdvance() ) + getDialog()->travelNext(); + } + + bool AdminDialogInvokationPage::canAdvance() const + { + return AddressBookSourcePage::canAdvance() && getDialog()->getDataSource().isConnected(); + } + + // davido: Do we need it? + IMPL_LINK_NOARG(AdminDialogInvokationPage, OnInvokeAdminDialog, weld::Button&, void) + { + OAdminDialogInvokation aInvokation(getORB(), getDialog()->getDataSource().getDataSource(), getDialog()->getDialog()); + if ( aInvokation.invokeAdministration() ) + { + // try to connect to this data source + implTryConnect(); + } + } + +} // namespace abp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/admininvokationpage.hxx b/extensions/source/abpilot/admininvokationpage.hxx new file mode 100644 index 000000000..3d4f676e2 --- /dev/null +++ b/extensions/source/abpilot/admininvokationpage.hxx @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "abspage.hxx" + + +namespace abp +{ + class AdminDialogInvokationPage final : public AddressBookSourcePage + { + std::unique_ptr m_xInvokeAdminDialog; + std::unique_ptr m_xErrorMessage; + + public: + explicit AdminDialogInvokationPage(weld::Container* pPage, OAddressBookSourcePilot* pDialog); + virtual ~AdminDialogInvokationPage() override; + private: + // BuilderPage overridables + virtual void Activate() override; + + // OWizard overridables + virtual void initializePage() override; + + // OImportPage overridables + virtual bool canAdvance() const override; + + DECL_LINK( OnInvokeAdminDialog, weld::Button&, void ); + + void implTryConnect(); + void implUpdateErrorMessage(); + }; + +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/datasourcehandling.cxx b/extensions/source/abpilot/datasourcehandling.cxx new file mode 100644 index 000000000..a411c2536 --- /dev/null +++ b/extensions/source/abpilot/datasourcehandling.cxx @@ -0,0 +1,620 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "abptypes.hxx" +#include +#include "datasourcehandling.hxx" +#include "addresssettings.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 +{ + +/// Returns the URL of this object shell. +OUString lcl_getOwnURL(SfxObjectShell const * pObjectShell) +{ + OUString aRet; + + if (!pObjectShell) + return aRet; + + const INetURLObject& rURLObject = pObjectShell->GetMedium()->GetURLObject(); + aRet = rURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE); + return aRet; +} + +} + +namespace abp +{ + + + using namespace ::utl; + using namespace ::comphelper; + using namespace ::com::sun::star; + 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::sdbcx; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::frame; + + static Reference< XDatabaseContext > lcl_getDataSourceContext( const Reference< XComponentContext >& _rxContext ) + { + Reference xContext = DatabaseContext::create(_rxContext); + return xContext; + } + + + /// creates a new data source and inserts it into the context + static void lcl_implCreateAndInsert( + const Reference< XComponentContext >& _rxContext, const OUString& _rName, + Reference< XPropertySet >& /* [out] */ _rxNewDataSource ) + { + + // get the data source context + Reference< XDatabaseContext > xContext = lcl_getDataSourceContext( _rxContext ); + + DBG_ASSERT( !xContext->hasByName( _rName ), "lcl_implCreateAndInsert: name already used!" ); + + + // create a new data source + Reference< XPropertySet > xNewDataSource; + if (xContext.is()) + xNewDataSource.set( xContext->createInstance(), UNO_QUERY ); + DBG_ASSERT( xNewDataSource.is(), "lcl_implCreateAndInsert: could not create a new data source!" ); + + + // insert the data source into the context + DBG_ASSERT( xContext.is(), "lcl_implCreateAndInsert: missing an interface on the context (XNamingService)!" ); + if (xContext.is()) + { + // xDynamicContext->registerObject( _rName, xNewDataSource ); + _rxNewDataSource = xNewDataSource; + } + } + + + /// creates and inserts a data source, and sets its URL property to the string given + static ODataSource lcl_implCreateAndSetURL( + const Reference< XComponentContext >& _rxORB, const OUString& _rName, + const char* _pInitialAsciiURL ) + { + ODataSource aReturn( _rxORB ); + try + { + // create the new data source + Reference< XPropertySet > xNewDataSource; + lcl_implCreateAndInsert( _rxORB, _rName, xNewDataSource ); + + + // set the URL property + if (xNewDataSource.is()) + { + xNewDataSource->setPropertyValue( + "URL", + Any( OUString::createFromAscii( _pInitialAsciiURL ) ) + ); + } + + aReturn.setDataSource( xNewDataSource, _rName ); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", + "caught an exception while creating the data source!"); + } + + return aReturn; + } + + static void lcl_registerDataSource( + const Reference< XComponentContext >& _rxORB, const OUString& _sName, + const OUString& _sURL ) + { + OSL_ENSURE( !_sName.isEmpty(), "lcl_registerDataSource: invalid name!" ); + OSL_ENSURE( !_sURL.isEmpty(), "lcl_registerDataSource: invalid URL!" ); + try + { + Reference< XDatabaseContext > xRegistrations( DatabaseContext::create(_rxORB) ); + if ( xRegistrations->hasRegisteredDatabase( _sName ) ) + xRegistrations->changeDatabaseLocation( _sName, _sURL ); + else + xRegistrations->registerDatabaseLocation( _sName, _sURL ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.abpilot"); + } + } + + struct ODataSourceContextImpl + { + Reference< XComponentContext > xORB; + Reference< XNameAccess > xContext; /// the UNO data source context + StringBag aDataSourceNames; /// for quicker name checks (without the UNO overhead) + + explicit ODataSourceContextImpl(const Reference< XComponentContext >& _rxORB) + : xORB(_rxORB) + { + } + ODataSourceContextImpl(const ODataSourceContextImpl&) = delete; + ODataSourceContextImpl& operator=(const ODataSourceContextImpl&) = delete; + }; + + ODataSourceContext::ODataSourceContext(const Reference< XComponentContext >& _rxORB) + :m_pImpl( new ODataSourceContextImpl( _rxORB ) ) + { + try + { + // create the UNO context + m_pImpl->xContext.set( lcl_getDataSourceContext( _rxORB ), UNO_QUERY_THROW ); + + // collect the data source names + Sequence< OUString > aDSNames = m_pImpl->xContext->getElementNames(); + const OUString* pDSNames = aDSNames.getConstArray(); + const OUString* pDSNamesEnd = pDSNames + aDSNames.getLength(); + + for ( ;pDSNames != pDSNamesEnd; ++pDSNames ) + m_pImpl->aDataSourceNames.insert( *pDSNames ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.abpilot", "ODataSourceContext::ODataSourceContext" ); + } + } + ODataSourceContext::~ODataSourceContext() + { + } + + + void ODataSourceContext::disambiguate(OUString& _rDataSourceName) + { + OUString sCheck( _rDataSourceName ); + StringBag::const_iterator aPos = m_pImpl->aDataSourceNames.find( sCheck ); + + sal_Int32 nPostfix = 1; + while ( ( m_pImpl->aDataSourceNames.end() != aPos ) && ( nPostfix < 65535 ) ) + { // there already is a data source with this name + sCheck = _rDataSourceName + OUString::number( nPostfix++ ); + + aPos = m_pImpl->aDataSourceNames.find( sCheck ); + } + + _rDataSourceName = sCheck; + } + + + void ODataSourceContext::getDataSourceNames( StringBag& _rNames ) const + { + _rNames = m_pImpl->aDataSourceNames; + } + + ODataSource ODataSourceContext::createNewThunderbird( const OUString& _rName ) + { + return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:thunderbird" ); + } + + + ODataSource ODataSourceContext::createNewEvolutionLdap( const OUString& _rName) + { + return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:ldap" ); + } + + ODataSource ODataSourceContext::createNewEvolutionGroupwise( const OUString& _rName) + { + return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:groupwise" ); + } + + ODataSource ODataSourceContext::createNewEvolution( const OUString& _rName) + { + return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:evolution:local" ); + } + + + ODataSource ODataSourceContext::createNewKab( const OUString& _rName) + { + return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:kab" ); + } + + + ODataSource ODataSourceContext::createNewMacab( const OUString& _rName) + { + return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:address:macab" ); + } + + + // tdf117101: Spreadsheet by default + ODataSource ODataSourceContext::createNewOther( const OUString& _rName) + { + return lcl_implCreateAndSetURL( m_pImpl->xORB, _rName, "sdbc:calc:" ); + } + + struct ODataSourceImpl + { + public: + Reference< XComponentContext > xORB; /// the service factory + Reference< XPropertySet > xDataSource; /// the UNO data source + ::utl::SharedUNOComponent< XConnection > + xConnection; + StringBag aTables; // the cached table names + OUString sName; + + explicit ODataSourceImpl(const Reference< XComponentContext >& _rxORB) + : xORB(_rxORB) + { + } + }; + + + ODataSource::ODataSource( const ODataSource& _rSource ) + { + *this = _rSource; + } + + ODataSource& ODataSource::operator=( const ODataSource& _rSource ) + { + if( this != &_rSource ) + { + m_pImpl.reset( new ODataSourceImpl( *_rSource.m_pImpl ) ); + } + return *this; + } + + ODataSource& ODataSource::operator=(ODataSource&& _rSource) noexcept + { + m_pImpl = std::move(_rSource.m_pImpl); + return *this; + } + + ODataSource::ODataSource( const Reference< XComponentContext >& _rxORB ) + :m_pImpl(new ODataSourceImpl(_rxORB)) + { + } + + ODataSource::~ODataSource( ) + { + } + + void ODataSource::store(const AddressSettings& rSettings) + { + if (!isValid()) + // nothing to do + return; + try + { + Reference< XDocumentDataSource > xDocAccess( m_pImpl->xDataSource, UNO_QUERY ); + Reference< XStorable > xStorable; + if ( xDocAccess.is() ) + xStorable.set(xDocAccess->getDatabaseDocument(), css::uno::UNO_QUERY); + OSL_ENSURE( xStorable.is(),"DataSource is no XStorable!" ); + if ( xStorable.is() ) + { + SfxViewFrame* pFrame = SfxViewFrame::Current(); + SfxObjectShell* pObjectShell = pFrame ? pFrame->GetObjectShell() : nullptr; + OUString aOwnURL = lcl_getOwnURL(pObjectShell); // empty if pObjectShell is nullptr + if (aOwnURL.isEmpty() || !rSettings.bEmbedDataSource) + { + // Cannot or should not embed. + xStorable->storeAsURL(m_pImpl->sName,Sequence()); + } + else + { + // Embed. + OUString aStreamRelPath = "EmbeddedDatabase"; + auto xContext(comphelper::getProcessComponentContext()); + auto xUri = css::uri::UriReferenceFactory::create(xContext)->parse(aOwnURL); + assert(xUri.is()); + xUri = css::uri::VndSunStarPkgUrlReferenceFactory::create(xContext)->createVndSunStarPkgUrlReference(xUri); + assert(xUri.is()); + OUString const sTmpName = xUri->getUriReference() + "/" + aStreamRelPath; + assert(pObjectShell); + uno::Reference xStorage = pObjectShell->GetStorage(); + uno::Sequence aSequence = comphelper::InitPropertySequence( + { + {"TargetStorage", uno::Any(xStorage)}, + {"StreamRelPath", uno::Any(aStreamRelPath)}, + {"BaseURI", uno::Any(aOwnURL)} + }); + xStorable->storeAsURL(sTmpName, aSequence); + m_pImpl->sName = sTmpName; + + // Refer to the sub-storage name in the document settings, so + // we can load it again next time the file is imported. + uno::Reference xFactory(pObjectShell->GetModel(), uno::UNO_QUERY); + uno::Reference xPropertySet(xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY); + xPropertySet->setPropertyValue("EmbeddedDatabaseName", uno::Any(aStreamRelPath)); + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", + "caught an exception while creating the data source!"); + } + } + + void ODataSource::registerDataSource( const OUString& _sRegisteredDataSourceName) + { + if (!isValid()) + // nothing to do + return; + + try + { + // invalidate ourself + lcl_registerDataSource(m_pImpl->xORB,_sRegisteredDataSourceName,m_pImpl->sName); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", + "caught an exception while creating the data source!"); + } + } + + + void ODataSource::setDataSource( const Reference< XPropertySet >& _rxDS,const OUString& _sName ) + { + if (m_pImpl->xDataSource.get() == _rxDS.get()) + // nothing to do + return; + + if ( isConnected() ) + disconnect(); + + m_pImpl->sName = _sName; + m_pImpl->xDataSource = _rxDS; + } + + + void ODataSource::remove() + { + if (!isValid()) + // nothing to do + return; + + try + { + // invalidate ourself + m_pImpl->xDataSource.clear(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", + "caught an exception while creating the data source!"); + } + } + + + bool ODataSource::rename( const OUString& _rName ) + { + if (!isValid()) + // nothing to do + return false; + + m_pImpl->sName = _rName; + return true; + } + + + OUString ODataSource::getName() const + { + if ( !isValid() ) + return OUString(); + return m_pImpl->sName; + } + + + bool ODataSource::hasTable( const OUString& _rTableName ) const + { + if ( !isConnected() ) + return false; + + const StringBag& aTables( getTableNames() ); + return aTables.find( _rTableName ) != aTables.end(); + } + + + const StringBag& ODataSource::getTableNames() const + { + m_pImpl->aTables.clear(); + if ( !isConnected() ) + { + OSL_FAIL( "ODataSource::getTableNames: not connected!" ); + } + else + { + try + { + // get the tables container from the connection + Reference< XTablesSupplier > xSuppTables( m_pImpl->xConnection.getTyped(), UNO_QUERY ); + Reference< XNameAccess > xTables; + if ( xSuppTables.is( ) ) + xTables = xSuppTables->getTables(); + DBG_ASSERT( xTables.is(), "ODataSource::getTableNames: could not retrieve the tables container!" ); + + // get the names + Sequence< OUString > aTableNames; + if ( xTables.is( ) ) + aTableNames = xTables->getElementNames( ); + + // copy the names + const OUString* pTableNames = aTableNames.getConstArray(); + const OUString* pTableNamesEnd = pTableNames + aTableNames.getLength(); + for (;pTableNames < pTableNamesEnd; ++pTableNames) + m_pImpl->aTables.insert( *pTableNames ); + } + catch(const Exception&) + { + } + } + + // now the table cache is up-to-date + return m_pImpl->aTables; + } + + + bool ODataSource::connect(weld::Window* _pMessageParent) + { + if ( isConnected( ) ) + // nothing to do + return true; + + + // create the interaction handler (needed for authentication and error handling) + Reference< XInteractionHandler > xInteractions; + try + { + xInteractions = InteractionHandler::createWithParent(m_pImpl->xORB, nullptr); + } + catch(const Exception&) + { + } + + + // failure to create the interaction handler is a serious issue ... + if (!xInteractions.is()) + { + if ( _pMessageParent ) + ShowServiceNotAvailableError( _pMessageParent, u"com.sun.star.task.InteractionHandler", true ); + return false; + } + + + // open the connection + Any aError; + Reference< XConnection > xConnection; + try + { + Reference< XCompletedConnection > xComplConn( m_pImpl->xDataSource, UNO_QUERY ); + DBG_ASSERT( xComplConn.is(), "ODataSource::connect: missing the XCompletedConnection interface on the data source!" ); + if ( xComplConn.is() ) + xConnection = xComplConn->connectWithCompletion( xInteractions ); + } + catch( const SQLContext& e ) { aError <<= e; } + catch( const SQLWarning& e ) { aError <<= e; } + catch( const SQLException& e ) { aError <<= e; } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", ""); + } + + + // handle errors + if ( aError.hasValue() && _pMessageParent ) + { + try + { + SQLException aException; + aError >>= aException; + if ( aException.Message.isEmpty() ) + { + // prepend some context info + SQLContext aDetailedError; + aDetailedError.Message = compmodule::ModuleRes(RID_STR_NOCONNECTION); + aDetailedError.Details = compmodule::ModuleRes(RID_STR_PLEASECHECKSETTINGS); + aDetailedError.NextException = aError; + // handle (aka display) the new context info + xInteractions->handle( new OInteractionRequest( Any( aDetailedError ) ) ); + } + else + { + // handle (aka display) the original error + xInteractions->handle( new OInteractionRequest( Any( aException ) ) ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", + "caught an exception while trying to display the error!"); + } + } + + if ( !xConnection.is() ) + return false; + + + // success + m_pImpl->xConnection.reset( xConnection ); + m_pImpl->aTables.clear(); + + return true; + } + + + void ODataSource::disconnect( ) + { + m_pImpl->xConnection.clear(); + m_pImpl->aTables.clear(); + } + + + bool ODataSource::isConnected( ) const + { + return m_pImpl->xConnection.is(); + } + + + bool ODataSource::isValid() const + { + return m_pImpl && m_pImpl->xDataSource.is(); + } + + Reference< XPropertySet > ODataSource::getDataSource() const + { + return m_pImpl ? m_pImpl->xDataSource : Reference< XPropertySet >(); + } + + +} // namespace abp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/datasourcehandling.hxx b/extensions/source/abpilot/datasourcehandling.hxx new file mode 100644 index 000000000..485c3c15b --- /dev/null +++ b/extensions/source/abpilot/datasourcehandling.hxx @@ -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 . + */ + +#pragma once + +#include +#include +#include + +#include "abptypes.hxx" + + +namespace com::sun::star { + namespace beans { + class XPropertySet; + } +} + +namespace weld { class Window; } + + +namespace abp +{ + + struct ODataSourceContextImpl; + class ODataSource; + /// a non-UNO wrapper for the data source context + class ODataSourceContext + { + private: + std::unique_ptr m_pImpl; + + public: + explicit ODataSourceContext( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ); + ~ODataSourceContext(); + + /// retrieves the names of all data sources + void getDataSourceNames( StringBag& _rNames ) const; + + /// disambiguates the given name by appending successive numbers + void disambiguate(OUString& _rDataSourceName); + + /// creates a new Thunderbird data source + ODataSource createNewThunderbird( const OUString& _rName ); + + /// creates a new Evolution local data source + ODataSource createNewEvolution( const OUString& _rName ); + + /// creates a new Evolution LDAP data source + ODataSource createNewEvolutionLdap( const OUString& _rName ); + + /// creates a new Evolution GROUPWISE data source + ODataSource createNewEvolutionGroupwise( const OUString& _rName ); + + /// creates a new KDE address book data source + ODataSource createNewKab( const OUString& _rName ); + + /// creates a new macOS address book data source + ODataSource createNewMacab( const OUString& _rName ); + + /// creates a new Other data source; tdf117101: Spreadsheet by default + ODataSource createNewOther( const OUString& _rName ); + }; + + struct ODataSourceImpl; + struct AddressSettings; + /** a non-UNO wrapper for a data source +

This class allows to access data sources without the need to compile the respective file with + exception handling enabled (hopefully :).

+

In addition to wrapping a UNO data source, an instance of this class can handle at most + one valid connection, as obtained from the data source.

+ */ + class ODataSource + { + private: + std::unique_ptr m_pImpl; + + public: + + // - ctor/dtor/assignment + + /// constructs an object which is initially invalid + explicit ODataSource( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ); + + /// copy ctor + ODataSource( const ODataSource& _rSource ); + + /// dtor + ~ODataSource( ); + + /// copy assignment + ODataSource& operator=( const ODataSource& _rSource ); + + /// move assignment + ODataSource& operator=(ODataSource&& _rSource) noexcept; + + /// checks whether or not the object represents a valid data source + bool isValid() const; + + + /// removes the data source represented by the object from the data source context + void remove(); + // TODO: put this into the context class + + /// returns the name of the data source + OUString + getName() const; + + /// renames the data source + bool rename( const OUString& _rName ); + // TODO: put this into the context class + + + // - connection handling + + /** connects to the data source represented by this object + @param _pMessageParent + the window to use as parent for any error messages. If this is , no messages are displayed + at all. + @see isConnected + */ + bool connect(weld::Window* _pMessageParent); + + /// returns if the object has a valid connection, obtained from its data source + bool isConnected( ) const; + + /// disconnects from the data source (i.e. disposes the UNO connection hold internally) + void disconnect( ); + + /// stores the database file + void store(const AddressSettings& rSettings); + + /// register the data source under the given name in the configuration + void registerDataSource( const OUString& _sRegisteredDataSourceName ); + + + /** retrieves the tables names from the connection +

to be called when isConnected returns only

+ */ + const StringBag& getTableNames() const; + + /** determines whether a given table exists + */ + bool hasTable( const OUString& _rTableName ) const; + + /// return the intern data source object + css::uno::Reference< css::beans::XPropertySet > getDataSource() const; + + + /** set a new data source. +

Available to selected clients only

+ */ + void setDataSource( + const css::uno::Reference< css::beans::XPropertySet >& _rxDS + ,const OUString& _sName + ); + }; + + +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/fieldmappingimpl.cxx b/extensions/source/abpilot/fieldmappingimpl.cxx new file mode 100644 index 000000000..145732bdf --- /dev/null +++ b/extensions/source/abpilot/fieldmappingimpl.cxx @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "fieldmappingimpl.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace abp +{ + + + using namespace ::utl; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::sdb; + using namespace ::com::sun::star::ui; + using namespace ::com::sun::star::ui::dialogs; + + + const char16_t sDriverSettingsNodeName[] = u"/org.openoffice.Office.DataAccess/DriverSettings/com.sun.star.comp.sdbc.MozabDriver"; + constexpr OUStringLiteral sAddressBookNodeName = u"/org.openoffice.Office.DataAccess/AddressBook"; + + namespace fieldmapping + { + bool invokeDialog( const Reference< XComponentContext >& _rxORB, class weld::Window* _pParent, + const Reference< XPropertySet >& _rxDataSource, AddressSettings& _rSettings ) + { + _rSettings.aFieldMapping.clear(); + + DBG_ASSERT( _rxORB.is(), "fieldmapping::invokeDialog: invalid service factory!" ); + DBG_ASSERT( _rxDataSource.is(), "fieldmapping::invokeDialog: invalid data source!" ); + if ( !_rxORB.is() || !_rxDataSource.is() ) + return false; + + try + { + + // create an instance of the dialog service + Reference< XWindow > xDialogParent = _pParent->GetXWindow(); + OUString sTitle(compmodule::ModuleRes(RID_STR_FIELDDIALOGTITLE)); + Reference< XExecutableDialog > xDialog = AddressBookSourceDialog::createWithDataSource(_rxORB, + // the parent window + xDialogParent, + _rxDataSource, + _rSettings.bRegisterDataSource ? _rSettings.sRegisteredDataSourceName : _rSettings.sDataSourceName, + // the table to use + _rSettings.sSelectedTable, + sTitle); + + // execute the dialog + if ( xDialog->execute() ) + { + // retrieve the field mapping as set by he user + Reference< XPropertySet > xDialogProps( xDialog, UNO_QUERY ); + + Sequence< AliasProgrammaticPair > aMapping; + bool bSuccess = + xDialogProps->getPropertyValue("FieldMapping") >>= aMapping; + DBG_ASSERT( bSuccess, "fieldmapping::invokeDialog: invalid property type for FieldMapping!" ); + + // and copy it into the map + const AliasProgrammaticPair* pMapping = aMapping.getConstArray(); + const AliasProgrammaticPair* pMappingEnd = pMapping + aMapping.getLength(); + for (;pMapping != pMappingEnd; ++pMapping) + _rSettings.aFieldMapping[ pMapping->ProgrammaticName ] = pMapping->Alias; + + return true; + } + + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", + "caught an exception while executing the dialog!"); + } + return false; + } + + + void defaultMapping( const Reference< XComponentContext >& _rxContext, MapString2String& _rFieldAssignment ) + { + _rFieldAssignment.clear(); + + try + { + // what we have: + // a) For the address data source, we need a mapping from programmatic names (1) to real column names + // b) The SDBC driver has a fixed set of columns, which, when returned, are named according to + // some configuration entries. E.g., the driver displays the field which it knows contains + // the first name as "First Name" - the latter string is stored in the config. + // For this, the driver uses programmatic names, too, but they differ from the programmatic names the + // template documents have. + // So what we need first is a mapping from programmatic names (1) to programmatic names (2) + const char* pMappingProgrammatics[] = + { + "FirstName", "FirstName", + "LastName", "LastName", + "Street", "HomeAddress", + "Zip", "HomeZipCode", + "City", "HomeCity", + "State", "HomeState", + "Country", "HomeCountry", + "PhonePriv", "HomePhone", + "PhoneComp", "WorkPhone", + "PhoneCell", "CellularNumber", + "Pager", "PagerNumber", + "Fax", "FaxNumber", + "EMail", "PrimaryEmail", + "URL", "WebPage1", + "Note", "Notes", + "Altfield1", "Custom1", + "Altfield2", "Custom2", + "Altfield3", "Custom3", + "Altfield4", "Custom4", + "Title", "JobTitle", + "Company", "Company", + "Department", "Department" + }; + // (this list is not complete: both lists of programmatic names are larger in real, + // but this list above is the intersection) + + + // access the configuration information which the driver uses for determining its column names + OUString sDriverAliasesNodeName( + OUString::Concat(sDriverSettingsNodeName) + + "/ColumnAliases"); + + // create a config node for this + OConfigurationTreeRoot aDriverFieldAliasing = OConfigurationTreeRoot::createWithComponentContext( + _rxContext, sDriverAliasesNodeName, -1, OConfigurationTreeRoot::CM_READONLY); + + // loop through all programmatic pairs + DBG_ASSERT( 0 == SAL_N_ELEMENTS( pMappingProgrammatics ) % 2, + "fieldmapping::defaultMapping: invalid programmatic map!" ); + // number of pairs + sal_Int32 const nIntersectedProgrammatics = SAL_N_ELEMENTS( pMappingProgrammatics ) / 2; + + const char** pProgrammatic = pMappingProgrammatics; + OUString sAddressProgrammatic; + OUString sDriverProgrammatic; + OUString sDriverUI; + for ( sal_Int32 i=0; + i < nIntersectedProgrammatics; + ++i + ) + { + sAddressProgrammatic = OUString::createFromAscii( *pProgrammatic++ ); + sDriverProgrammatic = OUString::createFromAscii( *pProgrammatic++ ); + + if ( aDriverFieldAliasing.hasByName( sDriverProgrammatic ) ) + { + aDriverFieldAliasing.getNodeValue( sDriverProgrammatic ) >>= sDriverUI; + if ( 0 == sDriverUI.getLength() ) + { + OSL_FAIL( "fieldmapping::defaultMapping: invalid driver UI column name!"); + } + else + _rFieldAssignment[ sAddressProgrammatic ] = sDriverUI; + } + else + { + OSL_FAIL( "fieldmapping::defaultMapping: invalid driver programmatic name!" ); + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", + "code is assumed to throw no exceptions!"); + // the config nodes we're using herein should not do this... + } + } + + + void writeTemplateAddressFieldMapping( const Reference< XComponentContext >& _rxContext, MapString2String&& aFieldAssignment ) + { + // access the configuration information which the driver uses for determining its column names + + // create a config node for this + OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithComponentContext( + _rxContext, sAddressBookNodeName); + + OConfigurationNode aFields = aAddressBookSettings.openNode( OUString( "Fields" ) ); + + // loop through all existent fields + Sequence< OUString > aExistentFields = aFields.getNodeNames(); + const OUString* pExistentFields = aExistentFields.getConstArray(); + const OUString* pExistentFieldsEnd = pExistentFields + aExistentFields.getLength(); + + static const OUStringLiteral sProgrammaticNodeName( u"ProgrammaticFieldName" ); + static const OUStringLiteral sAssignedNodeName( u"AssignedFieldName" ); + + for ( ; pExistentFields != pExistentFieldsEnd; ++pExistentFields ) + { + SAL_WARN_IF( + ((aFields.openNode(*pExistentFields) + .getNodeValue(sProgrammaticNodeName).get()) + != *pExistentFields), + "extensions.abpilot", + "fieldmapping::writeTemplateAddressFieldMapping: inconsistent config data!"); + // there should be a redundancy in the config data... if this asserts, there isn't anymore! + + // do we have a new alias for the programmatic? + MapString2String::iterator aPos = aFieldAssignment.find( *pExistentFields ); + if ( aFieldAssignment.end() != aPos ) + { // yes + // -> set a new value + OConfigurationNode aExistentField = aFields.openNode( *pExistentFields ); + aExistentField.setNodeValue( sAssignedNodeName, Any( aPos->second ) ); + // and remove the mapping entry + aFieldAssignment.erase( *pExistentFields ); + } + else + { // no + // -> remove it + aFields.removeNode( *pExistentFields ); + } + } + + // now everything remaining in aFieldAssignment marks a mapping entry which was not present + // in the config before + for (auto const& elem : aFieldAssignment) + { + DBG_ASSERT( !aFields.hasByName( elem.first ), + "fieldmapping::writeTemplateAddressFieldMapping: inconsistence!" ); + // in case the config node for the fields already has the node named first>, + // the entry should have been removed from aNewMapping (in the above loop) + OConfigurationNode aNewField = aFields.createNode( elem.first ); + aNewField.setNodeValue( sProgrammaticNodeName, Any( elem.first ) ); + aNewField.setNodeValue( sAssignedNodeName, Any( elem.second ) ); + } + + // commit the changes done + aAddressBookSettings.commit(); + } + + + } // namespace fieldmapping + + + namespace addressconfig + { + + + void writeTemplateAddressSource( const Reference< XComponentContext >& _rxContext, + const OUString& _rDataSourceName, const OUString& _rTableName ) + { + // access the configuration information which the driver uses for determining its column names + + // create a config node for this + OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithComponentContext( + _rxContext, sAddressBookNodeName); + + aAddressBookSettings.setNodeValue( OUString( "DataSourceName" ), Any( _rDataSourceName ) ); + aAddressBookSettings.setNodeValue( OUString( "Command" ), Any( _rTableName ) ); + aAddressBookSettings.setNodeValue( OUString( "CommandType" ), Any( sal_Int16(CommandType::TABLE) ) ); + + // commit the changes done + aAddressBookSettings.commit(); + } + + + void markPilotSuccess( const Reference< XComponentContext >& _rxContext ) + { + // access the configuration information which the driver uses for determining its column names + + // create a config node for this + OConfigurationTreeRoot aAddressBookSettings = OConfigurationTreeRoot::createWithComponentContext( + _rxContext, sAddressBookNodeName); + + // set the flag + aAddressBookSettings.setNodeValue( OUString( "AutoPilotCompleted" ), Any( true ) ); + + // commit the changes done + aAddressBookSettings.commit(); + } + + + } // namespace addressconfig + + +} // namespace abp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/fieldmappingimpl.hxx b/extensions/source/abpilot/fieldmappingimpl.hxx new file mode 100644 index 000000000..e4a2dd1c9 --- /dev/null +++ b/extensions/source/abpilot/fieldmappingimpl.hxx @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include "abptypes.hxx" +#include +#include "addresssettings.hxx" + +namespace com::sun::star { + namespace lang { + class XMultiServiceFactory; + } + namespace uno { + class XComponentContext; + } + namespace beans { + class XPropertySet; + } +} +namespace weld { class Window; } + +namespace abp +{ + + + namespace fieldmapping + { + + + /** invokes the field mapping dialog + @param _rxORB + service factory to use for creating UNO services + @param _pParent + window to use as parent for the dialog and error messages + @param _rSettings + current settings. Upon return, the field mapping member of this + structure will be filled with the settings the user did in the + field mapping dialog. + */ + bool invokeDialog( + const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + class weld::Window* _pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxDataSource, + AddressSettings& _rSettings + ); + + + /** creates a default field mapping for usage with the address book SDBC driver +

The column names as used by the SDBC driver for address books is stored in the configuration, + and this function creates a mapping which uses this configuration information.

+ */ + void defaultMapping( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + MapString2String& /* [out] */ _rFieldAssignment + ); + + + /** writes a field mapping for the template document address source + */ + void writeTemplateAddressFieldMapping( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + MapString2String&& _rFieldAssignment + ); + + + } // namespace fieldmapping + + + namespace addressconfig + { + + + /** writes the data source / table name given into the configuration, to where the template documents + expect it. + */ + void writeTemplateAddressSource( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const OUString& _rDataSourceName, + const OUString& _rTableName + ); + + /** writes the configuration entry which states the pilot has been completed successfully + */ + void markPilotSuccess( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + + } // namespace addressconfig + + +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/fieldmappingpage.cxx b/extensions/source/abpilot/fieldmappingpage.cxx new file mode 100644 index 000000000..1652723fd --- /dev/null +++ b/extensions/source/abpilot/fieldmappingpage.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 "fieldmappingpage.hxx" +#include "fieldmappingimpl.hxx" +#include "addresssettings.hxx" +#include "abspilot.hxx" + + +namespace abp +{ + FieldMappingPage::FieldMappingPage(weld::Container* pPage, OAddressBookSourcePilot* pController) + : AddressBookSourcePage(pPage, pController, "modules/sabpilot/ui/fieldassignpage.ui", "FieldAssignPage") + , m_xInvokeDialog(m_xBuilder->weld_button("assign")) + , m_xHint(m_xBuilder->weld_label("hint")) + { + m_xInvokeDialog->connect_clicked(LINK(this, FieldMappingPage, OnInvokeDialog)); + } + + FieldMappingPage::~FieldMappingPage() + { + } + + void FieldMappingPage::Activate() + { + AddressBookSourcePage::Activate(); + m_xInvokeDialog->grab_focus(); + } + + void FieldMappingPage::initializePage() + { + AddressBookSourcePage::initializePage(); + implUpdateHint(); + } + + void FieldMappingPage::implUpdateHint() + { + const AddressSettings& rSettings = getSettings(); + OUString sHint; + if ( rSettings.aFieldMapping.empty() ) + sHint = compmodule::ModuleRes(RID_STR_NOFIELDSASSIGNED); + m_xHint->set_label(sHint); + } + + IMPL_LINK_NOARG( FieldMappingPage, OnInvokeDialog, weld::Button&, void ) + { + AddressSettings& rSettings = getSettings(); + + // invoke the dialog doing the mapping + if ( fieldmapping::invokeDialog( getORB(), getDialog()->getDialog(), getDialog()->getDataSource().getDataSource(), rSettings ) ) + { + if ( !rSettings.aFieldMapping.empty() ) + getDialog()->travelNext(); + else + implUpdateHint(); + } + } + +} // namespace abp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/fieldmappingpage.hxx b/extensions/source/abpilot/fieldmappingpage.hxx new file mode 100644 index 000000000..e3ef93794 --- /dev/null +++ b/extensions/source/abpilot/fieldmappingpage.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "abspage.hxx" +#include + +namespace abp +{ + class FieldMappingPage final : public AddressBookSourcePage + { + std::unique_ptr m_xInvokeDialog; + std::unique_ptr m_xHint; + public: + explicit FieldMappingPage(weld::Container* pPage, OAddressBookSourcePilot* pController); + virtual ~FieldMappingPage() override; + private: + // OWizardPage overridables + virtual void initializePage() override; + + // BuilderPage overridables + virtual void Activate() override; + + DECL_LINK(OnInvokeDialog, weld::Button&, void); + + void implUpdateHint(); + }; +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/moduleabp.cxx b/extensions/source/abpilot/moduleabp.cxx new file mode 100644 index 000000000..0a8f8fd4d --- /dev/null +++ b/extensions/source/abpilot/moduleabp.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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/tableselectionpage.cxx b/extensions/source/abpilot/tableselectionpage.cxx new file mode 100644 index 000000000..abf8e5829 --- /dev/null +++ b/extensions/source/abpilot/tableselectionpage.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 "tableselectionpage.hxx" +#include "abptypes.hxx" +#include "addresssettings.hxx" +#include "abspilot.hxx" +#include + + +namespace abp +{ + + TableSelectionPage::TableSelectionPage(weld::Container* pPage, OAddressBookSourcePilot* pController) + : AddressBookSourcePage(pPage, pController, "modules/sabpilot/ui/selecttablepage.ui", "SelectTablePage") + , m_xTableList(m_xBuilder->weld_tree_view("table")) + { + m_xTableList->connect_changed( LINK( this, TableSelectionPage, OnTableSelected ) ); + m_xTableList->connect_row_activated( LINK( this, TableSelectionPage, OnTableDoubleClicked ) ); + } + + TableSelectionPage::~TableSelectionPage() + { + } + + void TableSelectionPage::Activate() + { + AddressBookSourcePage::Activate(); + + m_xTableList->grab_focus(); + } + + void TableSelectionPage::initializePage() + { + AddressBookSourcePage::initializePage(); + + const AddressSettings& rSettings = getSettings(); + + m_xTableList->clear(); + + // get the table names + const StringBag& aTableNames = getDialog()->getDataSource().getTableNames(); + DBG_ASSERT( aTableNames.size() > 1, "TableSelectionPage::initializePage: to be called for more than one table only!"); + // this page should never bother the user if there is 1 or less tables. + + // fill the list + for (auto const& tableName : aTableNames) + m_xTableList->append_text(tableName); + + // initially select the proper table + m_xTableList->select_text(rSettings.sSelectedTable); + } + + IMPL_LINK_NOARG( TableSelectionPage, OnTableDoubleClicked, weld::TreeView&, bool ) + { + if (m_xTableList->count_selected_rows() == 1) + getDialog()->travelNext(); + return true; + } + + IMPL_LINK_NOARG( TableSelectionPage, OnTableSelected, weld::TreeView&, void ) + { + updateDialogTravelUI(); + } + + bool TableSelectionPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!AddressBookSourcePage::commitPage(_eReason)) + return false; + + AddressSettings& rSettings = getSettings(); + rSettings.sSelectedTable = m_xTableList->get_selected_text(); + + return true; + } + + bool TableSelectionPage::canAdvance() const + { + return AddressBookSourcePage::canAdvance() + && (m_xTableList->count_selected_rows() > 0); + } + +} // namespace abp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/tableselectionpage.hxx b/extensions/source/abpilot/tableselectionpage.hxx new file mode 100644 index 000000000..a150bf844 --- /dev/null +++ b/extensions/source/abpilot/tableselectionpage.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "abspage.hxx" +#include + +namespace abp +{ + class TableSelectionPage final : public AddressBookSourcePage + { + std::unique_ptr m_xTableList; + + public: + explicit TableSelectionPage(weld::Container* pPage, OAddressBookSourcePilot* pController); + virtual ~TableSelectionPage() override; + private: + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + // BuilderPage overridables + virtual void Activate() override; + + // OImportPage overridables + virtual bool canAdvance() const override; + + DECL_LINK(OnTableSelected, weld::TreeView&, void); + DECL_LINK(OnTableDoubleClicked, weld::TreeView&, bool); + }; + +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/typeselectionpage.cxx b/extensions/source/abpilot/typeselectionpage.cxx new file mode 100644 index 000000000..79cfd5d6b --- /dev/null +++ b/extensions/source/abpilot/typeselectionpage.cxx @@ -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 incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "typeselectionpage.hxx" +#include "addresssettings.hxx" +#include "abspilot.hxx" +#include +#include +#include +#include + +namespace abp +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::sdbc; + + // TypeSelectionPage + TypeSelectionPage::TypeSelectionPage(weld::Container* pPage, OAddressBookSourcePilot* pDialog) + : AddressBookSourcePage(pPage, pDialog, "modules/sabpilot/ui/selecttypepage.ui", "SelectTypePage") + , m_xEvolution(m_xBuilder->weld_radio_button("evolution")) + , m_xEvolutionGroupwise(m_xBuilder->weld_radio_button("groupwise")) + , m_xEvolutionLdap(m_xBuilder->weld_radio_button("evoldap")) + , m_xThunderbird(m_xBuilder->weld_radio_button("thunderbird")) + , m_xKab(m_xBuilder->weld_radio_button("kde")) + , m_xMacab(m_xBuilder->weld_radio_button("macosx")) + , m_xOther(m_xBuilder->weld_radio_button("other")) + { + //TODO: For now, try to keep offering the same choices like before the + // Mozilla cleanup, even if the status of what driver actually + // provides which functionality is somewhat unclear, see the discussions + // of fdo#57285 "Address Book Data Source Wizard lists 'macOS address + // book' on Linux" and fdo#57322 "Moz-free LDAP Address Book driver." + // In accordance with ancient OOo 3.3, this is as follows: + // + // On Linux: + // - EVOLUTION, EVOLUTION_GROUPWISE, EVOLUTION_LDAP (if applicable) + // - KAB (if applicable) + // - OTHER + // + // On macOS: + // - MACAB (if applicable) + // - OTHER + // + // On Windows: + // - THUNDERBIRD + // - OTHER + +#if !defined(_WIN32) + bool bHaveEvolution = false; + bool bHaveKab = false; + bool bHaveMacab = false; + + Reference< XDriverManager2 > xManager = DriverManager::create( pDialog->getORB() ); + + try + { + // check whether Evolution is available + Reference< XDriver > xDriver( xManager->getDriverByURL("sdbc:address:evolution:local") ); + if ( xDriver.is() ) + bHaveEvolution = true; + } + catch (...) + { + } + + // check whether KDE address book is available + try + { + Reference< XDriver > xDriver( xManager->getDriverByURL("sdbc:address:kab") ); + if ( xDriver.is() ) + bHaveKab = true; + } + catch (...) + { + } + + try + { + // check whether macOS address book is available + Reference< XDriver > xDriver( xManager->getDriverByURL("sdbc:address:macab") ); + if ( xDriver.is() ) + bHaveMacab = true; + } + catch(...) + { + } +#else + bool const bHaveEvolution = false; + bool const bHaveKab = false; + bool const bHaveMacab = false; +#endif + + // Items are displayed in list order + m_aAllTypes.push_back( ButtonItem( m_xEvolution.get(), AST_EVOLUTION, bHaveEvolution ) ); + m_aAllTypes.push_back( ButtonItem( m_xEvolutionGroupwise.get(), AST_EVOLUTION_GROUPWISE, bHaveEvolution ) ); + m_aAllTypes.push_back( ButtonItem( m_xEvolutionLdap.get(), AST_EVOLUTION_LDAP, bHaveEvolution ) ); + m_aAllTypes.push_back( ButtonItem( m_xThunderbird.get(), AST_THUNDERBIRD, true ) ); + m_aAllTypes.push_back( ButtonItem( m_xKab.get(), AST_KAB, bHaveKab ) ); + m_aAllTypes.push_back( ButtonItem( m_xMacab.get(), AST_MACAB, bHaveMacab ) ); + m_aAllTypes.push_back( ButtonItem( m_xOther.get(), AST_OTHER, true ) ); + + Link aTypeSelectionHandler = LINK(this, TypeSelectionPage, OnTypeSelected ); + for (auto const& elem : m_aAllTypes) + { + if (!elem.m_bVisible) + elem.m_pItem->hide(); + else + { + elem.m_pItem->connect_toggled( aTypeSelectionHandler ); + elem.m_pItem->show(); + } + } + } + + TypeSelectionPage::~TypeSelectionPage() + { + for (auto & elem : m_aAllTypes) + { + elem.m_bVisible = false; + } + } + + void TypeSelectionPage::Activate() + { + AddressBookSourcePage::Activate(); + + for (auto const& elem : m_aAllTypes) + { + if( elem.m_pItem->get_active() && elem.m_bVisible ) + { + elem.m_pItem->grab_focus(); + break; + } + } + + getDialog()->enableButtons(WizardButtonFlags::PREVIOUS, false); + } + + void TypeSelectionPage::Deactivate() + { + AddressBookSourcePage::Deactivate(); + getDialog()->enableButtons(WizardButtonFlags::PREVIOUS, true); + } + + void TypeSelectionPage::selectType( AddressSourceType _eType ) + { + for (auto const& elem : m_aAllTypes) + { + elem.m_pItem->set_active( _eType == elem.m_eType ); + } + } + + AddressSourceType TypeSelectionPage::getSelectedType() const + { + for (auto const& elem : m_aAllTypes) + { + if ( elem.m_pItem->get_active() && elem.m_bVisible ) + return elem.m_eType; + } + + return AST_INVALID; + } + + void TypeSelectionPage::initializePage() + { + AddressBookSourcePage::initializePage(); + + const AddressSettings& rSettings = getSettings(); + selectType(rSettings.eType); + } + + bool TypeSelectionPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!AddressBookSourcePage::commitPage(_eReason)) + return false; + + if (AST_INVALID == getSelectedType( )) + { + std::unique_ptr xBox(Application::CreateMessageDialog(m_xContainer.get(), + VclMessageType::Warning, VclButtonsType::Ok, + compmodule::ModuleRes(RID_STR_NEEDTYPESELECTION))); + xBox->run(); + return false; + } + + AddressSettings& rSettings = getSettings(); + rSettings.eType = getSelectedType(); + + return true; + } + + bool TypeSelectionPage::canAdvance() const + { + return AddressBookSourcePage::canAdvance() + && (AST_INVALID != getSelectedType()); + } + + IMPL_LINK(TypeSelectionPage, OnTypeSelected, weld::Toggleable&, rButton, void) + { + if (!rButton.get_active()) + return; + getDialog()->typeSelectionChanged( getSelectedType() ); + updateDialogTravelUI(); + } + +} // namespace abp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/typeselectionpage.hxx b/extensions/source/abpilot/typeselectionpage.hxx new file mode 100644 index 000000000..7c908057d --- /dev/null +++ b/extensions/source/abpilot/typeselectionpage.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "abspage.hxx" +#include "addresssettings.hxx" +#include + +namespace abp +{ + + class TypeSelectionPage final : public AddressBookSourcePage + { + std::unique_ptr m_xEvolution; + std::unique_ptr m_xEvolutionGroupwise; + std::unique_ptr m_xEvolutionLdap; + std::unique_ptr m_xThunderbird; + std::unique_ptr m_xKab; + std::unique_ptr m_xMacab; + std::unique_ptr m_xOther; + + struct ButtonItem { + weld::RadioButton* m_pItem; + AddressSourceType m_eType; + bool m_bVisible; + + ButtonItem( weld::RadioButton *pItem, + AddressSourceType eType, + bool bVisible ) : + m_pItem( pItem ), + m_eType( eType ), + m_bVisible( bVisible ) + {} + }; + + std::vector< ButtonItem > m_aAllTypes; + + public: + explicit TypeSelectionPage(weld::Container* pPage, OAddressBookSourcePilot* pController); + virtual ~TypeSelectionPage() override; + + // retrieves the currently selected type + AddressSourceType getSelectedType() const; + + private: + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + // BuilderPage overridables + virtual void Activate() override; + virtual void Deactivate() override; + + // OImportPage overridables + virtual bool canAdvance() const override; + + DECL_LINK( OnTypeSelected, weld::Toggleable&, void ); + + void selectType( AddressSourceType _eType ); + }; + + +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/unodialogabp.cxx b/extensions/source/abpilot/unodialogabp.cxx new file mode 100644 index 000000000..4409a1911 --- /dev/null +++ b/extensions/source/abpilot/unodialogabp.cxx @@ -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 . + */ + +#include "unodialogabp.hxx" +#include "abspilot.hxx" +#include +#include +#include +#include +#include + +#define PROPERTY_ID_DATASOURCENAME 3 + +namespace abp +{ + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::ui::dialogs; + + OABSPilotUno::OABSPilotUno(const Reference< XComponentContext >& _rxORB) + :OGenericUnoDialog(_rxORB) + { + registerProperty( "DataSourceName", PROPERTY_ID_DATASOURCENAME, PropertyAttribute::READONLY , + &m_sDataSourceName, cppu::UnoType::get() ); + } + + Any SAL_CALL OABSPilotUno::queryInterface( const Type& aType ) + { + Any aReturn = svt::OGenericUnoDialog::queryInterface( aType ); + return aReturn.hasValue() ? aReturn : OABSPilotUno_JBase::queryInterface( aType ); + } + + void SAL_CALL OABSPilotUno::acquire( ) noexcept + { + svt::OGenericUnoDialog::acquire(); + } + + void SAL_CALL OABSPilotUno::release( ) noexcept + { + svt::OGenericUnoDialog::release(); + } + + Sequence< Type > SAL_CALL OABSPilotUno::getTypes( ) + { + return ::comphelper::concatSequences( + svt::OGenericUnoDialog::getTypes(), + OABSPilotUno_JBase::getTypes() + ); + } + + Sequence SAL_CALL OABSPilotUno::getImplementationId( ) + { + return css::uno::Sequence(); + } + + OUString SAL_CALL OABSPilotUno::getImplementationName() + { + return "org.openoffice.comp.abp.OAddressBookSourcePilot"; + } + + css::uno::Sequence SAL_CALL OABSPilotUno::getSupportedServiceNames() + { + return { "com.sun.star.ui.dialogs.AddressBookSourcePilot" }; + } + + Reference SAL_CALL OABSPilotUno::getPropertySetInfo() + { + Reference xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + + ::cppu::IPropertyArrayHelper& OABSPilotUno::getInfoHelper() + { + return *getArrayHelper(); + } + + + ::cppu::IPropertyArrayHelper* OABSPilotUno::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + } + + void SAL_CALL OABSPilotUno::initialize( const Sequence< Any >& aArguments ) + { + Reference xParentWindow; + if (aArguments.getLength() == 1 && (aArguments[0] >>= xParentWindow) ) { + Sequence< Any > aNewArgs{ Any(PropertyValue( + "ParentWindow", 0, Any(xParentWindow), PropertyState_DIRECT_VALUE )) }; + OGenericUnoDialog::initialize(aNewArgs); + } else { + OGenericUnoDialog::initialize(aArguments); + } + } + + std::unique_ptr OABSPilotUno::createDialog(const css::uno::Reference& rParent) + { + return std::make_unique(Application::GetFrameWeld(rParent), m_aContext); + } + + Any SAL_CALL OABSPilotUno::execute( const Sequence< NamedValue >& /*lArgs*/ ) + { + // not interested in the context, not interested in the args + // -> call the execute method of the XExecutableDialog + static_cast< XExecutableDialog* >( this )->execute(); + + // result interest not really ... + // We show this dialog one times only! + // User has one chance to accept it or not. + // (or he can start it again by using wizard-menu!) + // So we should deregister it on our general job execution service by using right protocol parameters. + css::uno::Sequence< css::beans::NamedValue > lProtocol { { "Deactivate", css::uno::Any( true ) } }; + return Any( lProtocol ); + } + + void OABSPilotUno::executedDialog(sal_Int16 _nExecutionResult) + { + if ( _nExecutionResult == RET_OK ) + { + const AddressSettings& aSettings = static_cast(m_xDialog.get())->getSettings(); + m_sDataSourceName = aSettings.bRegisterDataSource ? aSettings.sRegisteredDataSourceName : aSettings.sDataSourceName; + } + } + + +} // namespace abp + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +org_openoffice_comp_abp_OAddressBookSourcePilot( + css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new abp::OABSPilotUno(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/abpilot/unodialogabp.hxx b/extensions/source/abpilot/unodialogabp.hxx new file mode 100644 index 000000000..b8bd940af --- /dev/null +++ b/extensions/source/abpilot/unodialogabp.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace abp +{ + class OABSPilotUno; + typedef ::cppu::ImplHelper1< css::task::XJob > OABSPilotUno_JBase; + typedef ::comphelper::OPropertyArrayUsageHelper< OABSPilotUno > OABSPilotUno_PBase; + /// the UNO wrapper for the address book source pilot + class OABSPilotUno + : public svt::OGenericUnoDialog + , public OABSPilotUno_JBase + , public OABSPilotUno_PBase + { + OUString m_sDataSourceName; + + public: + explicit OABSPilotUno(const css::uno::Reference< css::uno::XComponentContext >& _rxORB); + + private: + // XInterface (disambiguation) + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire( ) noexcept override; + virtual void SAL_CALL release( ) noexcept override; + + // XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override; + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + // XJob + virtual css::uno::Any SAL_CALL execute( const css::uno::Sequence< css::beans::NamedValue >& lArgs ) override; + + // XInitialisation + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + using svt::OGenericUnoDialog::execute; + // OGenericUnoDialog overridables + virtual std::unique_ptr createDialog(const css::uno::Reference& rParent) override; + virtual void executedDialog(sal_Int16 _nExecutionResult) override; + }; + +} // namespace abp +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/README.txt b/extensions/source/activex/README.txt new file mode 100644 index 000000000..50c209150 --- /dev/null +++ b/extensions/source/activex/README.txt @@ -0,0 +1,33 @@ +Description. + +The StarOffice ActiveX control shows an example of access to UNO through COM technology. +It requires a properly installed StarOffice version 6.0/6.1 or OpenOffice 1.0. +This is a Lite ActiveX control so it can be used only in containers that +allows to use such controls. + +Pressing to any link to staroffice document should activate the control. +So the document will be opened in ReadOnly mode. + +Also it can be activated with an tag from a html-page. +Without any parameters for an object tag a new writer document will be +opened for editing. Possible parameters are + src - full URL to the file that should be edited/viewed; + it can contain "private:factory/..." URLs to open new documents + for edit, for example "private:factory/swriter" + readonly - the default value is "true", in case it is set to any other + value the document is opened for editing + +As any ActiveX control this one should be registered. +To let MSIE register it itself the "CODEBASE" parameter +for the "OBJECT" tag should be specified +with a URL to the library "so_activex.dll". +The example of registration with "OBJECT" tag is in example.html. + +Also it can be done using regsvr32 application. +To do it please write +\System32\regsvr32 so_activex.dll + +To unregister the control please use /u option: +\system32\regsvr32 so_activex.dll /u + + diff --git a/extensions/source/activex/SOActionsApproval.cxx b/extensions/source/activex/SOActionsApproval.cxx new file mode 100644 index 000000000..a40921662 --- /dev/null +++ b/extensions/source/activex/SOActionsApproval.cxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// SOActionsApproval.cpp : Implementation of CHelpApp and DLL registration. + +#include + +#include + +#include "StdAfx2.h" + +#include "SOActionsApproval.h" +#include + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif +#include +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +COM_DECLSPEC_NOTHROW STDMETHODIMP SOActionsApproval::InterfaceSupportsErrorInfo(REFIID riid) +{ + static const IID* arr[] = { + &IID_ISOActionsApproval, + }; + + for (std::size_t i = 0; i < SAL_N_ELEMENTS(arr); i++) + { +#ifdef _MSC_VER + if (InlineIsEqualGUID(*arr[i], riid)) +#else + if (::ATL::InlineIsEqualGUID(*arr[i], riid)) +#endif + return S_OK; + } + return S_FALSE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOActionsApproval.h b/extensions/source/activex/SOActionsApproval.h new file mode 100644 index 000000000..2484e7462 --- /dev/null +++ b/extensions/source/activex/SOActionsApproval.h @@ -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 . + */ + +// SOActionsApproval.h: Definition of the SOActionsApproval class + +#pragma once + +#ifdef _MSC_VER +#pragma once +#endif + +#include "resource.h" +#include +#include +#include + +#include + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif +#include +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +// SOActionsApproval + +class SOActionsApproval : + public IDispatchImpl, + public ISupportErrorInfo, + public CComObjectRoot, + public CComCoClass +{ +public: + SOActionsApproval() {} + virtual ~SOActionsApproval() {} + +BEGIN_COM_MAP(SOActionsApproval) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(ISOActionsApproval) + COM_INTERFACE_ENTRY(ISupportErrorInfo) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif +DECLARE_NOT_AGGREGATABLE(SOActionsApproval) +// Remove the comment from the line above if you don't want your object to +// support aggregation. + +DECLARE_REGISTRY_RESOURCEID(IDR_SODOCUMENTEVENTLISTENER) + +// ISupportsErrorInfo + STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) override; + +// ISOActionsApproval + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE approveAction( + /* [in] */ long nActionID, + /* [retval][out] */ boolean *pbApproval) override + { + // only PreventClose is approved + USES_CONVERSION; + *pbApproval = ( nActionID == 1 ); + + return S_OK; + } + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_Bridge_implementedInterfaces( + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *pVal) override + { + *pVal = SafeArrayCreateVector( VT_BSTR, 0, 1 ); + + if( !*pVal ) + return E_FAIL; + + LONG ix = 0; + CComBSTR aInterface( OLESTR( "com.sun.star.embed.XActionsApproval" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + return S_OK; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOActionsApproval.rgs b/extensions/source/activex/SOActionsApproval.rgs new file mode 100644 index 000000000..543320813 --- /dev/null +++ b/extensions/source/activex/SOActionsApproval.rgs @@ -0,0 +1,24 @@ +HKCR +{ +9F3697AC-7A18-4335-AF0A-65FAC2C35CC1 + so_activex.SOActionsApproval.1 = s 'SOActionsApproval Class' + { + CLSID = s '{9F3697AC-7A18-4335-AF0A-65FAC2C35CC1}' + } + so_activex.SOActionsApproval = s 'SOActionsApproval Class' + { + CLSID = s '{9F3697AC-7A18-4335-AF0A-65FAC2C35CC1}' + } + NoRemove CLSID + { + ForceRemove {9F3697AC-7A18-4335-AF0A-65FAC2C35CC1} = s 'SOActionsApproval Class' + { + ProgID = s 'so_activex.SOActionsApproval.1' + VersionIndependentProgID = s 'so_activex.SOActionsApproval' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'both' + } + } + } +} diff --git a/extensions/source/activex/SOActiveX.cxx b/extensions/source/activex/SOActiveX.cxx new file mode 100644 index 000000000..88b3ad769 --- /dev/null +++ b/extensions/source/activex/SOActiveX.cxx @@ -0,0 +1,1162 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// SOActiveX.cpp : Implementation of CSOActiveX + +#include "StdAfx2.h" +#include "SOActiveX.h" +#include "SOComWindowPeer.h" +#include "SODispatchInterceptor.h" +#include "SOActionsApproval.h" +#include "com_uno_helper.h" + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif +#include +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#define STAROFFICE_WINDOWCLASS L"SOParentWindow" + + +static void OutputError_Impl( HWND hw, HRESULT ErrorCode ) +{ + LPWSTR sMessage = nullptr; + FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + ErrorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + reinterpret_cast(&sMessage), + 0, + nullptr + ); + MessageBoxW( hw, sMessage, nullptr, MB_OK | MB_ICONINFORMATION ); + HeapFree( GetProcessHeap(), 0, sMessage ); +} + +HRESULT ExecuteFunc( IDispatch* idispUnoObject, + OLECHAR const * sFuncName, + CComVariant* params, + unsigned int count, + CComVariant* pResult ) +{ + if( !idispUnoObject ) + return E_FAIL; + + DISPID id; + HRESULT hr = idispUnoObject->GetIDsOfNames( IID_NULL, const_cast(&sFuncName), 1, LOCALE_USER_DEFAULT, &id); + if( !SUCCEEDED( hr ) ) return hr; + + DISPPARAMS dispparams= { params, nullptr, count, 0}; + + // DEBUG + EXCEPINFO myInfo; + hr = idispUnoObject->Invoke( id, IID_NULL,LOCALE_USER_DEFAULT, DISPATCH_METHOD, + &dispparams, pResult, &myInfo, nullptr); + + // for debugging purposes + // USES_CONVERSION; + // if ( !SUCCEEDED( hr ) ) + // ::MessageBox( NULL, OLE2A( myInfo.bstrDescription ), OLE2A( myInfo.bstrSource ), MB_OK | MB_ICONINFORMATION ); + + return hr; +} + +static HRESULT GetIDispByFunc( IDispatch* idispUnoObject, + OLECHAR const * sFuncName, + CComVariant* params, + unsigned int count, + CComPtr& pdispResult ) +{ + if( !idispUnoObject ) + return E_FAIL; + + CComVariant result; + HRESULT hr = ExecuteFunc( idispUnoObject, sFuncName, params, count, &result ); + if( !SUCCEEDED( hr ) ) return hr; + + if( result.vt != VT_DISPATCH || result.pdispVal == nullptr ) + return E_FAIL; + + pdispResult = CComPtr( result.pdispVal ); + + return S_OK; +} + +static HRESULT PutPropertiesToIDisp( IDispatch* pdispObject, + OLECHAR const ** sMemberNames, + CComVariant* pVariant, + unsigned int count ) +{ + for( unsigned int ind = 0; ind < count; ind++ ) + { + DISPID id; + HRESULT hr = pdispObject->GetIDsOfNames( IID_NULL, const_cast(&sMemberNames[ind]), 1, LOCALE_USER_DEFAULT, &id ); + if( !SUCCEEDED( hr ) ) return hr; + + hr = CComDispatchDriver::PutProperty( pdispObject, id, &pVariant[ind] ); + if( !SUCCEEDED( hr ) ) return hr; + } + + return S_OK; +} + +HRESULT GetPropertiesFromIDisp( IDispatch* pdispObject, + OLECHAR const ** sMemberNames, + CComVariant* pVariant, + unsigned int count ) +{ + for( unsigned int ind = 0; ind < count; ind++ ) + { + DISPID id; + HRESULT hr = pdispObject->GetIDsOfNames( IID_NULL, const_cast(&sMemberNames[ind]), 1, LOCALE_USER_DEFAULT, &id ); + if( !SUCCEEDED( hr ) ) return hr; + + hr = CComDispatchDriver::GetProperty( pdispObject, id, &pVariant[ind] ); + if( !SUCCEEDED( hr ) ) return hr; + } + + return S_OK; +} + +// CSOActiveX + +CSOActiveX::CSOActiveX() +: mCookie(0) +, mCurFileUrl( L"private:factory/swriter" ) +, mbLoad( FALSE ) +, mbViewOnly( TRUE ) +, mParentWin( nullptr ) +, mOffWin( nullptr ) +, mpDispatchInterceptor( nullptr ) +, mnVersion( SO_NOT_DETECTED ) +, mbReadyForActivation( FALSE ) +, mbDrawLocked( false ) +{ + CLSID const clsFactory = {0x82154420,0x0FBF,0x11d4,{0x83, 0x13,0x00,0x50,0x04,0x52,0x6A,0xB4}}; + HRESULT hr = CoCreateInstance( clsFactory, nullptr, CLSCTX_ALL, __uuidof(IDispatch), reinterpret_cast(&mpDispFactory)); + if( !SUCCEEDED( hr ) ) + OutputError_Impl( nullptr, hr ); + + mPWinClass.style = CS_HREDRAW|CS_VREDRAW; + mPWinClass.lpfnWndProc = DefWindowProcW; + mPWinClass.cbClsExtra = 0; + mPWinClass.cbWndExtra = 0; + mPWinClass.hInstance = GetModuleHandleW(nullptr); //myInstance; + mPWinClass.hIcon = nullptr; + mPWinClass.hCursor = nullptr; + mPWinClass.hbrBackground = reinterpret_cast(COLOR_BACKGROUND); + mPWinClass.lpszMenuName = nullptr; + mPWinClass.lpszClassName = STAROFFICE_WINDOWCLASS; + + RegisterClassW(&mPWinClass); +} + +CSOActiveX::~CSOActiveX() +{ + Cleanup(); + +} + +HRESULT CSOActiveX::Cleanup() +{ + CComVariant dummyResult; + + if( mpDispatchInterceptor ) + { + if( mpDispFrame ) + { + // remove dispatch interceptor + CComQIPtr< IDispatch, &IID_IDispatch > pIDispDispInter( mpDispatchInterceptor ); + CComVariant aVariant( pIDispDispInter ); + ExecuteFunc( mpDispFrame, + L"releaseDispatchProviderInterceptor", + &aVariant, + 1, + &dummyResult ); + } + + mpDispatchInterceptor->ClearParent(); + mpDispatchInterceptor->Release(); + mpDispatchInterceptor = nullptr; + } + + mpDispTempFile = CComPtr< IDispatch >(); + mbReadyForActivation = FALSE; + + if( mpInstanceLocker ) + { + ExecuteFunc( mpInstanceLocker, L"dispose", nullptr, 0, &dummyResult ); + mpInstanceLocker = CComPtr< IDispatch >(); + } + + if( mpDispFrame ) + { + bool bCloserActivated = false; + + CComPtr pDispDocumentCloser; + CComVariant aDocCloser( L"com.sun.star.embed.DocumentCloser" ); + HRESULT hr = GetIDispByFunc( mpDispFactory, + L"createInstance", + &aDocCloser, + 1, + pDispDocumentCloser ); + if ( SUCCEEDED( hr ) && pDispDocumentCloser ) + { + SAFEARRAY* pInitFrame = SafeArrayCreateVector(VT_VARIANT, 0, 1); + LONG nInitInd = 0; + CComVariant pFrameVariant( mpDispFrame ); + SafeArrayPutElement( pInitFrame, &nInitInd, &pFrameVariant ); + CComVariant aVarInitFrame; + aVarInitFrame.vt = VT_ARRAY | VT_VARIANT; aVarInitFrame.parray = pInitFrame; + hr = ExecuteFunc( pDispDocumentCloser, L"initialize", &aVarInitFrame, 1, &dummyResult ); + if( SUCCEEDED( hr ) ) + { + // the following call will let the closing happen + hr = ExecuteFunc( pDispDocumentCloser, L"dispose", nullptr, 0, &dummyResult ); + bCloserActivated = SUCCEEDED( hr ); + } + } + + if ( !bCloserActivated ) + { + CComVariant aPropVar; + aPropVar.vt = VT_BOOL; aPropVar.boolVal = VARIANT_TRUE; + if ( !SUCCEEDED( ExecuteFunc( mpDispFrame, L"close", &aPropVar, 1, &dummyResult ) ) ) + ExecuteFunc( mpDispFrame, L"dispose", nullptr, 0, &dummyResult ); + } + + mpDispFrame = CComPtr< IDispatch >(); + } + + if( ::IsWindow( mOffWin ) ) + ::DestroyWindow( mOffWin ); + + TerminateOffice(); + + return S_OK; +} + +HRESULT CSOActiveX::TerminateOffice() +{ + // create desktop + CComPtr pdispDesktop; + CComVariant aDesktopServiceName( L"com.sun.star.frame.Desktop" ); + + HRESULT hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aDesktopServiceName, 1, pdispDesktop ); + if( !pdispDesktop || !SUCCEEDED( hr ) ) return hr; + + // create tree of frames + CComPtr pdispChildren; + hr = GetIDispByFunc( pdispDesktop, L"getFrames", nullptr, 0, pdispChildren ); + if( !pdispChildren || !SUCCEEDED( hr ) ) return hr; + + CComVariant aFrames; + CComVariant nFlag( 4 ); + hr = ExecuteFunc( pdispChildren, L"queryFrames", &nFlag, 1, &aFrames ); + if ( SUCCEEDED( hr ) ) + { + if ( ( aFrames.vt == ( VT_ARRAY | VT_DISPATCH ) || aFrames.vt == ( VT_ARRAY | VT_VARIANT ) ) + && ( !aFrames.parray || (aFrames.parray->cDims == 1 && aFrames.parray->rgsabound[0].cElements == 0) ) ) + { + // there is no frames open + // TODO: check whether the frames are hidden if they are open? + CComVariant dummyResult; + hr = ExecuteFunc( pdispDesktop, L"terminate", nullptr, 0, &dummyResult ); + } + } + + return hr; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CSOActiveX::InitNew () +{ + mnVersion = GetVersionConnected(); + mbLoad = TRUE; + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CSOActiveX::Load ( LPSTREAM /*pStm*/ ) +{ + mnVersion = GetVersionConnected(); + mbLoad = TRUE; + + // may be later? + // for now just ignore + + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CSOActiveX::Load( LPPROPERTYBAG pPropBag, LPERRORLOG /*pErrorLog*/ ) +{ + mnVersion = GetVersionConnected(); + + IPropertyBag2* pPropBag2; + HRESULT hr = pPropBag->QueryInterface( IID_IPropertyBag2, reinterpret_cast(&pPropBag2) ); + //ATLASSERT( hr >= 0 ); + + if( !SUCCEEDED( hr ) ) + return hr; + + unsigned long aNum; + hr = pPropBag2->CountProperties( &aNum ); + //ATLASSERT( hr >= 0 ); + if( !SUCCEEDED( hr ) ) + return hr; + + PROPBAG2* aPropNames = new PROPBAG2[aNum]; + unsigned long aReaded; + + hr = pPropBag2->GetPropertyInfo( 0, + aNum, + aPropNames, + &aReaded ); + //ATLASSERT( hr >= 0 ); + if( !SUCCEEDED( hr ) ) + { + delete[] aPropNames; + return hr; + } + + CComVariant* aVal = new CComVariant[aNum]; + HRESULT* hvs = new HRESULT[aNum]; + hr = pPropBag2->Read( aNum, + aPropNames, + nullptr, + aVal, + hvs ); + //ATLASSERT( hr >= 0 ); + if( !SUCCEEDED( hr ) ) + { + delete[] hvs; + delete[] aVal; + delete[] aPropNames; + return hr; + } + + for( unsigned long ind = 0; ind < aNum; ind++ ) + { + // all information from the 'object' tag is in strings + if (aVal[ind].vt == VT_BSTR && !wcscmp(aPropNames[ind].pstrName, L"src")) + { + mCurFileUrl.AssignBSTR(aVal[ind].bstrVal); + } + else if( aVal[ind].vt == VT_BSTR + && !wcscmp(aPropNames[ind].pstrName, L"readonly")) + { + if (!wcscmp(aVal[ind].bstrVal, L"true")) + { + // the default value + mbViewOnly = TRUE; + } + else + { + mbViewOnly = FALSE; + } + } + } + + delete[] hvs; + delete[] aVal; + delete[] aPropNames; + + if( !mpDispFactory ) + return hr; + + mbReadyForActivation = FALSE; + hr = CBindStatusCallback::Download( + this, &CSOActiveX::CallbackCreateXInputStream, mCurFileUrl, m_spClientSite, FALSE); + if (hr == MK_S_ASYNCHRONOUS) + hr = S_OK; + + if ( !SUCCEEDED( hr ) ) + { + // trigger initialization without stream + mbLoad = TRUE; + + Invalidate(); + UpdateWindow(); + } + + return hr; +} + +HRESULT CSOActiveX::GetUnoStruct( OLECHAR const * sStructName, CComPtr& pdispResult ) +{ + CComVariant aComStruct( sStructName ); + return GetIDispByFunc( mpDispFactory, L"Bridge_GetStruct", &aComStruct, 1, pdispResult ); +} + +HRESULT CSOActiveX::GetUrlStruct( OLECHAR const * sUrl, CComPtr& pdispUrl ) +{ + HRESULT hr = GetUnoStruct( L"com.sun.star.util.URL", pdispUrl ); + if( !SUCCEEDED( hr ) ) return hr; + + OLECHAR const * sURLMemberName = L"Complete"; + DISPID nURLID; + hr = pdispUrl->GetIDsOfNames( IID_NULL, const_cast(&sURLMemberName), 1, LOCALE_USER_DEFAULT, &nURLID ); + if( !SUCCEEDED( hr ) ) return hr; + CComVariant aComUrl( sUrl ); + hr = CComDispatchDriver::PutProperty( pdispUrl, nURLID, &aComUrl ); + if( !SUCCEEDED( hr ) ) return hr; + + CComPtr pdispTransformer; + CComVariant aServiceName( L"com.sun.star.util.URLTransformer" ); + hr = GetIDispByFunc( mpDispFactory, + L"createInstance", + &aServiceName, + 1, + pdispTransformer ); + if( !SUCCEEDED( hr ) ) return hr; + + CComVariant dummyResult; + CComVariant aParam[2]; + aParam[1].ppdispVal = &pdispUrl; + aParam[1].vt = VT_DISPATCH | VT_BYREF; + aParam[0] = CComVariant( L"file:///" ); + + hr = ExecuteFunc( pdispTransformer, L"parseSmart", aParam, 2, &dummyResult ); + if( !SUCCEEDED( hr ) || dummyResult.vt != VT_BOOL || !dummyResult.boolVal ) return hr; + + return S_OK; +} + +HRESULT CSOActiveX::SetLayoutManagerProps() +{ + if ( !mpDispFrame ) + return E_FAIL; + + CComVariant pVarLayoutMgr; + OLECHAR const * sLMPropName = L"LayoutManager"; + HRESULT hr = GetPropertiesFromIDisp( mpDispFrame, &sLMPropName, &pVarLayoutMgr, 1 ); + if( pVarLayoutMgr.vt != VT_DISPATCH || pVarLayoutMgr.pdispVal == nullptr ) + return E_FAIL; + + CComPtr pdispLM( pVarLayoutMgr.pdispVal ); + + + if( !SUCCEEDED( hr ) || !pdispLM ) + return E_FAIL; + + OLECHAR const * sATName = L"AutomaticToolbars"; + CComVariant pATProp; + pATProp.vt = VT_BOOL; pATProp.boolVal = VARIANT_FALSE ; + hr = PutPropertiesToIDisp( pdispLM, &sATName, &pATProp, 1 ); + + return hr; +} + +HRESULT CSOActiveX::CreateFrameOldWay( HWND hwnd, int width, int height ) +{ + if( !mpDispFactory ) + return E_FAIL; + + // create window handle holder + CComPtr< CComObject< SOComWindowPeer > > pPeerToSend = new CComObject(); + pPeerToSend->SetHWNDInternally( hwnd ); + CComQIPtr< IDispatch, &IID_IDispatch > pIDispToSend( pPeerToSend ); + + // create rectangle structure + CComPtr pdispRectangle; + HRESULT hr = GetUnoStruct( L"com.sun.star.awt.Rectangle", pdispRectangle ); + if( !SUCCEEDED( hr ) ) return hr; + + OLECHAR const * sRectMemberNames[4] = { L"X", + L"Y", + L"Width", + L"Height" }; + CComVariant pRectVariant[4]; + pRectVariant[0] = pRectVariant[1] = pRectVariant[2] = pRectVariant[3] = CComVariant( 0 ); + + hr = PutPropertiesToIDisp( pdispRectangle, sRectMemberNames, pRectVariant, 4 ); + if( !SUCCEEDED( hr ) ) return hr; + + // create WindowDescriptor structure + CComPtr pdispWinDescr; + hr = GetUnoStruct( L"com.sun.star.awt.WindowDescriptor", pdispWinDescr ); + if( !SUCCEEDED( hr ) ) return hr; + + // fill in descriptor with info + OLECHAR const * sDescriptorMemberNames[6] = { L"Type", + L"WindowServiceName", + L"ParentIndex", + L"Parent", + L"Bounds", + L"WindowAttributes" }; + CComVariant pDescriptorVar[6]; + pDescriptorVar[0] = CComVariant( 0 ); + pDescriptorVar[1] = CComVariant( L"workwindow" ); + pDescriptorVar[2] = CComVariant( 1 ); + pDescriptorVar[3] = CComVariant( pIDispToSend ); + pDescriptorVar[4] = CComVariant( pdispRectangle ); + pDescriptorVar[5] = CComVariant( 33 ); + hr = PutPropertiesToIDisp( pdispWinDescr, sDescriptorMemberNames, pDescriptorVar, 6 ); + if( !SUCCEEDED( hr ) ) return hr; + + // create XToolkit instance + CComPtr pdispToolkit; + CComVariant aServiceName( L"com.sun.star.awt.Toolkit" ); + hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, pdispToolkit ); + if( !SUCCEEDED( hr ) ) return hr; + + // create window with toolkit + CComVariant aWinDescr( pdispWinDescr ); + hr = GetIDispByFunc( pdispToolkit, L"createWindow", &aWinDescr, 1, mpDispWin ); + if( !SUCCEEDED( hr ) ) return hr; + + // create frame + aServiceName = CComVariant( L"com.sun.star.frame.Task" ); + hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, mpDispFrame ); + if( !SUCCEEDED( hr ) || !mpDispFrame ) + { + // the interface com.sun.star.frame.Task is removed in 6.1 + // but the interface com.sun.star.frame.Frame has some bugs in 6.0 + aServiceName = CComVariant( L"com.sun.star.frame.Frame" ); + hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, mpDispFrame ); + if( !SUCCEEDED( hr ) ) return hr; + } + + // initialize frame + CComVariant dummyResult; + CComVariant aDispWin( mpDispWin ); + hr = ExecuteFunc( mpDispFrame, L"initialize", &aDispWin, 1, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + + // set some properties to the layout manager, ignore errors for now + SetLayoutManagerProps(); + + // create desktop + CComPtr pdispDesktop; + aServiceName = CComVariant( L"com.sun.star.frame.Desktop" ); + hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, pdispDesktop ); + if( !SUCCEEDED( hr ) ) return hr; + + // create tree of frames + CComPtr pdispChildren; + hr = GetIDispByFunc( pdispDesktop, L"getFrames", nullptr, 0, pdispChildren ); + if( !SUCCEEDED( hr ) ) return hr; + + // insert new frame into desktop hierarchy + CComVariant aDispFrame( mpDispFrame ); + hr = ExecuteFunc( pdispChildren, L"append", &aDispFrame, 1, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + + // initialize window + CComVariant aTransparent( long(0xFFFFFFFF) ); + hr = ExecuteFunc( mpDispWin, L"setBackground", &aTransparent, 1, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + + CComVariant aTrue( TRUE ); + hr = ExecuteFunc( mpDispWin, L"setVisible", &aTrue, 1, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + + CComVariant aPosArgs[5]; + aPosArgs[4] = CComVariant( 0 ); + aPosArgs[3] = CComVariant( 0 ); + aPosArgs[2] = CComVariant( width ); + aPosArgs[1] = CComVariant( height ); + aPosArgs[0] = CComVariant( 12 ); + hr = ExecuteFunc( mpDispWin, L"setPosSize", aPosArgs, 5, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + + // create frame locker if there is such service + aServiceName = CComVariant( L"com.sun.star.embed.InstanceLocker" ); + hr = GetIDispByFunc( mpDispFactory, L"createInstance", &aServiceName, 1, mpInstanceLocker ); + if( SUCCEEDED( hr ) && mpInstanceLocker ) + { + SAFEARRAY* pInitVals = SafeArrayCreateVector(VT_VARIANT, 0, 3); + + // the first sequence element + LONG nInitInd = 0; + CComVariant pFrameVariant( mpDispFrame ); + SafeArrayPutElement( pInitVals, &nInitInd, &pFrameVariant ); + + // the second sequence element + nInitInd = 1; + CComVariant pStrArr( 1 ); + SafeArrayPutElement( pInitVals, &nInitInd, &pStrArr ); + + // the third sequence element + nInitInd = 2; + CComPtr pdispValueObj; + hr = GetIDispByFunc( mpDispFactory, L"Bridge_GetValueObject", nullptr, 0, pdispValueObj ); + if( !SUCCEEDED( hr ) || !pdispValueObj ) return hr; + + CComVariant aValueArgs[2]; + aValueArgs[1] = CComVariant( L"com.sun.star.embed.XActionsApproval" ); + CComPtr< CComObject< SOActionsApproval > > pApproval( new CComObject() ); + aValueArgs[0] = CComVariant ( pApproval ); + + hr = ExecuteFunc( pdispValueObj, L"Set", aValueArgs, 2, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + + CComVariant aValueObj( pdispValueObj ); + SafeArrayPutElement( pInitVals, &nInitInd, &aValueObj ); + + // execute initialize() + CComVariant aVarInitVals; + aVarInitVals.vt = VT_ARRAY | VT_VARIANT; aVarInitVals.parray = pInitVals; + hr = ExecuteFunc( mpInstanceLocker, L"initialize", &aVarInitVals, 1, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + } + + return S_OK; +} + +HRESULT CSOActiveX::CallLoadComponentFromURL1PBool( OLECHAR const * sUrl, OLECHAR const * sArgName, BOOL sArgVal ) +{ + SAFEARRAY* pPropVals = SafeArrayCreateVector(VT_DISPATCH, 0, 1); + LONG ix = 0; + CComPtr pdispPropVal; + HRESULT hr = GetUnoStruct( L"com.sun.star.beans.PropertyValue", pdispPropVal ); + if( !SUCCEEDED( hr ) ) return hr; + + OLECHAR const * sPropMemberNames[2] = { L"Name", L"Value" }; + CComVariant pPropVar[2]; + pPropVar[0] = CComVariant( sArgName ); + pPropVar[1].vt = VT_BOOL; pPropVar[1].boolVal = sArgVal ? VARIANT_TRUE : VARIANT_FALSE ; + hr = PutPropertiesToIDisp( pdispPropVal, sPropMemberNames, pPropVar, 2 ); + if( !SUCCEEDED( hr ) ) return hr; + + SafeArrayPutElement( pPropVals, &ix, pdispPropVal ); + + CComVariant aDispArgs[4]; + aDispArgs[3] = CComVariant( sUrl ); + aDispArgs[2] = CComVariant( L"_self" ); + aDispArgs[1] = CComVariant( 0 ); + // aDispArgs[0] = CComVariant( pPropVals ); such constructor is not defined ??! + aDispArgs[0].vt = VT_ARRAY | VT_DISPATCH; aDispArgs[0].parray = pPropVals; + + CComVariant dummyResult; + hr = ExecuteFunc( mpDispFrame, L"loadComponentFromURL", aDispArgs, 4, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + + return S_OK; +} + +HRESULT CSOActiveX::CallDispatchMethod( OLECHAR const * sUrl, + CComVariant* aArgNames, + CComVariant* aArgVals, + unsigned int count ) +{ + CComPtr pdispURL; + HRESULT hr = GetUrlStruct( sUrl, pdispURL ); + if( !SUCCEEDED( hr ) ) return hr; + + CComPtr pdispXDispatch; + CComVariant aArgs[3]; + aArgs[2] = CComVariant( pdispURL ); + aArgs[1] = CComVariant( L"" ); + aArgs[0] = CComVariant( int(0) ); + hr = GetIDispByFunc( mpDispFrame, + L"queryDispatch", + aArgs, + 3, + pdispXDispatch ); + if( !SUCCEEDED( hr ) ) return hr; + + SAFEARRAY* pPropVals = SafeArrayCreateVector(VT_DISPATCH, 0, count); + for( LONG ix = 0; ix < static_cast(count); ix ++ ) + { + CComPtr pdispPropVal; + hr = GetUnoStruct( L"com.sun.star.beans.PropertyValue", pdispPropVal ); + if( !SUCCEEDED( hr ) ) return hr; + + OLECHAR const * sPropMemberNames[2] = { L"Name", L"Value" }; + CComVariant pPropVar[2]; + pPropVar[0] = aArgNames[ix]; + pPropVar[1] = aArgVals[ix]; + hr = PutPropertiesToIDisp( pdispPropVal, sPropMemberNames, pPropVar, 2 ); + if( !SUCCEEDED( hr ) ) return hr; + + SafeArrayPutElement( pPropVals, &ix, pdispPropVal ); + } + + CComVariant aDispArgs[2]; + aDispArgs[1] = CComVariant( pdispURL ); + // aDispArgs[0] = CComVariant( pPropVals ); such constructor is not defined ??! + aDispArgs[0].vt = VT_ARRAY | VT_DISPATCH; aDispArgs[0].parray = pPropVals; + + CComVariant dummyResult; + hr = ExecuteFunc( pdispXDispatch, L"dispatch", aDispArgs, 2, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + + return S_OK; +} + +void CSOActiveX::CallbackCreateXInputStream( CBindStatusCallback* /*pbsc*/, BYTE* pBytes, DWORD dwSize ) +{ + if ( mbReadyForActivation ) + return; + + bool bSuccess = false; + bool bFinishDownload = false; + if ( !pBytes ) + { + // means the download is finished, dwSize contains hresult + bFinishDownload = true; + if ( SUCCEEDED( dwSize ) ) + bSuccess = true; + } + else + { + HRESULT hr = S_OK; + + if ( !mpDispTempFile ) + { + CComVariant aServiceName( L"com.sun.star.io.TempFile" ); + hr = GetIDispByFunc( mpDispFactory, + L"createInstance", + &aServiceName, + 1, + mpDispTempFile ); + } + + if( SUCCEEDED( hr ) && mpDispTempFile ) + { + SAFEARRAY* pDataArray = SafeArrayCreateVector(VT_I1, 0, dwSize); + + if ( pDataArray ) + { + hr = SafeArrayLock( pDataArray ); + if ( SUCCEEDED( hr ) ) + { + for( DWORD ix = 0; ix < dwSize; ix++ ) + static_cast(pDataArray->pvData)[ix] = pBytes[ix]; + hr = SafeArrayUnlock( pDataArray ); + if ( SUCCEEDED( hr ) ) + { + CComVariant aArgs[1]; + aArgs[0].vt = VT_ARRAY | VT_I1; aArgs[0].parray = pDataArray; + CComVariant dummyResult; + hr = ExecuteFunc( mpDispTempFile, L"writeBytes", aArgs, 1, &dummyResult ); + if( SUCCEEDED( hr ) ) + bSuccess = true; + } + } + } + } + } + + if ( !bSuccess ) + { + // the download failed, let StarOffice download + bFinishDownload = true; + mpDispTempFile = CComPtr< IDispatch >(); + } + + if ( bFinishDownload ) + { + // trigger the loading now + mbLoad = TRUE; + mbReadyForActivation = TRUE; + + Invalidate(); + UpdateWindow(); + } +} + +HRESULT CSOActiveX::LoadURLToFrame( ) +{ + CComVariant aArgNames[4] = { L"ReadOnly", L"ViewOnly", L"AsTemplate", L"InputStream" }; + CComVariant aArgVals[4]; + unsigned int nCount = 3; // the 4-th argument is used only if the stream can be retrieved + + aArgVals[0].vt = VT_BOOL; aArgVals[0].boolVal = mbViewOnly ? VARIANT_TRUE : VARIANT_FALSE; + aArgVals[1].vt = VT_BOOL; aArgVals[1].boolVal = mbViewOnly ? VARIANT_TRUE : VARIANT_FALSE; + aArgVals[2].vt = VT_BOOL; aArgVals[2].boolVal = VARIANT_FALSE; + + if ( mpDispTempFile ) + { + aArgVals[3] = CComVariant( mpDispTempFile ); + nCount = 4; + } + + HRESULT hr = CallDispatchMethod( mCurFileUrl, aArgNames, aArgVals, nCount ); + if( !SUCCEEDED( hr ) ) return hr; + + // try to get the model and set the presentation specific property, the setting will fail for other document formats + CComPtr pdispController; + hr = GetIDispByFunc( mpDispFrame, L"getController", nullptr, 0, pdispController ); + if ( SUCCEEDED( hr ) && pdispController ) + { + CComPtr pdispModel; + hr = GetIDispByFunc( pdispController, L"getModel", nullptr, 0, pdispModel ); + if ( SUCCEEDED( hr ) && pdispModel ) + { + CComPtr pdispPres; + hr = GetIDispByFunc( pdispModel, L"getPresentation", nullptr, 0, pdispPres ); + if ( SUCCEEDED( hr ) && pdispPres ) + { + // this is a presentation + // let the slide show be shown in the document window + OLECHAR const * pPropName = L"IsFullScreen"; + CComVariant pPresProp; + pPresProp.vt = VT_BOOL; pPresProp.boolVal = VARIANT_FALSE ; + hr = PutPropertiesToIDisp( pdispPres, &pPropName, &pPresProp, 1 ); + + // start the slide show + if ( SUCCEEDED( hr ) ) + { + CComVariant dummyResult; + ExecuteFunc( pdispPres, L"Start", nullptr, 0, &dummyResult ); + } + } + } + } + + // create dispatch interceptor + mpDispatchInterceptor = new CComObject< SODispatchInterceptor >(); + mpDispatchInterceptor->AddRef(); + mpDispatchInterceptor->SetParent( this ); + CComQIPtr< IDispatch, &IID_IDispatch > pIDispDispInter( mpDispatchInterceptor ); + + // register dispatch interceptor in the frame + CComVariant aDispVariant( pIDispDispInter ); + CComVariant dummyResult; + hr = ExecuteFunc( mpDispFrame, + L"registerDispatchProviderInterceptor", + &aDispVariant, + 1, + &dummyResult ); + + if( !SUCCEEDED( hr ) ) return hr; + + return S_OK; +} + +SOVersion CSOActiveX::GetVersionConnected() +{ + SOVersion bResult = SO_NOT_DETECTED; + if( mpDispFactory ) + { + // create ConfigurationProvider instance + CComPtr pdispConfProv; + CComVariant aServiceName( L"com.sun.star.configuration.ConfigurationProvider" ); + HRESULT hr = GetIDispByFunc( mpDispFactory, + L"createInstance", + &aServiceName, + 1, + pdispConfProv ); + + if( SUCCEEDED( hr ) && pdispConfProv ) + { + CComPtr pdispConfAccess; + + SAFEARRAY* pInitParams = SafeArrayCreateVector( VT_VARIANT, 0, 1 ); + + if( pInitParams ) + { + LONG ix = 0; + CComVariant aConfPath( L"org.openoffice.Setup" ); + SafeArrayPutElement( pInitParams, &ix, &aConfPath ); + + CComVariant aArgs[2]; + aArgs[1] = CComVariant( L"com.sun.star.configuration.ConfigurationAccess" ); + aArgs[0].vt = VT_ARRAY | VT_VARIANT; aArgs[0].parray = pInitParams; + + hr = GetIDispByFunc( pdispConfProv, + L"createInstanceWithArguments", + aArgs, + 2, + pdispConfAccess ); + + if( SUCCEEDED( hr ) && pdispConfAccess ) + { + CComVariant aOfficeName; + + CComVariant aProductName( L"Product/ooName" ); + hr = ExecuteFunc( pdispConfAccess, + L"getByHierarchicalName", + &aProductName, + 1, + &aOfficeName ); + + if( SUCCEEDED( hr ) && aOfficeName.vt == VT_BSTR ) + { + CComVariant aOfficeVersion; + + CComVariant aProductVersion( L"Product/ooSetupVersion" ); + hr = ExecuteFunc( pdispConfAccess, + L"getByHierarchicalName", + &aProductVersion, + 1, + &aOfficeVersion ); + + if( SUCCEEDED( hr ) && aOfficeVersion.vt == VT_BSTR ) + { + if (!wcscmp(aOfficeName.bstrVal, L"StarOffice")) + { + if (!wcsncmp(aOfficeVersion.bstrVal, L"6.1", 3)) + bResult = SO_61; + else if (!wcsncmp(aOfficeVersion.bstrVal, L"6.0", 3)) + bResult = SO_60; + else if (!wcsncmp(aOfficeVersion.bstrVal, L"5.2", 3)) + bResult = SO_52; + else + bResult = SO_UNKNOWN; + } + else // OpenOffice + { + if (!wcsncmp(aOfficeVersion.bstrVal, L"1.1", 3)) + bResult = OO_11; + else if (!wcsncmp(aOfficeVersion.bstrVal, L"1.0", 3)) + bResult = OO_10; + else + bResult = OO_UNKNOWN; + } + } + } + } + } + } + } + + return bResult; +} + +namespace { + +class LockingGuard +{ + bool& mbLocked; +public: + explicit LockingGuard( bool& bLocked ) + : mbLocked( bLocked ) + { + mbLocked = true; + } + + ~LockingGuard() + { + mbLocked = false; + } +}; + +} + +HRESULT CSOActiveX::OnDrawAdvanced( ATL_DRAWINFO& di ) +{ + // This method is called only in main thread, no need to lock it + + // Get read of reentrance problems + if ( mbDrawLocked ) + return S_OK; + LockingGuard aGuard( mbDrawLocked ); + + if( m_spInPlaceSite && mCurFileUrl && mbReadyForActivation ) + { + HWND hwnd; + HRESULT hr = m_spInPlaceSite->GetWindow( &hwnd ); + if( !SUCCEEDED( hr ) ) return hr; + + if( mParentWin != hwnd || !mOffWin ) + { + if( mpDispFrame ) + { + CComVariant dummyResult; + CComVariant aPropVar; + aPropVar.vt = VT_BOOL; aPropVar.boolVal = VARIANT_FALSE; + (void) ExecuteFunc( mpDispFrame, L"close", &aPropVar, 1, &dummyResult ); + mpDispFrame = CComPtr(); + } + + mParentWin = hwnd; + mOffWin = CreateWindowW( + STAROFFICE_WINDOWCLASS, + L"OfficeContainer", + WS_CHILD | WS_CLIPCHILDREN | WS_BORDER, + di.prcBounds->left, + di.prcBounds->top, + di.prcBounds->right - di.prcBounds->left, + di.prcBounds->bottom - di.prcBounds->top, + mParentWin, + nullptr, + nullptr, + nullptr ); + + ::ShowWindow( mOffWin, SW_SHOW ); + } + else + { + RECT aRect; + ::GetWindowRect( mOffWin, &aRect ); + + if( aRect.left != di.prcBounds->left || aRect.top != di.prcBounds->top + || aRect.right != di.prcBounds->right || aRect.bottom != di.prcBounds->bottom ) + { + // on this state the office window should exist already + ::SetWindowPos( mOffWin, + HWND_TOP, + di.prcBounds->left, + di.prcBounds->top, + di.prcBounds->right - di.prcBounds->left, + di.prcBounds->bottom - di.prcBounds->top, + SWP_NOZORDER ); + + CComVariant aPosArgs[5]; + aPosArgs[4] = CComVariant( 0 ); + aPosArgs[3] = CComVariant( 0 ); + aPosArgs[2] = CComVariant( int(di.prcBounds->right - di.prcBounds->left) ); + aPosArgs[1] = CComVariant( int(di.prcBounds->bottom - di.prcBounds->top) ); + aPosArgs[0] = CComVariant( 12 ); + CComVariant dummyResult; + hr = ExecuteFunc( mpDispWin, L"setPosSize", aPosArgs, 5, &dummyResult ); + if( !SUCCEEDED( hr ) ) return hr; + } + } + + if (mnVersion == SO_NOT_DETECTED) + { + OutputError_Impl( mOffWin, CS_E_INVALID_VERSION ); + return E_FAIL; + } + + if( ! mpDispFrame ) + { + hr = CreateFrameOldWay( mOffWin, + di.prcBounds->right - di.prcBounds->left, + di.prcBounds->bottom - di.prcBounds->top ); + + if( !SUCCEEDED( hr ) ) + { + // if the frame can not be opened do not try any more + mbReadyForActivation = FALSE; + OutputError_Impl( mOffWin, STG_E_ABNORMALAPIEXIT ); + return hr; + } + } + + if( mbLoad ) + { + hr = LoadURLToFrame(); + mbLoad = FALSE; + + if( !SUCCEEDED( hr ) ) + { + // if the document can not be opened do not try any more + mbReadyForActivation = FALSE; + + OutputError_Impl( mOffWin, STG_E_ABNORMALAPIEXIT ); + + return hr; + } + } + } + else + { + // activate the fallback + CComControl::OnDrawAdvanced( di ); + } + + return S_OK; +} + +HRESULT CSOActiveX::OnDraw( ATL_DRAWINFO& di ) +{ + // fallback that is activated by the parent class + if ( di.hdcDraw ) + FillRect( di.hdcDraw, reinterpret_cast(di.prcBounds), reinterpret_cast(COLOR_BACKGROUND) ); + + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CSOActiveX::SetClientSite( IOleClientSite* aClientSite ) +{ + HRESULT hr = IOleObjectImpl::SetClientSite( aClientSite ); + + if( !aClientSite ) + { + //ATLASSERT( mWebBrowser2 ); + if( mWebBrowser2 ) + AtlUnadvise( mWebBrowser2, DIID_DWebBrowserEvents2, mCookie ); + return hr; + } + + CComPtr aContainer; + m_spClientSite->GetContainer( &aContainer ); +// ATLASSERT( aContainer ); + + if( SUCCEEDED( hr ) && aContainer ) + { + CComQIPtr aServiceProvider( aContainer ); + //ATLASSERT( aServiceProvider ); + + if( aServiceProvider ) + { + aServiceProvider->QueryService( SID_SInternetExplorer, + IID_IWebBrowser, + reinterpret_cast(&mWebBrowser2) ); +// ATLASSERT( mWebBrowser2 ); + if( mWebBrowser2 ) + AtlAdvise( mWebBrowser2, GetUnknown(), DIID_DWebBrowserEvents2, &mCookie ); + } + } + + return hr; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CSOActiveX::Invoke(DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pvarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) +{ + if (riid != IID_NULL) + return DISP_E_UNKNOWNINTERFACE; + + if (!pDispParams) + return DISP_E_PARAMNOTOPTIONAL; + + if ( dispidMember == DISPID_ONQUIT ) + Cleanup(); + + IDispatchImpl::Invoke( + dispidMember, riid, lcid, wFlags, pDispParams, + pvarResult, pExcepInfo, puArgErr); + + return S_OK; +} + +HRESULT CSOActiveX::GetURL( const OLECHAR* url, + const OLECHAR* target ) +{ + CComVariant aEmpty1, aEmpty2, aEmpty3; + CComVariant aUrl( url ); + CComVariant aTarget; + if ( target ) + aTarget = CComVariant( target ); + + return mWebBrowser2->Navigate2( &aUrl, + &aEmpty1, + &aTarget, + &aEmpty2, + &aEmpty3 ); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOActiveX.h b/extensions/source/activex/SOActiveX.h new file mode 100644 index 000000000..37d983ae9 --- /dev/null +++ b/extensions/source/activex/SOActiveX.h @@ -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 . + */ + +// SOActiveX.h : Declaration of the CSOActiveX + +#pragma once + +#include "resource.h" + +#include +#include +#include + +#include + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif +#include +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +class SODispatchInterceptor; + +enum SOVersion { + SO_NOT_DETECTED = 0, + SO_52, + SO_60, + SO_61, + SO_UNKNOWN, + OO_10, + OO_11, + OO_UNKNOWN +}; + + +// CSOActiveX +class ATL_NO_VTABLE CSOActiveX : + public CComObjectRootEx, + public IDispatchImpl, + public CComControl, + public IPersistStreamInitImpl, + public IOleControlImpl, + public IOleObjectImpl, + public IOleInPlaceActiveObjectImpl, + public IViewObjectExImpl, + public IOleInPlaceObjectWindowlessImpl, +// public IConnectionPointContainerImpl, + public CComCoClass, +// public CProxy_ItryPluginEvents< CSOActiveX >, + public IPersistPropertyBagImpl< CSOActiveX >, + public IProvideClassInfo2Impl< &CLSID_SOActiveX, + &DIID__ISOActiveXEvents, + &LIBID_SO_ACTIVEXLib >, + public IObjectSafetyImpl< CSOActiveX, + INTERFACESAFE_FOR_UNTRUSTED_DATA > +{ +protected: + CComPtr mWebBrowser2; + DWORD mCookie; + + CComPtr mpDispFactory; + CComPtr mpDispFrame; + CComPtr mpInstanceLocker; + CComPtr mpDispWin; + CComBSTR mCurFileUrl; + BOOL mbLoad; + BOOL mbViewOnly; + WNDCLASSW mPWinClass; + HWND mParentWin; + HWND mOffWin; + + SODispatchInterceptor* mpDispatchInterceptor; + SOVersion mnVersion; + + BOOL mbReadyForActivation; + CComPtr mpDispTempFile; + + bool mbDrawLocked; + +public: + CSOActiveX(); + ~CSOActiveX() override; + +DECLARE_REGISTRY_RESOURCEID(IDR_SOACTIVEX) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CSOActiveX) + COM_INTERFACE_ENTRY(ISOActiveX) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IViewObjectEx) + COM_INTERFACE_ENTRY(IViewObject2) + COM_INTERFACE_ENTRY(IViewObject) + COM_INTERFACE_ENTRY(IOleInPlaceObjectWindowless) + COM_INTERFACE_ENTRY(IOleInPlaceObject) + COM_INTERFACE_ENTRY2(IOleWindow, IOleInPlaceObjectWindowless) + COM_INTERFACE_ENTRY(IOleInPlaceActiveObject) + COM_INTERFACE_ENTRY(IOleControl) + COM_INTERFACE_ENTRY(IOleObject) + COM_INTERFACE_ENTRY(IPersistStreamInit) + COM_INTERFACE_ENTRY2(IPersist, IPersistStreamInit) +// COM_INTERFACE_ENTRY(IConnectionPointContainer) + COM_INTERFACE_ENTRY(IProvideClassInfo) + COM_INTERFACE_ENTRY(IProvideClassInfo2) + COM_INTERFACE_ENTRY(IPersistPropertyBag) + COM_INTERFACE_ENTRY(IObjectSafety) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winvalid-offsetof" + // offset of on non-standard-layout type '_PropMapClass' (aka 'CSOActiveX'), + // expanded from macro 'PROP_DATA_ENTRY' +#endif +BEGIN_PROP_MAP(CSOActiveX) + PROP_DATA_ENTRY("_cx", m_sizeExtent.cx, VT_UI4) + PROP_DATA_ENTRY("_cy", m_sizeExtent.cy, VT_UI4) + // Example entries + // PROP_ENTRY("Property Description", dispid, clsid) + // PROP_PAGE(CLSID_StockColorPage) +END_PROP_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +BEGIN_CONNECTION_POINT_MAP(CSOActiveX) +END_CONNECTION_POINT_MAP() + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +BEGIN_MSG_MAP(CSOActiveX) +#if defined __clang__ +#pragma clang diagnostic pop +#endif + CHAIN_MSG_MAP(CComControl) + DEFAULT_REFLECTION_HANDLER() +END_MSG_MAP() +// Handler prototypes: +// LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); +// LRESULT CommandHandler(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled); +// LRESULT NotifyHandler(int idCtrl, LPNMHDR pnmh, BOOL& bHandled); + + + +// IViewObjectEx + static DECLARE_VIEW_STATUS(VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE) + +// ISOActiveX +public: + + STDMETHOD(SetClientSite)( IOleClientSite* aClientSite ) override; + STDMETHOD(Invoke)( DISPID dispidMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS* pDispParams, + VARIANT* pvarResult, + EXCEPINFO* pExcepInfo, + UINT* puArgErr) override; + STDMETHOD(Load) ( LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog ) override; + STDMETHOD(Load) ( LPSTREAM pStm ) override; + STDMETHOD(InitNew) () override; + HRESULT OnDrawAdvanced(ATL_DRAWINFO& di) override; + HRESULT OnDraw(ATL_DRAWINFO& di) override; + + HRESULT SetLayoutManagerProps(); + HRESULT CreateFrameOldWay( HWND hwnd, int width, int height ); + HRESULT GetUnoStruct( OLECHAR const * sStructName, CComPtr& pdispResult ); + HRESULT LoadURLToFrame(); + HRESULT CallDispatchMethod( OLECHAR const * sUrl, CComVariant* sArgNames, CComVariant* sArgVal, unsigned int count ); + HRESULT CallLoadComponentFromURL1PBool( OLECHAR const * sUrl, OLECHAR const * sArgName, BOOL sArgVal ); + HRESULT GetUrlStruct( OLECHAR const * sUrl, CComPtr& pdispUrl ); + HRESULT Cleanup(); + HRESULT TerminateOffice(); + HRESULT GetURL( const OLECHAR* url, + const OLECHAR* target ); + + void CallbackCreateXInputStream( CBindStatusCallback* pbsc, BYTE* pBytes, DWORD dwSize ); + + + SOVersion GetVersionConnected(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOActiveX.rgs b/extensions/source/activex/SOActiveX.rgs new file mode 100644 index 000000000..d3814df3b --- /dev/null +++ b/extensions/source/activex/SOActiveX.rgs @@ -0,0 +1,33 @@ +HKCR +{ + so_activex.SOActiveX.1 = s 'SOActiveX Class' + { + CLSID = s '{67F2A879-82D5-4A6D-8CC5-FFB3C114B69D}' + } + so_activex.SOActiveX = s 'SOActiveX Class' + { + CLSID = s '{67F2A879-82D5-4A6D-8CC5-FFB3C114B69D}' + CurVer = s 'so_activex.SOActiveX.1' + } + NoRemove CLSID + { + ForceRemove {67F2A879-82D5-4A6D-8CC5-FFB3C114B69D} = s 'SOActiveX Class' + { + ProgID = s 'so_activex.SOActiveX.1' + VersionIndependentProgID = s 'so_activex.SOActiveX' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + ForceRemove 'Control' + ForceRemove 'ToolboxBitmap32' = s '%MODULE%, 101' + 'MiscStatus' = s '0' + { + '1' = s '131473' + } + 'TypeLib' = s '{61FA3F13-8061-4796-B055-3697ED28CB38}' + 'Version' = s '1.0' + } + } +} diff --git a/extensions/source/activex/SOComWindowPeer.cxx b/extensions/source/activex/SOComWindowPeer.cxx new file mode 100644 index 000000000..0a556466d --- /dev/null +++ b/extensions/source/activex/SOComWindowPeer.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 . + */ + +// SOComWindowPeer.cpp : Implementation of CHelpApp and DLL registration. + +#include + +#include + +#include "StdAfx2.h" +#include "SOComWindowPeer.h" +#include + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif +#include +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +COM_DECLSPEC_NOTHROW STDMETHODIMP SOComWindowPeer::InterfaceSupportsErrorInfo(REFIID riid) +{ + static const IID* arr[] = { + &IID_ISOComWindowPeer, + }; + + for (std::size_t i = 0; i < SAL_N_ELEMENTS(arr); i++) + { +#ifdef _MSC_VER + if (InlineIsEqualGUID(*arr[i], riid)) +#else + if (::ATL::InlineIsEqualGUID(*arr[i], riid)) +#endif + return S_OK; + } + return S_FALSE; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOComWindowPeer.h b/extensions/source/activex/SOComWindowPeer.h new file mode 100644 index 000000000..379ca767a --- /dev/null +++ b/extensions/source/activex/SOComWindowPeer.h @@ -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 . + */ + +// SOComWindowPeer.h: Definition of the SOComWindowPeer class + +#pragma once + +#ifdef _MSC_VER +#pragma once +#endif + +#include "resource.h" +#include +#include +#include + +#include + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif +#include +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +// SOComWindowPeer + +class SOComWindowPeer : + public IDispatchImpl, + public ISupportErrorInfo, + public CComObjectRoot, + public CComCoClass +{ + HWND m_hwnd; +public: + SOComWindowPeer() : m_hwnd( nullptr ) {} + virtual ~SOComWindowPeer() { } + +BEGIN_COM_MAP(SOComWindowPeer) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(ISOComWindowPeer) + COM_INTERFACE_ENTRY(ISupportErrorInfo) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif +DECLARE_NOT_AGGREGATABLE(SOComWindowPeer) +// Remove the comment from the line above if you don't want your object to +// support aggregation. + +DECLARE_REGISTRY_RESOURCEID(IDR_SOCOMWINDOWPEER) + +// ISupportsErrorInfo + STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) override; + +// ISOComWindowPeer + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getWindowHandle( + /* [in] */ SAFEARRAY __RPC_FAR * /*procId*/, + /* [in] */ short /*s*/, + /* [retval][out] */ long __RPC_FAR *ret) override + { + *ret = HandleToLong( m_hwnd ); + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getToolkit( + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *retVal) override + { + *retVal = nullptr; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setPointer( + /* [in] */ IDispatch __RPC_FAR* /*xPointer*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setBackground( + /* [in] */ int /*nColor*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE invalidate( + /* [in] */ short /*__MIDL_0015*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE invalidateRect( + /* [in] */ IDispatch __RPC_FAR* /*aRect*/, + /* [in] */ short /*nFlags*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE dispose( void) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE addEventListener( + /* [in] */ IDispatch __RPC_FAR* /*xListener*/) override + { + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE removeEventListener( + /* [in] */ IDispatch __RPC_FAR* /*xListener*/) override + { + return S_OK; + } + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_Bridge_implementedInterfaces( + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *pVal) override + { + *pVal = SafeArrayCreateVector( VT_BSTR, 0, 2 ); + + if( !*pVal ) + return E_FAIL; + + LONG ix = 0; + CComBSTR aInterface( OLESTR( "com.sun.star.awt.XSystemDependentWindowPeer" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + ix = 1; + aInterface = CComBSTR( OLESTR( "com.sun.star.awt.XWindowPeer" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + return S_OK; + } + + void SetHWNDInternally( HWND hwnd ) { m_hwnd = hwnd; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SOComWindowPeer.rgs b/extensions/source/activex/SOComWindowPeer.rgs new file mode 100644 index 000000000..42e985a31 --- /dev/null +++ b/extensions/source/activex/SOComWindowPeer.rgs @@ -0,0 +1,23 @@ +HKCR +{ + so_activex.SOComWindowPeer.1 = s 'SOComWindowPeer Class' + { + CLSID = s '{EE51BD3E-8BB6-4FB8-B319-F65B1BE3B21D}' + } + so_activex.SOComWindowPeer = s 'SOComWindowPeer Class' + { + CLSID = s '{EE51BD3E-8BB6-4FB8-B319-F65B1BE3B21D}' + } + NoRemove CLSID + { + ForceRemove {EE51BD3E-8BB6-4FB8-B319-F65B1BE3B21D} = s 'SOComWindowPeer Class' + { + ProgID = s 'so_activex.SOComWindowPeer.1' + VersionIndependentProgID = s 'so_activex.SOComWindowPeer' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'both' + } + } + } +} diff --git a/extensions/source/activex/SODispatchInterceptor.cxx b/extensions/source/activex/SODispatchInterceptor.cxx new file mode 100644 index 000000000..f40f62635 --- /dev/null +++ b/extensions/source/activex/SODispatchInterceptor.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 . + */ + +// SODispatchInterceptor.cpp : Implementation of CHelpApp and DLL registration. + +#include + +#include + +#include +#include "StdAfx2.h" +#include "SOActiveX.h" +#include "SODispatchInterceptor.h" +#include "com_uno_helper.h" +#include + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif +#include +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +COM_DECLSPEC_NOTHROW STDMETHODIMP SODispatchInterceptor::InterfaceSupportsErrorInfo(REFIID riid) +{ + static const IID* arr[] = + { + &IID_ISODispatchInterceptor, + }; + + for (std::size_t i=0;iGetIDsOfNames( IID_NULL, const_cast(&sURLMemberName), 1, LOCALE_USER_DEFAULT, &nURLID ); + if( !SUCCEEDED( hr ) ) return hr; + + hr = CComDispatchDriver::GetProperty( aURL, nURLID, &aTargetUrl ); + if( !SUCCEEDED( hr ) ) return hr; + + if( aTargetUrl.vt != VT_BSTR ) return E_FAIL; + + if (!wcsncmp(aTargetUrl.bstrVal, L".uno:OpenHyperlink", 18)) + { + CComQIPtr< IDispatch, &IID_IDispatch > pIDisp( this ); + if( pIDisp ) + { + this->AddRef(); + *retVal = pIDisp; + } + } + else + { + if( !m_xSlave ) + { + *retVal = nullptr; + return S_OK; + } + + CComVariant aResult; + CComVariant aArgs[3]; + aArgs[0] = CComVariant( nSearchFlags ); + aArgs[1] = CComVariant( aTargetFrameName ); + aArgs[2] = CComVariant( aURL ); + + hr = ExecuteFunc( m_xSlave, L"queryDispatch", aArgs, 3, &aResult ); + if( !SUCCEEDED( hr ) || aResult.vt != VT_DISPATCH || aResult.pdispVal == nullptr ) + { + *retVal = nullptr; + return S_OK; + } + + *retVal = aResult.pdispVal; + + CComQIPtr< IUnknown, &IID_IUnknown > pIUnk( *retVal ); + if( pIUnk ) + (*retVal)->AddRef(); + } + + return S_OK; +} + +STDMETHODIMP SODispatchInterceptor::queryDispatches(SAFEARRAY* aDescripts, SAFEARRAY** retVal) +{ + if ( !aDescripts || !retVal || SafeArrayGetDim( aDescripts ) != 1 ) + return E_FAIL; + + LONG nLB, nUB; + + HRESULT hr = SafeArrayGetLBound( aDescripts, 1, &nLB ); + if( !SUCCEEDED( hr ) ) return hr; + + hr = SafeArrayGetUBound( aDescripts, 1, &nUB ); + if( !SUCCEEDED( hr ) ) return hr; + if( nUB < nLB ) return E_FAIL; + + *retVal = SafeArrayCreateVector( VT_DISPATCH, 0, nUB - nLB ); + + for ( LONG ind = nLB; ind <= nUB; ind ++ ) + { + CComPtr pElem; + SafeArrayGetElement( aDescripts, &ind, pElem ); + if( pElem ) + { + OLECHAR const * pMemberNames[3] = { L"FeatureURL", L"FrameName", L"SearchFlags" }; + CComVariant pValues[3]; + hr = GetPropertiesFromIDisp( pElem, pMemberNames, pValues, 3 ); + if( !SUCCEEDED( hr ) ) return hr; + if( pValues[0].vt != VT_DISPATCH || pValues[0].pdispVal == nullptr + || pValues[1].vt != VT_BSTR || pValues[2].vt != VT_I4 ) + return E_FAIL; + + CComPtr aRes; + hr = queryDispatch( pValues[0].pdispVal, pValues[1].bstrVal, pValues[2].lVal, &aRes ); + SafeArrayPutElement( *retVal, &ind, aRes ); + } + } + + return S_OK; +} + + +STDMETHODIMP SODispatchInterceptor::dispatch(IDispatch* aURL, SAFEARRAY* aArgs) +{ + // get url from aURL + OLECHAR const * pUrlName = L"Complete"; + CComVariant pValue; + HRESULT hr = GetPropertiesFromIDisp( aURL, &pUrlName, &pValue, 1 ); + if( !SUCCEEDED( hr ) ) return hr; + if( pValue.vt != VT_BSTR || pValue.bstrVal == nullptr ) + return E_FAIL; + + if (!wcsncmp(pValue.bstrVal, L".uno:OpenHyperlink", 18)) + { + LONG nLB = 0, nUB = 0; + // long nDim = SafeArrayGetDim( aArgs ); + + hr = SafeArrayGetLBound( aArgs, 1, &nLB ); + if( !SUCCEEDED( hr ) ) return hr; + + hr = SafeArrayGetUBound( aArgs, 1, &nUB ); + if( !SUCCEEDED( hr ) ) return hr; + if( nUB < nLB ) return E_FAIL; + + for ( LONG ind = nLB; ind <= nUB; ind ++ ) + { + CComVariant pVarElem; + SafeArrayGetElement( aArgs, &ind, &pVarElem ); + if( pVarElem.vt == VT_DISPATCH && pVarElem.pdispVal != nullptr ) + { + OLECHAR const * pMemberNames[2] = { L"Name", L"Value" }; + CComVariant pValues[2]; + hr = GetPropertiesFromIDisp( pVarElem.pdispVal, pMemberNames, pValues, 2 ); + if( !SUCCEEDED( hr ) ) return hr; + + if( pValues[0].vt == VT_BSTR && pValues[1].vt == VT_BSTR ) + { + if (!wcsncmp(pValues[0].bstrVal, L"URL", 3)) + { + EnterCriticalSection( &mMutex ); + if( m_xParentControl ) + { + // call GetUrl to the browser instance + m_xParentControl->GetURL( pValues[1].bstrVal, L"_self" ); + } + LeaveCriticalSection( &mMutex ); + + break; + } + } + } + } + } + + return S_OK; +} + +STDMETHODIMP SODispatchInterceptor::addStatusListener(IDispatch* /*xControl*/, IDispatch* /*aURL*/) +{ + // not implemented + return S_OK; +} + +STDMETHODIMP SODispatchInterceptor::removeStatusListener(IDispatch* /*xControl*/, + IDispatch* /*aURL*/) +{ + // not implemented + return S_OK; +} + +STDMETHODIMP SODispatchInterceptor::getInterceptedURLs(SAFEARRAY** pVal) +{ + *pVal = SafeArrayCreateVector( VT_BSTR, 0, 3 ); + + if( !*pVal ) + return E_FAIL; + + LONG ix = 0; + CComBSTR aPattern( OLESTR( "ftp://*" ) ); + SafeArrayPutElement( *pVal, &ix, aPattern ); + + ix = 1; + aPattern = CComBSTR( OLESTR( "http://*" ) ); + SafeArrayPutElement( *pVal, &ix, aPattern ); + + ix = 2; + aPattern = CComBSTR( OLESTR( "file://*" ) ); + SafeArrayPutElement( *pVal, &ix, aPattern ); + + return S_OK; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SODispatchInterceptor.h b/extensions/source/activex/SODispatchInterceptor.h new file mode 100644 index 000000000..3c0604348 --- /dev/null +++ b/extensions/source/activex/SODispatchInterceptor.h @@ -0,0 +1,175 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// SODispatchInterceptor.h: Definition of the SODispatchInterceptor class + +#pragma once + +#ifdef _MSC_VER +#pragma once +#endif + +#include "resource.h" +#include +#include +#include + +#include + +#include + +class CSOActiveX; + + +// SODispatchInterceptor + +class SODispatchInterceptor : + public IDispatchImpl, + public ISupportErrorInfo, + public CComObjectRoot, + public CComCoClass +{ + CComPtr m_xMaster; + CComPtr m_xSlave; + CSOActiveX* m_xParentControl; + CRITICAL_SECTION mMutex; +public: + SODispatchInterceptor() : m_xParentControl( nullptr ) { InitializeCriticalSection(&mMutex); } + virtual ~SODispatchInterceptor() { ATLASSERT( !m_xParentControl ); DeleteCriticalSection(&mMutex); } + +BEGIN_COM_MAP(SODispatchInterceptor) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(ISODispatchInterceptor) + COM_INTERFACE_ENTRY(ISupportErrorInfo) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif +END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif +DECLARE_NOT_AGGREGATABLE(SODispatchInterceptor) +// Remove the comment from the line above if you don't want your object to +// support aggregation. + +DECLARE_REGISTRY_RESOURCEID(IDR_SODISPATCHINTERCEPTOR) + + void SetParent( CSOActiveX* pParent ) + { + ATLASSERT( !m_xParentControl ); + EnterCriticalSection( &mMutex ); + m_xParentControl = pParent; + LeaveCriticalSection( &mMutex ); + } + + void ClearParent() + { + EnterCriticalSection( &mMutex ); + m_xParentControl = nullptr; + LeaveCriticalSection( &mMutex ); + } + +// ISupportsErrorInfo + STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid) override; + +// ISODispatchInterceptor + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getSlaveDispatchProvider( + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *retVal) override + { + *retVal = m_xSlave; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setSlaveDispatchProvider( + /* [in] */ IDispatch __RPC_FAR *xNewDispatchProvider) override + { + m_xSlave = xNewDispatchProvider; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getMasterDispatchProvider( + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *retVal) override + { + *retVal = m_xMaster; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE setMasterDispatchProvider( + /* [in] */ IDispatch __RPC_FAR *xNewSupplier) override + { + m_xMaster = xNewSupplier; + return S_OK; + } + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE queryDispatch( + /* [in] */ IDispatch __RPC_FAR *aURL, + /* [in] */ BSTR aTargetFrameName, + /* [in] */ long nSearchFlags, + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *retVal) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE queryDispatches( + /* [in] */ SAFEARRAY __RPC_FAR * aDescripts, + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *retVal) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE dispatch( + /* [in] */ IDispatch __RPC_FAR *aURL, + /* [in] */ SAFEARRAY __RPC_FAR * aArgs) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE addStatusListener( + /* [in] */ IDispatch __RPC_FAR *xControl, + /* [in] */ IDispatch __RPC_FAR *aURL) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE removeStatusListener( + /* [in] */ IDispatch __RPC_FAR *xControl, + /* [in] */ IDispatch __RPC_FAR *aURL) override; + + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE getInterceptedURLs( + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *pVal) override; + + virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_Bridge_implementedInterfaces( + /* [retval][out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *pVal) override + { + *pVal = SafeArrayCreateVector( VT_BSTR, 0, 4 ); + + if( !*pVal ) + return E_FAIL; + + LONG ix = 0; + CComBSTR aInterface( OLESTR( "com.sun.star.frame.XDispatchProviderInterceptor" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + ix = 1; + aInterface = CComBSTR( OLESTR( "com.sun.star.frame.XDispatchProvider" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + ix = 2; + aInterface = CComBSTR( OLESTR( "com.sun.star.frame.XDispatch" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + ix = 3; + aInterface = CComBSTR( OLESTR( "com.sun.star.frame.XInterceptorInfo" ) ); + SafeArrayPutElement( *pVal, &ix, aInterface ); + + return S_OK; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/SODispatchInterceptor.rgs b/extensions/source/activex/SODispatchInterceptor.rgs new file mode 100644 index 000000000..19fe0b5f0 --- /dev/null +++ b/extensions/source/activex/SODispatchInterceptor.rgs @@ -0,0 +1,23 @@ +HKCR +{ + so_activex.SODispatchInterceptor.1 = s 'SODispatchInterceptor Class' + { + CLSID = s '{C5D6D568-57DA-4D6C-819A-451CB565E682}' + } + so_activex.SODispatchInterceptor = s 'SODispatchInterceptor Class' + { + CLSID = s '{C5D6D568-57DA-4D6C-819A-451CB565E682}' + } + NoRemove CLSID + { + ForceRemove {C5D6D568-57DA-4D6C-819A-451CB565E682} = s 'SODispatchInterceptor Class' + { + ProgID = s 'so_activex.SODispatchInterceptor.1' + VersionIndependentProgID = s 'so_activex.SODispatchInterceptor' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'both' + } + } + } +} diff --git a/extensions/source/activex/StdAfx2.cxx b/extensions/source/activex/StdAfx2.cxx new file mode 100644 index 000000000..c2df5c5c0 --- /dev/null +++ b/extensions/source/activex/StdAfx2.cxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// stdafx1.cpp : source file that includes just the standard includes +// stdafx1.pch will be the pre-compiled header +// stdafx1.obj will contain the pre-compiled type information + +#include "StdAfx2.h" + +#ifdef _ATL_STATIC_REGISTRY +#include +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/StdAfx2.h b/extensions/source/activex/StdAfx2.h new file mode 100644 index 000000000..56bd75b8a --- /dev/null +++ b/extensions/source/activex/StdAfx2.h @@ -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 . + */ + +// stdafx1.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#pragma once + +#define STRICT +#define _ATL_APARTMENT_THREADED +#define _ATL_STATIC_REGISTRY + +#pragma warning(push) +// local variable is initialized but not referenced - in atlctl.h +#pragma warning(disable : 4189) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wall" +#pragma clang diagnostic ignored "-Wattributes" +#pragma clang diagnostic ignored "-Wdelete-incomplete" +#pragma clang diagnostic ignored "-Wdynamic-class-memaccess" +#pragma clang diagnostic ignored "-Wint-to-pointer-cast" +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#pragma clang diagnostic ignored "-Wmicrosoft" +#pragma clang diagnostic ignored "-Wmissing-field-initializers" +#pragma clang diagnostic ignored "-Wnon-pod-varargs" +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#pragma clang diagnostic ignored "-Wnonportable-include-path" +#pragma clang diagnostic ignored "-Wsequence-point" +#pragma clang diagnostic ignored "-Wsign-compare" +#pragma clang diagnostic ignored "-Wtypename-missing" +#endif + +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#include + +//You may derive a class from CComModule and use it if you want to override +//something, but do not change the name of _Module +extern CComModule _Module; +#include +#include + +#if defined __clang__ +#pragma clang diagnostic pop +#endif +#pragma warning(pop) + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/com_uno_helper.h b/extensions/source/activex/com_uno_helper.h new file mode 100644 index 000000000..89aa0a7d1 --- /dev/null +++ b/extensions/source/activex/com_uno_helper.h @@ -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 "StdAfx2.h" + +HRESULT ExecuteFunc( IDispatch* idispUnoObject, + OLECHAR const * sFuncName, + CComVariant* params, + unsigned int count, + CComVariant* pResult ); + +HRESULT GetIDispByFunc( IDispatch* idispUnoObject, + OLECHAR* sFuncName, + CComVariant* params, + unsigned int count, + CComPtr& pdispResult ); + +HRESULT PutPropertiesToIDisp( IDispatch* pdispObject, + OLECHAR** sMemberNames, + CComVariant* pVariant, + unsigned int count ); + +HRESULT GetPropertiesFromIDisp( IDispatch* pdispObject, + OLECHAR const ** sMemberNames, + CComVariant* pVariant, + unsigned int count ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/example.html b/extensions/source/activex/example.html new file mode 100644 index 000000000..96e764c8f --- /dev/null +++ b/extensions/source/activex/example.html @@ -0,0 +1,43 @@ + + + +Document Title + + + +
+First you should edit the example.html file!!! +
+
+ + + + + + + +
+ + + diff --git a/extensions/source/activex/resource.h b/extensions/source/activex/resource.h new file mode 100644 index 000000000..b7a77a5c9 --- /dev/null +++ b/extensions/source/activex/resource.h @@ -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 . + */ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by so_activex.rc + +#define IDS_PROJNAME 100 +#define IDB_SOACTIVEX 101 +#define IDR_SOACTIVEX 102 +#define IDB_SOCOMWINDOWPEER 103 +#define IDR_SOCOMWINDOWPEER 104 +#define IDB_SODISPATCHINTERCEPTOR 105 +#define IDR_SODISPATCHINTERCEPTOR 106 +#define IDB_SODOCUMENTEVENTLISTENER 107 +#define IDR_SODOCUMENTEVENTLISTENER 108 + + +// Next default values for new objects + +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 107 +#endif +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/so_activex.cxx b/extensions/source/activex/so_activex.cxx new file mode 100644 index 000000000..70682a416 --- /dev/null +++ b/extensions/source/activex/so_activex.cxx @@ -0,0 +1,774 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// so_activex.cpp : Implementation of DLL Exports. + +// Note: Proxy/Stub Information +// To build a separate proxy/stub DLL, +// run nmake -f so_activexps.mk in the project directory. + +#include +#include "StdAfx2.h" +#include "resource.h" +#include + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif +#include +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-tokens" + // "#endif !_MIDL_USE_GUIDDEF_" in midl-generated code +#endif +#include +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#include "SOActiveX.h" + +#include +#include +#include + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_SOActiveX, CSOActiveX) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-field-initializers" +#endif +END_OBJECT_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#define X64_LIB_NAME L"so_activex_x64.dll" +#define X32_LIB_NAME L"so_activex.dll" + +const REGSAM n64KeyAccess = KEY_ALL_ACCESS | KEY_WOW64_64KEY; +const REGSAM n32KeyAccess = KEY_ALL_ACCESS; + +#ifdef _AMD64_ +const bool bX64 = true; +#define REG_DELETE_KEY_A( key, aPath, nKeyAccess ) RegDeleteKeyExA( key, aPath, nKeyAccess, 0 ) +#else +const bool bX64 = false; +#define REG_DELETE_KEY_A( key, aPath, nKeyAccess ) RegDeleteKeyA( key, aPath ) +#endif + +// DLL Entry Point + +extern "C" +BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_SO_ACTIVEXLib); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + return TRUE; // ok +} + + +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow() +{ + return (_Module.GetLockCount()==0) ? S_OK : S_FALSE; +} + + +// Returns a class factory to create an object of the requested type + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + + +// DllRegisterServer - Adds entries to the system registry + +namespace +{ +// Wraps an updatable Win32 error; keeps first incoming error. +// Ctor defines if upd will throw std::exception on error or +// return false. +class Status +{ +public: + explicit Status(bool bTrow) + : m_bThrow(bTrow) + { + } + // used to check success of an operation, and update the status if it's still ERROR_SUCCESS + bool upd(LSTATUS nNewStatus) + { + if (m_nStatus == ERROR_SUCCESS) + m_nStatus = nNewStatus; + if (m_bThrow && nNewStatus != ERROR_SUCCESS) + throw std::exception(); + return nNewStatus == ERROR_SUCCESS; + }; + LSTATUS get() { return m_nStatus; } + operator bool() { return m_nStatus == ERROR_SUCCESS; } + +private: + LSTATUS m_nStatus = ERROR_SUCCESS; + const bool m_bThrow; +}; + +class HRegKey +{ +public: + ~HRegKey() + { + if (m_hkey) + RegCloseKey(m_hkey); + } + PHKEY operator&() { return &m_hkey; } + operator HKEY() { return m_hkey; } + +private: + HKEY m_hkey = nullptr; +}; +} + +// for now database component and chart are always installed +#define SUPPORTED_EXT_NUM 30 +const char* const aFileExt[] = { ".vor", + ".sds", ".sda", ".sdd", ".sdp", ".sdc", ".sdw", ".smf", + ".stw", ".stc", ".sti", ".std", + ".sxw", ".sxc", ".sxi", ".sxd", ".sxg", ".sxm", + ".ott", ".otg", ".otp", ".ots", ".otf", + ".odt", ".oth", ".odm", ".odg", ".odp", ".ods", ".odf"}; +const sal_Unicode* const aMimeType[] = { + u"application/vnd.stardivision.writer", + + u"application/vnd.stardivision.chart", + u"application/vnd.stardivision.draw", + u"application/vnd.stardivision.impress", + u"application/vnd.stardivision.impress-packed", + u"application/vnd.stardivision.calc", + u"application/vnd.stardivision.writer", + u"application/vnd.stardivision.math", + + MIMETYPE_VND_SUN_XML_WRITER_TEMPLATE_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_CALC_TEMPLATE_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_IMPRESS_TEMPLATE_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_DRAW_TEMPLATE_ASCII.getStr(), + + MIMETYPE_VND_SUN_XML_WRITER_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_CALC_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_IMPRESS_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_DRAW_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_WRITER_GLOBAL_ASCII.getStr(), + MIMETYPE_VND_SUN_XML_MATH_ASCII.getStr(), + + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_TEMPLATE_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_TEMPLATE_ASCII.getStr(), + + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_WEB_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_TEXT_GLOBAL_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_DRAWING_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_PRESENTATION_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_SPREADSHEET_ASCII.getStr(), + MIMETYPE_OASIS_OPENDOCUMENT_FORMULA_ASCII.getStr() }; + +const int nForModes[] = { 16, + 1, 2, 4, 4, 8, 16, 32, + 16, 8, 4, 2, + 16, 8, 4, 2, 16, 32, + 16, 2, 4, 8, 32, + 16, 16, 16, 2, 4, 8, 32 }; + +const char* const aClassID = "{67F2A879-82D5-4A6D-8CC5-FFB3C114B69D}"; +const char* const aTypeLib = "{61FA3F13-8061-4796-B055-3697ED28CB38}"; + +// ISOComWindowPeer interface information +const char* const aInterIDWinPeer = "{BF5D10F3-8A10-4A0B-B150-2B6AA2D7E118}"; +const char* const aProxyStubWinPeer = "{00020424-0000-0000-C000-000000000046}"; + +// ISODispatchInterceptor interface information +const char* const aInterIDDispInt = "{9337694C-B27D-4384-95A4-9D8E0EABC9E5}"; +const char* const aProxyStubDispInt = "{00020424-0000-0000-C000-000000000046}"; + +// ISOActionsApproval interface information +const char* const aInterIDActApprove = "{029E9F1E-2B3F-4297-9160-8197DE7ED54F}"; +const char* const aProxyStubActApprove = "{00020424-0000-0000-C000-000000000046}"; + +// The following prefix is required for HKEY_LOCAL_MACHINE and HKEY_CURRENT_USER ( not for HKEY_CLASSES_ROOT ) +const char* const aLocalPrefix = "Software\\Classes\\"; + +static LSTATUS createKey( HKEY hkey, + const char* aKeyToCreate, + REGSAM nKeyAccess, + const char* aValue = nullptr, + const char* aChildName = nullptr, + const char* aChildValue = nullptr ) +{ + Status s(false); // no throw + HRegKey hkey1; + if (s.upd(RegCreateKeyExA(hkey, aKeyToCreate, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey1, nullptr))) + { + if (aValue) + s.upd(RegSetValueExA(hkey1, "", 0, REG_SZ, reinterpret_cast(aValue), + sal::static_int_cast(strlen(aValue)))); + if (aChildName) + s.upd(RegSetValueExA(hkey1, aChildName, 0, REG_SZ, + reinterpret_cast(aChildValue), + sal::static_int_cast(strlen(aChildValue)))); + } + return s.get(); +} + +static LSTATUS createKey(HKEY hkey, + const wchar_t* aKeyToCreate, + REGSAM nKeyAccess, + const wchar_t* aValue = nullptr, + const wchar_t* aChildName = nullptr, + const wchar_t* aChildValue = nullptr ) +{ + Status s(false); // no throw + HRegKey hkey1; + if (s.upd(RegCreateKeyExW(hkey, aKeyToCreate, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey1, nullptr))) + { + if (aValue) + s.upd(RegSetValueExW(hkey1, L"", 0, REG_SZ, reinterpret_cast(aValue), + sal::static_int_cast(wcslen(aValue) * sizeof(wchar_t)))); + if (aChildName) + s.upd(RegSetValueExW( + hkey1, aChildName, 0, REG_SZ, reinterpret_cast(aChildValue), + sal::static_int_cast(wcslen(aChildValue) * sizeof(wchar_t)))); + } + return s.get(); +} + +EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllUnregisterServerNative( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ); +static HRESULT DllRegisterServerNative_Impl( int nMode, bool bForAllUsers, REGSAM nKeyAccess, const wchar_t* pProgramPath, const wchar_t* pLibName ) +{ + char aSubKey[513]; + int ind; + const char* aPrefix = aLocalPrefix; // bForAllUsers ? "" : aLocalPrefix; + + // In case SO7 is installed for this user he can have local registry entries that will prevent him from + // using SO8 ActiveX control. The fix is just to clean up the local entries related to ActiveX control. + // Unfortunately it can be done only for the user who installs the office. + if ( bForAllUsers ) + DllUnregisterServerNative( nMode, false, false ); + + Status s(true); // throw + try + { + if (pProgramPath && wcslen(pProgramPath) < 1024) + { + wchar_t pActiveXPath[1124]; + wchar_t pActiveXPath101[1124]; + + swprintf(pActiveXPath, L"%s\\%s", pProgramPath, pLibName); + swprintf(pActiveXPath101, L"%s\\%s, 101", pProgramPath, pLibName); + + { + wsprintfA(aSubKey, "%sCLSID\\%s", aPrefix, aClassID); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(RegSetValueExA(hkey, "", 0, REG_SZ, + reinterpret_cast("SOActiveX Class"), 17)); + s.upd(createKey(hkey, "Control", nKeyAccess)); + s.upd(createKey(hkey, "EnableFullPage", nKeyAccess)); + s.upd(createKey(hkey, L"InprocServer32", nKeyAccess, pActiveXPath, + L"ThreadingModel", L"Apartment")); + s.upd(createKey(hkey, "MiscStatus", nKeyAccess, "0")); + s.upd(createKey(hkey, "MiscStatus\\1", nKeyAccess, "131473")); + s.upd(createKey(hkey, "ProgID", nKeyAccess, "so_activex.SOActiveX.1")); + s.upd(createKey(hkey, "Programmable", nKeyAccess)); + s.upd(createKey(hkey, L"ToolboxBitmap32", nKeyAccess, pActiveXPath101)); + s.upd(createKey(hkey, "TypeLib", nKeyAccess, aTypeLib)); + s.upd(createKey(hkey, "Version", nKeyAccess, "1.0")); + s.upd(createKey(hkey, "VersionIndependentProgID", nKeyAccess, + "so_activex.SOActiveX")); + } + { + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aPrefix, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(createKey(hkey, "so_activex.SOActiveX", nKeyAccess, "SOActiveX Class")); + { + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, "so_activex.SOActiveX", 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey1, + nullptr)); + s.upd(createKey(hkey1, "CLSID", nKeyAccess, aClassID)); + s.upd(createKey(hkey1, "CurVer", nKeyAccess, "so_activex.SOActiveX.1")); + } + s.upd(createKey(hkey, "so_activex.SOActiveX.1", nKeyAccess, "SOActiveX Class")); + { + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, "so_activex.SOActiveX.1", 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey1, + nullptr)); + s.upd(createKey(hkey1, "CLSID", nKeyAccess, aClassID)); + } + { + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, "TypeLib", 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey1, nullptr)); + { + HRegKey hkey2; + s.upd(RegCreateKeyExA(hkey1, aTypeLib, 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey2, nullptr)); + s.upd(createKey(hkey2, "1.0", nKeyAccess, "wrap_activex 1.0 Type Library")); + { + HRegKey hkey3; + s.upd(RegCreateKeyExA(hkey2, "1.0", 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey3, nullptr)); + { + HRegKey hkey4; + s.upd(RegCreateKeyExA(hkey3, "0", 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, + &hkey4, nullptr)); + s.upd(createKey(hkey4, L"win32", nKeyAccess, pActiveXPath)); + } + s.upd(createKey(hkey3, "FLAGS", nKeyAccess, "0")); + s.upd(createKey(hkey3, L"HELPDIR", nKeyAccess, pProgramPath)); + } + } + } + { + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, "Interface", 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey1, nullptr)); + s.upd(createKey(hkey1, aInterIDWinPeer, nKeyAccess, "ISOComWindowPeer")); + { + HRegKey hkey2; + s.upd(RegCreateKeyExA(hkey1, aInterIDWinPeer, 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey2, + nullptr)); + s.upd(createKey(hkey2, "ProxyStubClsid", nKeyAccess, aProxyStubWinPeer)); + s.upd(createKey(hkey2, "ProxyStubClsid32", nKeyAccess, aProxyStubWinPeer)); + s.upd(createKey(hkey2, "TypeLib", nKeyAccess, aTypeLib, "Version", "1.0")); + } + s.upd(createKey(hkey1, aInterIDActApprove, nKeyAccess, "ISOActionsApproval")); + { + HRegKey hkey2; + s.upd(RegCreateKeyExA(hkey1, aInterIDActApprove, 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey2, + nullptr)); + s.upd(createKey(hkey2, "ProxyStubClsid", nKeyAccess, aProxyStubActApprove)); + s.upd( + createKey(hkey2, "ProxyStubClsid32", nKeyAccess, aProxyStubActApprove)); + s.upd(createKey(hkey2, "TypeLib", nKeyAccess, aTypeLib, "Version", "1.0")); + } + s.upd(createKey(hkey1, aInterIDDispInt, nKeyAccess, "ISODispatchInterceptor")); + { + HRegKey hkey2; + s.upd(RegCreateKeyExA(hkey1, aInterIDDispInt, 0, nullptr, + REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey2, + nullptr)); + s.upd(createKey(hkey2, "ProxyStubClsid", nKeyAccess, aProxyStubDispInt)); + s.upd(createKey(hkey2, "ProxyStubClsid32", nKeyAccess, aProxyStubDispInt)); + s.upd(createKey(hkey2, "TypeLib", nKeyAccess, aTypeLib, "Version", "1.0")); + } + } + } + } + + for (ind = 0; ind < SUPPORTED_EXT_NUM; ind++) + { + if (nForModes[ind] & nMode) + { + wsprintfA(aSubKey, "%sMIME\\DataBase\\Content Type\\%ls", aPrefix, aMimeType[ind]); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(RegSetValueExA(hkey, "CLSID", 0, REG_SZ, + reinterpret_cast(aClassID), + sal::static_int_cast(strlen(aClassID)))); + } + } + + { + wsprintfA(aSubKey, "%sCLSID\\%s", aPrefix, aClassID); + HRegKey hkey; + s.upd(RegOpenKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, 0, + nKeyAccess, &hkey)); + for (ind = 0; ind < SUPPORTED_EXT_NUM; ind++) + { + wsprintfA(aSubKey, "EnableFullPage\\%s", aFileExt[ind]); + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey1, nullptr)); + } + } + } + catch (const std::exception&) {} + + return HRESULT_FROM_WIN32(s.get()); +} + +EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllRegisterServerNative( int nMode, BOOL bForAllUsers, BOOL bFor64Bit, const wchar_t* pProgramPath ) +{ + HRESULT hr = S_OK; + if ( bFor64Bit ) + hr = DllRegisterServerNative_Impl( nMode, bForAllUsers, n64KeyAccess, pProgramPath, X64_LIB_NAME ); + + if ( SUCCEEDED( hr ) ) + hr = DllRegisterServerNative_Impl( nMode, bForAllUsers, n32KeyAccess, pProgramPath, X32_LIB_NAME ); + + return hr; +} + + +// DllUnregisterServer - Removes entries from the system registry +static HRESULT DeleteKeyTree( HKEY hkey, const char* pPath, REGSAM nKeyAccess ) +{ + char pSubKeyName[256]; + // first delete the subkeys + while (true) + { + HRegKey hkey1; + if (ERROR_SUCCESS != RegOpenKeyExA(hkey, pPath, 0, nKeyAccess, &hkey1) + || ERROR_SUCCESS != RegEnumKeyA(hkey1, 0, pSubKeyName, 256) + || ERROR_SUCCESS != DeleteKeyTree(hkey1, pSubKeyName, nKeyAccess)) + break; + } + + // delete the key itself + return REG_DELETE_KEY_A( hkey, pPath, nKeyAccess & ( KEY_WOW64_64KEY | KEY_WOW64_32KEY ) ); +} + +static HRESULT DllUnregisterServerNative_Impl( int nMode, bool bForAllUsers, REGSAM nKeyAccess ) +{ + char aSubKey[513]; + const char* aPrefix = aLocalPrefix; // bForAllUsers ? "" : aLocalPrefix; + + Status s(false); // no throw + for( int ind = 0; ind < SUPPORTED_EXT_NUM; ind++ ) + { + if( nForModes[ind] & nMode ) + { + DWORD nSubKeys = 0, nValues = 0; + wsprintfA(aSubKey, "%sMIME\\DataBase\\Content Type\\%ls", aPrefix, aMimeType[ind]); + Status s1(false); // no throw + { + HRegKey hkey; + if (s1.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr))) + { + s1.upd(RegDeleteValueA(hkey, "CLSID")); + s1.upd(RegQueryInfoKeyA(hkey, nullptr, nullptr, nullptr, &nSubKeys, nullptr, + nullptr, &nValues, nullptr, nullptr, nullptr, nullptr)); + } + } + if (s1 && !nSubKeys && !nValues) + DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess); + s.upd(s1.get()); + + wsprintfA(aSubKey, "%s%s", aPrefix, aFileExt[ind]); + Status s2(false); // no throw + { + HRegKey hkey; + if (s2.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr))) + { + s2.upd(RegQueryInfoKeyA(hkey, nullptr, nullptr, nullptr, &nSubKeys, nullptr, + nullptr, &nValues, nullptr, nullptr, nullptr, nullptr)); + } + } + if (s2 && !nSubKeys && !nValues) + DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess); + s.upd(s2.get()); + } + } + + wsprintfA(aSubKey, "%sCLSID\\%s", aPrefix, aClassID); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%sso_activex.SOActiveX", aPrefix); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%sso_activex.SOActiveX.1", aPrefix); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%s\\TypeLib\\%s", aPrefix, aTypeLib); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%s\\Interface\\%s", aPrefix, aInterIDWinPeer); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%s\\Interface\\%s", aPrefix, aInterIDDispInt); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + wsprintfA(aSubKey, "%s\\Interface\\%s", aPrefix, aInterIDActApprove); + s.upd(DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess)); + + return HRESULT_FROM_WIN32(s.get()); +} + +STDAPI DllUnregisterServerNative( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ) +{ + HRESULT hr = DllUnregisterServerNative_Impl( nMode, bForAllUsers, n32KeyAccess ); + if ( SUCCEEDED( hr ) && bFor64Bit ) + hr = DllUnregisterServerNative_Impl( nMode, bForAllUsers, n64KeyAccess ); + + return hr; +} + + +// DllRegisterServerDoc - Adds entries to the system registry + +#define SUPPORTED_MSEXT_NUM 7 +const char* const aMSFileExt[] = { ".dot", ".doc", ".xlt", ".xls", ".pot", ".ppt", ".pps" }; +const char* const aMSMimeType[] = { "application/msword", + "application/msword", + "application/vnd.ms-excel", + "application/vnd.ms-excel", + "application/vnd.ms-powerpoint", + "application/vnd.ms-powerpoint", + "application/vnd.ms-powerpoint" }; +const int nForMSModes[] = { 1, 1, 2, 2, 4, 4, 4 }; + +EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllUnregisterServerDoc( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ); +static HRESULT DllRegisterServerDoc_Impl( int nMode, bool bForAllUsers, REGSAM nKeyAccess ) +{ + char aSubKey[513]; + int ind; + const char* aPrefix = aLocalPrefix; // bForAllUsers ? "" : aLocalPrefix; + + // In case SO7 is installed for this user he can have local registry entries that will prevent him from + // using SO8 ActiveX control. The fix is just to clean up the local entries related to ActiveX control. + // Unfortunately it can be done only for the user who installs the office. + if ( bForAllUsers ) + DllUnregisterServerDoc( nMode, false, false ); + + Status s(true); // throw + try + { + for (ind = 0; ind < SUPPORTED_MSEXT_NUM; ind++) + { + if (nForMSModes[ind] & nMode) + { + { + wsprintfA(aSubKey, "%sMIME\\DataBase\\Content Type\\%s", aPrefix, + aMSMimeType[ind]); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(RegSetValueExA(hkey, "Extension", 0, REG_SZ, + reinterpret_cast(aMSFileExt[ind]), + sal::static_int_cast(strlen(aMSFileExt[ind])))); + s.upd(RegSetValueExA(hkey, "CLSID", 0, REG_SZ, + reinterpret_cast(aClassID), + sal::static_int_cast(strlen(aClassID)))); + } + { + wsprintfA(aSubKey, "%s%s", aPrefix, aMSFileExt[ind]); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr)); + s.upd(RegSetValueExA(hkey, "Content Type", 0, REG_SZ, + reinterpret_cast(aMSMimeType[ind]), + sal::static_int_cast(strlen(aMSMimeType[ind])))); + } + } + } + + wsprintfA(aSubKey, "%sCLSID\\%s", aPrefix, aClassID); + HRegKey hkey; + s.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, 0, + nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, nullptr, &hkey, + nullptr)); + s.upd(createKey(hkey, "EnableFullPage", nKeyAccess)); + for (ind = 0; ind < SUPPORTED_MSEXT_NUM; ind++) + { + if (nForMSModes[ind] & nMode) + { + wsprintfA(aSubKey, "EnableFullPage\\%s", aMSFileExt[ind]); + HRegKey hkey1; + s.upd(RegCreateKeyExA(hkey, aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, + nKeyAccess, nullptr, &hkey1, nullptr)); + } + } + } + catch (const std::exception&) {} + + return HRESULT_FROM_WIN32(s.get()); +} + +EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE DllRegisterServerDoc( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ) +{ + HRESULT hr = S_OK; + if ( bFor64Bit ) + hr = DllRegisterServerDoc_Impl( nMode, bForAllUsers, n64KeyAccess ); + + if ( SUCCEEDED( hr ) ) + hr = DllRegisterServerDoc_Impl( nMode, bForAllUsers, n32KeyAccess ); + + return hr; +} + + +// DllUnregisterServerDoc - Removes entries from the system registry + +static HRESULT DllUnregisterServerDoc_Impl( int nMode, bool bForAllUsers, REGSAM nKeyAccess ) +{ + char aSubKey[513]; + const char* aPrefix = aLocalPrefix; // bForAllUsers ? "" : aLocalPrefix; + + Status s(false); // no throw + for (int ind = 0; ind < SUPPORTED_MSEXT_NUM; ind++) + { + if (nForMSModes[ind] & nMode) + { + DWORD nSubKeys = 0, nValues = 0; + Status s1(false); // no throw + { + wsprintfA(aSubKey, "%sMIME\\DataBase\\Content Type\\%s", aPrefix, aMSMimeType[ind]); + HRegKey hkey; + if (s1.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr))) + { + s.upd(RegDeleteValueA(hkey, "Extension")); + s.upd(RegDeleteValueA(hkey, "CLSID")); + s1.upd(RegQueryInfoKeyA(hkey, nullptr, nullptr, nullptr, &nSubKeys, nullptr, + nullptr, &nValues, nullptr, nullptr, nullptr, nullptr)); + } + } + if (s1 && !nSubKeys && !nValues) + DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess); + s.upd(s1.get()); + + Status s2(false); // no throw + { + wsprintfA(aSubKey, "%s%s", aPrefix, aMSFileExt[ind]); + HRegKey hkey; + if (s2.upd(RegCreateKeyExA(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, + aSubKey, 0, nullptr, REG_OPTION_NON_VOLATILE, nKeyAccess, + nullptr, &hkey, nullptr))) + { + s.upd(RegDeleteValueA(hkey, "Content Type")); + s2.upd(RegQueryInfoKeyA(hkey, nullptr, nullptr, nullptr, &nSubKeys, nullptr, + nullptr, &nValues, nullptr, nullptr, nullptr, nullptr)); + } + } + if (s2 && !nSubKeys && !nValues) + DeleteKeyTree(bForAllUsers ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER, aSubKey, + nKeyAccess); + s.upd(s2.get()); + } + } + + return HRESULT_FROM_WIN32(s.get()); +} + +STDAPI DllUnregisterServerDoc( int nMode, BOOL bForAllUsers, BOOL bFor64Bit ) +{ + HRESULT hr = S_OK; + if ( bFor64Bit ) + hr = DllUnregisterServerDoc_Impl( nMode, bForAllUsers, n64KeyAccess ); + + if ( SUCCEEDED( hr ) ) + hr = DllUnregisterServerDoc_Impl( nMode, bForAllUsers, n32KeyAccess ); + + return hr; +} + + +// DllRegisterServer - regsvr32 entry point + +STDAPI DllRegisterServer() +{ + HRESULT aResult = E_FAIL; + + HMODULE aCurModule{}; + GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(&DllRegisterServer), &aCurModule); + if( aCurModule ) + { + wchar_t pProgramPath[1024]; + wchar_t* pPathEnd = nullptr; + DWORD nLen = GetModuleFileNameW( aCurModule, pProgramPath, SAL_N_ELEMENTS(pProgramPath) ); + if ( nLen && nLen < SAL_N_ELEMENTS(pProgramPath) ) + pPathEnd = wcsrchr(pProgramPath, '\\'); + if (pPathEnd) + { + *pPathEnd = 0; + aResult = DllRegisterServerNative( 31, TRUE, bX64, pProgramPath ); + if( SUCCEEDED( aResult ) ) + aResult = DllRegisterServerDoc( 31, TRUE, bX64 ); + else + { + aResult = DllRegisterServerNative( 31, FALSE, bX64, pProgramPath ); + if( SUCCEEDED( aResult ) ) + aResult = DllRegisterServerDoc( 31, FALSE, bX64 ); + } + } + } + + return aResult; +} + + +// DllUnregisterServer - regsvr32 entry point + +STDAPI DllUnregisterServer() +{ + DllUnregisterServerDoc( 63, FALSE, bX64 ); + DllUnregisterServerNative( 63, FALSE, bX64 ); + DllUnregisterServerDoc( 63, TRUE, bX64 ); + return DllUnregisterServerNative( 63, TRUE, bX64 ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/so_activex.def b/extensions/source/activex/so_activex.def new file mode 100644 index 000000000..9f81e7917 --- /dev/null +++ b/extensions/source/activex/so_activex.def @@ -0,0 +1,13 @@ +; iervp.def : Declares the module parameters. + +LIBRARY + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + DllRegisterServerNative PRIVATE + DllRegisterServerDoc PRIVATE + DllUnregisterServerNative PRIVATE + DllUnregisterServerDoc PRIVATE diff --git a/extensions/source/activex/so_activex.idl b/extensions/source/activex/so_activex.idl new file mode 100644 index 000000000..a84dde219 --- /dev/null +++ b/extensions/source/activex/so_activex.idl @@ -0,0 +1,230 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// so_activex.idl : IDL source for so_activex.dll + + +// This file will be processed by the MIDL tool to +// produce the type library (so_activex.tlb) and marshalling code. + +import "oaidl.idl"; +import "ocidl.idl"; +#include + + + [ + object, + uuid(DACF7E3F-626B-4BF9-964B-F4910C843711), + dual, + helpstring("ISOActiveX Interface"), + pointer_default(unique) + ] + interface ISOActiveX : IDispatch + { + }; + +[ + object, + uuid(BF5D10F3-8A10-4A0B-B150-2B6AA2D7E118), + dual, + helpstring("ISOComWindowPeer Interface"), + pointer_default(unique) +] +interface ISOComWindowPeer : IDispatch +{ + [id(1), helpstring("method getWindowHandle")] + HRESULT getWindowHandle( [in] SAFEARRAY(VARIANT) procId, + [in] short s, + [out,retval] long* ret); + + [id(2), helpstring("method getToolkit")] + HRESULT getToolkit( [out,retval] IDispatch** retVal ); + + [id(3), helpstring("method setPointer")] + HRESULT setPointer( [in] IDispatch* xPointer ); + + [id(4), helpstring("method setBackground")] + HRESULT setBackground( [in] int nColor ); + + [id(5), helpstring("method invalidate")] + HRESULT invalidate( [in] short ); + + [id(6), helpstring("method invalidateRect")] + HRESULT invalidateRect( [in] IDispatch* aRect, [in] short nFlags ); + + [id(7), helpstring("method dispose")] + HRESULT dispose(); + + [id(8), helpstring("method addEventListener")] + HRESULT addEventListener( [in] IDispatch* xListener ); + + [id(9), helpstring("method removeEventListener")] + HRESULT removeEventListener( [in] IDispatch* xListener ); + + [propget, id(10), helpstring("property_implementedInterfaces")] + HRESULT Bridge_implementedInterfaces([out, retval] SAFEARRAY(BSTR) *pVal); +}; + +[ + object, + uuid(9337694C-B27D-4384-95A4-9D8E0EABC9E5), + dual, + helpstring("ISODispatchInterceptor Interface"), + pointer_default(unique) +] +interface ISODispatchInterceptor : IDispatch +{ +//com.sun.star.frame.XDispatchProviderInterceptor + + [id(1), helpstring("method getSlaveDispatchProvider")] + HRESULT getSlaveDispatchProvider( [out,retval] IDispatch** retVal ); + + [id(2), helpstring("method setSlaveDispatchProvider")] + HRESULT setSlaveDispatchProvider( [in] IDispatch* xNewDispatchProvider ); + + [id(3), helpstring("method getMasterDispatchProvider")] + HRESULT getMasterDispatchProvider( [out,retval] IDispatch** retVal ); + + [id(4), helpstring("method setMasterDispatchProvider")] + HRESULT setMasterDispatchProvider( [in] IDispatch* xNewSupplier ); + +// com.sun.star.frame.XDispatchProvider + + [id(5), helpstring("method queryDispatch")] + HRESULT queryDispatch( [in] IDispatch* aURL, + [in] BSTR aTargetFrameName, + [in] long nSearchFlags, + [out,retval] IDispatch** retVal ); + + [id(6), helpstring("method queryDispatches")] + HRESULT queryDispatches( [in] SAFEARRAY(IDispatch*) aDescripts, + [out,retval] SAFEARRAY(VARIANT)* retVal ); + + +// com.sun.star.frame.XDispatch + + [id(7), helpstring("method dispatch")] + HRESULT dispatch( [in] IDispatch* aURL, + [in] SAFEARRAY(VARIANT) aArgs ); + + [id(8), helpstring("method addStatusListener")] + HRESULT addStatusListener( [in] IDispatch* xControl, + [in] IDispatch* aURL ); + + [id(9), helpstring("method removeStatusListener")] + HRESULT removeStatusListener( [in] IDispatch* xControl, + [in] IDispatch* aURL ); + +// com.sun.star.frame.XInterceptorInfo + + + [id(10), helpstring("method getInterceptedURLs")] + HRESULT getInterceptedURLs( [out,retval] SAFEARRAY(BSTR)* pVal ); + +// the common UNO-COM staff + [propget, id(11), helpstring("property_implementedInterfaces")] + HRESULT Bridge_implementedInterfaces([out, retval] SAFEARRAY(BSTR) *pVal); + +}; + + + + +[ + object, + uuid(029E9F1E-2B3F-4297-9160-8197DE7ED54F), + dual, + helpstring("ISOActionsApproval Interface"), + pointer_default(unique) +] +interface ISOActionsApproval : IDispatch +{ +//com.sun.star.embed.XActionsApproval + + [id(1), helpstring("method approveAction")] + HRESULT approveAction( [in] long aActionID, + [out,retval] boolean* pbApproval ); + +// the common UNO-COM staff + [propget, id(2), helpstring("property_implementedInterfaces")] + HRESULT Bridge_implementedInterfaces([out, retval] SAFEARRAY(BSTR) *pVal); +}; + + + +[ + uuid(61FA3F13-8061-4796-B055-3697ED28CB38), + version(1.0), + helpstring("so_activex 1.0 Type Library") +] +library SO_ACTIVEXLib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + + [ + uuid(7F760565-5719-4F04-BA86-112C474B10EA), + helpstring("_ISOActiveXEvents Interface") + ] + dispinterface _ISOActiveXEvents + { + properties: + methods: + }; + + [ + uuid(67F2A879-82D5-4A6D-8CC5-FFB3C114B69D), + helpstring("SOActiveX Class") + ] + coclass SOActiveX + { + [default] interface ISOActiveX; + [default, source] dispinterface _ISOActiveXEvents; + }; + + [ + uuid(EE51BD3E-8BB6-4FB8-B319-F65B1BE3B21D), + helpstring("SOComWindowPeer Class") + ] + coclass SOComWindowPeer + { + [default] interface ISOComWindowPeer; + }; + + [ + uuid(C5D6D568-57DA-4D6C-819A-451CB565E682), + helpstring("SODispatchInterceptor Class") + ] + coclass SODispatchInterceptor + { + [default] interface ISODispatchInterceptor; + }; + + [ + uuid(9F3697AC-7A18-4335-AF0A-65FAC2C35CC1), + helpstring("SOActionsApproval Class") + ] + coclass SOActionsApproval + { + [default] interface ISOActionsApproval; + }; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/activex/so_activex.rc b/extensions/source/activex/so_activex.rc new file mode 100644 index 000000000..3891fa965 --- /dev/null +++ b/extensions/source/activex/so_activex.rc @@ -0,0 +1,124 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +//Microsoft Developer Studio generated resource script. + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS + + +// Generated from the TEXTINCLUDE 2 resource. + +#include +#define LB_ADDSTRING (WM_USER+1) +#define CB_ADDSTRING (WM_USER+3) +#define IDC_STATIC (-1) + + +#undef APSTUDIO_READONLY_SYMBOLS + + +// Russian resources + +//#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS) +//#ifdef _WIN32 +//LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT +//#pragma code_page(1251) +//#endif //_WIN32 + + + +// Bitmap + + +//IDB_SOACTIVEX BITMAP DISCARDABLE "soacti.bmp" + + + + +// REGISTRY + + +IDR_SOACTIVEX REGISTRY DISCARDABLE "SOActiveX.rgs" +IDR_SOCOMWINDOWPEER REGISTRY DISCARDABLE "SOComWindowPeer.rgs" +IDR_SODISPATCHINTERCEPTOR REGISTRY DISCARDABLE "SODispatchInterceptor.rgs" +//#endif // Russian resources + + + + +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED + + +// TEXTINCLUDE + + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""so_activex.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + + +// String Table + + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "so_activex" +END + +#endif // English (U.S.) resources + + + + +#ifndef APSTUDIO_INVOKED + + +// Generated from the TEXTINCLUDE 3 resource. + + +1 TYPELIB SO_ACTIVEX_TLB + + +#endif // not APSTUDIO_INVOKED + diff --git a/extensions/source/bibliography/bib.component b/extensions/source/bibliography/bib.component new file mode 100644 index 000000000..19841cc9e --- /dev/null +++ b/extensions/source/bibliography/bib.component @@ -0,0 +1,27 @@ + + + + + + + + + diff --git a/extensions/source/bibliography/bibbeam.cxx b/extensions/source/bibliography/bibbeam.cxx new file mode 100644 index 000000000..a38c72385 --- /dev/null +++ b/extensions/source/bibliography/bibbeam.cxx @@ -0,0 +1,267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 "bibbeam.hxx" +#include "datman.hxx" +#include "bibtools.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::uno; + + +#define ID_TOOLBAR 1 +#define ID_GRIDWIN 2 + +namespace bib +{ + + void HandleTaskPaneList( vcl::Window* pWindow, bool bAddToList ) + { + vcl::Window* pParent = pWindow->GetParent(); + + DBG_ASSERT( pParent, "-GetTaskPaneList(): everybody here should have a parent!" ); + + SystemWindow* pSysWin = pParent->GetSystemWindow(); + if( pSysWin ) + { + TaskPaneList* pTaskPaneList = pSysWin->GetTaskPaneList(); + if( pTaskPaneList ) + { + if( bAddToList ) + pTaskPaneList->AddWindow( pWindow ); + else + pTaskPaneList->RemoveWindow( pWindow ); + } + } + } + + + class BibGridwin + :public vcl::Window //DockingWindow + { + private: + Reference< awt::XWindow > m_xGridWin; + Reference< awt::XControlModel > m_xGridModel; + Reference< awt::XControl > m_xControl; + Reference< awt::XControlContainer > m_xControlContainer; + Reference< frame::XDispatchProviderInterception> m_xDispatchProviderInterception; + + protected: + + virtual void Resize() override; + + public: + + BibGridwin(vcl::Window* pParent, WinBits nStyle ); + virtual ~BibGridwin() override; + virtual void dispose() override; + + void createGridWin(const Reference< awt::XControlModel > & xDbForm); + void disposeGridWin(); + + const Reference< awt::XControlContainer >& getControlContainer() const { return m_xControlContainer; } + const Reference< frame::XDispatchProviderInterception>& getDispatchProviderInterception() const { return m_xDispatchProviderInterception; } + + virtual void GetFocus() override; + }; + + BibGridwin::BibGridwin( vcl::Window* _pParent, WinBits _nStyle ) : Window( _pParent, _nStyle ) + { + m_xControlContainer = VCLUnoHelper::CreateControlContainer(this); + + AddToTaskPaneList( this ); + } + + BibGridwin::~BibGridwin() + { + disposeOnce(); + } + + void BibGridwin::dispose() + { + RemoveFromTaskPaneList( this ); + + disposeGridWin(); + vcl::Window::dispose(); + } + + void BibGridwin::Resize() + { + if(m_xGridWin.is()) + { + ::Size aSize = GetOutputSizePixel(); + m_xGridWin->setPosSize(0, 0, aSize.Width(),aSize.Height(), awt::PosSize::SIZE); + } + } + + void BibGridwin::createGridWin(const uno::Reference< awt::XControlModel > & xGModel) + { + m_xGridModel = xGModel; + + if( !m_xControlContainer.is()) + return; + + uno::Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + + if ( !m_xGridModel.is()) + return; + + uno::Reference< XPropertySet > xPropSet( m_xGridModel, UNO_QUERY ); + + if ( xPropSet.is() && m_xGridModel.is() ) + { + uno::Any aAny = xPropSet->getPropertyValue( "DefaultControl" ); + OUString aControlName; + aAny >>= aControlName; + + m_xControl.set( xContext->getServiceManager()->createInstanceWithContext(aControlName, xContext), UNO_QUERY_THROW ); + m_xControl->setModel( m_xGridModel ); + } + + if ( !m_xControl.is() ) + return; + + // Peer as Child to the FrameWindow + m_xControlContainer->addControl("GridControl", m_xControl); + m_xGridWin.set(m_xControl, UNO_QUERY ); + m_xDispatchProviderInterception.set(m_xControl, UNO_QUERY ); + m_xGridWin->setVisible( true ); + m_xControl->setDesignMode( true ); + // initially switch on the design mode - switch it off _after_ loading the form + + ::Size aSize = GetOutputSizePixel(); + m_xGridWin->setPosSize(0, 0, aSize.Width(),aSize.Height(), awt::PosSize::POSSIZE); + } + + void BibGridwin::disposeGridWin() + { + if ( m_xControl.is() ) + { + Reference< awt::XControl > xDel( m_xControl ); + m_xControl = nullptr; + m_xGridWin = nullptr; + + m_xControlContainer->removeControl( xDel ); + xDel->dispose(); + } + } + + void BibGridwin::GetFocus() + { + if(m_xGridWin.is()) + m_xGridWin->setFocus(); + } + + BibBeamer::BibBeamer( vcl::Window* _pParent, BibDataManager* _pDM ) + :BibSplitWindow( _pParent, WB_3DLOOK | WB_NOSPLITDRAW ) + ,pDatMan( _pDM ) + ,pToolBar( nullptr ) + ,pGridWin( nullptr ) + { + createToolBar(); + createGridWin(); + pDatMan->SetToolbar(pToolBar); + pGridWin->Show(); + connectForm( pDatMan ); + } + + BibBeamer::~BibBeamer() + { + disposeOnce(); + } + + void BibBeamer::dispose() + { + if ( isFormConnected() ) + disconnectForm(); + + if ( pToolBar ) + pDatMan->SetToolbar(nullptr); + + pToolBar.disposeAndClear(); + pGridWin.disposeAndClear(); + BibSplitWindow::dispose(); + } + + void BibBeamer::createToolBar() + { + pToolBar= VclPtr::Create(this, LINK( this, BibBeamer, RecalcLayout_Impl )); + ::Size aSize=pToolBar->get_preferred_size(); + InsertItem(ID_TOOLBAR, pToolBar, aSize.Height(), 0, 0, SplitWindowItemFlags::Fixed ); + if ( m_xController.is() ) + pToolBar->SetXController( m_xController ); + } + + void BibBeamer::createGridWin() + { + pGridWin = VclPtr::Create(this,0); + + InsertItem(ID_GRIDWIN, pGridWin, 40, 1, 0, SplitWindowItemFlags::RelativeSize ); + + pGridWin->createGridWin( pDatMan->updateGridModel() ); + } + + Reference< awt::XControlContainer > BibBeamer::getControlContainer() + { + Reference< awt::XControlContainer > xReturn; + if ( pGridWin ) + xReturn = pGridWin->getControlContainer(); + return xReturn; + } + + Reference< frame::XDispatchProviderInterception > BibBeamer::getDispatchProviderInterception() const + { + Reference< frame::XDispatchProviderInterception > xReturn; + if ( pGridWin ) + xReturn = pGridWin->getDispatchProviderInterception(); + return xReturn; + } + + void BibBeamer::SetXController(const uno::Reference< frame::XController > & xCtr) + { + m_xController = xCtr; + + if ( pToolBar ) + pToolBar->SetXController( m_xController ); + + } + + void BibBeamer::GetFocus() + { + if( pGridWin ) + pGridWin->GrabFocus(); + } + + IMPL_LINK_NOARG( BibBeamer, RecalcLayout_Impl, void*, void ) + { + tools::Long nHeight = pToolBar->get_preferred_size().Height(); + SetItemSize( ID_TOOLBAR, nHeight ); + } + +} // namespace bib + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibbeam.hxx b/extensions/source/bibliography/bibbeam.hxx new file mode 100644 index 000000000..4cc32d7da --- /dev/null +++ b/extensions/source/bibliography/bibbeam.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include "toolbar.hxx" +#include "formcontrolcontainer.hxx" +#include "bibshortcuthandler.hxx" + +class BibDataManager; + + +namespace bib +{ + + + class BibGridwin; + class BibBeamer final + :public BibSplitWindow + ,public FormControlContainer + { + css::uno::Reference< css::frame::XController > m_xController; + + BibDataManager* pDatMan; + VclPtr pToolBar; + VclPtr pGridWin; + + DECL_LINK( RecalcLayout_Impl, void*, void ); + + void createToolBar(); + void createGridWin(); + + // FormControlContainer ---------- + virtual css::uno::Reference< css::awt::XControlContainer > + getControlContainer() override; + public: + css::uno::Reference< css::frame::XDispatchProviderInterception > + getDispatchProviderInterception() const; + + BibBeamer(vcl::Window* pParent,BibDataManager* pDatMan ); + virtual ~BibBeamer() override; + virtual void dispose() override; + + void SetXController(const css::uno::Reference< css::frame::XController > &); + + virtual void GetFocus() override; + }; + + +} // namespace bib + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibconfig.cxx b/extensions/source/bibliography/bibconfig.cxx new file mode 100644 index 000000000..14203ae6c --- /dev/null +++ b/extensions/source/bibliography/bibconfig.cxx @@ -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 . + */ + + +#include +#include "bibconfig.hxx" +#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::lang; +using namespace ::com::sun::star::sdb; + + +constexpr OUStringLiteral cDataSourceHistory = u"DataSourceHistory"; + +Sequence const & BibConfig::GetPropertyNames() +{ + static Sequence aNames = + { + "CurrentDataSource/DataSourceName", + "CurrentDataSource/Command", + "CurrentDataSource/CommandType", + "BeamerHeight", + "ViewHeight", + "QueryText", + "QueryField", + "ShowColumnAssignmentWarning" + }; + return aNames; +} + +BibConfig::BibConfig() + : ConfigItem("Office.DataAccess/Bibliography", ConfigItemMode::NONE) + , nTblOrQuery(0) + , nBeamerSize(0) + , nViewSize(0) + , bShowColumnAssignmentWarning(false) +{ + //Names of the default columns + aColumnDefaults[0] = "Identifier"; + aColumnDefaults[1] = "BibliographyType"; + aColumnDefaults[2] = "Author"; + aColumnDefaults[3] = "Title"; + aColumnDefaults[4] = "Year"; + aColumnDefaults[5] = "ISBN"; + aColumnDefaults[6] = "Booktitle"; + aColumnDefaults[7] = "Chapter"; + aColumnDefaults[8] = "Edition"; + aColumnDefaults[9] = "Editor"; + aColumnDefaults[10] = "Howpublished"; + aColumnDefaults[11] = "Institution"; + aColumnDefaults[12] = "Journal"; + aColumnDefaults[13] = "Month"; + aColumnDefaults[14] = "Note"; + aColumnDefaults[15] = "Annote"; + aColumnDefaults[16] = "Number"; + aColumnDefaults[17] = "Organizations"; + aColumnDefaults[18] = "Pages"; + aColumnDefaults[19] = "Publisher"; + aColumnDefaults[20] = "Address"; + aColumnDefaults[21] = "School"; + aColumnDefaults[22] = "Series"; + aColumnDefaults[23] = "ReportType"; + aColumnDefaults[24] = "Volume"; + aColumnDefaults[25] = "URL"; + aColumnDefaults[26] = "Custom1"; + aColumnDefaults[27] = "Custom2"; + aColumnDefaults[28] = "Custom3"; + aColumnDefaults[29] = "Custom4"; + aColumnDefaults[30] = "Custom5"; + aColumnDefaults[31] = "LocalURL"; + + + const Sequence< OUString > aPropertyNames = GetPropertyNames(); + const Sequence aPropertyValues = GetProperties( aPropertyNames ); + const Any* pValues = aPropertyValues.getConstArray(); + if(aPropertyValues.getLength() == aPropertyNames.getLength()) + { + for(int nProp = 0; nProp < aPropertyNames.getLength(); nProp++) + { + if(pValues[nProp].hasValue()) + { + switch(nProp) + { + case 0: pValues[nProp] >>= sDataSource; break; + case 1: pValues[nProp] >>= sTableOrQuery; break; + case 2: pValues[nProp] >>= nTblOrQuery; break; + case 3: pValues[nProp] >>= nBeamerSize; break; + case 4: pValues[nProp] >>= nViewSize ; break; + case 5: pValues[nProp] >>= sQueryText ; break; + case 6: pValues[nProp] >>= sQueryField; break; + case 7: + bShowColumnAssignmentWarning = *o3tl::doAccess(pValues[nProp]); + break; + } + } + } + } + const Sequence< OUString > aNodeNames = GetNodeNames(cDataSourceHistory); + for(OUString const & nodeName : aNodeNames) + { + Sequence aHistoryNames(3); + OUString* pHistoryNames = aHistoryNames.getArray(); + + OUString sPrefix = OUString::Concat(cDataSourceHistory) + "/" + nodeName + "/"; + pHistoryNames[0] = sPrefix + "DataSourceName"; + pHistoryNames[1] = sPrefix + "Command"; + pHistoryNames[2] = sPrefix + "CommandType"; + + Sequence aHistoryValues = GetProperties( aHistoryNames ); + const Any* pHistoryValues = aHistoryValues.getConstArray(); + + if(aHistoryValues.getLength() == aHistoryNames.getLength()) + { + Mapping* pMapping = new Mapping; + pHistoryValues[0] >>= pMapping->sURL; + pHistoryValues[1] >>= pMapping->sTableName; + pHistoryValues[2] >>= pMapping->nCommandType; + //field assignment is contained in another set + sPrefix += "Fields"; + const Sequence< OUString > aAssignmentNodeNames = GetNodeNames(sPrefix); + Sequence aAssignmentPropertyNames(aAssignmentNodeNames.getLength() * 2); + OUString* pAssignmentPropertyNames = aAssignmentPropertyNames.getArray(); + sal_Int16 nFieldIdx = 0; + for(OUString const & assignName : aAssignmentNodeNames) + { + OUString sSubPrefix = sPrefix + "/" + assignName; + pAssignmentPropertyNames[nFieldIdx] = sSubPrefix; + pAssignmentPropertyNames[nFieldIdx++] += "/ProgrammaticFieldName"; + pAssignmentPropertyNames[nFieldIdx] = sSubPrefix; + pAssignmentPropertyNames[nFieldIdx++] += "/AssignedFieldName"; + } + Sequence aAssignmentValues = GetProperties(aAssignmentPropertyNames); + const Any* pAssignmentValues = aAssignmentValues.getConstArray(); + OUString sTempLogical; + OUString sTempReal; + sal_Int16 nSetMapping = 0; + nFieldIdx = 0; + for(sal_Int32 nFieldVal = 0; nFieldVal < aAssignmentValues.getLength() / 2; nFieldVal++) + { + pAssignmentValues[nFieldIdx++] >>= sTempLogical; + pAssignmentValues[nFieldIdx++] >>= sTempReal; + if(!(sTempLogical.isEmpty() || sTempReal.isEmpty())) + { + pMapping->aColumnPairs[nSetMapping].sLogicalColumnName = sTempLogical; + pMapping->aColumnPairs[nSetMapping++].sRealColumnName = sTempReal; + } + } + mvMappings.push_back(std::unique_ptr(pMapping)); + } + } +} + +BibConfig::~BibConfig() +{ + assert(!IsModified()); // should have been committed +} + +BibDBDescriptor BibConfig::GetBibliographyURL() +{ + BibDBDescriptor aRet; + aRet.sDataSource = sDataSource; + aRet.sTableOrQuery = sTableOrQuery; + aRet.nCommandType = nTblOrQuery; + return aRet; +}; + +void BibConfig::SetBibliographyURL(const BibDBDescriptor& rDesc) +{ + sDataSource = rDesc.sDataSource; + sTableOrQuery = rDesc.sTableOrQuery; + nTblOrQuery = rDesc.nCommandType; + SetModified(); +}; + +void BibConfig::Notify( const css::uno::Sequence& ) +{ +} + +void BibConfig::ImplCommit() +{ + PutProperties( + GetPropertyNames(), + {css::uno::Any(sDataSource), css::uno::Any(sTableOrQuery), + css::uno::Any(nTblOrQuery), css::uno::Any(nBeamerSize), + css::uno::Any(nViewSize), css::uno::Any(sQueryText), + css::uno::Any(sQueryField), + css::uno::Any(bShowColumnAssignmentWarning)}); + ClearNodeSet(cDataSourceHistory); + Sequence< PropertyValue > aNodeValues(mvMappings.size() * 3); + PropertyValue* pNodeValues = aNodeValues.getArray(); + + sal_Int32 nIndex = 0; + for(sal_Int32 i = 0; i < static_cast(mvMappings.size()); i++) + { + const Mapping* pMapping = mvMappings[i].get(); + OUString sPrefix = OUString::Concat(cDataSourceHistory) + "/_" + OUString::number(i) + "/"; + pNodeValues[nIndex].Name = sPrefix + "DataSourceName"; + pNodeValues[nIndex++].Value <<= pMapping->sURL; + pNodeValues[nIndex].Name = sPrefix + "Command"; + pNodeValues[nIndex++].Value <<= pMapping->sTableName; + pNodeValues[nIndex].Name = sPrefix + "CommandType"; + pNodeValues[nIndex++].Value <<= pMapping->nCommandType; + SetSetProperties(cDataSourceHistory, aNodeValues); + + sPrefix += "Fields"; + sal_Int32 nFieldAssignment = 0; + OUString sFieldName = "/ProgrammaticFieldName"; + OUString sDatabaseFieldName = "/AssignedFieldName"; + ClearNodeSet( sPrefix ); + + while(nFieldAssignment < COLUMN_COUNT && + !pMapping->aColumnPairs[nFieldAssignment].sLogicalColumnName.isEmpty()) + { + OUString sSubPrefix = sPrefix + "/_" + OUString::number(nFieldAssignment); + Sequence< PropertyValue > aAssignmentValues + { + comphelper::makePropertyValue(sSubPrefix + sFieldName, pMapping->aColumnPairs[nFieldAssignment].sLogicalColumnName), + comphelper::makePropertyValue(sSubPrefix + sDatabaseFieldName, pMapping->aColumnPairs[nFieldAssignment].sRealColumnName) + }; + SetSetProperties( sPrefix, aAssignmentValues ); + nFieldAssignment++; + } + } +} + +const Mapping* BibConfig::GetMapping(const BibDBDescriptor& rDesc) const +{ + for(std::unique_ptr const & i : mvMappings) + { + Mapping& rMapping = *i; + bool bURLEqual = rDesc.sDataSource == rMapping.sURL; + if(rDesc.sTableOrQuery == rMapping.sTableName && bURLEqual) + return &rMapping; + } + return nullptr; +} + +void BibConfig::SetMapping(const BibDBDescriptor& rDesc, const Mapping* pSetMapping) +{ + for(size_t i = 0; i < mvMappings.size(); i++) + { + Mapping& rMapping = *mvMappings[i]; + bool bURLEqual = rDesc.sDataSource == rMapping.sURL; + if(rDesc.sTableOrQuery == rMapping.sTableName && bURLEqual) + { + mvMappings.erase(mvMappings.begin()+i); + break; + } + } + mvMappings.push_back(std::make_unique(*pSetMapping)); + SetModified(); +} + +DBChangeDialogConfig_Impl::DBChangeDialogConfig_Impl() +{ +} + +DBChangeDialogConfig_Impl::~DBChangeDialogConfig_Impl() +{ +} + +const Sequence& DBChangeDialogConfig_Impl::GetDataSourceNames() +{ + if(!aSourceNames.hasElements()) + { + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference xDBContext = DatabaseContext::create(xContext); + aSourceNames = xDBContext->getElementNames(); + } + return aSourceNames; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibconfig.hxx b/extensions/source/bibliography/bibconfig.hxx new file mode 100644 index 000000000..0d81491ff --- /dev/null +++ b/extensions/source/bibliography/bibconfig.hxx @@ -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 . + */ + +#pragma once + +#include +#include +#include +#include + +struct Mapping; +typedef std::vector > MappingArray; + + +#define COLUMN_COUNT 32 +#define IDENTIFIER_POS 0 +#define AUTHORITYTYPE_POS 1 +#define AUTHOR_POS 2 +#define TITLE_POS 3 +#define YEAR_POS 4 +#define ISBN_POS 5 +#define BOOKTITLE_POS 6 +#define CHAPTER_POS 7 +#define EDITION_POS 8 +#define EDITOR_POS 9 +#define HOWPUBLISHED_POS 10 +#define INSTITUTION_POS 11 +#define JOURNAL_POS 12 +#define MONTH_POS 13 +#define NOTE_POS 14 +#define ANNOTE_POS 15 +#define NUMBER_POS 16 +#define ORGANIZATIONS_POS 17 +#define PAGES_POS 18 +#define PUBLISHER_POS 19 +#define ADDRESS_POS 20 +#define SCHOOL_POS 21 +#define SERIES_POS 22 +#define REPORTTYPE_POS 23 +#define VOLUME_POS 24 +#define URL_POS 25 +#define CUSTOM1_POS 26 +#define CUSTOM2_POS 27 +#define CUSTOM3_POS 28 +#define CUSTOM4_POS 29 +#define CUSTOM5_POS 30 +#define LOCAL_URL_POS 31 + +struct StringPair +{ + OUString sRealColumnName; + OUString sLogicalColumnName; +}; + +struct Mapping +{ + OUString sTableName; + OUString sURL; + sal_Int16 nCommandType; + StringPair aColumnPairs[COLUMN_COUNT]; + + Mapping() : + nCommandType(0){} +}; + +struct BibDBDescriptor +{ + OUString sDataSource; + OUString sTableOrQuery; + sal_Int32 nCommandType; +}; + + +class BibConfig : public utl::ConfigItem +{ + OUString sDataSource; + OUString sTableOrQuery; + sal_Int32 nTblOrQuery; + + OUString sQueryField; + OUString sQueryText; + MappingArray mvMappings; + tools::Long nBeamerSize; + tools::Long nViewSize; + bool bShowColumnAssignmentWarning; + + OUString aColumnDefaults[COLUMN_COUNT]; + + static css::uno::Sequence const & GetPropertyNames(); + + virtual void ImplCommit() override; + +public: + BibConfig(); + virtual ~BibConfig() override; + + virtual void Notify( const css::uno::Sequence& aPropertyNames) override; + + BibDBDescriptor GetBibliographyURL(); + void SetBibliographyURL(const BibDBDescriptor& rDesc); + + const Mapping* GetMapping(const BibDBDescriptor& rDesc) const; + void SetMapping(const BibDBDescriptor& rDesc, const Mapping* pMapping); + + const OUString& GetDefColumnName(sal_uInt16 nIndex) const + {return aColumnDefaults[nIndex];} + + + void setBeamerSize(tools::Long nSize) {SetModified(); nBeamerSize = nSize;} + tools::Long getBeamerSize()const {return nBeamerSize;} + void setViewSize(tools::Long nSize) {SetModified(); nViewSize = nSize;} + tools::Long getViewSize() const {return nViewSize;} + + const OUString& getQueryField() const {return sQueryField;} + void setQueryField(const OUString& rSet) {SetModified(); sQueryField = rSet;} + + const OUString& getQueryText() const {return sQueryText;} + void setQueryText(const OUString& rSet) {SetModified(); sQueryText = rSet;} + + bool IsShowColumnAssignmentWarning() const + { return bShowColumnAssignmentWarning;} + void SetShowColumnAssignmentWarning(bool bSet) + { bShowColumnAssignmentWarning = bSet;} +}; + +class DBChangeDialogConfig_Impl +{ + css::uno::Sequence aSourceNames; +public: + DBChangeDialogConfig_Impl(); + ~DBChangeDialogConfig_Impl(); + + const css::uno::Sequence& GetDataSourceNames(); + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibcont.cxx b/extensions/source/bibliography/bibcont.cxx new file mode 100644 index 000000000..7c24b0fb3 --- /dev/null +++ b/extensions/source/bibliography/bibcont.cxx @@ -0,0 +1,241 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "bibconfig.hxx" + + +#include "bibcont.hxx" + + +BibShortCutHandler::~BibShortCutHandler() +{ +} + +bool BibShortCutHandler::HandleShortCutKey( const KeyEvent& ) +{ + return false; +} + + +BibWindow::BibWindow( vcl::Window* pParent, WinBits nStyle ) : Window( pParent, nStyle ), BibShortCutHandler( this ) +{ +} + +BibWindow::~BibWindow() +{ +} + + +BibSplitWindow::BibSplitWindow( vcl::Window* pParent, WinBits nStyle ) : SplitWindow( pParent, nStyle ), BibShortCutHandler( this ) +{ +} + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +//split window size is a percent value +#define WIN_MIN_HEIGHT 10 +#define WIN_STEP_SIZE 5 + +BibWindowContainer::BibWindowContainer( vcl::Window* pParent, BibShortCutHandler* pChildWin ) : + BibWindow( pParent, WB_3DLOOK ), + pChild( pChildWin ) +{ + if(pChild!=nullptr) + { + vcl::Window* pChildWindow = GetChild(); + pChildWindow->SetParent(this); + pChildWindow->Show(); + pChildWindow->SetPosPixel(Point(0,0)); + } +} + +BibWindowContainer::~BibWindowContainer() +{ + disposeOnce(); +} + +void BibWindowContainer::dispose() +{ + if( pChild ) + { + VclPtr pDel = GetChild(); + pChild = nullptr; // prevents GetFocus for child while deleting! + pDel.disposeAndClear(); + } + vcl::Window::dispose(); +} + +void BibWindowContainer::Resize() +{ + if( pChild ) + GetChild()->SetSizePixel( GetOutputSizePixel() ); +} + +void BibWindowContainer::GetFocus() +{ + if( pChild ) + GetChild()->GrabFocus(); +} + +bool BibWindowContainer::HandleShortCutKey( const KeyEvent& rKeyEvent ) +{ + return pChild && pChild->HandleShortCutKey( rKeyEvent ); +} + + +BibBookContainer::BibBookContainer(vcl::Window* pParent): + BibSplitWindow(pParent,WB_3DLOOK), + pTopWin(nullptr), + pBottomWin(nullptr), + aIdle("extensions BibBookContainer Split Idle") +{ + pBibMod = OpenBibModul(); + aIdle.SetInvokeHandler(LINK( this, BibBookContainer, SplitHdl)); + aIdle.SetPriority(TaskPriority::LOWEST); +} + +BibBookContainer::~BibBookContainer() +{ + disposeOnce(); +} + +void BibBookContainer::dispose() +{ + if( pTopWin ) + { + VclPtr pDel = pTopWin; + pTopWin = nullptr; // prevents GetFocus for child while deleting! + pDel.disposeAndClear(); + } + + if( pBottomWin ) + { + VclPtr pDel = pBottomWin; + pBottomWin = nullptr; // prevents GetFocus for child while deleting! + pDel.disposeAndClear(); + } + + CloseBibModul( pBibMod ); + pTopWin.clear(); + pBottomWin.clear(); + BibSplitWindow::dispose(); +} + +void BibBookContainer::Split() +{ + aIdle.Start(); +} +IMPL_LINK_NOARG( BibBookContainer, SplitHdl, Timer*, void) +{ + tools::Long nSize= GetItemSize( TOP_WINDOW); + BibConfig* pConfig = BibModul::GetConfig(); + pConfig->setBeamerSize(nSize); + nSize = GetItemSize( BOTTOM_WINDOW); + pConfig->setViewSize(nSize); +} + +void BibBookContainer::createTopFrame( BibShortCutHandler* pWin ) +{ + if(pTopWin) + { + RemoveItem(TOP_WINDOW); + pTopWin.disposeAndClear(); + } + pTopWin=VclPtr::Create(this,pWin); + pTopWin->Show(); + BibConfig* pConfig = BibModul::GetConfig(); + tools::Long nSize = pConfig->getBeamerSize(); + InsertItem(TOP_WINDOW, pTopWin, nSize, 1, 0, SplitWindowItemFlags::PercentSize ); + +} + +void BibBookContainer::createBottomFrame( BibShortCutHandler* pWin ) +{ + if(pBottomWin) + { + RemoveItem(BOTTOM_WINDOW); + pBottomWin.disposeAndClear(); + } + + pBottomWin=VclPtr::Create(this,pWin); + + BibConfig* pConfig = BibModul::GetConfig(); + tools::Long nSize = pConfig->getViewSize(); + InsertItem(BOTTOM_WINDOW, pBottomWin, nSize, 1, 0, SplitWindowItemFlags::PercentSize ); + +} + +void BibBookContainer::GetFocus() +{ + if( pBottomWin ) + pBottomWin->GrabFocus(); +} + +bool BibBookContainer::PreNotify( NotifyEvent& rNEvt ) +{ + bool bHandled = false; + if( MouseNotifyEvent::KEYINPUT == rNEvt.GetType() ) + { + const KeyEvent* pKEvt = rNEvt.GetKeyEvent(); + const vcl::KeyCode aKeyCode = pKEvt->GetKeyCode(); + sal_uInt16 nKey = aKeyCode.GetCode(); + const sal_uInt16 nModifier = aKeyCode.GetModifier(); + + if( KEY_MOD2 == nModifier ) + { + if( KEY_UP == nKey || KEY_DOWN == nKey ) + { + if(pTopWin && pBottomWin) + { + sal_uInt16 nFirstWinId = KEY_UP == nKey ? TOP_WINDOW : BOTTOM_WINDOW; + sal_uInt16 nSecondWinId = KEY_UP == nKey ? BOTTOM_WINDOW : TOP_WINDOW; + tools::Long nHeight = GetItemSize( nFirstWinId ); + nHeight -= WIN_STEP_SIZE; + if(nHeight < WIN_MIN_HEIGHT) + nHeight = WIN_MIN_HEIGHT; + SetItemSize( nFirstWinId, nHeight ); + SetItemSize( nSecondWinId, 100 - nHeight ); + } + bHandled = true; + } + else if( pKEvt->GetCharCode() && HandleShortCutKey( *pKEvt ) ) + bHandled = true; + } + } + + return bHandled; +} + +bool BibBookContainer::HandleShortCutKey( const KeyEvent& rKeyEvent ) +{ + bool bRet = false; + + if( pTopWin ) + bRet = pTopWin->HandleShortCutKey( rKeyEvent ); + + if( !bRet && pBottomWin ) + bRet = pBottomWin->HandleShortCutKey( rKeyEvent ); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibcont.hxx b/extensions/source/bibliography/bibcont.hxx new file mode 100644 index 000000000..d90952ac3 --- /dev/null +++ b/extensions/source/bibliography/bibcont.hxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include "bibshortcuthandler.hxx" + +#include "bibmod.hxx" + +#define TOP_WINDOW 1 +#define BOTTOM_WINDOW 2 + +class BibWindowContainer : public BibWindow //Window +{ + private: + // !BibShortCutHandler is also always a Window! + BibShortCutHandler* pChild; + + protected: + virtual void Resize() override; + + public: + BibWindowContainer( vcl::Window* pParent, BibShortCutHandler* pChild); + virtual ~BibWindowContainer() override; + virtual void dispose() override; + + inline vcl::Window* GetChild(); + + virtual void GetFocus() override; + + virtual bool HandleShortCutKey( const KeyEvent& rKeyEvent ) override; // returns true, if key was handled + + using Window::GetChild; +}; + +inline vcl::Window* BibWindowContainer::GetChild() +{ + return pChild ? pChild->GetWindow() : nullptr; +} + + +class BibBookContainer: public BibSplitWindow +{ + private: + + VclPtr pTopWin; + VclPtr pBottomWin; + HdlBibModul pBibMod; + Idle aIdle; + + DECL_LINK( SplitHdl, Timer*, void ); + + protected: + + virtual void Split() override; + + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + + public: + + explicit BibBookContainer(vcl::Window* pParent ); + virtual ~BibBookContainer() override; + virtual void dispose() override; + + // !BibShortCutHandler is also always a Window! + void createTopFrame( BibShortCutHandler* pWin ); + + void createBottomFrame( BibShortCutHandler* pWin ); + + virtual void GetFocus() override; + + virtual bool HandleShortCutKey( const KeyEvent& rKeyEvent ) override; // returns true, if key was handled +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibload.cxx b/extensions/source/bibliography/bibload.cxx new file mode 100644 index 000000000..82c08e007 --- /dev/null +++ b/extensions/source/bibliography/bibload.cxx @@ -0,0 +1,609 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 "bibresid.hxx" +#include +#include "bibcont.hxx" +#include "bibbeam.hxx" +#include "bibmod.hxx" +#include "bibview.hxx" +#include "framectr.hxx" +#include "datman.hxx" +#include "bibconfig.hxx" +#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::lang; +using namespace ::com::sun::star::sdb; +using namespace ::com::sun::star::sdbc; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::frame; + +namespace { + +class BibliographyLoader : public cppu::WeakImplHelper + < XServiceInfo, XNameAccess, XPropertySet, XFrameLoader > +{ + HdlBibModul m_pBibMod; + rtl::Reference m_xDatMan; + Reference< XNameAccess > m_xColumns; + Reference< XResultSet > m_xCursor; + +private: + + void loadView(const Reference< XFrame > & aFrame, + const Reference< XLoadEventListener > & aListener); + + BibDataManager* GetDataManager()const; + Reference< XNameAccess > const & GetDataColumns() const; + Reference< XResultSet > const & GetDataCursor() const; + Reference< sdb::XColumn > GetIdentifierColumn() const; + +public: + BibliographyLoader(); + virtual ~BibliographyLoader() override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + //XNameAccess + virtual Any SAL_CALL getByName(const OUString& aName) override; + virtual Sequence< OUString > SAL_CALL getElementNames() override; + virtual sal_Bool SAL_CALL hasByName(const OUString& aName) override; + + //XElementAccess + virtual Type SAL_CALL getElementType() override; + virtual sal_Bool SAL_CALL hasElements() override; + + //XPropertySet + virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + virtual void SAL_CALL setPropertyValue(const OUString& PropertyName, const Any& aValue) override; + virtual Any SAL_CALL getPropertyValue(const OUString& PropertyName) override; + virtual void SAL_CALL addPropertyChangeListener(const OUString& PropertyName, const Reference< XPropertyChangeListener > & aListener) override; + virtual void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference< XPropertyChangeListener > & aListener) override; + virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference< XVetoableChangeListener > & aListener) override; + virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference< XVetoableChangeListener > & aListener) override; + + // XLoader + virtual void SAL_CALL load(const Reference< XFrame > & aFrame, const OUString& aURL, + const Sequence< PropertyValue >& aArgs, + const Reference< XLoadEventListener > & aListener) override; + virtual void SAL_CALL cancel() override; +}; + +} + +BibliographyLoader::BibliographyLoader() : + m_pBibMod(nullptr) +{ +} + +BibliographyLoader::~BibliographyLoader() +{ + Reference< lang::XComponent > xComp(m_xCursor, UNO_QUERY); + if (xComp.is()) + xComp->dispose(); + if(m_pBibMod) + CloseBibModul(m_pBibMod); +} + + +// XServiceInfo +OUString BibliographyLoader::getImplementationName() +{ + return "com.sun.star.extensions.Bibliography"; +} + +// XServiceInfo +sal_Bool BibliographyLoader::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > BibliographyLoader::getSupportedServiceNames() +{ + return { "com.sun.star.frame.FrameLoader", "com.sun.star.frame.Bibliography" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_BibliographyLoader_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + return cppu::acquire(new BibliographyLoader()); +} + +void BibliographyLoader::cancel() +{ + //! + //! +} + +void BibliographyLoader::load(const Reference< XFrame > & rFrame, const OUString& rURL, + const Sequence< PropertyValue >& /*rArgs*/, + const Reference< XLoadEventListener > & rListener) +{ + + SolarMutexGuard aGuard; + + m_pBibMod = OpenBibModul(); + + std::u16string_view aPartName = o3tl::getToken(rURL, 1, '/' ); + Reference xPrSet(rFrame, UNO_QUERY); + if(xPrSet.is()) + { + Any aTitle; + aTitle <<= BibResId(RID_BIB_STR_FRAME_TITLE); + xPrSet->setPropertyValue("Title", aTitle); + } + if(aPartName == u"View" || aPartName == u"View1") + { + loadView(rFrame, rListener); + } +} + + +void BibliographyLoader::loadView(const Reference< XFrame > & rFrame, + const Reference< XLoadEventListener > & rListener) +{ + SolarMutexGuard aGuard; + //! + if(!m_pBibMod) + m_pBibMod = OpenBibModul(); + + m_xDatMan = BibModul::createDataManager(); + BibDBDescriptor aBibDesc = BibModul::GetConfig()->GetBibliographyURL(); + + if(aBibDesc.sDataSource.isEmpty()) + { + DBChangeDialogConfig_Impl aConfig; + const Sequence aSources = aConfig.GetDataSourceNames(); + if(aSources.hasElements()) + aBibDesc.sDataSource = aSources.getConstArray()[0]; + } + + m_xDatMan->createDatabaseForm( aBibDesc ); + + Reference aWindow = rFrame->getContainerWindow(); + + VclPtr pParent = VCLUnoHelper::GetWindow( aWindow ); + + VclPtrInstance pMyWindow( pParent ); + pMyWindow->Show(); + + VclPtrInstance< ::bib::BibView> pView( pMyWindow, m_xDatMan.get(), WB_VSCROLL | WB_HSCROLL | WB_3DLOOK ); + pView->Show(); + m_xDatMan->SetView( pView ); + + VclPtrInstance< ::bib::BibBeamer> pBeamer( pMyWindow, m_xDatMan.get() ); + pBeamer->Show(); + pMyWindow->createTopFrame(pBeamer); + + pMyWindow->createBottomFrame(pView); + + Reference< awt::XWindow > xWin ( pMyWindow->GetComponentInterface(), UNO_QUERY ); + + Reference< XController > xCtrRef( new BibFrameController_Impl( xWin, m_xDatMan.get() ) ); + + xCtrRef->attachFrame(rFrame); + rFrame->setComponent( xWin, xCtrRef); + pBeamer->SetXController(xCtrRef); + + if (aWindow) + { + // not earlier because SetFocus() is triggered in setVisible() + aWindow->setVisible(true); + } + + Reference(m_xDatMan)->load(); + m_xDatMan->RegisterInterceptor(pBeamer); + + if ( rListener.is() ) + rListener->loadFinished( this ); + + // attach menu bar + Reference< XPropertySet > xPropSet( rFrame, UNO_QUERY ); + Reference< css::frame::XLayoutManager > xLayoutManager; + if ( xPropSet.is() ) + { + try + { + Any a = xPropSet->getPropertyValue("LayoutManager"); + a >>= xLayoutManager; + } + catch ( const uno::Exception& ) + { + } + } + + if ( xLayoutManager.is() ) + xLayoutManager->createElement( "private:resource/menubar/menubar" ); +} + +BibDataManager* BibliographyLoader::GetDataManager()const +{ + if(!m_xDatMan.is()) + { + if(!m_pBibMod) + const_cast< BibliographyLoader* >( this )->m_pBibMod = OpenBibModul(); + const_cast< BibliographyLoader* >( this )->m_xDatMan = BibModul::createDataManager(); + } + return m_xDatMan.get(); +} + +Reference< XNameAccess > const & BibliographyLoader::GetDataColumns() const +{ + if (!m_xColumns.is()) + { + Reference< XMultiServiceFactory > xMgr = comphelper::getProcessServiceFactory(); + Reference< XRowSet > xRowSet(xMgr->createInstance("com.sun.star.sdb.RowSet"), UNO_QUERY); + Reference< XPropertySet > xResultSetProps(xRowSet, UNO_QUERY); + DBG_ASSERT(xResultSetProps.is() , "BibliographyLoader::GetDataCursor : invalid row set (no XResultSet or no XPropertySet) !"); + + BibDBDescriptor aBibDesc = BibModul::GetConfig()->GetBibliographyURL(); + + Any aBibUrlAny; aBibUrlAny <<= aBibDesc.sDataSource; + xResultSetProps->setPropertyValue("DataSourceName", aBibUrlAny); + Any aCommandType; aCommandType <<= aBibDesc.nCommandType; + xResultSetProps->setPropertyValue("CommandType", aCommandType); + Any aTableName; aTableName <<= aBibDesc.sTableOrQuery; + xResultSetProps->setPropertyValue("Command", aTableName); + Any aResultSetType; aResultSetType <<= sal_Int32(ResultSetType::SCROLL_INSENSITIVE); + xResultSetProps->setPropertyValue("ResultSetType", aResultSetType); + Any aResultSetCurrency; aResultSetCurrency <<= sal_Int32(ResultSetConcurrency::UPDATABLE); + xResultSetProps->setPropertyValue("ResultSetConcurrency", aResultSetCurrency); + + bool bSuccess = false; + try + { + xRowSet->execute(); + bSuccess = true; + } + catch(const SQLException&) + { + DBG_UNHANDLED_EXCEPTION("extensions.biblio"); + } + catch(const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.biblio"); + bSuccess = false; + } + + if (!bSuccess) + { + Reference< XComponent > xSetComp(xRowSet, UNO_QUERY); + if (xSetComp.is()) + xSetComp->dispose(); + xRowSet = nullptr; + } + else + const_cast(this)->m_xCursor = xRowSet.get(); + + Reference< sdbcx::XColumnsSupplier > xSupplyCols(m_xCursor, UNO_QUERY); + if (xSupplyCols.is()) + const_cast(this)->m_xColumns = xSupplyCols->getColumns(); + } + + return m_xColumns; +} + +Reference< sdb::XColumn > BibliographyLoader::GetIdentifierColumn() const +{ + BibDataManager* pDatMan = GetDataManager(); + Reference< XNameAccess > xColumns = GetDataColumns(); + OUString sIdentifierColumnName = pDatMan->GetIdentifierMapping(); + + Reference< sdb::XColumn > xReturn; + if (xColumns.is() && xColumns->hasByName(sIdentifierColumnName)) + { + xReturn.set(xColumns->getByName(sIdentifierColumnName), UNO_QUERY); + } + return xReturn; +} + +Reference< XResultSet > const & BibliographyLoader::GetDataCursor() const +{ + if (!m_xCursor.is()) + GetDataColumns(); + if (m_xCursor.is()) + m_xCursor->first(); + return m_xCursor; +} + +static OUString lcl_AddProperty(const Reference< XNameAccess >& xColumns, + const Mapping* pMapping, const OUString& rColumnName) +{ + OUString sColumnName(rColumnName); + if(pMapping) + { + for(const auto & aColumnPair : pMapping->aColumnPairs) + { + if(aColumnPair.sLogicalColumnName == rColumnName) + { + sColumnName = aColumnPair.sRealColumnName; + break; + } + } + } + OUString uColumnName(sColumnName); + OUString uRet; + Reference< sdb::XColumn > xCol; + if (xColumns->hasByName(uColumnName)) + xCol.set(xColumns->getByName(uColumnName), UNO_QUERY); + if (xCol.is()) + uRet = xCol->getString(); + return uRet; +} + +Any BibliographyLoader::getByName(const OUString& rName) +{ + Any aRet; + try + { + BibDataManager* pDatMan = GetDataManager(); + Reference< XResultSet > xCursor = GetDataCursor(); + Reference< sdbcx::XColumnsSupplier > xSupplyCols(xCursor, UNO_QUERY); + Reference< XNameAccess > xColumns; + if (!xSupplyCols.is()) + return aRet; + xColumns = xSupplyCols->getColumns(); + DBG_ASSERT(xSupplyCols.is(), "BibliographyLoader::getByName : invalid columns returned by the data cursor (may be the result set is not alive ?) !"); + if (!xColumns.is()) + return aRet; + + const OUString sIdentifierMapping = pDatMan->GetIdentifierMapping(); + Reference< sdb::XColumn > xColumn; + if (xColumns->hasByName(sIdentifierMapping)) + xColumn.set(xColumns->getByName(sIdentifierMapping), UNO_QUERY); + if (xColumn.is()) + { + do + { + if ((rName == xColumn->getString()) && !xColumn->wasNull()) + { + Sequence aPropSequ(COLUMN_COUNT); + PropertyValue* pValues = aPropSequ.getArray(); + BibConfig* pConfig = BibModul::GetConfig(); + BibDBDescriptor aBibDesc = BibModul::GetConfig()->GetBibliographyURL(); + const Mapping* pMapping = pConfig->GetMapping(aBibDesc); + for(sal_uInt16 nEntry = 0; nEntry < COLUMN_COUNT; nEntry++) + { + const OUString& sColName = pConfig->GetDefColumnName( + nEntry); + pValues[nEntry].Name = sColName; + pValues[nEntry].Value <<= lcl_AddProperty(xColumns, pMapping, sColName); + } + aRet <<= aPropSequ; + + break; + } + } + while(xCursor->next()); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("extensions.biblio"); + } + return aRet; +} + +Sequence< OUString > BibliographyLoader::getElementNames() +{ + Sequence< OUString > aRet(10); + int nRealNameCount = 0; + try + { + Reference< XResultSet > xCursor(GetDataCursor()); + Reference< sdb::XColumn > xIdColumn(GetIdentifierColumn()); + if (xIdColumn.is()) // implies xCursor.is() + { + do + { + OUString sTemp = xIdColumn->getString(); + if (!sTemp.isEmpty() && !xIdColumn->wasNull()) + { + int nLen = aRet.getLength(); + if(nLen == nRealNameCount) + aRet.realloc(nLen + 10); + OUString* pArray = aRet.getArray(); + pArray[nRealNameCount] = sTemp; + nRealNameCount++; + } + } + while (xCursor->next()); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("extensions.biblio"); + } + + aRet.realloc(nRealNameCount); + return aRet; +} + +sal_Bool BibliographyLoader::hasByName(const OUString& rName) +{ + bool bRet = false; + try + { + Reference< XResultSet > xCursor = GetDataCursor(); + Reference< sdb::XColumn > xIdColumn = GetIdentifierColumn(); + + if (xIdColumn.is()) // implies xCursor.is() + { + do + { + OUString sCurrentId = xIdColumn->getString(); + if (!xIdColumn->wasNull() && rName.startsWith(sCurrentId)) + { + bRet = true; + break; + } + } + while(xCursor->next()); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("extensions.biblio"); + } + return bRet; +} + +Type BibliographyLoader::getElementType() +{ + return cppu::UnoType>::get(); +} + +sal_Bool BibliographyLoader::hasElements() +{ + Reference< XNameAccess > xColumns = GetDataColumns(); + return xColumns.is() && xColumns->getElementNames().hasElements(); +} + +Reference< XPropertySetInfo > BibliographyLoader::getPropertySetInfo() +{ + static const SfxItemPropertyMapEntry aBibProps_Impl[] = + { + { u"BibliographyDataFieldNames", 0, cppu::UnoType>::get(), PropertyAttribute::READONLY, 0}, + { u"", 0, css::uno::Type(), 0, 0 } + }; + static Reference< XPropertySetInfo > xRet = + SfxItemPropertySet(aBibProps_Impl).getPropertySetInfo(); + return xRet; +} + +void BibliographyLoader::setPropertyValue(const OUString& /*PropertyName*/, + const Any& /*aValue*/) +{ + throw UnknownPropertyException(); + //no changeable properties +} + +Any BibliographyLoader::getPropertyValue(const OUString& rPropertyName) +{ + Any aRet; + static const sal_uInt16 aInternalMapping[] = + { + IDENTIFIER_POS , // BibliographyDataField_IDENTIFIER + AUTHORITYTYPE_POS , // BibliographyDataField_BIBILIOGRAPHIC_TYPE + ADDRESS_POS , // BibliographyDataField_ADDRESS + ANNOTE_POS , // BibliographyDataField_ANNOTE + AUTHOR_POS , // BibliographyDataField_AUTHOR + BOOKTITLE_POS , // BibliographyDataField_BOOKTITLE + CHAPTER_POS , // BibliographyDataField_CHAPTER + EDITION_POS , // BibliographyDataField_EDITION + EDITOR_POS , // BibliographyDataField_EDITOR + HOWPUBLISHED_POS , // BibliographyDataField_HOWPUBLISHED + INSTITUTION_POS , // BibliographyDataField_INSTITUTION + JOURNAL_POS , // BibliographyDataField_JOURNAL + MONTH_POS , // BibliographyDataField_MONTH + NOTE_POS , // BibliographyDataField_NOTE + NUMBER_POS , // BibliographyDataField_NUMBER + ORGANIZATIONS_POS , // BibliographyDataField_ORGANIZATIONS + PAGES_POS , // BibliographyDataField_PAGES + PUBLISHER_POS , // BibliographyDataField_PUBLISHER + SCHOOL_POS , // BibliographyDataField_SCHOOL + SERIES_POS , // BibliographyDataField_SERIES + TITLE_POS , // BibliographyDataField_TITLE + REPORTTYPE_POS , // BibliographyDataField_REPORT_TYPE + VOLUME_POS , // BibliographyDataField_VOLUME + YEAR_POS , // BibliographyDataField_YEAR + URL_POS , // BibliographyDataField_URL + CUSTOM1_POS , // BibliographyDataField_CUSTOM1 + CUSTOM2_POS , // BibliographyDataField_CUSTOM2 + CUSTOM3_POS , // BibliographyDataField_CUSTOM3 + CUSTOM4_POS , // BibliographyDataField_CUSTOM4 + CUSTOM5_POS , // BibliographyDataField_CUSTOM5 + ISBN_POS , // BibliographyDataField_ISBN + LOCAL_URL_POS // BibliographyDataField_LOCAL_URL + }; + if(rPropertyName != "BibliographyDataFieldNames") + throw UnknownPropertyException(rPropertyName); + Sequence aSeq(COLUMN_COUNT); + PropertyValue* pArray = aSeq.getArray(); + BibConfig* pConfig = BibModul::GetConfig(); + for(sal_uInt16 i = 0; i <= text::BibliographyDataField::LOCAL_URL ; i++) + { + pArray[i].Name = pConfig->GetDefColumnName(aInternalMapping[i]); + pArray[i].Value <<= static_cast(i); + } + aRet <<= aSeq; + return aRet; +} + +void BibliographyLoader::addPropertyChangeListener( + const OUString& /*PropertyName*/, const Reference< XPropertyChangeListener > & /*aListener*/) +{ + //no bound properties +} + +void BibliographyLoader::removePropertyChangeListener( + const OUString& /*PropertyName*/, const Reference< XPropertyChangeListener > & /*aListener*/) +{ + //no bound properties +} + +void BibliographyLoader::addVetoableChangeListener( + const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener > & /*aListener*/) +{ + //no vetoable properties +} + +void BibliographyLoader::removeVetoableChangeListener( + const OUString& /*PropertyName*/, const Reference< XVetoableChangeListener > & /*aListener*/) +{ + //no vetoable properties +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibmod.cxx b/extensions/source/bibliography/bibmod.cxx new file mode 100644 index 000000000..3a6d06672 --- /dev/null +++ b/extensions/source/bibliography/bibmod.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 + +#include "bibmod.hxx" +#include "bibresid.hxx" +#include "datman.hxx" +#include "bibconfig.hxx" +#include + +static BibModul* pBibModul=nullptr; +static sal_uInt32 nBibModulCount=0; + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::util; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ucb; + +HdlBibModul OpenBibModul() +{ + if(pBibModul==nullptr) + { + pBibModul=new BibModul(); + } + nBibModulCount++; + return &pBibModul; +} + +void CloseBibModul(HdlBibModul ppBibModul) +{ + nBibModulCount--; + if(nBibModulCount==0 && ppBibModul!=nullptr) + { + delete pBibModul; + pBibModul=nullptr; + } +} + +OUString BibResId(TranslateId aId) +{ + return Translate::get(aId, pBibModul->GetResLocale()); +} + +BibConfig* BibModul::pBibConfig = nullptr; + +BibModul::BibModul() + : m_aResLocale(Translate::Create("pcr")) +{ +} + +BibModul::~BibModul() +{ + if (pBibConfig && pBibConfig->IsModified()) + pBibConfig->Commit(); + delete pBibConfig; + pBibConfig = nullptr; +} + +rtl::Reference BibModul::createDataManager() +{ + return new BibDataManager(); +} + +BibConfig* BibModul::GetConfig() +{ + if(! pBibConfig) + pBibConfig = new BibConfig; + return pBibConfig; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibmod.hxx b/extensions/source/bibliography/bibmod.hxx new file mode 100644 index 000000000..a695f93d6 --- /dev/null +++ b/extensions/source/bibliography/bibmod.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +class BibDataManager; +class BibConfig; + +class BibModul +{ + private: + std::locale m_aResLocale; + static BibConfig* pBibConfig; + + public: + BibModul(); + ~BibModul(); + + const std::locale& GetResLocale() const { return m_aResLocale; } + static BibConfig* GetConfig(); + + static rtl::Reference createDataManager(); + +}; + +typedef BibModul** HdlBibModul; + +HdlBibModul OpenBibModul(); +void CloseBibModul(HdlBibModul ppBibModul); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibresid.hxx b/extensions/source/bibliography/bibresid.hxx new file mode 100644 index 000000000..6e17e76f2 --- /dev/null +++ b/extensions/source/bibliography/bibresid.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 . + */ + +#pragma once + +#include +#include + +OUString BibResId(TranslateId aId); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibshortcuthandler.hxx b/extensions/source/bibliography/bibshortcuthandler.hxx new file mode 100644 index 000000000..79563543b --- /dev/null +++ b/extensions/source/bibliography/bibshortcuthandler.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +// additional classes to handle shortcuts +// code in bibcont.cxx + + +class BibShortCutHandler +{ +private: + VclPtr pBaseClass; // in cases, where BibShortCutHandler also has to be a window + +protected: + explicit BibShortCutHandler( vcl::Window* pBaseClass ); + +public: + virtual ~BibShortCutHandler(); + virtual bool HandleShortCutKey( const KeyEvent& rKeyEvent ); // returns true, if key was handled + + inline vcl::Window* GetWindow(); +}; + +inline BibShortCutHandler::BibShortCutHandler( vcl::Window* _pBaseClass ) : pBaseClass( _pBaseClass ) +{ +} + +inline vcl::Window* BibShortCutHandler::GetWindow() +{ + return pBaseClass; +} + +class BibWindow : public vcl::Window, public BibShortCutHandler +{ +public: + BibWindow( vcl::Window* pParent, WinBits nStyle); + virtual ~BibWindow() override; +}; + +class BibSplitWindow : public SplitWindow, public BibShortCutHandler +{ +public: + BibSplitWindow( vcl::Window* pParent, WinBits nStyle); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibtools.hxx b/extensions/source/bibliography/bibtools.hxx new file mode 100644 index 000000000..9b0d388fa --- /dev/null +++ b/extensions/source/bibliography/bibtools.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +namespace bib +{ + // source in bibbeam.cxx + + void HandleTaskPaneList( vcl::Window* pWindow, bool bAddToList ); + // pWindow: just an system window or something which is child of a system window + + inline void AddToTaskPaneList( vcl::Window* pWindowToBeHandled ) + { + HandleTaskPaneList( pWindowToBeHandled, true ); + } + + inline void RemoveFromTaskPaneList( vcl::Window* pWindowToBeHandled ) + { + HandleTaskPaneList( pWindowToBeHandled, false ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibview.cxx b/extensions/source/bibliography/bibview.cxx new file mode 100644 index 000000000..b175fb78a --- /dev/null +++ b/extensions/source/bibliography/bibview.cxx @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "general.hxx" +#include "bibview.hxx" +#include "datman.hxx" +#include "bibresid.hxx" +#include "bibmod.hxx" +#include "bibconfig.hxx" + + +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; + +namespace +{ + class MessageWithCheck : public weld::MessageDialogController + { + private: + std::unique_ptr m_xWarningOnBox; + public: + MessageWithCheck(weld::Window *pParent) + : MessageDialogController(pParent, "modules/sbibliography/ui/querydialog.ui", "QueryDialog", "ask") + , m_xWarningOnBox(m_xBuilder->weld_check_button("ask")) + { + } + bool get_active() const { return m_xWarningOnBox->get_active(); } + }; +} + +namespace bib +{ + + + BibView::BibView( vcl::Window* _pParent, BibDataManager* _pManager, WinBits _nStyle ) + :BibWindow( _pParent, _nStyle ) + ,m_pDatMan( _pManager ) + ,m_xDatMan( _pManager ) + ,m_pGeneralPage( nullptr ) + ,m_aFormControlContainer(this) + { + if ( m_xDatMan.is() ) + m_aFormControlContainer.connectForm( m_xDatMan ); + } + + + BibView::~BibView() + { + disposeOnce(); + } + + void BibView::dispose() + { + VclPtr pGeneralPage = m_pGeneralPage; + m_pGeneralPage.clear(); + pGeneralPage.disposeAndClear(); // dispose will commit any uncommitted weld::Entry changes + + if ( m_aFormControlContainer.isFormConnected() ) + m_aFormControlContainer.disconnectForm(); + + BibWindow::dispose(); + } + + void BibView::UpdatePages() + { + // TODO: + // this is _strange_: Why not updating the existent general page? + // I consider the current behaviour a HACK. + if ( m_pGeneralPage ) + { + m_pGeneralPage->Hide(); + m_pGeneralPage.disposeAndClear(); + } + + m_pGeneralPage = VclPtr::Create( this, m_pDatMan ); + m_pGeneralPage->Show(); + + if( HasFocus() ) + // "delayed" GetFocus() because GetFocus() is initially called before GeneralPage is created + m_pGeneralPage->GrabFocus(); + + OUString sErrorString( m_pGeneralPage->GetErrorString() ); + if ( sErrorString.isEmpty() ) + return; + + bool bExecute = BibModul::GetConfig()->IsShowColumnAssignmentWarning(); + if(!m_pDatMan->HasActiveConnection()) + { + //no connection is available -> the data base has to be assigned + m_pDatMan->DispatchDBChangeDialog(); + bExecute = false; + } + else if(bExecute) + { + sErrorString += "\n" + BibResId(RID_MAP_QUESTION); + + MessageWithCheck aQueryBox(GetFrameWeld()); + aQueryBox.set_primary_text(sErrorString); + + short nResult = aQueryBox.run(); + BibModul::GetConfig()->SetShowColumnAssignmentWarning(!aQueryBox.get_active()); + + if( RET_YES != nResult ) + { + bExecute = false; + } + } + if(bExecute) + { + Application::PostUserEvent( LINK( this, BibView, CallMappingHdl ), nullptr, true ); + } + } + + BibViewFormControlContainer::BibViewFormControlContainer(BibView *pBibView) : mpBibView(pBibView) {} + + void BibViewFormControlContainer::_loaded( const EventObject& _rEvent ) + { + mpBibView->UpdatePages(); + FormControlContainer::_loaded( _rEvent ); + mpBibView->Resize(); + } + + void BibViewFormControlContainer::_reloaded( const EventObject& _rEvent ) + { + mpBibView->UpdatePages(); + FormControlContainer::_loaded( _rEvent ); + mpBibView->Resize(); + } + + IMPL_LINK_NOARG( BibView, CallMappingHdl, void*, void) + { + m_pDatMan->CreateMappingDialog(GetFrameWeld()); + } + + void BibView::Resize() + { + if ( m_pGeneralPage ) + { + ::Size aSz( GetOutputSizePixel() ); + m_pGeneralPage->SetSizePixel( aSz ); + } + Window::Resize(); + } + + Reference< awt::XControlContainer > BibViewFormControlContainer::getControlContainer() + { + return nullptr; + } + + void BibView::GetFocus() + { + if( m_pGeneralPage ) + m_pGeneralPage->GrabFocus(); + } + + bool BibView::HandleShortCutKey( const KeyEvent& rKeyEvent ) + { + return m_pGeneralPage && m_pGeneralPage->HandleShortCutKey( rKeyEvent ); + } + + +} // namespace bib + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/bibview.hxx b/extensions/source/bibliography/bibview.hxx new file mode 100644 index 000000000..3bed8ed13 --- /dev/null +++ b/extensions/source/bibliography/bibview.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 +#include "formcontrolcontainer.hxx" +#include "bibshortcuthandler.hxx" + +class BibGeneralPage; +class BibDataManager; + +namespace com::sun::star::awt{ class XFocusListener;} + +namespace bib +{ + class BibView; + class BibViewFormControlContainer : public FormControlContainer + { + private: + VclPtr mpBibView; + protected: + // FormControlContainer + virtual css::uno::Reference< css::awt::XControlContainer > + getControlContainer() override; + // XLoadListener equivalents + virtual void _loaded( const css::lang::EventObject& _rEvent ) override; + virtual void _reloaded( const css::lang::EventObject& _rEvent ) override; + public: + using FormControlContainer::connectForm; + using FormControlContainer::disconnectForm; + using FormControlContainer::isFormConnected; + explicit BibViewFormControlContainer(BibView *pBibView); + }; + + class BibView : public BibWindow + { + private: + BibDataManager* m_pDatMan; + css::uno::Reference< css::form::XLoadable> m_xDatMan; + VclPtr m_pGeneralPage; + BibViewFormControlContainer m_aFormControlContainer; + + private: + DECL_LINK(CallMappingHdl, void*, void); + + public: + // Window overridables + virtual void Resize() override; + + public: + BibView( vcl::Window* _pParent, BibDataManager* _pDatMan, WinBits nStyle ); + virtual ~BibView() override; + virtual void dispose() override; + + void UpdatePages(); + + virtual void GetFocus() override; + + virtual bool HandleShortCutKey( const KeyEvent& rKeyEvent ) override; // returns true, if key was handled + }; + + +} // namespace bib + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/datman.cxx b/extensions/source/bibliography/datman.cxx new file mode 100644 index 000000000..e010f8185 --- /dev/null +++ b/extensions/source/bibliography/datman.cxx @@ -0,0 +1,1390 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 "datman.hxx" +#include "bibresid.hxx" +#include "bibmod.hxx" +#include "bibview.hxx" +#include "toolbar.hxx" +#include "bibconfig.hxx" +#include "bibbeam.hxx" +#include "general.hxx" +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +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::form; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::lang; + +// PropertyNames +constexpr OUStringLiteral FM_PROP_LABEL = u"Label"; +constexpr OUStringLiteral FM_PROP_CONTROLSOURCE = u"DataField"; +constexpr OUStringLiteral FM_PROP_NAME = u"Name"; + +static Reference< XConnection > getConnection(const OUString& _rURL) +{ + // first get the sdb::DataSource corresponding to the url + Reference< XDataSource > xDataSource; + // is it a favorite title ? + Reference xContext = comphelper::getProcessComponentContext(); + Reference< XDatabaseContext > xNamingContext = DatabaseContext::create(xContext); + if (xNamingContext->hasByName(_rURL)) + { + DBG_ASSERT(xNamingContext.is(), "::getDataSource : no NamingService interface on the sdb::DatabaseAccessContext !"); + try + { + xDataSource.set(xNamingContext->getRegisteredObject(_rURL), UNO_QUERY); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.biblio", ""); + } + } + // build the connection from the data source + Reference< XConnection > xConn; + if (xDataSource.is()) + { + // need user/pwd for this + Reference< XCompletedConnection > xComplConn(xDataSource, UNO_QUERY); + try + { + Reference xIHdl( task::InteractionHandler::createWithParent(xContext, nullptr), UNO_QUERY_THROW); + xConn = xComplConn->connectWithCompletion(xIHdl); + } + catch (const SQLException&) + { + // TODO : a real error handling + } + catch (const Exception&) + { + } + } + return xConn; +} + +static Reference< XConnection > getConnection(const Reference< XInterface > & xRowSet) +{ + Reference< XConnection > xConn; + try + { + Reference< XPropertySet > xFormProps(xRowSet, UNO_QUERY); + if (!xFormProps.is()) + return xConn; + + xConn.set(xFormProps->getPropertyValue("ActiveConnection"), UNO_QUERY); + if (!xConn.is()) + { + SAL_INFO("extensions.biblio", "no active connection"); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.biblio", ""); + } + + return xConn; +} + +static Reference< XNameAccess > getColumns(const Reference< XForm > & _rxForm) +{ + Reference< XNameAccess > xReturn; + // check if the form is alive + Reference< XColumnsSupplier > xSupplyCols( _rxForm, UNO_QUERY ); + if (xSupplyCols.is()) + xReturn = xSupplyCols->getColumns(); + + if (!xReturn.is() || !xReturn->getElementNames().hasElements()) + { // no... + xReturn = nullptr; + // -> get the table the form is bound to and ask it for their columns + Reference< XTablesSupplier > xSupplyTables( getConnection( _rxForm ), UNO_QUERY ); + Reference< XPropertySet > xFormProps( _rxForm, UNO_QUERY ); + if (xFormProps.is() && xSupplyTables.is()) + { + try + { + DBG_ASSERT(*o3tl::forceAccess(xFormProps->getPropertyValue("CommandType")) == CommandType::TABLE, + "::getColumns : invalid form (has no table as data source) !"); + OUString sTable; + xFormProps->getPropertyValue("Command") >>= sTable; + Reference< XNameAccess > xTables = xSupplyTables->getTables(); + if (xTables.is() && xTables->hasByName(sTable)) + xSupplyCols.set(xTables->getByName(sTable), UNO_QUERY); + if (xSupplyCols.is()) + xReturn = xSupplyCols->getColumns(); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.biblio", "::getColumns"); + } + + } + } + return xReturn; +} + +namespace { + +class MappingDialog_Impl : public weld::GenericDialogController +{ + BibDataManager* pDatMan; + + OUString sNone; + bool bModified; + + std::unique_ptr m_xOKBT; + std::unique_ptr m_xIdentifierLB; + std::unique_ptr m_xAuthorityTypeLB; + std::unique_ptr m_xAuthorLB; + std::unique_ptr m_xTitleLB; + std::unique_ptr m_xMonthLB; + std::unique_ptr m_xYearLB; + std::unique_ptr m_xISBNLB; + std::unique_ptr m_xBooktitleLB; + std::unique_ptr m_xChapterLB; + std::unique_ptr m_xEditionLB; + std::unique_ptr m_xEditorLB; + std::unique_ptr m_xHowpublishedLB; + std::unique_ptr m_xInstitutionLB; + std::unique_ptr m_xJournalLB; + std::unique_ptr m_xNoteLB; + std::unique_ptr m_xAnnoteLB; + std::unique_ptr m_xNumberLB; + std::unique_ptr m_xOrganizationsLB; + std::unique_ptr m_xPagesLB; + std::unique_ptr m_xPublisherLB; + std::unique_ptr m_xAddressLB; + std::unique_ptr m_xSchoolLB; + std::unique_ptr m_xSeriesLB; + std::unique_ptr m_xReportTypeLB; + std::unique_ptr m_xVolumeLB; + std::unique_ptr m_xURLLB; + std::unique_ptr m_xCustom1LB; + std::unique_ptr m_xCustom2LB; + std::unique_ptr m_xCustom3LB; + std::unique_ptr m_xCustom4LB; + std::unique_ptr m_xCustom5LB; + std::unique_ptr m_xLocalURLLB; + weld::ComboBox* aListBoxes[COLUMN_COUNT]; + + DECL_LINK(OkHdl, weld::Button&, void); + DECL_LINK(ListBoxSelectHdl, weld::ComboBox&, void); + +public: + MappingDialog_Impl(weld::Window* pParent, BibDataManager* pDatMan); +}; + +} + +static sal_uInt16 lcl_FindLogicalName(BibConfig const * pConfig , + std::u16string_view rLogicalColumnName) +{ + for(sal_uInt16 i = 0; i < COLUMN_COUNT; i++) + { + if(rLogicalColumnName == pConfig->GetDefColumnName(i)) + return i; + } + return USHRT_MAX; +} + +MappingDialog_Impl::MappingDialog_Impl(weld::Window* pParent, BibDataManager* pMan) + : GenericDialogController(pParent, "modules/sbibliography/ui/mappingdialog.ui", "MappingDialog") + , pDatMan(pMan) + , sNone(BibResId(RID_BIB_STR_NONE)) + , bModified(false) + , m_xOKBT(m_xBuilder->weld_button("ok")) + , m_xIdentifierLB(m_xBuilder->weld_combo_box("identifierCombobox")) + , m_xAuthorityTypeLB(m_xBuilder->weld_combo_box("authorityTypeCombobox")) + , m_xAuthorLB(m_xBuilder->weld_combo_box("authorCombobox")) + , m_xTitleLB(m_xBuilder->weld_combo_box("titleCombobox")) + , m_xMonthLB(m_xBuilder->weld_combo_box("monthCombobox")) + , m_xYearLB(m_xBuilder->weld_combo_box("yearCombobox")) + , m_xISBNLB(m_xBuilder->weld_combo_box("ISBNCombobox")) + , m_xBooktitleLB(m_xBuilder->weld_combo_box("bookTitleCombobox")) + , m_xChapterLB(m_xBuilder->weld_combo_box("chapterCombobox")) + , m_xEditionLB(m_xBuilder->weld_combo_box("editionCombobox")) + , m_xEditorLB(m_xBuilder->weld_combo_box("editorCombobox")) + , m_xHowpublishedLB(m_xBuilder->weld_combo_box("howPublishedCombobox")) + , m_xInstitutionLB(m_xBuilder->weld_combo_box("institutionCombobox")) + , m_xJournalLB(m_xBuilder->weld_combo_box("journalCombobox")) + , m_xNoteLB(m_xBuilder->weld_combo_box("noteCombobox")) + , m_xAnnoteLB(m_xBuilder->weld_combo_box("annoteCombobox")) + , m_xNumberLB(m_xBuilder->weld_combo_box("numberCombobox")) + , m_xOrganizationsLB(m_xBuilder->weld_combo_box("organizationCombobox")) + , m_xPagesLB(m_xBuilder->weld_combo_box("pagesCombobox")) + , m_xPublisherLB(m_xBuilder->weld_combo_box("publisherCombobox")) + , m_xAddressLB(m_xBuilder->weld_combo_box("addressCombobox")) + , m_xSchoolLB(m_xBuilder->weld_combo_box("schoolCombobox")) + , m_xSeriesLB(m_xBuilder->weld_combo_box("seriesCombobox")) + , m_xReportTypeLB(m_xBuilder->weld_combo_box("reportTypeCombobox")) + , m_xVolumeLB(m_xBuilder->weld_combo_box("volumeCombobox")) + , m_xURLLB(m_xBuilder->weld_combo_box("URLCombobox")) + , m_xCustom1LB(m_xBuilder->weld_combo_box("custom1Combobox")) + , m_xCustom2LB(m_xBuilder->weld_combo_box("custom2Combobox")) + , m_xCustom3LB(m_xBuilder->weld_combo_box("custom3Combobox")) + , m_xCustom4LB(m_xBuilder->weld_combo_box("custom4Combobox")) + , m_xCustom5LB(m_xBuilder->weld_combo_box("custom5Combobox")) + , m_xLocalURLLB(m_xBuilder->weld_combo_box("LocalURLCombobox")) +{ + m_xOKBT->connect_clicked(LINK(this, MappingDialog_Impl, OkHdl)); + OUString sTitle = m_xDialog->get_title(); + sTitle = sTitle.replaceFirst("%1", pDatMan->getActiveDataTable()); + m_xDialog->set_title(sTitle); + + aListBoxes[0] = m_xIdentifierLB.get(); + aListBoxes[1] = m_xAuthorityTypeLB.get(); + aListBoxes[2] = m_xAuthorLB.get(); + aListBoxes[3] = m_xTitleLB.get(); + aListBoxes[4] = m_xYearLB.get(); + aListBoxes[5] = m_xISBNLB.get(); + aListBoxes[6] = m_xBooktitleLB.get(); + aListBoxes[7] = m_xChapterLB.get(); + aListBoxes[8] = m_xEditionLB.get(); + aListBoxes[9] = m_xEditorLB.get(); + aListBoxes[10] = m_xHowpublishedLB.get(); + aListBoxes[11] = m_xInstitutionLB.get(); + aListBoxes[12] = m_xJournalLB.get(); + aListBoxes[13] = m_xMonthLB.get(); + aListBoxes[14] = m_xNoteLB.get(); + aListBoxes[15] = m_xAnnoteLB.get(); + aListBoxes[16] = m_xNumberLB.get(); + aListBoxes[17] = m_xOrganizationsLB.get(); + aListBoxes[18] = m_xPagesLB.get(); + aListBoxes[19] = m_xPublisherLB.get(); + aListBoxes[20] = m_xAddressLB.get(); + aListBoxes[21] = m_xSchoolLB.get(); + aListBoxes[22] = m_xSeriesLB.get(); + aListBoxes[23] = m_xReportTypeLB.get(); + aListBoxes[24] = m_xVolumeLB.get(); + aListBoxes[25] = m_xURLLB.get(); + aListBoxes[26] = m_xCustom1LB.get(); + aListBoxes[27] = m_xCustom2LB.get(); + aListBoxes[28] = m_xCustom3LB.get(); + aListBoxes[29] = m_xCustom4LB.get(); + aListBoxes[30] = m_xCustom5LB.get(); + aListBoxes[31] = m_xLocalURLLB.get(); + + aListBoxes[0]->append_text(sNone); + Reference< XNameAccess > xFields = getColumns( pDatMan->getForm() ); + DBG_ASSERT(xFields.is(), "MappingDialog_Impl::MappingDialog_Impl : gave me an invalid form !"); + if (xFields.is()) + { + const Sequence aFieldNames = xFields->getElementNames(); + for(const OUString& rName : aFieldNames) + aListBoxes[0]->append_text(rName); + } + + Link aLnk = LINK(this, MappingDialog_Impl, ListBoxSelectHdl); + + aListBoxes[0]->set_active(0); + aListBoxes[0]->connect_changed(aLnk); + for(sal_uInt16 i = 1; i < COLUMN_COUNT; i++) + { + for(sal_Int32 j = 0, nEntryCount = aListBoxes[0]->get_count(); j < nEntryCount; ++j) + aListBoxes[i]->append_text(aListBoxes[0]->get_text(j)); + aListBoxes[i]->set_active(0); + aListBoxes[i]->connect_changed(aLnk); + } + BibConfig* pConfig = BibModul::GetConfig(); + BibDBDescriptor aDesc; + aDesc.sDataSource = pDatMan->getActiveDataSource(); + aDesc.sTableOrQuery = pDatMan->getActiveDataTable(); + aDesc.nCommandType = CommandType::TABLE; + const Mapping* pMapping = pConfig->GetMapping(aDesc); + if(pMapping) + { + for(const auto & aColumnPair : pMapping->aColumnPairs) + { + sal_uInt16 nListBoxIndex = lcl_FindLogicalName( pConfig, aColumnPair.sLogicalColumnName); + if(nListBoxIndex < COLUMN_COUNT) + { + aListBoxes[nListBoxIndex]->set_active_text(aColumnPair.sRealColumnName); + } + } + } +} + +IMPL_LINK(MappingDialog_Impl, ListBoxSelectHdl, weld::ComboBox&, rListBox, void) +{ + const sal_Int32 nEntryPos = rListBox.get_active(); + if (0 < nEntryPos) + { + for(auto & pListBoxe : aListBoxes) + { + if (&rListBox != pListBoxe && pListBoxe->get_active() == nEntryPos) + pListBoxe->set_active(0); + } + } + bModified = true; +} + +IMPL_LINK_NOARG(MappingDialog_Impl, OkHdl, weld::Button&, void) +{ + if(bModified) + { + Mapping aNew; + aNew.sTableName = pDatMan->getActiveDataTable(); + aNew.sURL = pDatMan->getActiveDataSource(); + + sal_uInt16 nWriteIndex = 0; + BibConfig* pConfig = BibModul::GetConfig(); + for(sal_uInt16 nEntry = 0; nEntry < COLUMN_COUNT; nEntry++) + { + OUString sSel = aListBoxes[nEntry]->get_active_text(); + if(sSel != sNone) + { + aNew.aColumnPairs[nWriteIndex].sRealColumnName = sSel; + aNew.aColumnPairs[nWriteIndex].sLogicalColumnName = pConfig->GetDefColumnName(nEntry); + nWriteIndex++; + } + } + BibDBDescriptor aDesc; + aDesc.sDataSource = pDatMan->getActiveDataSource(); + aDesc.sTableOrQuery = pDatMan->getActiveDataTable(); + aDesc.nCommandType = CommandType::TABLE; + pDatMan->ResetIdentifierMapping(); + pConfig->SetMapping(aDesc, &aNew); + } + m_xDialog->response(bModified ? RET_OK : RET_CANCEL); +} + +namespace { + +class DBChangeDialog_Impl : public weld::GenericDialogController +{ + DBChangeDialogConfig_Impl aConfig; + + std::unique_ptr m_xSelectionLB; + + DECL_LINK(DoubleClickHdl, weld::TreeView&, bool); +public: + DBChangeDialog_Impl(weld::Window* pParent, const BibDataManager* pMan); + + OUString GetCurrentURL()const; +}; + +} + +DBChangeDialog_Impl::DBChangeDialog_Impl(weld::Window* pParent, const BibDataManager* pDatMan ) + : GenericDialogController(pParent, "modules/sbibliography/ui/choosedatasourcedialog.ui", "ChooseDataSourceDialog") + , m_xSelectionLB(m_xBuilder->weld_tree_view("treeview")) +{ + m_xSelectionLB->set_size_request(-1, m_xSelectionLB->get_height_rows(6)); + m_xSelectionLB->connect_row_activated(LINK(this, DBChangeDialog_Impl, DoubleClickHdl)); + m_xSelectionLB->make_sorted(); + + try + { + OUString sActiveSource = pDatMan->getActiveDataSource(); + for (const OUString& rSourceName : aConfig.GetDataSourceNames()) + m_xSelectionLB->append_text(rSourceName); + m_xSelectionLB->select_text(sActiveSource); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.biblio", ""); + } +} + +IMPL_LINK_NOARG(DBChangeDialog_Impl, DoubleClickHdl, weld::TreeView&, bool) +{ + m_xDialog->response(RET_OK); + return true; +} + +OUString DBChangeDialog_Impl::GetCurrentURL()const +{ + return m_xSelectionLB->get_selected_text(); +} + +// XDispatchProvider +BibInterceptorHelper::BibInterceptorHelper( const ::bib::BibBeamer* pBibBeamer, css::uno::Reference< css::frame::XDispatch > const & xDispatch) +{ + if( pBibBeamer ) + { + xInterception = pBibBeamer->getDispatchProviderInterception(); + if( xInterception.is() ) + xInterception->registerDispatchProviderInterceptor( this ); + } + if( xDispatch.is() ) + xFormDispatch = xDispatch; +} + +BibInterceptorHelper::~BibInterceptorHelper( ) +{ +} + +void BibInterceptorHelper::ReleaseInterceptor() +{ + if ( xInterception.is() ) + xInterception->releaseDispatchProviderInterceptor( this ); + xInterception.clear(); +} + +css::uno::Reference< css::frame::XDispatch > SAL_CALL + BibInterceptorHelper::queryDispatch( const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags ) +{ + Reference< XDispatch > xReturn; + + OUString aCommand( aURL.Path ); + if ( aCommand == "FormSlots/ConfirmDeletion" ) + xReturn = xFormDispatch; + else + if ( xSlaveDispatchProvider.is() ) + xReturn = xSlaveDispatchProvider->queryDispatch( aURL, aTargetFrameName, nSearchFlags); + + return xReturn; +} + +css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL + BibInterceptorHelper::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& aDescripts ) +{ + Sequence< Reference< XDispatch> > aReturn( aDescripts.getLength() ); + Reference< XDispatch >* pReturn = aReturn.getArray(); + for ( const DispatchDescriptor& rDescript : aDescripts ) + { + *pReturn++ = queryDispatch( rDescript.FeatureURL, rDescript.FrameName, rDescript.SearchFlags ); + } + return aReturn; +} + +// XDispatchProviderInterceptor +css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL + BibInterceptorHelper::getSlaveDispatchProvider( ) +{ + return xSlaveDispatchProvider; +} + +void SAL_CALL BibInterceptorHelper::setSlaveDispatchProvider( const css::uno::Reference< css::frame::XDispatchProvider >& xNewSlaveDispatchProvider ) +{ + xSlaveDispatchProvider = xNewSlaveDispatchProvider; +} + +css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL + BibInterceptorHelper::getMasterDispatchProvider( ) +{ + return xMasterDispatchProvider; +} + +void SAL_CALL BibInterceptorHelper::setMasterDispatchProvider( const css::uno::Reference< css::frame::XDispatchProvider >& xNewMasterDispatchProvider ) +{ + xMasterDispatchProvider = xNewMasterDispatchProvider; +} + + +constexpr OUStringLiteral gGridName(u"theGrid"); + +BibDataManager::BibDataManager() + :BibDataManager_Base( GetMutex() ) + ,m_aLoadListeners(m_aMutex) + ,pBibView( nullptr ) + ,pToolbar(nullptr) +{ +} + + +BibDataManager::~BibDataManager() +{ + Reference< XLoadable > xLoad( m_xForm, UNO_QUERY ); + Reference< XPropertySet > xPrSet( m_xForm, UNO_QUERY ); + Reference< XComponent > xComp( m_xForm, UNO_QUERY ); + if ( m_xForm.is() ) + { + Reference< XComponent > xConnection; + xPrSet->getPropertyValue("ActiveConnection") >>= xConnection; + if (xLoad.is()) + xLoad->unload(); + if (xComp.is()) + xComp->dispose(); + if(xConnection.is()) + xConnection->dispose(); + m_xForm = nullptr; + } + if( m_xInterceptorHelper.is() ) + { + m_xInterceptorHelper->ReleaseInterceptor(); + m_xInterceptorHelper.clear(); + } +} + +void BibDataManager::InsertFields(const Reference< XFormComponent > & _rxGrid) +{ + if ( !_rxGrid.is() ) + return; + + try + { + Reference< XNameContainer > xColContainer( _rxGrid, UNO_QUERY ); + // remove the old fields + if ( xColContainer->hasElements() ) + { + const Sequence aOldNames = xColContainer->getElementNames(); + for ( const OUString& rName : aOldNames ) + xColContainer->removeByName( rName ); + } + + Reference< XNameAccess > xFields = getColumns( m_xForm ); + if (!xFields.is()) + return; + + Reference< XGridColumnFactory > xColFactory( _rxGrid, UNO_QUERY ); + + Reference< XPropertySet > xField; + + const Sequence aFieldNames = xFields->getElementNames(); + for ( const OUString& rField : aFieldNames ) + { + xFields->getByName( rField ) >>= xField; + + OUString sCurrentModelType; + sal_Int32 nType = 0; + bool bIsFormatted = false; + bool bFormattedIsNumeric = true; + xField->getPropertyValue("Type") >>= nType; + switch(nType) + { + case DataType::BIT: + case DataType::BOOLEAN: + sCurrentModelType = "CheckBox"; + break; + + case DataType::BINARY: + case DataType::VARBINARY: + case DataType::LONGVARBINARY: + case DataType::BLOB: + sCurrentModelType = "TextField"; + break; + + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + case DataType::CHAR: + case DataType::CLOB: + bFormattedIsNumeric = false; + [[fallthrough]]; + default: + sCurrentModelType = "FormattedField"; + bIsFormatted = true; + break; + } + + Reference< XPropertySet > xCurrentCol = xColFactory->createColumn(sCurrentModelType); + if (bIsFormatted) + { + OUString sFormatKey("FormatKey"); + xCurrentCol->setPropertyValue(sFormatKey, xField->getPropertyValue(sFormatKey)); + Any aFormatted(bFormattedIsNumeric); + xCurrentCol->setPropertyValue("TreatAsNumber", aFormatted); + } + Any aColName( rField ); + xCurrentCol->setPropertyValue(FM_PROP_CONTROLSOURCE, aColName); + xCurrentCol->setPropertyValue(FM_PROP_LABEL, aColName); + + xColContainer->insertByName( rField, Any( xCurrentCol ) ); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.biblio", ""); + } +} + +Reference< awt::XControlModel > BibDataManager::updateGridModel() +{ + return updateGridModel( m_xForm ); +} + +Reference< awt::XControlModel > const & BibDataManager::updateGridModel(const Reference< XForm > & xDbForm) +{ + try + { + Reference< XPropertySet > aFormPropSet( xDbForm, UNO_QUERY ); + OUString sName; + aFormPropSet->getPropertyValue("Command") >>= sName; + + if ( !m_xGridModel.is() ) + { + m_xGridModel = createGridModel( gGridName ); + + Reference< XNameContainer > xNameCont(xDbForm, UNO_QUERY); + xNameCont->insertByName( sName, Any( m_xGridModel ) ); + } + + // insert the fields + Reference< XFormComponent > xFormComp( m_xGridModel, UNO_QUERY ); + InsertFields( xFormComp ); + } + catch (const Exception&) + { + OSL_FAIL("::updateGridModel: something went wrong !"); + } + + return m_xGridModel; +} + +Reference< XForm > BibDataManager::createDatabaseForm(BibDBDescriptor& rDesc) +{ + Reference< XForm > xResult; + try + { + Reference< XMultiServiceFactory > xMgr = comphelper::getProcessServiceFactory(); + m_xForm.set( xMgr->createInstance( "com.sun.star.form.component.Form" ), UNO_QUERY ); + + Reference< XPropertySet > aPropertySet( m_xForm, UNO_QUERY ); + + aDataSourceURL = rDesc.sDataSource; + if(aPropertySet.is()) + { + Any aVal; + aVal <<= sal_Int32(ResultSetType::SCROLL_INSENSITIVE); + aPropertySet->setPropertyValue("ResultSetType",aVal ); + aVal <<= sal_Int32(ResultSetConcurrency::READ_ONLY); + aPropertySet->setPropertyValue("ResultSetConcurrency", aVal); + + //Caching for Performance + aVal <<= sal_Int32(50); + aPropertySet->setPropertyValue("FetchSize", aVal); + + Reference< XConnection > xConnection = getConnection(rDesc.sDataSource); + aVal <<= xConnection; + aPropertySet->setPropertyValue("ActiveConnection", aVal); + + Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY); + Reference< XNameAccess > xTables = xSupplyTables.is() ? + xSupplyTables->getTables() : Reference< XNameAccess > (); + + Sequence< OUString > aTableNameSeq; + if (xTables.is()) + aTableNameSeq = xTables->getElementNames(); + + if(aTableNameSeq.hasElements()) + { + if(!rDesc.sTableOrQuery.isEmpty()) + aActiveDataTable = rDesc.sTableOrQuery; + else + { + rDesc.sTableOrQuery = aActiveDataTable = aTableNameSeq[0]; + rDesc.nCommandType = CommandType::TABLE; + } + + aVal <<= aActiveDataTable; + aPropertySet->setPropertyValue("Command", aVal); + aVal <<= rDesc.nCommandType; + aPropertySet->setPropertyValue("CommandType", aVal); + + + Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + aQuoteChar = xMetaData->getIdentifierQuoteString(); + + Reference< XMultiServiceFactory > xFactory(xConnection, UNO_QUERY); + if ( xFactory.is() ) + m_xParser.set( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"), UNO_QUERY ); + + OUString aString("SELECT * FROM "); + + OUString sCatalog, sSchema, sName; + ::dbtools::qualifiedNameComponents( xMetaData, aActiveDataTable, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation ); + aString += ::dbtools::composeTableNameForSelect( xConnection, sCatalog, sSchema, sName ); + + m_xParser->setElementaryQuery(aString); + BibConfig* pConfig = BibModul::GetConfig(); + pConfig->setQueryField(getQueryField()); + startQueryWith(pConfig->getQueryText()); + + xResult = m_xForm; + } + } + } + catch (const Exception&) + { + OSL_FAIL("::createDatabaseForm: something went wrong !"); + } + + return xResult; +} + +Sequence< OUString > BibDataManager::getDataSources() const +{ + Sequence< OUString > aTableNameSeq; + + try + { + Reference< XTablesSupplier > xSupplyTables( getConnection( m_xForm ), UNO_QUERY ); + Reference< XNameAccess > xTables; + if (xSupplyTables.is()) + xTables = xSupplyTables->getTables(); + if (xTables.is()) + aTableNameSeq = xTables->getElementNames(); + } + catch (const Exception&) + { + OSL_FAIL("::getDataSources: something went wrong !"); + } + + return aTableNameSeq; +} + + +void BibDataManager::setFilter(const OUString& rQuery) +{ + if(!m_xParser.is()) + return; + try + { + m_xParser->setFilter( rQuery ); + OUString aQuery = m_xParser->getFilter(); + Reference< XPropertySet > xFormProps( m_xForm, UNO_QUERY_THROW ); + xFormProps->setPropertyValue( "Filter", Any( aQuery ) ); + xFormProps->setPropertyValue( "ApplyFilter", Any( true ) ); + reload(); + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("extensions.biblio"); + } + + +} + +OUString BibDataManager::getFilter() const +{ + + OUString aQueryString; + try + { + Reference< XPropertySet > xFormProps( m_xForm, UNO_QUERY_THROW ); + OSL_VERIFY( xFormProps->getPropertyValue( "Filter" ) >>= aQueryString ); + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("extensions.biblio"); + } + + + return aQueryString; + +} + +Sequence< OUString > BibDataManager::getQueryFields() const +{ + Sequence< OUString > aFieldSeq; + Reference< XNameAccess > xFields = getColumns( m_xForm ); + if (xFields.is()) + aFieldSeq = xFields->getElementNames(); + return aFieldSeq; +} + +OUString BibDataManager::getQueryField() const +{ + BibConfig* pConfig = BibModul::GetConfig(); + OUString aFieldString = pConfig->getQueryField(); + if(aFieldString.isEmpty()) + { + const Sequence< OUString > aSeq = getQueryFields(); + if(aSeq.hasElements()) + { + aFieldString=aSeq[0]; + } + } + return aFieldString; +} + +void BibDataManager::startQueryWith(const OUString& rQuery) +{ + BibConfig* pConfig = BibModul::GetConfig(); + pConfig->setQueryText( rQuery ); + + OUString aQueryString; + if(!rQuery.isEmpty()) + { + aQueryString=aQuoteChar + getQueryField() + aQuoteChar + " like '"; + OUString sQuery = rQuery.replaceAll("?","_").replaceAll("*","%"); + aQueryString += sQuery + "%'"; + } + setFilter(aQueryString); +} + +void BibDataManager::setActiveDataSource(const OUString& rURL) +{ + OUString sTmp(aDataSourceURL); + aDataSourceURL = rURL; + + Reference< XPropertySet > aPropertySet( m_xForm, UNO_QUERY ); + if(!aPropertySet.is()) + return; + + unload(); + + Reference< XComponent > xOldConnection; + aPropertySet->getPropertyValue("ActiveConnection") >>= xOldConnection; + + Reference< XConnection > xConnection = getConnection(rURL); + if(!xConnection.is()) + { + aDataSourceURL = sTmp; + return; + } + Any aVal; aVal <<= xConnection; + aPropertySet->setPropertyValue("ActiveConnection", aVal); + Reference< XMultiServiceFactory > xFactory(xConnection, UNO_QUERY); + if ( xFactory.is() ) + m_xParser.set( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"), UNO_QUERY ); + + if(xOldConnection.is()) + xOldConnection->dispose(); + + Sequence< OUString > aTableNameSeq; + Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY); + if(xSupplyTables.is()) + { + Reference< XNameAccess > xAccess = xSupplyTables->getTables(); + aTableNameSeq = xAccess->getElementNames(); + } + if(aTableNameSeq.hasElements()) + { + aActiveDataTable = aTableNameSeq[0]; + aVal <<= aActiveDataTable; + aPropertySet->setPropertyValue("Command", aVal); + aPropertySet->setPropertyValue("CommandType", Any(CommandType::TABLE)); + //Caching for Performance + aVal <<= sal_Int32(50); + aPropertySet->setPropertyValue("FetchSize", aVal); + OUString aString("SELECT * FROM "); + // quote the table name which may contain catalog.schema.table + Reference xMetaData = xConnection->getMetaData(); + aQuoteChar = xMetaData->getIdentifierQuoteString(); + + OUString sCatalog, sSchema, sName; + ::dbtools::qualifiedNameComponents( xMetaData, aActiveDataTable, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation ); + aString += ::dbtools::composeTableNameForSelect( xConnection, sCatalog, sSchema, sName ); + + m_xParser->setElementaryQuery(aString); + BibConfig* pConfig = BibModul::GetConfig(); + pConfig->setQueryField(getQueryField()); + startQueryWith(pConfig->getQueryText()); + setActiveDataTable(aActiveDataTable); + } + FeatureStateEvent aEvent; + util::URL aURL; + aEvent.IsEnabled = true; + aEvent.Requery = false; + aEvent.FeatureDescriptor = getActiveDataTable(); + + aEvent.State <<= getDataSources(); + + if(pToolbar) + { + aURL.Complete =".uno:Bib/source"; + aEvent.FeatureURL = aURL; + pToolbar->statusChanged( aEvent ); + } + + updateGridModel(); + load(); +} + + +void BibDataManager::setActiveDataTable(const OUString& rTable) +{ + ResetIdentifierMapping(); + try + { + Reference< XPropertySet > aPropertySet( m_xForm, UNO_QUERY ); + + if(aPropertySet.is()) + { + Reference< XConnection > xConnection = getConnection( m_xForm ); + Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY); + Reference< XNameAccess > xAccess = xSupplyTables->getTables(); + Sequence< OUString > aTableNameSeq = xAccess->getElementNames(); + sal_uInt32 nCount = aTableNameSeq.getLength(); + + const OUString* pTableNames = aTableNameSeq.getConstArray(); + const OUString* pTableNamesEnd = pTableNames + nCount; + + for ( ; pTableNames != pTableNamesEnd; ++pTableNames ) + { + if ( rTable == *pTableNames ) + { + aActiveDataTable = rTable; + Any aVal; aVal <<= rTable; + aPropertySet->setPropertyValue( "Command", aVal ); + break; + } + } + if (pTableNames != pTableNamesEnd) + { + Reference< XDatabaseMetaData > xMetaData = xConnection->getMetaData(); + aQuoteChar = xMetaData->getIdentifierQuoteString(); + + Reference< XMultiServiceFactory > xFactory(xConnection, UNO_QUERY); + if ( xFactory.is() ) + m_xParser.set( xFactory->createInstance("com.sun.star.sdb.SingleSelectQueryComposer"), UNO_QUERY ); + + OUString aString("SELECT * FROM "); + + OUString sCatalog, sSchema, sName; + ::dbtools::qualifiedNameComponents( xMetaData, aActiveDataTable, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation ); + aString += ::dbtools::composeTableNameForSelect( xConnection, sCatalog, sSchema, sName ); + + m_xParser->setElementaryQuery(aString); + + BibConfig* pConfig = BibModul::GetConfig(); + pConfig->setQueryField(getQueryField()); + startQueryWith(pConfig->getQueryText()); + + BibDBDescriptor aDesc; + aDesc.sDataSource = aDataSourceURL; + aDesc.sTableOrQuery = aActiveDataTable; + aDesc.nCommandType = CommandType::TABLE; + BibModul::GetConfig()->SetBibliographyURL(aDesc); + } + } + } + catch (const Exception&) + { + OSL_FAIL("::setActiveDataTable: something went wrong !"); + } +} + + +void SAL_CALL BibDataManager::load( ) +{ + if ( isLoaded() ) + // nothing to do + return; + + Reference< XLoadable > xFormAsLoadable( m_xForm, UNO_QUERY ); + DBG_ASSERT( xFormAsLoadable.is() || !m_xForm.is(), "BibDataManager::load: invalid form!"); + if ( xFormAsLoadable.is() ) + { + xFormAsLoadable->load(); + + EventObject aEvt( static_cast< XWeak* >( this ) ); + m_aLoadListeners.notifyEach( &XLoadListener::loaded, aEvt ); + } +} + + +void SAL_CALL BibDataManager::unload( ) +{ + if ( !isLoaded() ) + // nothing to do + return; + + Reference< XLoadable >xFormAsLoadable( m_xForm, UNO_QUERY ); + DBG_ASSERT( xFormAsLoadable.is() || !m_xForm.is(), "BibDataManager::unload: invalid form!"); + if ( !xFormAsLoadable.is() ) + return; + + EventObject aEvt( static_cast< XWeak* >( this ) ); + + { + m_aLoadListeners.notifyEach( &XLoadListener::unloading, aEvt ); + } + + xFormAsLoadable->unload(); + + { + m_aLoadListeners.notifyEach( &XLoadListener::unloaded, aEvt ); + } +} + + +void SAL_CALL BibDataManager::reload( ) +{ + if ( !isLoaded() ) + // nothing to do + return; + + Reference< XLoadable >xFormAsLoadable( m_xForm, UNO_QUERY ); + DBG_ASSERT( xFormAsLoadable.is() || !m_xForm.is(), "BibDataManager::unload: invalid form!"); + if ( !xFormAsLoadable.is() ) + return; + + EventObject aEvt( static_cast< XWeak* >( this ) ); + + { + m_aLoadListeners.notifyEach( &XLoadListener::reloading, aEvt ); + } + + xFormAsLoadable->reload(); + + { + m_aLoadListeners.notifyEach( &XLoadListener::reloaded, aEvt ); + } +} + + +sal_Bool SAL_CALL BibDataManager::isLoaded( ) +{ + Reference< XLoadable >xFormAsLoadable( m_xForm, UNO_QUERY ); + DBG_ASSERT( xFormAsLoadable.is() || !m_xForm.is(), "BibDataManager::isLoaded: invalid form!"); + + bool bLoaded = false; + if ( xFormAsLoadable.is() ) + bLoaded = xFormAsLoadable->isLoaded(); + return bLoaded; +} + + +void SAL_CALL BibDataManager::addLoadListener( const Reference< XLoadListener >& aListener ) +{ + m_aLoadListeners.addInterface( aListener ); +} + + +void SAL_CALL BibDataManager::removeLoadListener( const Reference< XLoadListener >& aListener ) +{ + m_aLoadListeners.removeInterface( aListener ); +} + + +Reference< awt::XControlModel > BibDataManager::createGridModel(const OUString& rName) +{ + Reference< awt::XControlModel > xModel; + + try + { + // create the control model + Reference< XMultiServiceFactory > xMgr = ::comphelper::getProcessServiceFactory(); + Reference< XInterface > xObject = xMgr->createInstance("com.sun.star.form.component.GridControl"); + xModel.set( xObject, UNO_QUERY ); + + // set the + Reference< XPropertySet > xPropSet( xModel, UNO_QUERY ); + xPropSet->setPropertyValue( "Name", Any( rName ) ); + + // set the name of the to-be-created control + Any aAny(OUString("com.sun.star.form.control.InteractionGridControl")); + xPropSet->setPropertyValue( "DefaultControl",aAny ); + + // the helpURL + OUString uProp("HelpURL"); + Reference< XPropertySetInfo > xPropInfo = xPropSet->getPropertySetInfo(); + if (xPropInfo->hasPropertyByName(uProp)) + { + xPropSet->setPropertyValue( + uProp, Any(OUString(INET_HID_SCHEME + HID_BIB_DB_GRIDCTRL))); + } + } + catch (const Exception&) + { + OSL_FAIL("::createGridModel: something went wrong !"); + } + + return xModel; +} + +OUString BibDataManager::getControlName(sal_Int32 nFormatKey ) +{ + OUString aResStr; + switch (nFormatKey) + { + case DataType::BIT: + case DataType::BOOLEAN: + aResStr="CheckBox"; + break; + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + aResStr="NumericField"; + break; + case DataType::REAL: + case DataType::DOUBLE: + case DataType::NUMERIC: + case DataType::DECIMAL: + aResStr="FormattedField"; + break; + case DataType::TIMESTAMP: + aResStr="FormattedField"; + break; + case DataType::DATE: + aResStr="DateField"; + break; + case DataType::TIME: + aResStr="TimeField"; + break; + case DataType::CHAR: + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + default: + aResStr="TextField"; + break; + } + return aResStr; +} + +Reference< awt::XControlModel > BibDataManager::loadControlModel( + const OUString& rName, bool bForceListBox) +{ + Reference< awt::XControlModel > xModel; + OUString aName = "View_" + rName; + + try + { + Reference< XNameAccess > xFields = getColumns( m_xForm ); + if (!xFields.is()) + return xModel; + Reference< XPropertySet > xField; + + Any aElement; + + if(xFields->hasByName(rName)) + { + aElement = xFields->getByName(rName); + aElement >>= xField; + + sal_Int32 nFormatKey = 0; + xField->getPropertyValue("Type") >>= nFormatKey; + + OUString aInstanceName("com.sun.star.form.component."); + + if (bForceListBox) + aInstanceName += "ListBox"; + else + aInstanceName += getControlName(nFormatKey); + + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + Reference< XInterface > xObject = xContext->getServiceManager()->createInstanceWithContext(aInstanceName, xContext); + xModel.set( xObject, UNO_QUERY ); + Reference< XPropertySet > xPropSet( xModel, UNO_QUERY ); + Any aFieldName; aFieldName <<= aName; + + xPropSet->setPropertyValue( FM_PROP_NAME,aFieldName); + xPropSet->setPropertyValue( FM_PROP_CONTROLSOURCE, Any( rName ) ); + xPropSet->setPropertyValue("NativeWidgetLook", Any( true ) ); + + if (bForceListBox) + { + uno::Any aAny; + + //uno::Reference< beans::XPropertySet > xPropSet(xControl, UNO_QUERY); + aAny <<= sal_Int16(1); + xPropSet->setPropertyValue("BoundColumn", aAny); + aAny <<= ListSourceType_VALUELIST; + xPropSet->setPropertyValue("ListSourceType", aAny); + + uno::Sequence aListSource(TYPE_COUNT); + OUString* pListSourceArr = aListSource.getArray(); + //pListSourceArr[0] = "select TypeName, TypeIndex from TypeNms"; + for(sal_Int32 i = 0; i < TYPE_COUNT; ++i) + pListSourceArr[i] = OUString::number(i); + aAny <<= aListSource; + + xPropSet->setPropertyValue("ListSource", aAny); + + uno::Sequence aValues(TYPE_COUNT + 1); + OUString* pValuesArr = aValues.getArray(); + pValuesArr[0] = BibResId(ST_TYPE_ARTICLE); + pValuesArr[1] = BibResId(ST_TYPE_BOOK); + pValuesArr[2] = BibResId(ST_TYPE_BOOKLET); + pValuesArr[3] = BibResId(ST_TYPE_CONFERENCE); + pValuesArr[4] = BibResId(ST_TYPE_INBOOK ); + pValuesArr[5] = BibResId(ST_TYPE_INCOLLECTION); + pValuesArr[6] = BibResId(ST_TYPE_INPROCEEDINGS); + pValuesArr[7] = BibResId(ST_TYPE_JOURNAL ); + pValuesArr[8] = BibResId(ST_TYPE_MANUAL ); + pValuesArr[9] = BibResId(ST_TYPE_MASTERSTHESIS); + pValuesArr[10] = BibResId(ST_TYPE_MISC ); + pValuesArr[11] = BibResId(ST_TYPE_PHDTHESIS ); + pValuesArr[12] = BibResId(ST_TYPE_PROCEEDINGS ); + pValuesArr[13] = BibResId(ST_TYPE_TECHREPORT ); + pValuesArr[14] = BibResId(ST_TYPE_UNPUBLISHED ); + pValuesArr[15] = BibResId(ST_TYPE_EMAIL ); + pValuesArr[16] = BibResId(ST_TYPE_WWW ); + pValuesArr[17] = BibResId(ST_TYPE_CUSTOM1 ); + pValuesArr[18] = BibResId(ST_TYPE_CUSTOM2 ); + pValuesArr[19] = BibResId(ST_TYPE_CUSTOM3 ); + pValuesArr[20] = BibResId(ST_TYPE_CUSTOM4 ); + pValuesArr[21] = BibResId(ST_TYPE_CUSTOM5 ); + // empty string if an invalid value no values is set + pValuesArr[TYPE_COUNT].clear(); + + aAny <<= aValues; + + xPropSet->setPropertyValue("StringItemList", aAny); + + xPropSet->setPropertyValue( "Dropdown", Any(true) ); + } + + Reference< XFormComponent > aFormComp(xModel,UNO_QUERY ); + + Reference< XNameContainer > xNameCont( m_xForm, UNO_QUERY ); + xNameCont->insertByName(aName, Any( aFormComp ) ); + + // now if the form where we inserted the new model is already loaded, notify the model of this + // Note that this implementation below is a HACK as it relies on the fact that the model adds itself + // as load listener to its parent, which is an implementation detail of the model. + // + // the better solution would be the following: + // in the current scenario, we insert a control model into a form. This results in the control model + // adding itself as load listener to the form. Now, the form should realize that it's already loaded + // and notify the model (which it knows as XLoadListener only) immediately. This seems to make sense. + // (as an analogon to the XStatusListener semantics). + // + // But this would be way too risky for this last-day fix here. + Reference< XLoadable > xLoad( m_xForm, UNO_QUERY ); + if ( xLoad.is() && xLoad->isLoaded() ) + { + Reference< XLoadListener > xListener( aFormComp, UNO_QUERY ); + if ( xListener.is() ) + { + EventObject aLoadSource; + aLoadSource.Source = xLoad; + xListener->loaded( aLoadSource ); + } + } + } + } + catch (const Exception&) + { + OSL_FAIL("::loadControlModel: something went wrong !"); + } + return xModel; +} + +void BibDataManager::CreateMappingDialog(weld::Window* pParent) +{ + MappingDialog_Impl aDlg(pParent, this); + if (RET_OK == aDlg.run() && pBibView) + { + reload(); + } +} + +OUString BibDataManager::CreateDBChangeDialog(weld::Window* pParent) +{ + OUString uRet; + DBChangeDialog_Impl aDlg(pParent, this); + if (aDlg.run() == RET_OK) + { + OUString sNewURL = aDlg.GetCurrentURL(); + if(sNewURL != getActiveDataSource()) + { + uRet = sNewURL; + } + } + return uRet; +} + +void BibDataManager::DispatchDBChangeDialog() +{ + if (pToolbar) + pToolbar->SendDispatch(pToolbar->GetChangeSourceId(), Sequence< PropertyValue >()); +} + +const OUString& BibDataManager::GetIdentifierMapping() +{ + if(sIdentifierMapping.isEmpty()) + { + BibConfig* pConfig = BibModul::GetConfig(); + BibDBDescriptor aDesc; + aDesc.sDataSource = getActiveDataSource(); + aDesc.sTableOrQuery = getActiveDataTable(); + aDesc.nCommandType = CommandType::TABLE; + const Mapping* pMapping = pConfig->GetMapping(aDesc); + sIdentifierMapping = pConfig->GetDefColumnName(IDENTIFIER_POS); + if(pMapping) + { + for(const auto & aColumnPair : pMapping->aColumnPairs) + { + if(aColumnPair.sLogicalColumnName == sIdentifierMapping) + { + sIdentifierMapping = aColumnPair.sRealColumnName; + break; + } + } + } + } + return sIdentifierMapping; +} + +void BibDataManager::SetToolbar(BibToolBar* pSet) +{ + pToolbar = pSet; + if(pToolbar) + pToolbar->SetDatMan(*this); +} + +uno::Reference< form::runtime::XFormController > const & BibDataManager::GetFormController() +{ + if(!m_xFormCtrl.is()) + { + Reference< uno::XComponentContext > xContext = comphelper::getProcessComponentContext(); + m_xFormCtrl = form::runtime::FormController::create(xContext); + m_xFormCtrl->setModel(uno::Reference< awt::XTabControllerModel > (getForm(), UNO_QUERY)); + m_xFormDispatch.set( m_xFormCtrl, UNO_QUERY); + } + return m_xFormCtrl; +} + +void BibDataManager::RegisterInterceptor( const ::bib::BibBeamer* pBibBeamer) +{ + DBG_ASSERT( !m_xInterceptorHelper.is(), "BibDataManager::RegisterInterceptor: called twice!" ); + + if( pBibBeamer ) + m_xInterceptorHelper = new BibInterceptorHelper( pBibBeamer, m_xFormDispatch); +} + + +bool BibDataManager::HasActiveConnection() const +{ + return getConnection( m_xForm ).is(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/datman.hxx b/extensions/source/bibliography/datman.hxx new file mode 100644 index 000000000..36cbdcd59 --- /dev/null +++ b/extensions/source/bibliography/datman.hxx @@ -0,0 +1,169 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "bibview.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace weld { class Window; } + +namespace bib +{ + class BibView; + class BibBeamer; +} + +class BibToolBar; +struct BibDBDescriptor; + +class BibInterceptorHelper + :public cppu::WeakImplHelper< css::frame::XDispatchProviderInterceptor > +{ +private: + css::uno::Reference< css::frame::XDispatchProvider > xMasterDispatchProvider; + css::uno::Reference< css::frame::XDispatchProvider > xSlaveDispatchProvider; + css::uno::Reference< css::frame::XDispatch > xFormDispatch; + css::uno::Reference< css::frame::XDispatchProviderInterception > xInterception; + +protected: + virtual ~BibInterceptorHelper( ) override; + +public: + BibInterceptorHelper( const ::bib::BibBeamer* pBibBeamer, css::uno::Reference< css::frame::XDispatch > const & xDispatch); + + void ReleaseInterceptor(); + + // XDispatchProvider + virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL queryDispatch( const css::util::URL& aURL, const OUString& aTargetFrameName, sal_Int32 nSearchFlags ) override; + virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& aDescripts ) 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 >& xNewSlaveDispatchProvider ) override; + virtual css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL getMasterDispatchProvider( ) override; + virtual void SAL_CALL setMasterDispatchProvider( const css::uno::Reference< css::frame::XDispatchProvider >& xNewMasterDispatchProvider ) override; +}; + +typedef cppu::WeakComponentImplHelper < css::form::XLoadable + > BibDataManager_Base; +class BibDataManager final + :public ::comphelper::OMutexAndBroadcastHelper + ,public BibDataManager_Base +{ +private: + css::uno::Reference< css::form::XForm > m_xForm; + css::uno::Reference< css::awt::XControlModel > m_xGridModel; + css::uno::Reference< css::sdb::XSingleSelectQueryComposer > m_xParser; + css::uno::Reference< css::form::runtime::XFormController > m_xFormCtrl; + css::uno::Reference< css::frame::XDispatch > m_xFormDispatch; + rtl::Reference m_xInterceptorHelper; + + OUString aActiveDataTable; + OUString aDataSourceURL; + OUString aQuoteChar; + + ::comphelper::OInterfaceContainerHelper2 m_aLoadListeners; + + VclPtr< ::bib::BibView> pBibView; + VclPtr pToolbar; + + OUString sIdentifierMapping; + + void InsertFields(const css::uno::Reference< css::form::XFormComponent > & xGrid); + + css::uno::Reference< css::awt::XControlModel > const & + updateGridModel(const css::uno::Reference< css::form::XForm > & xDbForm); + static css::uno::Reference< css::awt::XControlModel > + createGridModel( const OUString& rName ); + + // 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; + + using WeakComponentImplHelperBase::disposing; + +public: + + BibDataManager(); + virtual ~BibDataManager() override; + + css::uno::Reference< css::form::XForm > createDatabaseForm( BibDBDescriptor& aDesc); + + css::uno::Reference< css::awt::XControlModel > updateGridModel(); + + css::uno::Sequence< OUString> getDataSources() const; + + const OUString& getActiveDataSource() const {return aDataSourceURL;} + void setActiveDataSource(const OUString& rURL); + + const OUString& getActiveDataTable() const { return aActiveDataTable;} + void setActiveDataTable(const OUString& rTable); + + void setFilter(const OUString& rQuery); + OUString getFilter() const; + + css::uno::Sequence< OUString> getQueryFields() const; + OUString getQueryField() const; + void startQueryWith(const OUString& rQuery); + + const css::uno::Reference< css::sdb::XSingleSelectQueryComposer >& getParser() const { return m_xParser; } + const css::uno::Reference< css::form::XForm >& getForm() const { return m_xForm; } + + + static OUString getControlName(sal_Int32 nFormatKey ); + + css::uno::Reference< css::awt::XControlModel > loadControlModel(const OUString& rName, + bool bForceListBox); + + void CreateMappingDialog(weld::Window* pParent); + OUString CreateDBChangeDialog(weld::Window* pParent); + + void DispatchDBChangeDialog(); + + void SetView( ::bib::BibView* pView ) { pBibView = pView; } + + void SetToolbar(BibToolBar* pSet); + + const OUString& GetIdentifierMapping(); + void ResetIdentifierMapping() {sIdentifierMapping.clear();} + + css::uno::Reference< css::form::runtime::XFormController > const & GetFormController(); + void RegisterInterceptor( const ::bib::BibBeamer* pBibBeamer); + + bool HasActiveConnection() const; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/formcontrolcontainer.cxx b/extensions/source/bibliography/formcontrolcontainer.cxx new file mode 100644 index 000000000..c6ec73700 --- /dev/null +++ b/extensions/source/bibliography/formcontrolcontainer.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 "formcontrolcontainer.hxx" +#include +#include + +#include + +namespace bib +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::awt; + + FormControlContainer::FormControlContainer( ) + :OLoadListener( m_aMutex ) + { + } + + FormControlContainer::~FormControlContainer( ) + { + SAL_WARN_IF( isFormConnected(), "extensions.biblio", "FormControlContainer::~FormControlContainer: you should disconnect in your derived class!" ); + if ( isFormConnected() ) + disconnectForm(); + } + + void FormControlContainer::disconnectForm() + { + ::osl::MutexGuard aGuard( m_aMutex ); + SAL_WARN_IF( !isFormConnected(), "extensions.biblio", "FormControlContainer::connectForm: not connected!" ); + if ( isFormConnected() ) + { + m_xFormAdapter->dispose(); + m_xFormAdapter.clear(); + } + } + + void FormControlContainer::connectForm( const Reference< XLoadable >& _rxForm ) + { + SAL_WARN_IF( isFormConnected(), "extensions.biblio", "FormControlContainer::connectForm: already connected!" ); + + SAL_WARN_IF( !_rxForm.is(), "extensions.biblio", "FormControlContainer::connectForm: invalid form!" ); + if ( !isFormConnected() && _rxForm.is() ) + { + m_xFormAdapter = new OLoadListenerAdapter( _rxForm ); + m_xFormAdapter->Init( this ); + + implSetDesignMode( !m_xForm.is() || !m_xForm->isLoaded() ); + } + + m_xForm = _rxForm; + } + + namespace { + + struct ControlModeSwitch + { + bool bDesign; + explicit ControlModeSwitch( bool _bDesign ) : bDesign( _bDesign ) { } + + void operator() ( const Reference< XControl >& _rxControl ) const + { + if ( _rxControl.is() ) + _rxControl->setDesignMode( bDesign ); + } + }; + + } + + void FormControlContainer::implSetDesignMode( bool _bDesign ) + { + try + { + Reference< XControlContainer > xControlCont = getControlContainer(); + if ( xControlCont.is() ) + { + const Sequence> aControls = xControlCont->getControls(); + + std::for_each( + aControls.begin(), + aControls.end(), + ControlModeSwitch( _bDesign ) + ); + } + } + catch( const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.biblio", "FormControlContainer::implSetDesignMode" ); + } + } + + void FormControlContainer::_loaded( const css::lang::EventObject& /*_rEvent*/ ) + { + implSetDesignMode( false ); + } + + void FormControlContainer::_unloading( const css::lang::EventObject& /*_rEvent*/ ) + { + implSetDesignMode( true ); + } + + void FormControlContainer::_reloading( const css::lang::EventObject& /*_rEvent*/ ) + { + implSetDesignMode( true ); + } + + void FormControlContainer::_reloaded( const css::lang::EventObject& /*_rEvent*/ ) + { + implSetDesignMode( false ); + } + + +} // namespace bib + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/formcontrolcontainer.hxx b/extensions/source/bibliography/formcontrolcontainer.hxx new file mode 100644 index 000000000..b15105ad0 --- /dev/null +++ b/extensions/source/bibliography/formcontrolcontainer.hxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include "loadlisteneradapter.hxx" +#include +#include + + +namespace bib +{ + + class FormControlContainer + :public ::cppu::BaseMutex + ,public ::bib::OLoadListener + { + private: + rtl::Reference m_xFormAdapter; + css::uno::Reference< css::form::XLoadable > m_xForm; + private: + void implSetDesignMode( bool _bDesign ); + + protected: + FormControlContainer( ); + virtual ~FormControlContainer( ) override; + + bool isFormConnected() const { return m_xFormAdapter.is(); } + void connectForm( const css::uno::Reference< css::form::XLoadable >& _rxForm ); + void disconnectForm(); + + virtual css::uno::Reference< css::awt::XControlContainer > + getControlContainer() = 0; + + protected: + // XLoadListener equivalents + virtual void _loaded( const css::lang::EventObject& _rEvent ) override; + virtual void _unloading( const css::lang::EventObject& _rEvent ) override; + virtual void _reloading( const css::lang::EventObject& _rEvent ) override; + virtual void _reloaded( const css::lang::EventObject& _rEvent ) override; + + }; + + +} // namespace bib + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/framectr.cxx b/extensions/source/bibliography/framectr.cxx new file mode 100644 index 000000000..a273635d9 --- /dev/null +++ b/extensions/source/bibliography/framectr.cxx @@ -0,0 +1,869 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include "framectr.hxx" +#include "datman.hxx" +#include +#include "bibconfig.hxx" +#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 osl; +using namespace cppu; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::frame; +using namespace com::sun::star::uno; +using namespace com::sun::star; + +namespace { + +struct DispatchInfo +{ + const char* pCommand; + sal_Int16 nGroupId; + bool bActiveConnection; +}; + +struct CacheDispatchInfo +{ + sal_Int16 nGroupId; + bool bActiveConnection; +}; + +} + +// Attention: commands must be sorted by command groups. Implementation is dependent +// on this!! +const DispatchInfo SupportedCommandsArray[] = +{ + { ".uno:Undo" , frame::CommandGroup::EDIT , false }, + { ".uno:Cut" , frame::CommandGroup::EDIT , false }, + { ".uno:Copy" , frame::CommandGroup::EDIT , false }, + { ".uno:Paste" , frame::CommandGroup::EDIT , false }, + { ".uno:SelectAll" , frame::CommandGroup::EDIT , false }, + { ".uno:CloseDoc" , frame::CommandGroup::DOCUMENT , false }, + { ".uno:StatusBarVisible" , frame::CommandGroup::VIEW , false }, + { ".uno:AvailableToolbars" , frame::CommandGroup::VIEW , false }, + { ".uno:Bib/standardFilter" , frame::CommandGroup::DATA , true }, + { ".uno:Bib/DeleteRecord" , frame::CommandGroup::DATA , true }, + { ".uno:Bib/InsertRecord" , frame::CommandGroup::DATA , true }, + { ".uno:Bib/query" , frame::CommandGroup::DATA , true }, + { ".uno:Bib/autoFilter" , frame::CommandGroup::DATA , true }, + { ".uno:Bib/source" , frame::CommandGroup::DATA , true }, + { ".uno:Bib/removeFilter" , frame::CommandGroup::DATA , true }, + { ".uno:Bib/sdbsource" , frame::CommandGroup::DATA , true }, + { ".uno:Bib/Mapping" , frame::CommandGroup::DATA , true }, +}; + +typedef std::unordered_map< OUString, CacheDispatchInfo > CmdToInfoCache; + +static const CmdToInfoCache& GetCommandToInfoCache() +{ + static CmdToInfoCache aCmdToInfoCache = []() { + CmdToInfoCache aCache; + for (const auto& command : SupportedCommandsArray) + { + OUString aCommand(OUString::createFromAscii(command.pCommand)); + + CacheDispatchInfo aDispatchInfo; + aDispatchInfo.nGroupId = command.nGroupId; + aDispatchInfo.bActiveConnection = command.bActiveConnection; + aCache.emplace(aCommand, aDispatchInfo); + } + return aCache; + }(); + + return aCmdToInfoCache; +} + + +class BibFrameCtrl_Impl : public cppu::WeakImplHelper < XFrameActionListener > +{ +public: + Mutex aMutex; + comphelper::OMultiTypeInterfaceContainerHelper2 aLC; + + BibFrameController_Impl* pController; + + BibFrameCtrl_Impl() + : aLC( aMutex ) + , pController(nullptr) + {} + + virtual void SAL_CALL frameAction(const FrameActionEvent& aEvent) override; + virtual void SAL_CALL disposing( const lang::EventObject& Source ) override; +}; + +void BibFrameCtrl_Impl::frameAction(const FrameActionEvent& ) +{ +} + +void BibFrameCtrl_Impl::disposing( const lang::EventObject& /*Source*/ ) +{ + ::SolarMutexGuard aGuard; + if ( pController ) + pController->getFrame()->removeFrameActionListener( this ); +} + +BibFrameController_Impl::BibFrameController_Impl( const uno::Reference< awt::XWindow > & xComponent, + BibDataManager* pDataManager) + :m_xWindow( xComponent ) + ,m_xDatMan( pDataManager ) +{ + m_bDisposing = false; + m_xImpl = new BibFrameCtrl_Impl; + m_xImpl->pController = this; +} + +BibFrameController_Impl::~BibFrameController_Impl() +{ + m_xImpl->pController = nullptr; + m_xDatMan.clear(); +} + +OUString SAL_CALL BibFrameController_Impl::getImplementationName() +{ + return "com.sun.star.comp.extensions.Bibliography"; +} + +sal_Bool SAL_CALL BibFrameController_Impl::supportsService( const OUString& sServiceName ) +{ + return cppu::supportsService( this, sServiceName ); +} + +css::uno::Sequence< OUString > SAL_CALL BibFrameController_Impl::getSupportedServiceNames() +{ + // return only top level services ... + // base services are included there and should be asked by uno-rtti. + return { "com.sun.star.frame.Bibliography" }; +} + +void BibFrameController_Impl::attachFrame( const uno::Reference< XFrame > & xArg ) +{ + m_xFrame = xArg; + m_xFrame->addFrameActionListener( m_xImpl ); +} + +sal_Bool BibFrameController_Impl::attachModel( const uno::Reference< XModel > & /*xModel*/ ) +{ + return false; +} + +sal_Bool BibFrameController_Impl::suspend( sal_Bool bSuspend ) +{ + if ( bSuspend ) + getFrame()->removeFrameActionListener( m_xImpl ); + else + getFrame()->addFrameActionListener( m_xImpl ); + return true; +} + +uno::Any BibFrameController_Impl::getViewData() +{ + return uno::Any(); +} + +void BibFrameController_Impl::restoreViewData( const uno::Any& /*Value*/ ) +{ +} + +uno::Reference< XFrame > BibFrameController_Impl::getFrame() +{ + return m_xFrame; +} + +uno::Reference< XModel > BibFrameController_Impl::getModel() +{ + return uno::Reference< XModel > (); +} + +void BibFrameController_Impl::dispose() +{ + m_bDisposing = true; + lang::EventObject aObject; + uno::Reference< XFrame > xFrame = getFrame(); + + if (xFrame.is()) + xFrame->removeFrameActionListener( m_xImpl ); + + aObject.Source = static_cast(this); + m_xImpl->aLC.disposeAndClear(aObject); + m_xDatMan.clear(); + m_aStatusListeners.clear(); + m_xLastQueriedFocusWin.clear(); +} + +void BibFrameController_Impl::addEventListener( const uno::Reference< lang::XEventListener > & aListener ) +{ + m_xImpl->aLC.addInterface( cppu::UnoType::get(), aListener ); +} + +void BibFrameController_Impl::removeEventListener( const uno::Reference< lang::XEventListener > & aListener ) +{ + m_xImpl->aLC.removeInterface( cppu::UnoType::get(), aListener ); +} + +uno::Reference< frame::XDispatch > BibFrameController_Impl::queryDispatch( const util::URL& aURL, const OUString& /*aTarget*/, sal_Int32 /*nSearchFlags*/ ) +{ + if ( !m_bDisposing ) + { + const CmdToInfoCache& rCmdCache = GetCommandToInfoCache(); + CmdToInfoCache::const_iterator pIter = rCmdCache.find( aURL.Complete ); + if ( pIter != rCmdCache.end() ) + { + if (( m_xDatMan->HasActiveConnection() ) || + ( !pIter->second.bActiveConnection )) + return static_cast(this); + } + } + + return uno::Reference< frame::XDispatch > (); +} + +uno::Sequence > BibFrameController_Impl::queryDispatches( const uno::Sequence& aDescripts ) +{ + uno::Sequence< uno::Reference< XDispatch > > aDispatches( aDescripts.getLength() ); + auto aDispatchesRange = asNonConstRange(aDispatches); + for ( sal_Int32 i=0; i SAL_CALL BibFrameController_Impl::getSupportedCommandGroups() +{ + uno::Sequence< ::sal_Int16 > aDispatchInfo{ frame::CommandGroup::EDIT, + frame::CommandGroup::DOCUMENT, + frame::CommandGroup::DATA, + frame::CommandGroup::VIEW }; + + return aDispatchInfo; +} + +uno::Sequence< frame::DispatchInformation > SAL_CALL BibFrameController_Impl::getConfigurableDispatchInformation( ::sal_Int16 nCommandGroup ) +{ + const CmdToInfoCache& rCmdCache = GetCommandToInfoCache(); + + frame::DispatchInformation aDispatchInfo; + std::vector< frame::DispatchInformation > aDispatchInfoVector; + + if (( nCommandGroup == frame::CommandGroup::EDIT ) || + ( nCommandGroup == frame::CommandGroup::DOCUMENT ) || + ( nCommandGroup == frame::CommandGroup::DATA ) || + ( nCommandGroup == frame::CommandGroup::VIEW )) + { + bool bGroupFound = false; + for (auto const& item : rCmdCache) + { + if ( item.second.nGroupId == nCommandGroup ) + { + bGroupFound = true; + aDispatchInfo.Command = item.first; + aDispatchInfo.GroupId = item.second.nGroupId; + aDispatchInfoVector.push_back( aDispatchInfo ); + } + else if ( bGroupFound ) + break; + } + } + + return comphelper::containerToSequence( aDispatchInfoVector ); +} + +static bool canInsertRecords(const Reference< beans::XPropertySet>& _rxCursorSet) +{ + sal_Int32 nPriv = 0; + _rxCursorSet->getPropertyValue("Privileges") >>= nPriv; + return _rxCursorSet.is() && (nPriv & sdbcx::Privilege::INSERT) != 0; +} + +bool BibFrameController_Impl::SaveModified(const Reference< form::runtime::XFormController>& xController) +{ + if (!xController.is()) + return false; + + Reference< XResultSetUpdate> _xCursor(xController->getModel(), UNO_QUERY); + + if (!_xCursor.is()) + return false; + + Reference< beans::XPropertySet> _xSet(_xCursor, UNO_QUERY); + if (!_xSet.is()) + return false; + + // need to save? + bool bIsNew = ::comphelper::getBOOL(_xSet->getPropertyValue("IsNew")); + bool bIsModified = ::comphelper::getBOOL(_xSet->getPropertyValue("IsModified")); + bool bResult = !bIsModified; + if (bIsModified) + { + try + { + if (bIsNew) + _xCursor->insertRow(); + else + _xCursor->updateRow(); + bResult = true; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.biblio", ""); + } + } + return bResult; +} + +static vcl::Window* lcl_GetFocusChild( vcl::Window const * pParent ) +{ + sal_uInt16 nChildren = pParent->GetChildCount(); + for( sal_uInt16 nChild = 0; nChild < nChildren; ++nChild) + { + vcl::Window* pChild = pParent->GetChild( nChild ); + if(pChild->HasFocus()) + return pChild; + vcl::Window* pSubChild = lcl_GetFocusChild( pChild ); + if(pSubChild) + return pSubChild; + } + return nullptr; +} + +//class XDispatch +void BibFrameController_Impl::dispatch(const util::URL& _rURL, const uno::Sequence< beans::PropertyValue >& aArgs) +{ + if ( m_bDisposing ) + return; + + ::SolarMutexGuard aGuard; + weld::Window* pParent = Application::GetFrameWeld(m_xWindow); + weld::WaitObject aWaitObject(pParent); + + OUString aCommand( _rURL.Path); + if(aCommand == "Bib/Mapping") + { + m_xDatMan->CreateMappingDialog(pParent); + } + else if(aCommand == "Bib/source") + { + ChangeDataSource(aArgs); + } + else if(aCommand == "Bib/sdbsource") + { + OUString aURL = m_xDatMan->CreateDBChangeDialog(pParent); + if(!aURL.isEmpty()) + { + try + { + uno::Sequence< beans::PropertyValue > aNewDataSource + { + comphelper::makePropertyValue( {}, OUString() ), + comphelper::makePropertyValue( {}, aURL ) + }; + ChangeDataSource(aNewDataSource); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.biblio", + "Exception caught while changing the data source"); + } + } + } + else if(aCommand == "Bib/autoFilter") + { + sal_uInt16 nCount = m_aStatusListeners.size(); + for ( sal_uInt16 n=0; naURL.Path == "Bib/removeFilter" ) + { + FeatureStateEvent aEvent; + aEvent.FeatureURL = pObj->aURL; + aEvent.IsEnabled = true; + aEvent.Requery = false; + aEvent.Source = static_cast(this); + pObj->xListener->statusChanged( aEvent ); + //break; because there are more than one + } + } + + const beans::PropertyValue* pPropertyValue = aArgs.getConstArray(); + uno::Any aValue=pPropertyValue[0].Value; + OUString aQuery; + aValue >>= aQuery; + + aValue=pPropertyValue[1].Value; + OUString aQueryField; + aValue >>= aQueryField; + BibConfig* pConfig = BibModul::GetConfig(); + pConfig->setQueryField(aQueryField); + m_xDatMan->startQueryWith(aQuery); + } + else if(aCommand == "Bib/standardFilter") + { + try + { + uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + + // create the dialog object + uno::Reference< ui::dialogs::XExecutableDialog > xDialog = sdb::FilterDialog::createWithQuery(xContext, m_xDatMan->getParser(), + Reference(m_xDatMan->getForm(), uno::UNO_QUERY_THROW), m_xWindow); + // execute it + if ( xDialog->execute( ) ) + { + // the dialog has been executed successfully, and the filter on the query composer + // has been changed + OUString sNewFilter = m_xDatMan->getParser()->getFilter(); + m_xDatMan->setFilter( sNewFilter ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.biblio", "BibFrameController_Impl::dispatch" ); + } + + sal_uInt16 nCount = m_aStatusListeners.size(); + for ( sal_uInt16 n=0; naURL.Path == "Bib/removeFilter" && m_xDatMan->getParser().is()) + { + FeatureStateEvent aEvent; + aEvent.FeatureURL = pObj->aURL; + aEvent.IsEnabled = !m_xDatMan->getParser()->getFilter().isEmpty(); + aEvent.Requery = false; + aEvent.Source = static_cast(this); + pObj->xListener->statusChanged( aEvent ); + } + } + } + else if(aCommand == "Bib/removeFilter") + { + RemoveFilter(); + } + else if( _rURL.Complete == "slot:5503" || aCommand == "CloseDoc" ) + { + Application::PostUserEvent( LINK( this, BibFrameController_Impl, + DisposeHdl ) ); + + } + else if(aCommand == "Bib/InsertRecord") + { + Reference xFormCtrl = m_xDatMan->GetFormController(); + if(SaveModified(xFormCtrl)) + { + try + { + Reference< sdbc::XResultSet > xCursor( m_xDatMan->getForm(), UNO_QUERY ); + xCursor->last(); + + Reference< XResultSetUpdate > xUpdateCursor( m_xDatMan->getForm(), UNO_QUERY ); + xUpdateCursor->moveToInsertRow(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.biblio", + "Exception in last() or moveToInsertRow()"); + } + } + } + else if(aCommand == "Bib/DeleteRecord") + { + Reference< css::sdbc::XResultSet > xCursor(m_xDatMan->getForm(), UNO_QUERY); + Reference< XResultSetUpdate > xUpdateCursor(xCursor, UNO_QUERY); + Reference< beans::XPropertySet > xSet(m_xDatMan->getForm(), UNO_QUERY); + bool bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue("IsNew")); + if(!bIsNew) + { + sal_uInt32 nCount = 0; + xSet->getPropertyValue("RowCount") >>= nCount; + // determine next position + bool bSuccess = false; + bool bLeft = false; + bool bRight = false; + try + { + bLeft = xCursor->isLast() && nCount > 1; + bRight= !xCursor->isLast(); + // ask for confirmation + Reference< form::XConfirmDeleteListener > xConfirm(m_xDatMan->GetFormController(),UNO_QUERY); + if (xConfirm.is()) + { + sdb::RowChangeEvent aEvent; + aEvent.Source.set(xCursor, UNO_QUERY); + aEvent.Action = sdb::RowChangeAction::DELETE; + aEvent.Rows = 1; + bSuccess = xConfirm->confirmDelete(aEvent); + } + + // delete it + if (bSuccess) + xUpdateCursor->deleteRow(); + } + catch(const Exception&) + { + bSuccess = false; + } + if (bSuccess) + { + if (bLeft || bRight) + xCursor->relative(bRight ? 1 : -1); + else + { + bool bCanInsert = canInsertRecords(xSet); + // can another entry be inserted? + try + { + if (bCanInsert) + xUpdateCursor->moveToInsertRow(); + else + // move data entry to reset state + xCursor->first(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.biblio", + "DeleteRecord: exception caught!"); + } + } + } + } + } + else if(aCommand == "Cut") + { + vcl::Window* pChild = m_xLastQueriedFocusWin.get(); + if(pChild) + { + KeyEvent aEvent( 0, KeyFuncType::CUT ); + pChild->KeyInput( aEvent ); + } + } + else if(aCommand == "Copy") + { + vcl::Window* pChild = m_xLastQueriedFocusWin.get(); + if(pChild) + { + KeyEvent aEvent( 0, KeyFuncType::COPY ); + pChild->KeyInput( aEvent ); + } + } + else if(aCommand == "Paste") + { + vcl::Window* pChild = m_xLastQueriedFocusWin.get(); + if(pChild) + { + KeyEvent aEvent( 0, KeyFuncType::PASTE ); + pChild->KeyInput( aEvent ); + } + } +} +IMPL_LINK_NOARG( BibFrameController_Impl, DisposeHdl, void*, void ) +{ + if (m_xFrame.is()) + m_xFrame->dispose(); +}; + +void BibFrameController_Impl::addStatusListener( + const uno::Reference< frame::XStatusListener > & aListener, + const util::URL& aURL) +{ + BibConfig* pConfig = BibModul::GetConfig(); + // create a new Reference and insert into listener array + m_aStatusListeners.push_back( std::make_unique( aURL, aListener ) ); + + // send first status synchronously + FeatureStateEvent aEvent; + aEvent.FeatureURL = aURL; + aEvent.Requery = false; + aEvent.Source = static_cast(this); + if ( aURL.Path == "StatusBarVisible" ) + { + aEvent.IsEnabled = false; + aEvent.State <<= false; + } + else if ( aURL.Path == "Bib/hierarchical" ) + { + aEvent.IsEnabled = true; + aEvent.State <<= OUString(); + } + else if(aURL.Path == "Bib/MenuFilter") + { + aEvent.IsEnabled = true; + aEvent.FeatureDescriptor=m_xDatMan->getQueryField(); + + aEvent.State <<= m_xDatMan->getQueryFields(); + + } + else if ( aURL.Path == "Bib/source") + { + aEvent.IsEnabled = true; + aEvent.FeatureDescriptor=m_xDatMan->getActiveDataTable(); + + aEvent.State <<= m_xDatMan->getDataSources(); + } + else if( aURL.Path == "Bib/sdbsource" || + aURL.Path == "Bib/Mapping" || + aURL.Path == "Bib/autoFilter" || + aURL.Path == "Bib/standardFilter" ) + { + aEvent.IsEnabled = true; + } + else if(aURL.Path == "Bib/query") + { + aEvent.IsEnabled = true; + aEvent.State <<= pConfig->getQueryText(); + } + else if (aURL.Path == "Bib/removeFilter" ) + { + OUString aFilterStr=m_xDatMan->getFilter(); + aEvent.IsEnabled = !aFilterStr.isEmpty(); + } + else if(aURL.Path == "Cut") + { + m_xLastQueriedFocusWin = lcl_GetFocusChild( VCLUnoHelper::GetWindow( m_xWindow ) ); + if (m_xLastQueriedFocusWin) + { + Reference xEdit(m_xLastQueriedFocusWin->GetComponentInterface(), css::uno::UNO_QUERY); + aEvent.IsEnabled = xEdit && xEdit->isEditable() && !xEdit->getSelectedText().isEmpty(); + } + } + if(aURL.Path == "Copy") + { + m_xLastQueriedFocusWin = lcl_GetFocusChild( VCLUnoHelper::GetWindow( m_xWindow ) ); + if (m_xLastQueriedFocusWin) + { + Reference xEdit(m_xLastQueriedFocusWin->GetComponentInterface(), css::uno::UNO_QUERY); + aEvent.IsEnabled = xEdit && !xEdit->getSelectedText().isEmpty(); + } + } + else if(aURL.Path == "Paste" ) + { + aEvent.IsEnabled = false; + m_xLastQueriedFocusWin = lcl_GetFocusChild( VCLUnoHelper::GetWindow( m_xWindow ) ); + if (m_xLastQueriedFocusWin) + { + Reference xEdit(m_xLastQueriedFocusWin->GetComponentInterface(), css::uno::UNO_QUERY); + if (xEdit && !xEdit->isEditable()) + { + uno::Reference< datatransfer::clipboard::XClipboard > xClip = m_xLastQueriedFocusWin->GetClipboard(); + if(xClip.is()) + { + uno::Reference< datatransfer::XTransferable > xDataObj; + + try + { + SolarMutexReleaser aReleaser; + xDataObj = xClip->getContents(); + } + catch( const uno::Exception& ) + { + } + + if ( xDataObj.is() ) + { + datatransfer::DataFlavor aFlavor; + SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor ); + try + { + uno::Any aData = xDataObj->getTransferData( aFlavor ); + OUString aText; + aData >>= aText; + aEvent.IsEnabled = !aText.isEmpty(); + } + catch( const uno::Exception& ) + { + } + } + } + } + } + } + else if(aURL.Path == "Bib/DeleteRecord") + { + Reference< beans::XPropertySet > xSet(m_xDatMan->getForm(), UNO_QUERY); + bool bIsNew = ::comphelper::getBOOL(xSet->getPropertyValue("IsNew")); + if(!bIsNew) + { + sal_uInt32 nCount = 0; + xSet->getPropertyValue("RowCount") >>= nCount; + aEvent.IsEnabled = nCount > 0; + } + } + else if (aURL.Path == "Bib/InsertRecord") + { + Reference< beans::XPropertySet > xSet(m_xDatMan->getForm(), UNO_QUERY); + aEvent.IsEnabled = canInsertRecords(xSet); + } + aListener->statusChanged( aEvent ); +} + +void BibFrameController_Impl::removeStatusListener( + const uno::Reference< frame::XStatusListener > & aObject, const util::URL& aURL) +{ + // search listener array for given listener + // for checking equality always "cast" to XInterface + if ( m_bDisposing ) + return; + + sal_uInt16 nCount = m_aStatusListeners.size(); + for ( sal_uInt16 n=0; nxListener.is(); + if (!bFlag || (pObj->xListener == aObject && + ( aURL.Complete.isEmpty() || pObj->aURL.Path == aURL.Path ))) + { + m_aStatusListeners.erase( m_aStatusListeners.begin() + n ); + break; + } + } +} + +void BibFrameController_Impl::RemoveFilter() +{ + OUString aQuery; + m_xDatMan->startQueryWith(aQuery); + + sal_uInt16 nCount = m_aStatusListeners.size(); + + bool bRemoveFilter=false; + bool bQueryText=false; + + for ( sal_uInt16 n=0; naURL.Path == "Bib/removeFilter" ) + { + FeatureStateEvent aEvent; + aEvent.FeatureURL = pObj->aURL; + aEvent.IsEnabled = false; + aEvent.Requery = false; + aEvent.Source = static_cast(this); + pObj->xListener->statusChanged( aEvent ); + bRemoveFilter=true; + } + else if(pObj->aURL.Path == "Bib/query") + { + FeatureStateEvent aEvent; + aEvent.FeatureURL = pObj->aURL; + aEvent.IsEnabled = true; + aEvent.Requery = false; + aEvent.Source = static_cast(this); + aEvent.State <<= aQuery; + pObj->xListener->statusChanged( aEvent ); + bQueryText=true; + } + + if(bRemoveFilter && bQueryText) + break; + + } +} + +void BibFrameController_Impl::ChangeDataSource(const uno::Sequence< beans::PropertyValue >& aArgs) +{ + const beans::PropertyValue* pPropertyValue = aArgs.getConstArray(); + uno::Any aValue=pPropertyValue[0].Value; + OUString aDBTableName; + aValue >>= aDBTableName; + + + if(aArgs.getLength() > 1) + { + uno::Any aDB = pPropertyValue[1].Value; + OUString aURL; + aDB >>= aURL; + m_xDatMan->setActiveDataSource(aURL); + aDBTableName = m_xDatMan->getActiveDataTable(); + } + else + { + Reference xLoadable(m_xDatMan); + xLoadable->unload(); + m_xDatMan->setActiveDataTable(aDBTableName); + m_xDatMan->updateGridModel(); + xLoadable->load(); + } + + + sal_uInt16 nCount = m_aStatusListeners.size(); + + bool bMenuFilter=false; + bool bQueryText=false; + for ( sal_uInt16 n=0; naURL.Path == "Bib/MenuFilter") + { + FeatureStateEvent aEvent; + aEvent.FeatureURL = pObj->aURL; + aEvent.IsEnabled = true; + aEvent.Requery = false; + aEvent.Source = static_cast(this); + aEvent.FeatureDescriptor=m_xDatMan->getQueryField(); + + uno::Sequence aStringSeq=m_xDatMan->getQueryFields(); + aEvent.State <<= aStringSeq; + + pObj->xListener->statusChanged( aEvent ); + bMenuFilter=true; + } + else if (pObj->aURL.Path == "Bib/query") + { + FeatureStateEvent aEvent; + aEvent.FeatureURL = pObj->aURL; + aEvent.IsEnabled = true; + aEvent.Requery = false; + aEvent.Source = static_cast(this); + BibConfig* pConfig = BibModul::GetConfig(); + aEvent.State <<= pConfig->getQueryText(); + pObj->xListener->statusChanged( aEvent ); + bQueryText=true; + } + + if (bMenuFilter && bQueryText) + break; + + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/framectr.hxx b/extensions/source/bibliography/framectr.hxx new file mode 100644 index 000000000..be91982cc --- /dev/null +++ b/extensions/source/bibliography/framectr.hxx @@ -0,0 +1,117 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bibmod.hxx" +class BibDataManager; +class BibFrameCtrl_Impl; +namespace com::sun::star{ + namespace form::runtime { + class XFormController; + } +} +class BibStatusDispatch +{ +public: + css::util::URL aURL; + css::uno::Reference< css::frame::XStatusListener > xListener; + BibStatusDispatch( const css::util::URL& rURL, const css::uno::Reference< css::frame::XStatusListener >& rRef ) + : aURL( rURL ) + , xListener( rRef ) + {} +}; + +typedef std::vector > BibStatusDispatchArr; + +class BibFrameController_Impl : public cppu::WeakImplHelper < + css::lang::XServiceInfo, + css::frame::XController, + css::frame::XDispatch, + css::frame::XDispatchProvider, + css::frame::XDispatchInformationProvider +> +{ +friend class BibFrameCtrl_Impl; + rtl::Reference m_xImpl; + BibStatusDispatchArr m_aStatusListeners; + css::uno::Reference< css::awt::XWindow > m_xWindow; + css::uno::Reference< css::frame::XFrame > m_xFrame; + bool m_bDisposing; + rtl::Reference m_xDatMan; + VclPtr m_xLastQueriedFocusWin; + + DECL_LINK( DisposeHdl, void*, void ); + + static bool SaveModified(const css::uno::Reference< css::form::runtime::XFormController>& xController); +public: + BibFrameController_Impl( const css::uno::Reference< css::awt::XWindow > & xComponent, + BibDataManager* pDatMan); + virtual ~BibFrameController_Impl() override; + + + void ChangeDataSource(const css::uno::Sequence< css::beans::PropertyValue >& aArgs); + void RemoveFilter(); + + // css::lang::XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& sServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // css::frame::XController + virtual void SAL_CALL attachFrame( const css::uno::Reference< css::frame::XFrame > & xFrame ) override; + virtual sal_Bool SAL_CALL attachModel( const css::uno::Reference< css::frame::XModel > & xModel ) override; + virtual sal_Bool SAL_CALL suspend( sal_Bool bSuspend ) override; + virtual css::uno::Any SAL_CALL getViewData() override; + virtual void SAL_CALL restoreViewData( const css::uno::Any& Value ) override; + virtual css::uno::Reference< css::frame::XFrame > SAL_CALL getFrame() override; + virtual css::uno::Reference< css::frame::XModel > SAL_CALL getModel() override; + + // css::lang::XComponent + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener > & aListener ) override; + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener > & aListener ) 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; + virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& aDescripts) override; + + //class 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::XDispatchInformationProvider + virtual css::uno::Sequence< ::sal_Int16 > SAL_CALL getSupportedCommandGroups( ) override; + virtual css::uno::Sequence< css::frame::DispatchInformation > SAL_CALL getConfigurableDispatchInformation( ::sal_Int16 CommandGroup ) override; + }; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/general.cxx b/extensions/source/bibliography/general.cxx new file mode 100644 index 000000000..ff3625d30 --- /dev/null +++ b/extensions/source/bibliography/general.cxx @@ -0,0 +1,876 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 "general.hxx" +#include "bibresid.hxx" +#include "datman.hxx" +#include "bibconfig.hxx" +#include +#include "bibmod.hxx" +#include +#include +#include +#include + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::form; +using namespace ::com::sun::star::sdb; + +namespace +{ +/// Tries to split rText into rURL and nPageNumber. +bool SplitUrlAndPage(const OUString& rText, OUString& rUrl, int& nPageNumber) +{ + uno::Reference xUriReferenceFactory + = uri::UriReferenceFactory::create(comphelper::getProcessComponentContext()); + uno::Reference xUriRef; + try + { + xUriRef = xUriReferenceFactory->parse(rText); + } + catch (const uno::Exception& rException) + { + SAL_WARN("extensions.biblio", + "SplitUrlAndPage: failed to parse url: " << rException.Message); + return false; + } + + OUString aPagePrefix("page="); + if (!xUriRef->getFragment().startsWith(aPagePrefix)) + { + return false; + } + + nPageNumber = o3tl::toInt32(xUriRef->getFragment().subView(aPagePrefix.getLength())); + xUriRef->clearFragment(); + rUrl = xUriRef->getUriReference(); + return true; +} + +/// Merges rUrl and rPageSB to a URL string. +OUString MergeUrlAndPage(const OUString& rUrl, const weld::SpinButton& rPageSB) +{ + if (!rPageSB.get_sensitive()) + { + return rUrl; + } + + uno::Reference xUriReferenceFactory + = uri::UriReferenceFactory::create(comphelper::getProcessComponentContext()); + uno::Reference xUriRef; + try + { + xUriRef = xUriReferenceFactory->parse(rUrl); + } + catch (const uno::Exception& rException) + { + SAL_WARN("extensions.biblio", + "MergeUrlAndPage: failed to parse url: " << rException.Message); + return rUrl; + } + + OUString aFragment("page=" + OUString::number(rPageSB.get_value())); + xUriRef->setFragment(aFragment); + return xUriRef->getUriReference(); +} +} + +static OUString lcl_GetColumnName( const Mapping* pMapping, sal_uInt16 nIndexPos ) +{ + BibConfig* pBibConfig = BibModul::GetConfig(); + OUString sRet = pBibConfig->GetDefColumnName(nIndexPos); + if(pMapping) + for(const auto & aColumnPair : pMapping->aColumnPairs) + { + if(aColumnPair.sLogicalColumnName == sRet) + { + sRet = aColumnPair.sRealColumnName; + break; + } + } + return sRet; +} + +BibGeneralPage::BibGeneralPage(vcl::Window* pParent, BibDataManager* pMan) + : InterimItemWindow(pParent, "modules/sbibliography/ui/generalpage.ui", "GeneralPage") + , BibShortCutHandler(this) + , xScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow")) + , xGrid(m_xBuilder->weld_widget("grid")) + , xIdentifierFT(m_xBuilder->weld_label("shortname")) + , xIdentifierED(m_xBuilder->weld_entry("shortnamecontrol")) + , xAuthTypeFT(m_xBuilder->weld_label("authtype")) + , xAuthTypeLB(m_xBuilder->weld_combo_box("authtypecontrol")) + , xYearFT(m_xBuilder->weld_label("year")) + , xYearED(m_xBuilder->weld_entry("yearcontrol")) + , xAuthorFT(m_xBuilder->weld_label("authors")) + , xAuthorED(m_xBuilder->weld_entry("authorscontrol")) + , xTitleFT(m_xBuilder->weld_label("title")) + , xTitleED(m_xBuilder->weld_entry("titlecontrol")) + , xPublisherFT(m_xBuilder->weld_label("publisher")) + , xPublisherED(m_xBuilder->weld_entry("publishercontrol")) + , xAddressFT(m_xBuilder->weld_label("address")) + , xAddressED(m_xBuilder->weld_entry("addresscontrol")) + , xISBNFT(m_xBuilder->weld_label("isbn")) + , xISBNED(m_xBuilder->weld_entry("isbncontrol")) + , xChapterFT(m_xBuilder->weld_label("chapter")) + , xChapterED(m_xBuilder->weld_entry("chaptercontrol")) + , xPagesFT(m_xBuilder->weld_label("pages")) + , xPagesED(m_xBuilder->weld_entry("pagescontrol")) + , xEditorFT(m_xBuilder->weld_label("editor")) + , xEditorED(m_xBuilder->weld_entry("editorcontrol")) + , xEditionFT(m_xBuilder->weld_label("edition")) + , xEditionED(m_xBuilder->weld_entry("editioncontrol")) + , xBooktitleFT(m_xBuilder->weld_label("booktitle")) + , xBooktitleED(m_xBuilder->weld_entry("booktitlecontrol")) + , xVolumeFT(m_xBuilder->weld_label("volume")) + , xVolumeED(m_xBuilder->weld_entry("volumecontrol")) + , xHowpublishedFT(m_xBuilder->weld_label("publicationtype")) + , xHowpublishedED(m_xBuilder->weld_entry("publicationtypecontrol")) + , xOrganizationsFT(m_xBuilder->weld_label("organization")) + , xOrganizationsED(m_xBuilder->weld_entry("organizationcontrol")) + , xInstitutionFT(m_xBuilder->weld_label("institution")) + , xInstitutionED(m_xBuilder->weld_entry("institutioncontrol")) + , xSchoolFT(m_xBuilder->weld_label("university")) + , xSchoolED(m_xBuilder->weld_entry("universitycontrol")) + , xReportTypeFT(m_xBuilder->weld_label("reporttype")) + , xReportTypeED(m_xBuilder->weld_entry("reporttypecontrol")) + , xMonthFT(m_xBuilder->weld_label("month")) + , xMonthED(m_xBuilder->weld_entry("monthcontrol")) + , xJournalFT(m_xBuilder->weld_label("journal")) + , xJournalED(m_xBuilder->weld_entry("journalcontrol")) + , xNumberFT(m_xBuilder->weld_label("number")) + , xNumberED(m_xBuilder->weld_entry("numbercontrol")) + , xSeriesFT(m_xBuilder->weld_label("series")) + , xSeriesED(m_xBuilder->weld_entry("seriescontrol")) + , xAnnoteFT(m_xBuilder->weld_label("annotation")) + , xAnnoteED(m_xBuilder->weld_entry("annotationcontrol")) + , xNoteFT(m_xBuilder->weld_label("note")) + , xNoteED(m_xBuilder->weld_entry("notecontrol")) + , xURLFT(m_xBuilder->weld_label("url")) + , xURLED(m_xBuilder->weld_entry("urlcontrol")) + , xCustom1FT(m_xBuilder->weld_label("custom1")) + , xCustom1ED(m_xBuilder->weld_entry("custom1control")) + , xCustom2FT(m_xBuilder->weld_label("custom2")) + , xCustom2ED(m_xBuilder->weld_entry("custom2control")) + , xCustom3FT(m_xBuilder->weld_label("custom3")) + , xCustom3ED(m_xBuilder->weld_entry("custom3control")) + , xCustom4FT(m_xBuilder->weld_label("custom4")) + , xCustom4ED(m_xBuilder->weld_entry("custom4control")) + , xCustom5FT(m_xBuilder->weld_label("custom5")) + , xCustom5ED(m_xBuilder->weld_entry("custom5control")) + , m_xLocalURLFT(m_xBuilder->weld_label("localurl")) + , m_xLocalURLED(m_xBuilder->weld_entry("localurlcontrol")) + , m_xLocalBrowseButton(m_xBuilder->weld_button("localbrowse")) + , m_xLocalPageCB(m_xBuilder->weld_check_button("localpagecb")) + , m_xLocalPageSB(m_xBuilder->weld_spin_button("localpagesb")) + , pDatMan(pMan) +{ + SetStyle(GetStyle() | WB_DIALOGCONTROL); + + BibConfig* pBibConfig = BibModul::GetConfig(); + BibDBDescriptor aDesc; + aDesc.sDataSource = pDatMan->getActiveDataSource(); + aDesc.sTableOrQuery = pDatMan->getActiveDataTable(); + aDesc.nCommandType = CommandType::TABLE; + const Mapping* pMapping = pBibConfig->GetMapping(aDesc); + + xIdentifierED->connect_key_press(LINK(this, BibGeneralPage, FirstElementKeyInputHdl)); + + AddControlWithError(lcl_GetColumnName(pMapping, IDENTIFIER_POS), + xIdentifierFT->get_label(), *xIdentifierED, + sTableErrorString, HID_BIB_IDENTIFIER_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, AUTHORITYTYPE_POS), + xAuthTypeFT->get_label(), *xAuthTypeLB, + sTableErrorString, HID_BIB_AUTHORITYTYPE_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, YEAR_POS), + xYearFT->get_label(), *xYearED, + sTableErrorString, HID_BIB_YEAR_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, AUTHOR_POS), + xAuthorFT->get_label(), *xAuthorED, + sTableErrorString, HID_BIB_AUTHOR_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, TITLE_POS), + xTitleFT->get_label(), *xTitleED, + sTableErrorString, HID_BIB_TITLE_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, PUBLISHER_POS), + xPublisherFT->get_label(), *xPublisherED, + sTableErrorString, HID_BIB_PUBLISHER_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, ADDRESS_POS), + xAddressFT->get_label(), *xAddressED, + sTableErrorString, HID_BIB_ADDRESS_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, ISBN_POS), + xISBNFT->get_label(), *xISBNED, + sTableErrorString, HID_BIB_ISBN_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, CHAPTER_POS), + xChapterFT->get_label(), *xChapterED, + sTableErrorString, HID_BIB_CHAPTER_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, PAGES_POS), + xPagesFT->get_label(), *xPagesED, + sTableErrorString, HID_BIB_PAGES_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, EDITOR_POS), + xEditorFT->get_label(), *xEditorED, + sTableErrorString, HID_BIB_EDITOR_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, EDITION_POS), + xEditionFT->get_label(), *xEditionED, + sTableErrorString, HID_BIB_EDITION_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, BOOKTITLE_POS), + xBooktitleFT->get_label(), *xBooktitleED, + sTableErrorString, HID_BIB_BOOKTITLE_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, VOLUME_POS), + xVolumeFT->get_label(), *xVolumeED, + sTableErrorString, HID_BIB_VOLUME_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, HOWPUBLISHED_POS), + xHowpublishedFT->get_label(), *xHowpublishedED, + sTableErrorString, HID_BIB_HOWPUBLISHED_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, ORGANIZATIONS_POS), + xOrganizationsFT->get_label(), *xOrganizationsED, + sTableErrorString, HID_BIB_ORGANIZATIONS_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, INSTITUTION_POS), + xInstitutionFT->get_label(), *xInstitutionED, + sTableErrorString, HID_BIB_INSTITUTION_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, SCHOOL_POS), + xSchoolFT->get_label(), *xSchoolED, + sTableErrorString, HID_BIB_SCHOOL_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, REPORTTYPE_POS), + xReportTypeFT->get_label(), *xReportTypeED, + sTableErrorString, HID_BIB_REPORTTYPE_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, MONTH_POS), + xMonthFT->get_label(), *xMonthED, + sTableErrorString, HID_BIB_MONTH_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, JOURNAL_POS), + xJournalFT->get_label(), *xJournalED, + sTableErrorString, HID_BIB_JOURNAL_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, NUMBER_POS), + xNumberFT->get_label(), *xNumberED, + sTableErrorString, HID_BIB_NUMBER_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, SERIES_POS), + xSeriesFT->get_label(), *xSeriesED, + sTableErrorString, HID_BIB_SERIES_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, ANNOTE_POS), + xAnnoteFT->get_label(), *xAnnoteED, + sTableErrorString, HID_BIB_ANNOTE_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, NOTE_POS), + xNoteFT->get_label(), *xNoteED, + sTableErrorString, HID_BIB_NOTE_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, URL_POS), + xURLFT->get_label(), *xURLED, + sTableErrorString, HID_BIB_URL_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, CUSTOM1_POS), + xCustom1FT->get_label(), *xCustom1ED, + sTableErrorString, HID_BIB_CUSTOM1_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, CUSTOM2_POS), + xCustom2FT->get_label(), *xCustom2ED, + sTableErrorString, HID_BIB_CUSTOM2_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, CUSTOM3_POS), + xCustom3FT->get_label(), *xCustom3ED, + sTableErrorString, HID_BIB_CUSTOM3_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, CUSTOM4_POS), + xCustom4FT->get_label(), *xCustom4ED, + sTableErrorString, HID_BIB_CUSTOM4_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, CUSTOM5_POS), + xCustom5FT->get_label(), *xCustom5ED, + sTableErrorString, HID_BIB_CUSTOM5_POS); + + AddControlWithError(lcl_GetColumnName(pMapping, LOCAL_URL_POS), + m_xLocalURLFT->get_label(), *m_xLocalURLED, + sTableErrorString, HID_BIB_LOCAL_URL_POS); + + m_xLocalBrowseButton->connect_clicked(LINK(this, BibGeneralPage, BrowseHdl)); + m_xLocalPageCB->connect_toggled(LINK(this, BibGeneralPage, PageNumHdl)); + + m_xLocalURLED->connect_key_press(LINK(this, BibGeneralPage, LastElementKeyInputHdl)); + + if(!sTableErrorString.isEmpty()) + sTableErrorString = BibResId(ST_ERROR_PREFIX) + sTableErrorString; + + SetText(BibResId(ST_TYPE_TITLE)); + + Size aSize(LogicToPixel(Size(0, 209), MapMode(MapUnit::MapAppFont))); + set_height_request(aSize.Height()); +} + +IMPL_LINK_NOARG(BibGeneralPage, BrowseHdl, weld::Button&, void) +{ + sfx2::FileDialogHelper aFileDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, GetFrameWeld()); + OUString aPath = m_xLocalURLED->get_text(); + if (!aPath.isEmpty()) + { + aFileDlg.SetDisplayDirectory(aPath); + } + else + { + OUString aBaseURL; + if (SfxObjectShell* pShell = SfxObjectShell::Current()) + { + aBaseURL = pShell->getDocumentBaseURL(); + } + if (!aBaseURL.isEmpty()) + { + aFileDlg.SetDisplayDirectory(aBaseURL); + } + } + + if (aFileDlg.Execute() != ERRCODE_NONE) + { + return; + } + + weld::Entry& rEntry = *m_xLocalURLED; + rEntry.set_text(aFileDlg.GetPath()); +}; + +IMPL_LINK(BibGeneralPage, PageNumHdl, weld::Toggleable&, rPageCB, void) +{ + weld::SpinButton& rPageSB = *m_xLocalPageSB; + if (rPageCB.get_active()) + { + rPageSB.set_sensitive(true); + rPageSB.set_value(1); + } + else + { + rPageSB.set_sensitive(false); + } +} + +IMPL_LINK(BibGeneralPage, FirstElementKeyInputHdl, const KeyEvent&, rKeyEvent, bool) +{ + sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode(); + bool bShift = rKeyEvent.GetKeyCode().IsShift(); + bool bCtrl = rKeyEvent.GetKeyCode().IsMod1(); + bool bAlt = rKeyEvent.GetKeyCode().IsMod2(); + if (KEY_TAB == nCode && bShift && !bCtrl && !bAlt) + { + SaveChanges(); + uno::Reference xRowSet(pDatMan->getForm(), UNO_QUERY); + if (xRowSet.is() && !xRowSet->isFirst()) + xRowSet->previous(); + m_xLocalURLED->grab_focus(); + m_xLocalURLED->select_region(0, -1); + GainFocusHdl(*m_xLocalURLED); + return true; + } + return false; +} + +void BibGeneralPage::SaveChanges() +{ + Reference< XForm > xForm = pDatMan->getForm(); + Reference< beans::XPropertySet > xProps( xForm, UNO_QUERY ); + Reference< sdbc::XResultSetUpdate > xResUpd( xProps, UNO_QUERY ); + if (!xResUpd.is() ) + return; + + Any aModified = xProps->getPropertyValue( "IsModified" ); + bool bFlag = false; + if ( !( aModified >>= bFlag ) || !bFlag ) + return; + + try + { + Any aNew = xProps->getPropertyValue( "IsNew" ); + aNew >>= bFlag; + if ( bFlag ) + xResUpd->insertRow(); + else + xResUpd->updateRow(); + } + catch( const uno::Exception&) {} +} + +IMPL_LINK(BibGeneralPage, LastElementKeyInputHdl, const KeyEvent&, rKeyEvent, bool) +{ + sal_uInt16 nCode = rKeyEvent.GetKeyCode().GetCode(); + bool bShift = rKeyEvent.GetKeyCode().IsShift(); + bool bCtrl = rKeyEvent.GetKeyCode().IsMod1(); + bool bAlt = rKeyEvent.GetKeyCode().IsMod2(); + if (KEY_TAB != nCode || bShift || bCtrl || bAlt) + return false; + SaveChanges(); + uno::Reference xRowSet(pDatMan->getForm(), UNO_QUERY); + if (xRowSet.is()) + { + if (xRowSet->isLast()) + { + uno::Reference xUpdateCursor(xRowSet, UNO_QUERY); + if (xUpdateCursor.is()) + xUpdateCursor->moveToInsertRow(); + } + else + (void)xRowSet->next(); + } + xIdentifierED->grab_focus(); + xIdentifierED->select_region(0, -1); + GainFocusHdl(*xIdentifierED); + return true; +} + +BibGeneralPage::~BibGeneralPage() +{ + disposeOnce(); +} + +class ChangeListener : public cppu::WeakImplHelper +{ +public: + explicit ChangeListener(const css::uno::Reference& rPropSet) + : m_xPropSet(rPropSet) + , m_bSelfChanging(false) + { + } + + virtual void SAL_CALL disposing(lang::EventObject const &) override + { + } + + virtual void start() = 0; + virtual void stop() + { + WriteBack(); + } + + virtual void WriteBack() = 0; + +protected: + css::uno::Reference m_xPropSet; + bool m_bSelfChanging; +}; + +namespace +{ + class EntryChangeListener : public ChangeListener + { + public: + explicit EntryChangeListener(weld::Entry& rEntry, const css::uno::Reference& rPropSet, + BibGeneralPage& rPage) + : ChangeListener(rPropSet) + , m_rEntry(rEntry) + , m_rPage(rPage) + { + rEntry.connect_focus_out(LINK(this, EntryChangeListener, LoseFocusHdl)); + setValue(rPropSet->getPropertyValue("Text")); + } + + virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override + { + if (m_bSelfChanging) + return; + setValue(evt.NewValue); + } + + virtual void start() override + { + m_xPropSet->addPropertyChangeListener("Text", this); + } + + virtual void stop() override + { + m_xPropSet->removePropertyChangeListener("Text", this); + ChangeListener::stop(); + } + + private: + weld::Entry& m_rEntry; + BibGeneralPage& m_rPage; + + DECL_LINK(LoseFocusHdl, weld::Widget&, void); + + /// Updates the UI widget(s) based on rValue. + void setValue(const css::uno::Any& rValue) + { + OUString sNewName; + rValue >>= sNewName; + if (&m_rEntry == &m_rPage.GetLocalURLED()) + { + OUString aUrl; + int nPageNumber; + if (SplitUrlAndPage(sNewName, aUrl, nPageNumber)) + { + m_rEntry.set_text(aUrl); + m_rPage.GetLocalPageCB().set_active(true); + m_rPage.GetLocalPageSB().set_sensitive(true); + m_rPage.GetLocalPageSB().set_value(nPageNumber); + } + else + { + m_rEntry.set_text(sNewName); + m_rPage.GetLocalPageCB().set_active(false); + m_rPage.GetLocalPageSB().set_sensitive(false); + m_rPage.GetLocalPageSB().set_value(0); + } + } + else + { + m_rEntry.set_text(sNewName); + } + + m_rEntry.save_value(); + if (&m_rEntry == &m_rPage.GetLocalURLED()) + { + m_rPage.GetLocalPageSB().save_value(); + } + } + + /// Updates m_xPropSet based on the UI widget(s). + virtual void WriteBack() override + { + bool bLocalURL = &m_rEntry == &m_rPage.GetLocalURLED() + && m_rPage.GetLocalPageSB().get_value_changed_from_saved(); + if (!m_rEntry.get_value_changed_from_saved() && !bLocalURL) + return; + + m_bSelfChanging = true; + + OUString aText; + if (&m_rEntry == &m_rPage.GetLocalURLED()) + { + aText = MergeUrlAndPage(m_rEntry.get_text(), m_rPage.GetLocalPageSB()); + } + else + { + aText = m_rEntry.get_text(); + } + m_xPropSet->setPropertyValue("Text", Any(aText)); + + css::uno::Reference xBound(m_xPropSet, css::uno::UNO_QUERY); + if (xBound.is()) + xBound->commit(); + + m_bSelfChanging = false; + m_rEntry.save_value(); + if (&m_rEntry == &m_rPage.GetLocalURLED()) + { + m_rPage.GetLocalPageSB().save_value(); + } + } + + }; + + IMPL_LINK_NOARG(EntryChangeListener, LoseFocusHdl, weld::Widget&, void) + { + WriteBack(); + } + + class ComboBoxChangeListener : public ChangeListener + { + public: + explicit ComboBoxChangeListener(weld::ComboBox& rComboBox, const css::uno::Reference& rPropSet) + : ChangeListener(rPropSet) + , m_rComboBox(rComboBox) + { + rComboBox.connect_changed(LINK(this, ComboBoxChangeListener, ChangeHdl)); + setValue(rPropSet->getPropertyValue("SelectedItems")); + } + + virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override + { + if (m_bSelfChanging) + return; + setValue(evt.NewValue); + } + + virtual void start() override + { + m_xPropSet->addPropertyChangeListener("SelectedItems", this); + } + + virtual void stop() override + { + m_xPropSet->removePropertyChangeListener("SelectedItems", this); + ChangeListener::stop(); + } + + private: + weld::ComboBox& m_rComboBox; + + DECL_LINK(ChangeHdl, weld::ComboBox&, void); + + void setValue(const css::uno::Any& rValue) + { + sal_Int16 nSelection = -1; + Sequence aSelection; + rValue >>= aSelection; + if (aSelection.hasElements()) + nSelection = aSelection[0]; + + m_rComboBox.set_active(nSelection); + m_rComboBox.save_value(); + } + + virtual void WriteBack() override + { + if (!m_rComboBox.get_value_changed_from_saved()) + return; + m_bSelfChanging = true; + + Sequence aSelection{ o3tl::narrowing(m_rComboBox.get_active()) }; + m_xPropSet->setPropertyValue("SelectedItems", Any(aSelection)); + + css::uno::Reference xBound(m_xPropSet, css::uno::UNO_QUERY); + if (xBound.is()) + xBound->commit(); + + m_bSelfChanging = false; + m_rComboBox.save_value(); + } + }; + + IMPL_LINK_NOARG(ComboBoxChangeListener, ChangeHdl, weld::ComboBox&, void) + { + WriteBack(); + } +} + +void BibGeneralPage::dispose() +{ + for (auto& listener : maChangeListeners) + listener->stop(); + maChangeListeners.clear(); + + SaveChanges(); + + xScrolledWindow.reset(); + xGrid.reset(); + xIdentifierFT.reset(); + xIdentifierED.reset(); + xAuthTypeFT.reset(); + xAuthTypeLB.reset(); + xYearFT.reset(); + xYearED.reset(); + xAuthorFT.reset(); + xAuthorED.reset(); + xTitleFT.reset(); + xTitleED.reset(); + xPublisherFT.reset(); + xPublisherED.reset(); + xAddressFT.reset(); + xAddressED.reset(); + xISBNFT.reset(); + xISBNED.reset(); + xChapterFT.reset(); + xChapterED.reset(); + xPagesFT.reset(); + xPagesED.reset(); + xEditorFT.reset(); + xEditorED.reset(); + xEditionFT.reset(); + xEditionED.reset(); + xBooktitleFT.reset(); + xBooktitleED.reset(); + xVolumeFT.reset(); + xVolumeED.reset(); + xHowpublishedFT.reset(); + xHowpublishedED.reset(); + xOrganizationsFT.reset(); + xOrganizationsED.reset(); + xInstitutionFT.reset(); + xInstitutionED.reset(); + xSchoolFT.reset(); + xSchoolED.reset(); + xReportTypeFT.reset(); + xReportTypeED.reset(); + xMonthFT.reset(); + xMonthED.reset(); + xJournalFT.reset(); + xJournalED.reset(); + xNumberFT.reset(); + xNumberED.reset(); + xSeriesFT.reset(); + xSeriesED.reset(); + xAnnoteFT.reset(); + xAnnoteED.reset(); + xNoteFT.reset(); + xNoteED.reset(); + xURLFT.reset(); + xURLED.reset(); + xCustom1FT.reset(); + xCustom1ED.reset(); + xCustom2FT.reset(); + xCustom2ED.reset(); + xCustom3FT.reset(); + xCustom3ED.reset(); + xCustom4FT.reset(); + xCustom4ED.reset(); + xCustom5FT.reset(); + xCustom5ED.reset(); + m_xLocalURLFT.reset(); + m_xLocalURLED.reset(); + m_xLocalBrowseButton.reset(); + m_xLocalPageCB.reset(); + m_xLocalPageSB.reset(); + InterimItemWindow::dispose(); +} + +weld::Entry& BibGeneralPage::GetLocalURLED() { return *m_xLocalURLED; } + +weld::CheckButton& BibGeneralPage::GetLocalPageCB() { return *m_xLocalPageCB; } + +weld::SpinButton& BibGeneralPage::GetLocalPageSB() { return *m_xLocalPageSB; } + +bool BibGeneralPage::AddXControl(const OUString& rName, weld::Entry& rEntry) +{ + uno::Reference< awt::XControlModel > xCtrModel; + try + { + xCtrModel = pDatMan->loadControlModel(rName, false); + if ( xCtrModel.is() ) + { + uno::Reference< beans::XPropertySet > xPropSet( xCtrModel, UNO_QUERY ); + + if( xPropSet.is()) + { + maChangeListeners.emplace_back(new EntryChangeListener(rEntry, xPropSet, *this)); + maChangeListeners.back()->start(); + if (&rEntry == m_xLocalURLED.get()) + { + m_aURLListener = maChangeListeners.back(); + m_xLocalPageSB->connect_focus_out(LINK(this, BibGeneralPage, LosePageFocusHdl)); + } + } + } + } + catch(const Exception&) + { + OSL_FAIL("BibGeneralPage::AddXControl: something went wrong!"); + } + return xCtrModel.is(); +} + +IMPL_LINK_NOARG(BibGeneralPage, LosePageFocusHdl, weld::Widget&, void) +{ + m_aURLListener->WriteBack(); +} + +IMPL_LINK(BibGeneralPage, GainFocusHdl, weld::Widget&, rWidget, void) +{ + int x, y, width, height; + if (!rWidget.get_extents_relative_to(*xGrid, x, y, width, height)) + return; + + int bottom = y + height; + int nVScrollPos = xScrolledWindow->vadjustment_get_value(); + if (y < nVScrollPos || bottom > nVScrollPos + xScrolledWindow->vadjustment_get_page_size()) + xScrolledWindow->vadjustment_set_value(y); + + int right = x + width; + int nHScrollPos = xScrolledWindow->hadjustment_get_value(); + if (x < nHScrollPos || right > nHScrollPos + xScrolledWindow->hadjustment_get_page_size()) + xScrolledWindow->hadjustment_set_value(x); +} + +template void BibGeneralPage::AddControlWithError(const OUString& rColumnName, const OUString& rColumnUIName, + Target& rWidget, OUString& rErrorString, const OString& rHelpId) +{ + rWidget.set_help_id(rHelpId); + rWidget.connect_focus_in(LINK(this, BibGeneralPage, GainFocusHdl)); + bool bSuccess = AddXControl(rColumnName, rWidget); + if (!bSuccess) + { + if( !rErrorString.isEmpty() ) + rErrorString += "\n"; + + rErrorString += MnemonicGenerator::EraseAllMnemonicChars(rColumnUIName); + } +} + +bool BibGeneralPage::AddXControl(const OUString& rName, weld::ComboBox& rList) +{ + uno::Reference< awt::XControlModel > xCtrModel; + try + { + xCtrModel = pDatMan->loadControlModel(rName, true); + if ( xCtrModel.is() ) + { + uno::Reference< beans::XPropertySet > xPropSet( xCtrModel, UNO_QUERY ); + + if( xPropSet.is()) + { + css::uno::Sequence aEntries; + xPropSet->getPropertyValue("StringItemList") >>= aEntries; + for (const OUString& rString : std::as_const(aEntries)) + rList.append_text(rString); + + sal_Int16 nSelection = -1; + Sequence aSelection; + xPropSet->getPropertyValue("SelectedItems") >>= aSelection; + if (aSelection.hasElements()) + nSelection = aSelection[0]; + + rList.set_active(nSelection); + rList.save_value(); + + maChangeListeners.emplace_back(new ComboBoxChangeListener(rList, xPropSet)); + maChangeListeners.back()->start(); + } + } + } + catch(const Exception&) + { + OSL_FAIL("BibGeneralPage::AddXControl: something went wrong!"); + } + return xCtrModel.is(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/general.hxx b/extensions/source/bibliography/general.hxx new file mode 100644 index 000000000..b4d981955 --- /dev/null +++ b/extensions/source/bibliography/general.hxx @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in 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 "bibshortcuthandler.hxx" + + +class BibDataManager; +#define TYPE_COUNT 22 +#define FIELD_COUNT 31 + +class ChangeListener; + +class BibGeneralPage : public InterimItemWindow + , public BibShortCutHandler +{ + std::unique_ptr xScrolledWindow; + std::unique_ptr xGrid; + + std::unique_ptr xIdentifierFT; + std::unique_ptr xIdentifierED; + + std::unique_ptr xAuthTypeFT; + std::unique_ptr xAuthTypeLB; + std::unique_ptr xYearFT; + std::unique_ptr xYearED; + + std::unique_ptr xAuthorFT; + std::unique_ptr xAuthorED; + std::unique_ptr xTitleFT; + std::unique_ptr xTitleED; + + std::unique_ptr xPublisherFT; + std::unique_ptr xPublisherED; + std::unique_ptr xAddressFT; + std::unique_ptr xAddressED; + std::unique_ptr xISBNFT; + std::unique_ptr xISBNED; + + std::unique_ptr xChapterFT; + std::unique_ptr xChapterED; + std::unique_ptr xPagesFT; + std::unique_ptr xPagesED; + + std::unique_ptr xEditorFT; + std::unique_ptr xEditorED; + std::unique_ptr xEditionFT; + std::unique_ptr xEditionED; + + std::unique_ptr xBooktitleFT; + std::unique_ptr xBooktitleED; + std::unique_ptr xVolumeFT; + std::unique_ptr xVolumeED; + std::unique_ptr xHowpublishedFT; + std::unique_ptr xHowpublishedED; + + std::unique_ptr xOrganizationsFT; + std::unique_ptr xOrganizationsED; + std::unique_ptr xInstitutionFT; + std::unique_ptr xInstitutionED; + std::unique_ptr xSchoolFT; + std::unique_ptr xSchoolED; + + std::unique_ptr xReportTypeFT; + std::unique_ptr xReportTypeED; + std::unique_ptr xMonthFT; + std::unique_ptr xMonthED; + + std::unique_ptr xJournalFT; + std::unique_ptr xJournalED; + std::unique_ptr xNumberFT; + std::unique_ptr xNumberED; + std::unique_ptr xSeriesFT; + std::unique_ptr xSeriesED; + + std::unique_ptr xAnnoteFT; + std::unique_ptr xAnnoteED; + std::unique_ptr xNoteFT; + std::unique_ptr xNoteED; + std::unique_ptr xURLFT; + std::unique_ptr xURLED; + + std::unique_ptr xCustom1FT; + std::unique_ptr xCustom1ED; + std::unique_ptr xCustom2FT; + std::unique_ptr xCustom2ED; + std::unique_ptr xCustom3FT; + std::unique_ptr xCustom3ED; + std::unique_ptr xCustom4FT; + std::unique_ptr xCustom4ED; + std::unique_ptr xCustom5FT; + std::unique_ptr xCustom5ED; + std::unique_ptr m_xLocalURLFT; + std::unique_ptr m_xLocalURLED; + std::unique_ptr m_xLocalBrowseButton; + std::unique_ptr m_xLocalPageCB; + std::unique_ptr m_xLocalPageSB; + + OUString sTableErrorString; + + std::vector> maChangeListeners; + rtl::Reference m_aURLListener; + + BibDataManager* pDatMan; + + bool AddXControl(const OUString& rName, weld::Entry& rEntry); + bool AddXControl(const OUString& rName, weld::ComboBox& rList); + + template void AddControlWithError(const OUString& rColumnName, const OUString& rColumnUIName, + Target& rWidget, OUString& rErrorString, const OString& rHelpId); + + void SaveChanges(); + + DECL_LINK(GainFocusHdl, weld::Widget&, void); + + DECL_LINK(FirstElementKeyInputHdl, const KeyEvent&, bool); + DECL_LINK(LastElementKeyInputHdl, const KeyEvent&, bool); + DECL_LINK(BrowseHdl, weld::Button&, void); + DECL_LINK(PageNumHdl, weld::Toggleable&, void); + DECL_LINK(LosePageFocusHdl, weld::Widget&, void); + +public: + BibGeneralPage(vcl::Window* pParent, BibDataManager* pDatMan); + virtual ~BibGeneralPage() override; + virtual void dispose() override; + + const OUString& GetErrorString() const + { + return sTableErrorString; + } + + weld::Entry& GetLocalURLED(); + weld::CheckButton& GetLocalPageCB(); + weld::SpinButton& GetLocalPageSB(); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/loadlisteneradapter.cxx b/extensions/source/bibliography/loadlisteneradapter.cxx new file mode 100644 index 000000000..27f4ea2e5 --- /dev/null +++ b/extensions/source/bibliography/loadlisteneradapter.cxx @@ -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 . + */ + +#include "loadlisteneradapter.hxx" +#include +#include + + +namespace bib +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::form; + + OComponentListener::~OComponentListener() + { + ::osl::MutexGuard aGuard( m_rMutex ); + if ( m_xAdapter.is() ) + m_xAdapter->dispose(); + } + + + void OComponentListener::setAdapter( OComponentAdapterBase* pAdapter ) + { + ::osl::MutexGuard aGuard( m_rMutex ); + m_xAdapter = pAdapter; + } + + OComponentAdapterBase::OComponentAdapterBase( const Reference< XComponent >& _rxComp ) + :m_xComponent( _rxComp ) + ,m_pListener( nullptr ) + ,m_bListening( false ) + { + OSL_ENSURE( m_xComponent.is(), "OComponentAdapterBase::OComponentAdapterBase: invalid component!" ); + } + + + void OComponentAdapterBase::Init( OComponentListener* _pListener ) + { + OSL_ENSURE( !m_pListener, "OComponentAdapterBase::Init: already initialized!" ); + OSL_ENSURE( _pListener, "OComponentAdapterBase::Init: invalid listener!" ); + + m_pListener = _pListener; + if ( m_pListener ) + m_pListener->setAdapter( this ); + + startComponentListening( ); + m_bListening = true; + } + + + OComponentAdapterBase::~OComponentAdapterBase() + { + } + + + void OComponentAdapterBase::dispose() + { + if ( !m_bListening ) + return; + + ::rtl::Reference< OComponentAdapterBase > xPreventDelete(this); + + disposing(); + + m_pListener->setAdapter(nullptr); + + m_pListener = nullptr; + m_bListening = false; + + m_xComponent = nullptr; + } + + // XEventListener + + + void SAL_CALL OComponentAdapterBase::disposing( const EventObject& ) + { + if (m_pListener) + { + // disconnect the listener + m_pListener->setAdapter( nullptr ); + m_pListener = nullptr; + } + + m_bListening = false; + m_xComponent = nullptr; + } + + OLoadListenerAdapter::OLoadListenerAdapter( const Reference< XLoadable >& _rxLoadable ) + :OComponentAdapterBase( Reference< XComponent >( _rxLoadable, UNO_QUERY ) ) + { + } + + + void OLoadListenerAdapter::startComponentListening() + { + Reference< XLoadable > xLoadable( getComponent(), UNO_QUERY ); + OSL_ENSURE( xLoadable.is(), "OLoadListenerAdapter::OLoadListenerAdapter: invalid object!" ); + if ( xLoadable.is() ) + xLoadable->addLoadListener( this ); + } + + + void SAL_CALL OLoadListenerAdapter::acquire( ) noexcept + { + OLoadListenerAdapter_Base::acquire(); + } + + + void SAL_CALL OLoadListenerAdapter::release( ) noexcept + { + OLoadListenerAdapter_Base::release(); + } + + + void SAL_CALL OLoadListenerAdapter::disposing( const EventObject& _rSource ) + { + OComponentAdapterBase::disposing( _rSource ); + } + + + void OLoadListenerAdapter::disposing() + { + Reference< XLoadable > xLoadable( getComponent(), UNO_QUERY ); + if ( xLoadable.is() ) + xLoadable->removeLoadListener( this ); + } + + + void SAL_CALL OLoadListenerAdapter::loaded( const EventObject& _rEvent ) + { + if ( getLoadListener( ) ) + getLoadListener( )->_loaded( _rEvent ); + } + + + void SAL_CALL OLoadListenerAdapter::unloading( const EventObject& _rEvent ) + { + if ( getLoadListener( ) ) + getLoadListener( )->_unloading( _rEvent ); + } + + + void SAL_CALL OLoadListenerAdapter::unloaded( const EventObject& ) + { + } + + + void SAL_CALL OLoadListenerAdapter::reloading( const EventObject& _rEvent ) + { + if ( getLoadListener( ) ) + getLoadListener( )->_reloading( _rEvent ); + } + + + void SAL_CALL OLoadListenerAdapter::reloaded( const EventObject& _rEvent ) + { + if ( getLoadListener( ) ) + getLoadListener( )->_reloaded( _rEvent ); + } + + +} // namespace bib + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/loadlisteneradapter.hxx b/extensions/source/bibliography/loadlisteneradapter.hxx new file mode 100644 index 000000000..1031dedca --- /dev/null +++ b/extensions/source/bibliography/loadlisteneradapter.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 . + */ + +#pragma once + +#include +#include +#include +#include +#include + + +namespace bib +{ + + + class OComponentAdapterBase; + + class OComponentListener + { + friend class OComponentAdapterBase; + + private: + rtl::Reference m_xAdapter; + ::osl::Mutex& m_rMutex; + protected: + explicit OComponentListener( ::osl::Mutex& _rMutex ) + :m_rMutex( _rMutex ) + { + } + + virtual ~OComponentListener(); + + protected: + void setAdapter( OComponentAdapterBase* _pAdapter ); + }; + + class OComponentAdapterBase + { + friend class OComponentListener; + + private: + css::uno::Reference< css::lang::XComponent > m_xComponent; + OComponentListener* m_pListener; + bool m_bListening : 1; + + // impl method for dispose - virtual, 'cause you at least need to remove the listener from the broadcaster + virtual void disposing() = 0; + + protected: + // attribute access for derivees + const css::uno::Reference< css::lang::XComponent >& + getComponent() const { return m_xComponent; } + OComponentListener* getListener() { return m_pListener; } + + // to be called by derivees which started listening at the component + virtual void startComponentListening() = 0; + + virtual ~OComponentAdapterBase(); + + public: + explicit OComponentAdapterBase( + const css::uno::Reference< css::lang::XComponent >& _rxComp + ); + + // late construction + // can be called from within you ctor, to have you're object fully initialized at the moment of + // the call (which would not be the case when calling this ctor) + void Init( OComponentListener* _pListener ); + + // base for ref-counting, implemented by OComponentAdapter + virtual void SAL_CALL acquire( ) noexcept = 0; + virtual void SAL_CALL release( ) noexcept = 0; + + /// dispose the object - stop listening and such + void dispose(); + + protected: + // XEventListener + /// @throws css::uno::RuntimeException + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ); + }; + + class OLoadListener : public OComponentListener + { + friend class OLoadListenerAdapter; + + protected: + explicit OLoadListener( ::osl::Mutex& _rMutex ) : OComponentListener( _rMutex ) { } + + // XLoadListener equivalents + virtual void _loaded( const css::lang::EventObject& aEvent ) = 0; + virtual void _unloading( const css::lang::EventObject& aEvent ) = 0; + virtual void _reloading( const css::lang::EventObject& aEvent ) = 0; + virtual void _reloaded( const css::lang::EventObject& aEvent ) = 0; + }; + + typedef ::cppu::WeakImplHelper< css::form::XLoadListener > OLoadListenerAdapter_Base; + class OLoadListenerAdapter + :public OLoadListenerAdapter_Base + ,public OComponentAdapterBase + { + protected: + OLoadListener* getLoadListener( ) { return static_cast< OLoadListener* >( getListener() ); } + + protected: + virtual void disposing() override; + virtual void startComponentListening() override; + + public: + explicit OLoadListenerAdapter( + const css::uno::Reference< css::form::XLoadable >& _rxLoadable + ); + + + virtual void SAL_CALL acquire( ) noexcept override; + virtual void SAL_CALL release( ) noexcept override; + + protected: + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& _rSource ) override; + + // 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; + }; + + +} // namespace bib + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/toolbar.cxx b/extensions/source/bibliography/toolbar.cxx new file mode 100644 index 000000000..fd74a04e6 --- /dev/null +++ b/extensions/source/bibliography/toolbar.cxx @@ -0,0 +1,620 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 "datman.hxx" +#include "toolbar.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bibtools.hxx" + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; + + +// Constants -------------------------------------------------------------- + + +BibToolBarListener::BibToolBarListener(BibToolBar *pTB, const OUString& aStr, ToolBoxItemId nId): + nIndex(nId), + aCommand(aStr), + pToolBar(pTB) +{ +} + +BibToolBarListener::~BibToolBarListener() +{ +} + +void BibToolBarListener::statusChanged(const css::frame::FeatureStateEvent& rEvt) +{ + if(rEvt.FeatureURL.Complete == aCommand) + { + SolarMutexGuard aGuard; + pToolBar->EnableItem(nIndex,rEvt.IsEnabled); + + css::uno::Any aState=rEvt.State; + if(auto bChecked = o3tl::tryAccess(aState)) + { + pToolBar->CheckItem(nIndex, *bChecked); + } + + } +}; + + +BibTBListBoxListener::BibTBListBoxListener(BibToolBar *pTB, const OUString& aStr, ToolBoxItemId nId): + BibToolBarListener(pTB,aStr,nId) +{ +} + +BibTBListBoxListener::~BibTBListBoxListener() +{ +} + +void BibTBListBoxListener::statusChanged(const css::frame::FeatureStateEvent& rEvt) +{ + if(rEvt.FeatureURL.Complete != GetCommand()) + return; + + SolarMutexGuard aGuard; + pToolBar->EnableSourceList(rEvt.IsEnabled); + + Any aState = rEvt.State; + if(auto pStringSeq = o3tl::tryAccess>(aState)) + { + pToolBar->UpdateSourceList(false); + pToolBar->ClearSourceList(); + + const OUString* pStringArray = pStringSeq->getConstArray(); + + sal_uInt32 nCount = pStringSeq->getLength(); + OUString aEntry; + for( sal_uInt32 i=0; iInsertSourceEntry(aEntry); + } + pToolBar->UpdateSourceList(true); + } + + pToolBar->SelectSourceEntry(rEvt.FeatureDescriptor); +}; + +BibTBQueryMenuListener::BibTBQueryMenuListener(BibToolBar *pTB, const OUString& aStr, ToolBoxItemId nId): + BibToolBarListener(pTB,aStr,nId) +{ +} + +BibTBQueryMenuListener::~BibTBQueryMenuListener() +{ +} + +void BibTBQueryMenuListener::statusChanged(const frame::FeatureStateEvent& rEvt) +{ + if(rEvt.FeatureURL.Complete != GetCommand()) + return; + + SolarMutexGuard aGuard; + pToolBar->EnableSourceList(rEvt.IsEnabled); + + uno::Any aState=rEvt.State; + auto pStringSeq = o3tl::tryAccess>(aState); + if(!pStringSeq) + return; + + pToolBar->ClearFilterMenu(); + + const OUString* pStringArray = pStringSeq->getConstArray(); + + sal_uInt32 nCount = pStringSeq->getLength(); + for( sal_uInt32 i=0; iInsertFilterItem(pStringArray[i]); + if(pStringArray[i]==rEvt.FeatureDescriptor) + { + pToolBar->SelectFilterItem(nID); + } + } +}; + +BibTBEditListener::BibTBEditListener(BibToolBar *pTB, const OUString& aStr, ToolBoxItemId nId): + BibToolBarListener(pTB,aStr,nId) +{ +} + +BibTBEditListener::~BibTBEditListener() +{ +} + +void BibTBEditListener::statusChanged(const frame::FeatureStateEvent& rEvt) +{ + if(rEvt.FeatureURL.Complete == GetCommand()) + { + SolarMutexGuard aGuard; + pToolBar->EnableQuery(rEvt.IsEnabled); + + uno::Any aState=rEvt.State; + if(auto aStr = o3tl::tryAccess(aState)) + { + pToolBar->SetQueryString(*aStr); + } + } +} + +ComboBoxControl::ComboBoxControl(vcl::Window* pParent) + : InterimItemWindow(pParent, "modules/sbibliography/ui/combobox.ui", "ComboBox") + , m_xFtSource(m_xBuilder->weld_label("label")) + , m_xLBSource(m_xBuilder->weld_combo_box("combobox")) +{ + m_xFtSource->set_toolbar_background(); + m_xLBSource->set_toolbar_background(); + m_xLBSource->set_size_request(100, -1); + SetSizePixel(get_preferred_size()); +} + +void ComboBoxControl::dispose() +{ + m_xLBSource.reset(); + m_xFtSource.reset(); + InterimItemWindow::dispose(); +} + +ComboBoxControl::~ComboBoxControl() +{ + disposeOnce(); +} + +EditControl::EditControl(vcl::Window* pParent) + : InterimItemWindow(pParent, "modules/sbibliography/ui/editbox.ui", "EditBox") + , m_xFtQuery(m_xBuilder->weld_label("label")) + , m_xEdQuery(m_xBuilder->weld_entry("entry")) +{ + m_xFtQuery->set_toolbar_background(); + m_xEdQuery->set_toolbar_background(); + m_xEdQuery->set_size_request(100, -1); + SetSizePixel(get_preferred_size()); +} + +void EditControl::dispose() +{ + m_xEdQuery.reset(); + m_xFtQuery.reset(); + InterimItemWindow::dispose(); +} + +EditControl::~EditControl() +{ + disposeOnce(); +} + +BibToolBar::BibToolBar(vcl::Window* pParent, Link aLink) + : ToolBox(pParent, "toolbar", "modules/sbibliography/ui/toolbar.ui") + , aIdle("BibToolBar") + , xSource(VclPtr::Create(this)) + , pLbSource(xSource->get_widget()) + , xQuery(VclPtr::Create(this)) + , pEdQuery(xQuery->get_widget()) + , xBuilder(Application::CreateBuilder(nullptr, "modules/sbibliography/ui/autofiltermenu.ui")) + , xPopupMenu(xBuilder->weld_menu("menu")) + , nMenuId(0) + , aLayoutManager(aLink) + , nSymbolsSize(SFX_SYMBOLS_SIZE_SMALL) +{ + SvtMiscOptions aSvtMiscOptions; + nSymbolsSize = aSvtMiscOptions.GetCurrentSymbolsSize(); + + xSource->Show(); + pLbSource->connect_changed(LINK( this, BibToolBar, SelHdl)); + + SvtMiscOptions().AddListenerLink( LINK( this, BibToolBar, OptionsChanged_Impl ) ); + Application::AddEventListener( LINK( this, BibToolBar, SettingsChanged_Impl ) ); + + aIdle.SetInvokeHandler(LINK( this, BibToolBar, SendSelHdl)); + aIdle.SetPriority(TaskPriority::LOWEST); + + SetDropdownClickHdl( LINK( this, BibToolBar, MenuHdl)); + + xQuery->Show(); + + nTBC_SOURCE = GetItemId(".uno:Bib/source"); + nTBC_QUERY = GetItemId(".uno:Bib/query"); + nTBC_BT_AUTOFILTER = GetItemId(".uno:Bib/autoFilter"); + nTBC_BT_COL_ASSIGN = GetItemId("TBC_BT_COL_ASSIGN"); + nTBC_BT_CHANGESOURCE = GetItemId(".uno:Bib/sdbsource"); + nTBC_BT_FILTERCRIT = GetItemId(".uno:Bib/standardFilter"); + nTBC_BT_REMOVEFILTER = GetItemId(".uno:Bib/removeFilter"); + + SetItemWindow(nTBC_SOURCE, xSource.get()); + SetItemWindow(nTBC_QUERY , xQuery.get()); + + ApplyImageList(); + + ::bib::AddToTaskPaneList( this ); +} + +BibToolBar::~BibToolBar() +{ + disposeOnce(); +} + +void BibToolBar::dispose() +{ + SvtMiscOptions().RemoveListenerLink( LINK( this, BibToolBar, OptionsChanged_Impl ) ); + Application::RemoveEventListener( LINK( this, BibToolBar, SettingsChanged_Impl ) ); + ::bib::RemoveFromTaskPaneList( this ); + pEdQuery = nullptr; + xQuery.disposeAndClear(); + pLbSource = nullptr; + xSource.disposeAndClear(); + xPopupMenu.reset(); + xBuilder.reset(); + ToolBox::dispose(); +} + +void BibToolBar::InitListener() +{ + ToolBox::ImplToolItems::size_type nCount=GetItemCount(); + + uno::Reference< frame::XDispatch > xDisp(xController,UNO_QUERY); + uno::Reference< util::XURLTransformer > xTrans( util::URLTransformer::create(comphelper::getProcessComponentContext()) ); + if( !xTrans.is() ) + return; + + util::URL aQueryURL; + aQueryURL.Complete = ".uno:Bib/MenuFilter"; + xTrans->parseStrict( aQueryURL); + rtl::Reference pQuery=new BibTBQueryMenuListener(this, aQueryURL.Complete, nTBC_BT_AUTOFILTER); + xDisp->addStatusListener(pQuery, aQueryURL); + + for(ToolBox::ImplToolItems::size_type nPos=0;nPosparseStrict( aURL ); + + css::uno::Reference< css::frame::XStatusListener> xListener; + if (nId == nTBC_SOURCE) + { + xListener=new BibTBListBoxListener(this,aURL.Complete,nId); + } + else if (nId == nTBC_QUERY) + { + xListener=new BibTBEditListener(this,aURL.Complete,nId); + } + else + { + xListener=new BibToolBarListener(this,aURL.Complete,nId); + } + + aListenerArr.push_back( xListener ); + xDisp->addStatusListener(xListener,aURL); + } +} + +void BibToolBar::SetXController(const uno::Reference< frame::XController > & xCtr) +{ + xController=xCtr; + InitListener(); + +} + +void BibToolBar::Select() +{ + ToolBoxItemId nId=GetCurItemId(); + + if (nId != nTBC_BT_AUTOFILTER) + { + SendDispatch(nId,Sequence() ); + } + else + { + Sequence aPropVal + { + comphelper::makePropertyValue("QueryText", pEdQuery->get_text()), + comphelper::makePropertyValue("QueryField", aQueryField) + }; + SendDispatch(nId,aPropVal); + } +} + +void BibToolBar::SendDispatch(ToolBoxItemId nId, const Sequence< PropertyValue >& rArgs) +{ + OUString aCommand = GetItemCommand(nId); + + uno::Reference< frame::XDispatchProvider > xDSP( xController, UNO_QUERY ); + + if( !xDSP.is() || aCommand.isEmpty() ) + return; + + uno::Reference< util::XURLTransformer > xTrans( util::URLTransformer::create(comphelper::getProcessComponentContext()) ); + if( !xTrans.is() ) + return; + + // load the file + util::URL aURL; + aURL.Complete = aCommand; + + xTrans->parseStrict( aURL ); + + uno::Reference< frame::XDispatch > xDisp = xDSP->queryDispatch( aURL, OUString(), frame::FrameSearchFlag::SELF ); + + if ( xDisp.is() ) + xDisp->dispatch( aURL, rArgs); + +} + +void BibToolBar::Click() +{ + ToolBoxItemId nId = GetCurItemId(); + + vcl::Window* pWin = GetParent(); + + if (nId == nTBC_BT_COL_ASSIGN ) + { + if (pDatMan) + pDatMan->CreateMappingDialog(pWin ? pWin->GetFrameWeld() : nullptr); + CheckItem( nId, false ); + } + else if (nId == nTBC_BT_CHANGESOURCE) + { + if (pDatMan) + { + OUString sNew = pDatMan->CreateDBChangeDialog(pWin ? pWin->GetFrameWeld() : nullptr); + if (!sNew.isEmpty()) + pDatMan->setActiveDataSource(sNew); + } + CheckItem( nId, false ); + } +} + +void BibToolBar::ClearFilterMenu() +{ + xPopupMenu->clear(); + nMenuId=0; +} + +sal_uInt16 BibToolBar::InsertFilterItem(const OUString& rMenuEntry) +{ + nMenuId++; + xPopupMenu->append_check(OUString::number(nMenuId), rMenuEntry); + return nMenuId; +} + +void BibToolBar::SelectFilterItem(sal_uInt16 nId) +{ + OString sId = OString::number(nId); + xPopupMenu->set_active(sId, true); + sSelMenuItem = sId; + aQueryField = MnemonicGenerator::EraseAllMnemonicChars(xPopupMenu->get_label(sId)); +} + +void BibToolBar::EnableSourceList(bool bFlag) +{ + xSource->set_sensitive(bFlag); +} + +void BibToolBar::ClearSourceList() +{ + pLbSource->clear(); +} + +void BibToolBar::UpdateSourceList(bool bFlag) +{ + if (bFlag) + pLbSource->thaw(); + else + pLbSource->freeze(); +} + +void BibToolBar::InsertSourceEntry(const OUString& aEntry) +{ + pLbSource->append_text(aEntry); +} + +void BibToolBar::SelectSourceEntry(const OUString& aStr) +{ + pLbSource->set_active_text(aStr); +} + +void BibToolBar::EnableQuery(bool bFlag) +{ + xQuery->set_sensitive(bFlag); +} + +void BibToolBar::SetQueryString(const OUString& aStr) +{ + pEdQuery->set_text(aStr); +} + +bool BibToolBar::PreNotify( NotifyEvent& rNEvt ) +{ + bool bResult = true; + + MouseNotifyEvent nSwitch=rNEvt.GetType(); + if (pEdQuery && pEdQuery->has_focus() && nSwitch == MouseNotifyEvent::KEYINPUT) + { + const vcl::KeyCode& aKeyCode=rNEvt.GetKeyEvent()->GetKeyCode(); + sal_uInt16 nKey = aKeyCode.GetCode(); + if(nKey == KEY_RETURN) + { + Sequence aPropVal + { + comphelper::makePropertyValue("QueryText", pEdQuery->get_text()), + comphelper::makePropertyValue("QueryField", aQueryField) + }; + SendDispatch(nTBC_BT_AUTOFILTER, aPropVal); + return bResult; + } + + } + + bResult=ToolBox::PreNotify(rNEvt); + + return bResult; +} + +IMPL_LINK_NOARG( BibToolBar, SelHdl, weld::ComboBox&, void ) +{ + aIdle.Start(); +} + +IMPL_LINK_NOARG( BibToolBar, SendSelHdl, Timer*, void ) +{ + Sequence aPropVal + { + comphelper::makePropertyValue("DataSourceName", MnemonicGenerator::EraseAllMnemonicChars( pLbSource->get_active_text() )) + }; + SendDispatch(nTBC_SOURCE, aPropVal); +} + +IMPL_LINK_NOARG(BibToolBar, MenuHdl, ToolBox*, void) +{ + ToolBoxItemId nId = GetCurItemId(); + if (nId != nTBC_BT_AUTOFILTER) + return; + + EndSelection(); // before SetDropMode (SetDropMode calls SetItemImage) + + SetItemDown(nTBC_BT_AUTOFILTER, true); + + tools::Rectangle aRect(GetItemRect(nTBC_BT_AUTOFILTER)); + weld::Window* pParent = weld::GetPopupParent(*this, aRect); + OString sId = xPopupMenu->popup_at_rect(pParent, aRect); + + if (!sId.isEmpty()) + { + xPopupMenu->set_active(sSelMenuItem, false); + xPopupMenu->set_active(sId, true); + sSelMenuItem = sId; + aQueryField = MnemonicGenerator::EraseAllMnemonicChars(xPopupMenu->get_label(sId)); + Sequence aPropVal + { + comphelper::makePropertyValue("QueryText", pEdQuery->get_text()), + comphelper::makePropertyValue("QueryField", aQueryField) + }; + SendDispatch(nTBC_BT_AUTOFILTER, aPropVal); + } + + MouseEvent aLeave( Point(), 0, MouseEventModifiers::LEAVEWINDOW | MouseEventModifiers::SYNTHETIC ); + MouseMove( aLeave ); + SetItemDown(nTBC_BT_AUTOFILTER, false); +} + +void BibToolBar::statusChanged(const frame::FeatureStateEvent& rEvent) +{ + for(uno::Reference & rListener : aListenerArr) + { + rListener->statusChanged(rEvent); + } +} + +void BibToolBar::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) && + (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + ApplyImageList(); + ToolBox::DataChanged( rDCEvt ); +} + +IMPL_LINK_NOARG( BibToolBar, OptionsChanged_Impl, LinkParamNone*, void ) +{ + bool bRebuildToolBar = false; + sal_Int16 eSymbolsSize = SvtMiscOptions().GetCurrentSymbolsSize(); + if ( nSymbolsSize != eSymbolsSize ) + { + nSymbolsSize = eSymbolsSize; + bRebuildToolBar = true; + } + + if ( bRebuildToolBar ) + RebuildToolbar(); +} + +IMPL_LINK_NOARG( BibToolBar, SettingsChanged_Impl, VclSimpleEvent&, void ) +{ + // Check if toolbar button size have changed and we have to use system settings + sal_Int16 eSymbolsSize = SvtMiscOptions().GetCurrentSymbolsSize(); + if ( eSymbolsSize != nSymbolsSize ) + { + nSymbolsSize = eSymbolsSize; + RebuildToolbar(); + } +} + +void BibToolBar::RebuildToolbar() +{ + ApplyImageList(); + // We have to call parent asynchronously as SetSize works also asynchronously! + Application::PostUserEvent( aLayoutManager ); +} + +void BibToolBar::ApplyImageList() +{ + SetItemImage(nTBC_BT_AUTOFILTER, Image(StockImage::Yes, nSymbolsSize == SFX_SYMBOLS_SIZE_SMALL ? OUString(RID_EXTBMP_AUTOFILTER_SC) : OUString(RID_EXTBMP_AUTOFILTER_LC))); + SetItemImage(nTBC_BT_FILTERCRIT, Image(StockImage::Yes, nSymbolsSize == SFX_SYMBOLS_SIZE_SMALL ? OUString(RID_EXTBMP_FILTERCRIT_SC) : OUString(RID_EXTBMP_FILTERCRIT_LC))); + SetItemImage(nTBC_BT_REMOVEFILTER, Image(StockImage::Yes, nSymbolsSize == SFX_SYMBOLS_SIZE_SMALL ? OUString(RID_EXTBMP_REMOVE_FILTER_SORT_SC) : OUString(RID_EXTBMP_REMOVE_FILTER_SORT_LC))); + AdjustToolBox(); +} + +void BibToolBar::AdjustToolBox() +{ + Size aOldSize = GetSizePixel(); + Size aSize = CalcWindowSizePixel(); + if ( !aSize.Width() ) + aSize.setWidth( aOldSize.Width() ); + else if ( !aSize.Height() ) + aSize.setHeight( aOldSize.Height() ); + + Size aTbSize = GetSizePixel(); + if ( + (aSize.Width() && aSize.Width() != aTbSize.Width()) || + (aSize.Height() && aSize.Height() != aTbSize.Height()) + ) + { + SetPosSizePixel( GetPosPixel(), aSize ); + Invalidate(); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/bibliography/toolbar.hxx b/extensions/source/bibliography/toolbar.hxx new file mode 100644 index 000000000..4f800f050 --- /dev/null +++ b/extensions/source/bibliography/toolbar.hxx @@ -0,0 +1,217 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include + +class BibDataManager; +class BibToolBar; + +class BibToolBarListener: public cppu::WeakImplHelper < css::frame::XStatusListener> +{ +private: + + ToolBoxItemId nIndex; + OUString aCommand; + +protected: + + VclPtr pToolBar; + +public: + + BibToolBarListener(BibToolBar *pTB, const OUString& aStr, ToolBoxItemId nId); + virtual ~BibToolBarListener() override; + + const OUString& GetCommand() const { return aCommand;} + + // css::lang::XEventListener + // we do not hold References to dispatches, so there is nothing to do on disposal + virtual void SAL_CALL disposing(const css::lang::EventObject& /*Source*/) override {}; + + // css::frame::XStatusListener + virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& Event) override; + +}; + +class BibTBListBoxListener: public BibToolBarListener +{ +public: + + BibTBListBoxListener(BibToolBar *pTB, const OUString& aStr, ToolBoxItemId nId); + virtual ~BibTBListBoxListener() override; + + virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& Event) override; + +}; + +class BibTBEditListener: public BibToolBarListener +{ +public: + + BibTBEditListener(BibToolBar *pTB, const OUString& aStr, ToolBoxItemId nId); + virtual ~BibTBEditListener() override; + + virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& Event) override; + +}; + +class BibTBQueryMenuListener: public BibToolBarListener +{ +public: + + BibTBQueryMenuListener(BibToolBar *pTB, const OUString& aStr, ToolBoxItemId nId); + virtual ~BibTBQueryMenuListener() override; + + virtual void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& Event) override; + +}; + + +typedef std::vector< css::uno::Reference< css::frame::XStatusListener> > BibToolBarListenerArr; + +class ComboBoxControl final : public InterimItemWindow +{ +public: + ComboBoxControl(vcl::Window* pParent); + virtual ~ComboBoxControl() override; + virtual void dispose() override; + + weld::ComboBox* get_widget() { return m_xLBSource.get(); } + + void set_sensitive(bool bSensitive) + { + m_xFtSource->set_sensitive(bSensitive); + m_xLBSource->set_sensitive(bSensitive); + Enable(bSensitive); + } + +private: + std::unique_ptr m_xFtSource; + std::unique_ptr m_xLBSource; +}; + +class EditControl final : public InterimItemWindow +{ +public: + EditControl(vcl::Window* pParent); + virtual ~EditControl() override; + virtual void dispose() override; + + weld::Entry* get_widget() { return m_xEdQuery.get(); } + + void set_sensitive(bool bSensitive) + { + m_xFtQuery->set_sensitive(bSensitive); + m_xEdQuery->set_sensitive(bSensitive); + Enable(bSensitive); + } + +private: + std::unique_ptr m_xFtQuery; + std::unique_ptr m_xEdQuery; +}; + +class BibToolBar: public ToolBox +{ + private: + + BibToolBarListenerArr aListenerArr; + css::uno::Reference< css::frame::XController > xController; + Idle aIdle; + VclPtr xSource; + weld::ComboBox* pLbSource; + VclPtr xQuery; + weld::Entry* pEdQuery; + std::unique_ptr xBuilder; + std::unique_ptr xPopupMenu; + sal_uInt16 nMenuId; + OString sSelMenuItem; + OUString aQueryField; + Link aLayoutManager; + sal_Int16 nSymbolsSize; + + ToolBoxItemId nTBC_SOURCE; + ToolBoxItemId nTBC_QUERY; + ToolBoxItemId nTBC_BT_AUTOFILTER; + ToolBoxItemId nTBC_BT_COL_ASSIGN; + ToolBoxItemId nTBC_BT_CHANGESOURCE; + ToolBoxItemId nTBC_BT_FILTERCRIT; + ToolBoxItemId nTBC_BT_REMOVEFILTER; + + BibDataManager* pDatMan; + DECL_LINK( SelHdl, weld::ComboBox&, void ); + DECL_LINK( SendSelHdl, Timer*, void ); + DECL_LINK( MenuHdl, ToolBox*, void ); + DECL_LINK( OptionsChanged_Impl, LinkParamNone*, void ); + DECL_LINK( SettingsChanged_Impl, VclSimpleEvent&, void ); + + void ApplyImageList(); + void RebuildToolbar(); + + protected: + + void DataChanged( const DataChangedEvent& rDCEvt ) override; + void InitListener(); + virtual void Select() override; + virtual void Click() override; + virtual bool PreNotify( NotifyEvent& rNEvt ) override; + + + public: + + BibToolBar(vcl::Window* pParent, Link aLink); + virtual ~BibToolBar() override; + virtual void dispose() override; + + ToolBoxItemId GetChangeSourceId() const { return nTBC_BT_CHANGESOURCE; } + + void SetXController(const css::uno::Reference< css::frame::XController > &); + + void ClearSourceList(); + void UpdateSourceList(bool bFlag); + void EnableSourceList(bool bFlag); + void InsertSourceEntry(const OUString& ); + void SelectSourceEntry(const OUString& ); + + void EnableQuery(bool bFlag); + void SetQueryString(const OUString& ); + void AdjustToolBox(); + + void ClearFilterMenu(); + sal_uInt16 InsertFilterItem(const OUString& ); + void SelectFilterItem(sal_uInt16 nId); + + /// @throws css::uno::RuntimeException + void statusChanged(const css::frame::FeatureStateEvent& Event); + + void SetDatMan(BibDataManager& rDatMan) {pDatMan = &rDatMan;} + void SendDispatch(ToolBoxItemId nId, const css::uno::Sequence< css::beans::PropertyValue >& rArgs); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/config/WinUserInfo/WinUserInfoBe.component b/extensions/source/config/WinUserInfo/WinUserInfoBe.component new file mode 100644 index 000000000..5dd7d21ad --- /dev/null +++ b/extensions/source/config/WinUserInfo/WinUserInfoBe.component @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/extensions/source/config/WinUserInfo/WinUserInfoBe.cxx b/extensions/source/config/WinUserInfo/WinUserInfoBe.cxx new file mode 100644 index 000000000..2914cf78d --- /dev/null +++ b/extensions/source/config/WinUserInfo/WinUserInfoBe.cxx @@ -0,0 +1,433 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "WinUserInfoBe.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#define SECURITY_WIN32 +#include + +#include +#include + +namespace extensions +{ +namespace config +{ +namespace WinUserInfo +{ +class WinUserInfoBe_Impl +{ +public: + virtual ~WinUserInfoBe_Impl(){}; + virtual OUString GetGivenName() = 0; + virtual OUString GetSn() { return ""; } + virtual OUString GetFathersname() { return ""; } + virtual OUString GetInitials() { return ""; } + virtual OUString GetStreet() { return ""; } + virtual OUString GetCity() { return ""; } + virtual OUString GetState() { return ""; } + virtual OUString GetApartment() { return ""; } + virtual OUString GetPostalCode() { return ""; } + virtual OUString GetCountry() { return ""; } + virtual OUString GetOrganization() { return ""; } + virtual OUString GetPosition() { return ""; } + virtual OUString GetTitle() { return ""; } + virtual OUString GetHomePhone() { return ""; } + virtual OUString GetTelephoneNumber() { return ""; } + virtual OUString GetFaxNumber() { return ""; } + virtual OUString GetMail() { return ""; } +}; +} +} +} + +namespace +{ +constexpr OUStringLiteral givenname(u"givenname"); +constexpr OUStringLiteral sn(u"sn"); +constexpr char fathersname[]("fathersname"); +constexpr OUStringLiteral initials(u"initials"); +constexpr OUStringLiteral street(u"street"); +constexpr OUStringLiteral l(u"l"); +constexpr OUStringLiteral st(u"st"); +constexpr char apartment[]("apartment"); +constexpr OUStringLiteral postalcode(u"postalcode"); +constexpr OUStringLiteral c(u"c"); +constexpr OUStringLiteral o(u"o"); +constexpr char position[]("position"); +constexpr OUStringLiteral title(u"title"); +constexpr OUStringLiteral homephone(u"homephone"); +constexpr OUStringLiteral telephonenumber(u"telephonenumber"); +constexpr OUStringLiteral facsimiletelephonenumber(u"facsimiletelephonenumber"); +constexpr OUStringLiteral mail(u"mail"); + +// Backend class implementing access to Active Directory user data. It caches its encoded data +// in a configuration entry, to allow reusing it when user later doesn't have access to AD DC +// (otherwise the user would get different data when connected vs not connected). +class ADsUserAccess : public extensions::config::WinUserInfo::WinUserInfoBe_Impl +{ +public: + ADsUserAccess() + { + try + { + sal::systools::CoInitializeGuard aCoInitializeGuard(COINIT_APARTMENTTHREADED); + + sal::systools::COMReference pADsys(CLSID_ADSystemInfo, nullptr, + CLSCTX_INPROC_SERVER); + + sal::systools::BStr sUserDN; + sal::systools::ThrowIfFailed(pADsys->get_UserName(&sUserDN), "get_UserName failed"); + // If this user is an AD user, then without an active connection to the domain, all the + // above will succeed, and m_sUserDN will be correctly initialized, but the following + // call to ADsGetObject will fail, and we will attempt reading cached values. + m_sUserDN = sUserDN; + OUString sLdapUserDN = "LDAP://" + m_sUserDN; + sal::systools::COMReference pUser; + sal::systools::ThrowIfFailed(ADsGetObject(o3tl::toW(sLdapUserDN.getStr()), IID_IADsUser, + reinterpret_cast(&pUser)), + "ADsGetObject failed"); + // Fetch all the required information right now, when we know to have access to AD + // (later the connection may already be lost) + m_aMap[givenname] = Str(pUser, &IADsUser::get_FirstName); + m_aMap[sn] = Str(pUser, &IADsUser::get_LastName); + m_aMap[initials] = Str(pUser, L"initials"); + m_aMap[street] = Str(pUser, L"streetAddress"); + m_aMap[l] = Str(pUser, L"l"); + m_aMap[st] = Str(pUser, L"st"); + m_aMap[postalcode] = Str(pUser, L"postalCode"); + m_aMap[c] = Str(pUser, L"co"); + m_aMap[o] = Str(pUser, L"company"); + m_aMap[title] = Str(pUser, &IADsUser::get_Title); + m_aMap[homephone] = Str(pUser, L"homePhone"); + m_aMap[telephonenumber] = Str(pUser, L"TelephoneNumber"); + m_aMap[facsimiletelephonenumber] = Str(pUser, L"facsimileTelephoneNumber"); + m_aMap[mail] = Str(pUser, &IADsUser::get_EmailAddress); + + CacheData(); + } + catch (sal::systools::ComError&) + { + // Maybe we temporarily lost connection to AD; try to get cached data + GetCachedData(); + } + } + + virtual OUString GetGivenName() override { return m_aMap[givenname]; } + virtual OUString GetSn() override { return m_aMap[sn]; } + virtual OUString GetInitials() override { return m_aMap[initials]; } + virtual OUString GetStreet() override { return m_aMap[street]; } + virtual OUString GetCity() override { return m_aMap[l]; } + virtual OUString GetState() override { return m_aMap[st]; } + virtual OUString GetPostalCode() override { return m_aMap[postalcode]; } + virtual OUString GetCountry() override { return m_aMap[c]; } + virtual OUString GetOrganization() override { return m_aMap[o]; } + virtual OUString GetTitle() override { return m_aMap[title]; } + virtual OUString GetHomePhone() override { return m_aMap[homephone]; } + virtual OUString GetTelephoneNumber() override { return m_aMap[telephonenumber]; } + virtual OUString GetFaxNumber() override { return m_aMap[facsimiletelephonenumber]; } + virtual OUString GetMail() override { return m_aMap[mail]; } + +private: + typedef HRESULT (__stdcall IADsUser::*getstrfunc)(BSTR*); + static OUString Str(IADsUser* pUser, getstrfunc func) + { + sal::systools::BStr sBstr; + if (FAILED((pUser->*func)(&sBstr))) + return ""; + return OUString(sBstr); + } + static OUString Str(IADsUser* pUser, const wchar_t* property) + { + sal::systools::BStr sBstrProp{ o3tl::toU(property) }; + struct AutoVariant : public VARIANT + { + AutoVariant() { VariantInit(this); } + ~AutoVariant() { VariantClear(this); } + } varArr; + if (FAILED(pUser->GetEx(sBstrProp, &varArr))) + return ""; + SAFEARRAY* sa = V_ARRAY(&varArr); + LONG nStart, nEnd; + if (FAILED(SafeArrayGetLBound(sa, 1, &nStart)) || FAILED(SafeArrayGetUBound(sa, 1, &nEnd))) + return ""; + AutoVariant varItem; + for (LONG i = nStart; i <= nEnd; i++) + { + if (FAILED(SafeArrayGetElement(sa, &i, &varItem))) + continue; + if (varItem.vt == VT_BSTR) + return OUString(o3tl::toU(V_BSTR(&varItem))); + VariantClear(&varItem); + } + return ""; + } + + void CacheData() + { + try + { + OUString sCachedData = "user=" + m_sUserDN // user DN + + "\0" + givenname + "=" + GetGivenName() // 1st name + + "\0" + sn + "=" + GetSn() // sn + + "\0" + initials + "=" + GetInitials() // initials + + "\0" + street + "=" + GetStreet() // street + + "\0" + l + "=" + GetCity() // l + + "\0" + st + "=" + GetState() // st + + "\0" + postalcode + "=" + GetPostalCode() // p.code + + "\0" + c + "=" + GetCountry() // c + + "\0" + o + "=" + GetOrganization() // o + + "\0" + title + "=" + GetTitle() // title + + "\0" + homephone + "=" + GetHomePhone() // h.phone + + "\0" + telephonenumber + "=" + GetTelephoneNumber() // tel + + "\0" + facsimiletelephonenumber + "=" + GetFaxNumber() // fax + + "\0" + mail + "=" + GetMail(); // mail + const css::uno::Sequence seqCachedData( + reinterpret_cast(sCachedData.getStr()), + sCachedData.getLength() * sizeof(sal_Unicode)); + OUStringBuffer sOutBuf; + comphelper::Base64::encode(sOutBuf, seqCachedData); + + std::shared_ptr batch( + comphelper::ConfigurationChanges::create()); + officecfg::UserProfile::WinUserInfo::Cache::set(sOutBuf.makeStringAndClear(), batch); + batch->commit(); + } + catch (const css::uno::Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.config", + "ADsUserAccess: access to configuration data failed:"); + } + } + + void GetCachedData() + { + if (m_sUserDN.isEmpty()) + throw css::uno::RuntimeException(); + + OUString sCache = officecfg::UserProfile::WinUserInfo::Cache::get(); + + if (sCache.isEmpty()) + throw css::uno::RuntimeException(); + + { + css::uno::Sequence seqCachedData; + comphelper::Base64::decode(seqCachedData, sCache); + sCache = OUString(reinterpret_cast(seqCachedData.getConstArray()), + seqCachedData.getLength() / sizeof(sal_Unicode)); + } + + OUString sUserDN; + std::map aMap; + sal_Int32 nIndex = 0; + do + { + const OUString sEntry = sCache.getToken(0, '\0', nIndex); + sal_Int32 nEqIndex = 0; + const OUString sEntryName = sEntry.getToken(0, '=', nEqIndex); + OUString sEntryVal; + if (nEqIndex >= 0) + sEntryVal = sEntry.copy(nEqIndex); + if (sEntryName == "user") + sUserDN = sEntryVal; + else + aMap[sEntryName] = sEntryVal; + } while (nIndex >= 0); + + if (sUserDN != m_sUserDN) + throw css::uno::RuntimeException(); + m_aMap = std::move(aMap); + } + + OUString m_sUserDN; // used to check if the cached data is for current user + std::map m_aMap; +}; + +class SysInfoUserAccess : public extensions::config::WinUserInfo::WinUserInfoBe_Impl +{ +public: + SysInfoUserAccess() + { + try + { + ULONG nSize = 0; + GetUserNameExW(NameDisplay, nullptr, &nSize); + if (GetLastError() != ERROR_MORE_DATA) + throw css::uno::RuntimeException(); + auto pNameBuf(std::make_unique(nSize)); + if (!GetUserNameExW(NameDisplay, pNameBuf.get(), &nSize)) + throw css::uno::RuntimeException(); + m_sName = o3tl::toU(pNameBuf.get()); + } + catch (css::uno::RuntimeException&) + { + // GetUserNameEx may fail in some cases (e.g., for built-in AD domain + // administrator account on non-DC systems), where GetUserName will + // still give a name. + DWORD nSize = UNLEN + 1; + auto pNameBuf(std::make_unique(nSize)); + if (!GetUserNameW(pNameBuf.get(), &nSize)) + throw css::uno::RuntimeException(); + m_sName = o3tl::toU(pNameBuf.get()); + } + } + + virtual OUString GetGivenName() override { return m_sName; } + +private: + OUString m_sName; +}; +} + +namespace extensions +{ +namespace config +{ +namespace WinUserInfo +{ +WinUserInfoBe::WinUserInfoBe() + : WinUserInfoMutexHolder() + , BackendBase(mMutex) +{ + try + { + m_pImpl.reset(new ADsUserAccess()); + } + catch (css::uno::RuntimeException&) + { + m_pImpl.reset(new SysInfoUserAccess); + } +} + +WinUserInfoBe::~WinUserInfoBe() {} + +void WinUserInfoBe::setPropertyValue(OUString const&, css::uno::Any const&) +{ + throw css::lang::IllegalArgumentException("setPropertyValue not supported", + static_cast(this), -1); +} + +css::uno::Any WinUserInfoBe::getPropertyValue(OUString const& PropertyName) +{ + OUString sValue; + // Only process the first argument of possibly multiple space- or comma-separated arguments + OUString sToken = PropertyName.getToken(0, ' ').getToken(0, ','); + if (sToken == givenname) + { + sValue = m_pImpl->GetGivenName(); + } + else if (sToken == sn) + { + sValue = m_pImpl->GetSn(); + } + else if (sToken == fathersname) + { + sValue = m_pImpl->GetFathersname(); + } + else if (sToken == initials) + { + sValue = m_pImpl->GetInitials(); + } + else if (sToken == street) + { + sValue = m_pImpl->GetStreet(); + } + else if (sToken == l) + { + sValue = m_pImpl->GetCity(); + } + else if (sToken == st) + { + sValue = m_pImpl->GetState(); + } + else if (sToken == apartment) + { + sValue = m_pImpl->GetApartment(); + } + else if (sToken == postalcode) + { + sValue = m_pImpl->GetPostalCode(); + } + else if (sToken == c) + { + sValue = m_pImpl->GetCountry(); + } + else if (sToken == o) + { + sValue = m_pImpl->GetOrganization(); + } + else if (sToken == position) + { + sValue = m_pImpl->GetPosition(); + } + else if (sToken == title) + { + sValue = m_pImpl->GetTitle(); + } + else if (sToken == homephone) + { + sValue = m_pImpl->GetHomePhone(); + } + else if (sToken == telephonenumber) + { + sValue = m_pImpl->GetTelephoneNumber(); + } + else if (sToken == facsimiletelephonenumber) + { + sValue = m_pImpl->GetFaxNumber(); + } + else if (sToken == mail) + { + sValue = m_pImpl->GetMail(); + } + else + throw css::beans::UnknownPropertyException(sToken, static_cast(this)); + + return css::uno::Any(css::beans::Optional( + !sValue.isEmpty(), sValue.isEmpty() ? css::uno::Any() : css::uno::Any(sValue))); +} + +OUString SAL_CALL WinUserInfoBe::getImplementationName() +{ + return "com.sun.star.comp.configuration.backend.WinUserInfoBe"; +} + +sal_Bool SAL_CALL WinUserInfoBe::supportsService(const OUString& aServiceName) +{ + return cppu::supportsService(this, aServiceName); +} + +css::uno::Sequence SAL_CALL WinUserInfoBe::getSupportedServiceNames() +{ + return { "com.sun.star.configuration.backend.WinUserInfoBe" }; +} +} +} +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_WinUserInfoBe_get_implementation(css::uno::XComponentContext*, + css::uno::Sequence const&) +{ + return cppu::acquire(new extensions::config::WinUserInfo::WinUserInfoBe()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/config/WinUserInfo/WinUserInfoBe.hxx b/extensions/source/config/WinUserInfo/WinUserInfoBe.hxx new file mode 100644 index 000000000..30ca088c3 --- /dev/null +++ b/extensions/source/config/WinUserInfo/WinUserInfoBe.hxx @@ -0,0 +1,101 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include +#include + +namespace com +{ +namespace sun +{ +namespace star +{ +namespace uno +{ +class XComponentContext; +} +} +} +} + +namespace extensions +{ +namespace config +{ +namespace WinUserInfo +{ +class WinUserInfoBe_Impl; + +typedef cppu::WeakComponentImplHelper + BackendBase; + +struct WinUserInfoMutexHolder +{ + osl::Mutex mMutex; +}; +/** + Implements the PlatformBackend service, a specialization of the + XPropertySet service for retrieving Active Directory user profile + configuration settings. +*/ +class WinUserInfoBe : private WinUserInfoMutexHolder, public BackendBase +{ +public: + explicit WinUserInfoBe(); + virtual ~WinUserInfoBe() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + + virtual sal_Bool SAL_CALL supportsService(const OUString& aServiceName) override; + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference SAL_CALL getPropertySetInfo() override + { + return css::uno::Reference(); + } + + virtual void SAL_CALL setPropertyValue(OUString const&, css::uno::Any const&) override; + + virtual css::uno::Any SAL_CALL getPropertyValue(OUString const& PropertyName) override; + + virtual void SAL_CALL addPropertyChangeListener( + OUString const&, css::uno::Reference const&) override + { + } + + virtual void SAL_CALL removePropertyChangeListener( + OUString const&, css::uno::Reference const&) override + { + } + + virtual void SAL_CALL addVetoableChangeListener( + OUString const&, css::uno::Reference const&) override + { + } + + virtual void SAL_CALL removeVetoableChangeListener( + OUString const&, css::uno::Reference const&) override + { + } + +private: + std::unique_ptr m_pImpl; +}; +} +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/config/ldap/ldapaccess.cxx b/extensions/source/config/ldap/ldapaccess.cxx new file mode 100644 index 000000000..7e35408b3 --- /dev/null +++ b/extensions/source/config/ldap/ldapaccess.cxx @@ -0,0 +1,289 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "ldapaccess.hxx" + +#include +#include + +#include + + +namespace extensions::config::ldap { + + +typedef int LdapErrCode; + +struct LdapMessageHolder +{ + LdapMessageHolder() : msg(nullptr) {} + ~LdapMessageHolder() + { + if (msg) + ldap_msgfree(msg); + } + LdapMessageHolder(const LdapMessageHolder&) = delete; + LdapMessageHolder& operator=(const LdapMessageHolder&) = delete; + + LDAPMessage * msg; +}; + +LdapConnection::~LdapConnection() +{ + if (isValid()) disconnect(); +} + + +void LdapConnection::disconnect() +{ + if (mConnection != nullptr) + { + ldap_unbind_s(mConnection) ; + mConnection = nullptr; + } +} + + +static void checkLdapReturnCode(const char *aOperation, + LdapErrCode aRetCode) +{ + if (aRetCode == LDAP_SUCCESS) { return ; } + + OUString message; + + if (aOperation != nullptr) + { + message += OUString::createFromAscii(aOperation) + ": "; + } + message += OUString::createFromAscii(ldap_err2string(aRetCode)) + " (" ; + +#ifndef LDAP_OPT_SIZELIMIT // for use with OpenLDAP + char* stub = nullptr; + ldap_get_lderrno(aConnection, NULL, &stub) ; + if (stub != nullptr) + { + message += OUString::createFromAscii(stub) ; + // It would seem the message returned is actually + // not a copy of a string but rather some static + // string itself. At any rate freeing it seems to + // cause some undue problems at least on Windows. + // This call is thus disabled for the moment. + //ldap_memfree(stub) ; + } + else +#endif + { message += "No additional information"; } + + message += ")" ; + throw ldap::LdapGenericException(message, nullptr, aRetCode) ; +} + +void LdapConnection::connectSimple(const LdapDefinition& aDefinition) +{ + OSL_ENSURE(!isValid(), "Re-connecting to an LDAP connection that is already established"); + if (isValid()) disconnect(); + + mLdapDefinition = aDefinition; + connectSimple(); +} + +void LdapConnection::connectSimple() +{ + if (isValid()) + return; + + // Connect to the server + initConnection() ; + // Set Protocol V3 + int version = LDAP_VERSION3; + ldap_set_option(mConnection, + LDAP_OPT_PROTOCOL_VERSION, + &version); + +#ifdef LDAP_X_OPT_CONNECT_TIMEOUT // OpenLDAP doesn't support this and the func + /* timeout is specified in milliseconds -> 4 seconds*/ + int timeout = 4000; +#ifdef _WIN32 + ldap_set_optionW( mConnection, + LDAP_X_OPT_CONNECT_TIMEOUT, + &timeout ); +#else + ldap_set_option( mConnection, + LDAP_X_OPT_CONNECT_TIMEOUT, + &timeout ); +#endif +#endif + + // Do the bind +#ifdef _WIN32 + LdapErrCode retCode = ldap_simple_bind_sW(mConnection, + const_cast(o3tl::toW(mLdapDefinition.mAnonUser.getStr())), + const_cast(o3tl::toW(mLdapDefinition.mAnonCredentials.getStr())) ); +#else + LdapErrCode retCode = ldap_simple_bind_s(mConnection, + OUStringToOString( mLdapDefinition.mAnonUser, RTL_TEXTENCODING_UTF8 ).getStr(), + OUStringToOString( mLdapDefinition.mAnonCredentials, RTL_TEXTENCODING_UTF8 ).getStr()) ; +#endif + + checkLdapReturnCode("SimpleBind", retCode) ; +} + +void LdapConnection::initConnection() +{ + if (mLdapDefinition.mServer.isEmpty()) + { + throw ldap::LdapConnectionException("Cannot initialise connection to LDAP: No server specified."); + } + + if (mLdapDefinition.mPort == 0) mLdapDefinition.mPort = LDAP_PORT; + +#ifdef _WIN32 + mConnection = ldap_initW(const_cast(o3tl::toW(mLdapDefinition.mServer.getStr())), + mLdapDefinition.mPort) ; +#else + mConnection = ldap_init(OUStringToOString( mLdapDefinition.mServer, RTL_TEXTENCODING_UTF8 ).getStr(), + mLdapDefinition.mPort) ; +#endif + if (mConnection == nullptr) + { + throw ldap::LdapConnectionException( + "Cannot initialise connection to LDAP server " + + mLdapDefinition.mServer + ":" + OUString::number(mLdapDefinition.mPort)); + } +} + + void LdapConnection::getUserProfile( + const OUString& aUser, LdapData * data) +{ + OSL_ASSERT(data != nullptr); + if (!isValid()) { connectSimple(); } + + OUString aUserDn =findUserDn( aUser ); + + LdapMessageHolder result; +#ifdef _WIN32 + LdapErrCode retCode = ldap_search_sW(mConnection, + const_cast(o3tl::toW(aUserDn.getStr())), + LDAP_SCOPE_BASE, + const_cast( L"(objectclass=*)" ), + nullptr, + 0, // Attributes + values + &result.msg) ; +#else + LdapErrCode retCode = ldap_search_s(mConnection, + OUStringToOString( aUserDn, RTL_TEXTENCODING_UTF8 ).getStr(), + LDAP_SCOPE_BASE, + "(objectclass=*)", + nullptr, + 0, // Attributes + values + &result.msg) ; +#endif + checkLdapReturnCode("getUserProfile", retCode) ; + + BerElement * ptr; +#ifdef _WIN32 + PWCHAR attr = ldap_first_attributeW(mConnection, result.msg, &ptr); + while (attr) { + PWCHAR * values = ldap_get_valuesW(mConnection, result.msg, attr); + if (values) { + const OUString aAttr( o3tl::toU( attr ) ); + const OUString aValues( o3tl::toU( *values ) ); + data->emplace( aAttr, aValues ); + ldap_value_freeW(values); + } + attr = ldap_next_attributeW(mConnection, result.msg, ptr); +#else + char * attr = ldap_first_attribute(mConnection, result.msg, &ptr); + while (attr) { + char ** values = ldap_get_values(mConnection, result.msg, attr); + if (values) { + data->emplace( + OStringToOUString(attr, RTL_TEXTENCODING_ASCII_US), + OStringToOUString(*values, RTL_TEXTENCODING_UTF8)); + ldap_value_free(values); + } + attr = ldap_next_attribute(mConnection, result.msg, ptr); +#endif + } +} + + OUString LdapConnection::findUserDn(const OUString& aUser) +{ + if (!isValid()) { connectSimple(); } + + if (aUser.isEmpty()) + { + throw lang::IllegalArgumentException( + "LdapConnection::findUserDn -User id is empty", + nullptr, 0) ; + } + + OUString filter = "(&(objectclass=" + + mLdapDefinition.mUserObjectClass + + ")(" + + mLdapDefinition.mUserUniqueAttr + + "=" + + aUser + + "))"; + + LdapMessageHolder result; +#ifdef _WIN32 + PWCHAR attributes [2] = { const_cast( L"1.1" ), nullptr }; + LdapErrCode retCode = ldap_search_sW(mConnection, + const_cast(o3tl::toW(mLdapDefinition.mBaseDN.getStr())), + LDAP_SCOPE_SUBTREE, + const_cast(o3tl::toW(filter.getStr())), attributes, 0, &result.msg) ; +#else + char * attributes [2] = { const_cast(LDAP_NO_ATTRS), nullptr }; + LdapErrCode retCode = ldap_search_s(mConnection, + OUStringToOString( mLdapDefinition.mBaseDN, RTL_TEXTENCODING_UTF8 ).getStr(), + LDAP_SCOPE_SUBTREE, + OUStringToOString( filter, RTL_TEXTENCODING_UTF8 ).getStr(), attributes, 0, &result.msg) ; +#endif + checkLdapReturnCode("FindUserDn", retCode) ; + OUString userDn ; + LDAPMessage *entry = ldap_first_entry(mConnection, result.msg) ; + + if (entry != nullptr) + { +#ifdef _WIN32 + PWCHAR charsDn = ldap_get_dnW(mConnection, entry) ; + + userDn = OUString( o3tl::toU( charsDn ) ); + ldap_memfreeW(charsDn) ; +#else + char *charsDn = ldap_get_dn(mConnection, entry) ; + + userDn = OStringToOUString( charsDn, RTL_TEXTENCODING_UTF8 ); + ldap_memfree(charsDn) ; +#endif + } + else + { + OSL_FAIL( "LdapConnection::findUserDn-could not get DN for User "); + } + + return userDn ; +} + + +} // extensions::config::ldap + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/config/ldap/ldapaccess.hxx b/extensions/source/config/ldap/ldapaccess.hxx new file mode 100644 index 000000000..36a0708b1 --- /dev/null +++ b/extensions/source/config/ldap/ldapaccess.hxx @@ -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 . + */ + +#pragma once + +#include + +#include + +#ifdef _WIN32 +#if !defined WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#else // !defined _WIN32 +#include +#endif // _WIN32 + +#include + +#include + +namespace extensions::config::ldap +{ +namespace uno = css::uno; +namespace lang = css::lang; +namespace ldap = css::ldap; + +struct LdapUserProfile; + +/** Struct containing the information on LDAP connection */ +struct LdapDefinition +{ + /** LDAP server name */ + OUString mServer; + /** LDAP server port number */ + sal_Int32 mPort; + /** Repository base DN */ + OUString mBaseDN; + /** DN to use for "anonymous" connection */ + OUString mAnonUser; + /** Credentials to use for "anonymous" connection */ + OUString mAnonCredentials; + /** User Entity Object Class */ + OUString mUserObjectClass; + /** User Entity Unique Attribute */ + OUString mUserUniqueAttr; + + LdapDefinition() + : mPort(0) + { + } +}; + +typedef std::map LdapData; // key/value pairs + +/** Class encapsulating all LDAP functionality */ +class LdapConnection +{ + friend struct LdapMessageHolder; + +public: + /** Default constructor */ + LdapConnection() + : mConnection(nullptr) + , mLdapDefinition() + { + } + /** Destructor, releases the connection */ + ~LdapConnection(); + /** Make connection to LDAP server + @throws ldap::LdapConnectionException + @throws ldap::LdapGenericException + */ + void connectSimple(const LdapDefinition& aDefinition); + + /** + Gets LdapUserProfile from LDAP repository for specified user + @param aUser name of logged on user + @param aUserProfileMap Map containing LDAP->00o mapping + @param aUserProfile struct for holding OOo values + + @throws css::ldap::LdapGenericException + if an LDAP error occurs. + */ + void getUserProfile(const OUString& aUser, LdapData* data); + + /** finds DN of user + @return DN of User + @throws lang::IllegalArgumentException + @throws ldap::LdapConnectionException + @throws ldap::LdapGenericException + */ + OUString findUserDn(const OUString& aUser); + +private: + /// @throws ldap::LdapConnectionException + void initConnection(); + void disconnect(); + /** + Indicates whether the connection is in a valid state. + @return sal_True if connection is valid, sal_False otherwise + */ + bool isValid() const { return mConnection != nullptr; } + + /// @throws ldap::LdapConnectionException + /// @throws ldap::LdapGenericException + void connectSimple(); + + /** LDAP connection object */ + LDAP* mConnection; + LdapDefinition mLdapDefinition; +}; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/config/ldap/ldapbe2.component b/extensions/source/config/ldap/ldapbe2.component new file mode 100644 index 000000000..8f6ea3f80 --- /dev/null +++ b/extensions/source/config/ldap/ldapbe2.component @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/extensions/source/config/ldap/ldapuserprofilebe.cxx b/extensions/source/config/ldap/ldapuserprofilebe.cxx new file mode 100644 index 000000000..2012afd8b --- /dev/null +++ b/extensions/source/config/ldap/ldapuserprofilebe.cxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "ldapaccess.hxx" +#include "ldapuserprofilebe.hxx" +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace extensions::config::ldap { + +LdapUserProfileBe::LdapUserProfileBe( const uno::Reference& xContext) +: BackendBase(m_aMutex) +{ + LdapDefinition aDefinition; + OUString loggedOnUser; + // true initially to handle reentrant call; will become false if readLdapConfiguration fails + bool bHaveLdapConfiguration = true; + + // This whole rigmarole is to prevent an infinite recursion where reading + // the configuration for the backend would create another instance of the + // backend, which would try and read the configuration which would... + { + osl::Mutex & aInitMutex = rtl::Static< osl::Mutex, LdapUserProfileBe >::get(); + osl::MutexGuard aInitGuard(aInitMutex); + + static bool bReentrantCall; // = false + OSL_ENSURE(!bReentrantCall, "configuration: Ldap Backend constructor called reentrantly - probably a registration error."); + + if (!bReentrantCall) + { + bReentrantCall = true ; + comphelper::ScopeGuard aReentrantCallGuard([]() { bReentrantCall = false; }); + // Don't throw on fail: this will crash if LDAP is misconfigured, and user opens + // Expert Configuration dialog. Instead, just don't fill data_, which will make the + // backend return empty values. This happens in SvtUserOptions::Impl::GetValue_Impl + // anyway even in throwing scenario, but doing it here also improves performance + // because of avoiding repeated attempts to create the backend. + bHaveLdapConfiguration = readLdapConfiguration( + xContext, &aDefinition, &loggedOnUser); + if (!bHaveLdapConfiguration) + SAL_WARN("extensions.config", "LdapUserProfileBackend: LDAP not configured"); + } + } + + if (bHaveLdapConfiguration) + { + LdapConnection connection; + connection.connectSimple(aDefinition); + connection.getUserProfile(loggedOnUser, &data_); + } +} + +LdapUserProfileBe::~LdapUserProfileBe() +{ +} + + +bool LdapUserProfileBe::readLdapConfiguration( + css::uno::Reference< css::uno::XComponentContext > const & context, + LdapDefinition * definition, OUString * loggedOnUser) +{ + OSL_ASSERT(context.is() && definition != nullptr && loggedOnUser != nullptr); + + uno::Reference< XInterface > xIface; + try + { + uno::Reference< lang::XMultiServiceFactory > xCfgProvider( + css::configuration::theDefaultProvider::get(context)); + + css::beans::NamedValue aPath("nodepath", uno::Any(OUString("org.openoffice.LDAP/UserDirectory")) ); + + uno::Sequence< uno::Any > aArgs{ uno::Any(aPath) }; + + xIface = xCfgProvider->createInstanceWithArguments("com.sun.star.configuration.ConfigurationAccess", aArgs); + + uno::Reference xAccess(xIface, uno::UNO_QUERY_THROW); + xAccess->getByName("ServerDefinition") >>= xIface; + + uno::Reference xChildAccess(xIface, uno::UNO_QUERY_THROW); + + if (!getLdapStringParam(xChildAccess, "Server", definition->mServer)) + return false; + if (!getLdapStringParam(xChildAccess, "BaseDN", definition->mBaseDN)) + return false; + + definition->mPort=0; + xChildAccess->getByName("Port") >>= definition->mPort ; + if (definition->mPort == 0) + return false; + + if (!getLdapStringParam(xAccess, "UserObjectClass", definition->mUserObjectClass)) + return false; + if (!getLdapStringParam(xAccess, "UserUniqueAttribute", definition->mUserUniqueAttr)) + return false; + + getLdapStringParam(xAccess, "SearchUser", definition->mAnonUser); + getLdapStringParam(xAccess, "SearchPassword", definition->mAnonCredentials); + } + catch (const uno::Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.config", "LdapUserProfileBackend: access to configuration data failed"); + return false; + } + + osl::Security aSecurityContext; + if (!aSecurityContext.getUserName(*loggedOnUser)) + SAL_WARN("extensions.config", "LdapUserProfileBackend - could not get Logged on user from system"); + + sal_Int32 nIndex = loggedOnUser->indexOf('/'); + if (nIndex > 0) + *loggedOnUser = loggedOnUser->copy(nIndex+1); + + return true; +} + + +bool LdapUserProfileBe::getLdapStringParam( + uno::Reference const & xAccess, + const OUString& aLdapSetting, + OUString& aServerParameter) +{ + xAccess->getByName(aLdapSetting) >>= aServerParameter; + + return !aServerParameter.isEmpty(); +} + +void LdapUserProfileBe::setPropertyValue( + OUString const &, css::uno::Any const &) +{ + throw css::lang::IllegalArgumentException( + "setPropertyValue not supported", + static_cast< cppu::OWeakObject * >(this), -1); +} + +css::uno::Any LdapUserProfileBe::getPropertyValue( + OUString const & PropertyName) +{ + for (sal_Int32 i = 0;;) { + sal_Int32 j = PropertyName.indexOf(',', i); + if (j == -1) { + j = PropertyName.getLength(); + } + if (j == i) { + throw css::beans::UnknownPropertyException( + PropertyName, static_cast< cppu::OWeakObject * >(this)); + } + LdapData::iterator k(data_.find(PropertyName.copy(i, j - i))); + if (k != data_.end()) { + return css::uno::Any( + css::beans::Optional< css::uno::Any >( + true, css::uno::Any(k->second))); + } + if (j == PropertyName.getLength()) { + break; + } + i = j + 1; + } + return css::uno::Any(css::beans::Optional< css::uno::Any >()); +} + + +OUString SAL_CALL LdapUserProfileBe::getImplementationName() +{ + return "com.sun.star.comp.configuration.backend.LdapUserProfileBe"; +} + +sal_Bool SAL_CALL LdapUserProfileBe::supportsService(const OUString& aServiceName) +{ + return cppu::supportsService(this, aServiceName); +} + +uno::Sequence +SAL_CALL LdapUserProfileBe::getSupportedServiceNames() +{ + return { "com.sun.star.configuration.backend.LdapUserProfileBe" }; +} + +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_ldp_LdapUserProfileBe_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new extensions::config::ldap::LdapUserProfileBe(context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/config/ldap/ldapuserprofilebe.hxx b/extensions/source/config/ldap/ldapuserprofilebe.hxx new file mode 100644 index 000000000..2f0536532 --- /dev/null +++ b/extensions/source/config/ldap/ldapuserprofilebe.hxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "ldapaccess.hxx" + +namespace com::sun::star::uno { + class XComponentContext; +} + +namespace extensions::config::ldap { + +namespace uno = css::uno ; +namespace lang = css::lang ; +namespace container = css::container; + +struct LdapDefinition; + +typedef cppu::WeakComponentImplHelper BackendBase ; + +/** + Implements the PlatformBackend service, a specialization of the + XPropertySet service for retrieving LDAP user profile + configuration settings from an LDAP repository. + */ +class LdapUserProfileBe : private cppu::BaseMutex, public BackendBase +{ + public: + + explicit LdapUserProfileBe(const uno::Reference& xContext); + virtual ~LdapUserProfileBe() override ; + + // XServiceInfo + virtual OUString SAL_CALL + getImplementationName( ) override ; + + virtual sal_Bool SAL_CALL + supportsService( const OUString& aServiceName ) override ; + + virtual uno::Sequence SAL_CALL + getSupportedServiceNames( ) override ; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() override + { return css::uno::Reference< css::beans::XPropertySetInfo >(); } + + virtual void SAL_CALL setPropertyValue( + OUString const &, css::uno::Any const &) override; + + virtual css::uno::Any SAL_CALL getPropertyValue( + OUString const & PropertyName) override; + + virtual void SAL_CALL addPropertyChangeListener( + OUString const &, + css::uno::Reference< css::beans::XPropertyChangeListener > const &) override + {} + + virtual void SAL_CALL removePropertyChangeListener( + OUString const &, + css::uno::Reference< css::beans::XPropertyChangeListener > const &) override + {} + + virtual void SAL_CALL addVetoableChangeListener( + OUString const &, + css::uno::Reference< css::beans::XVetoableChangeListener > const &) override + {} + + virtual void SAL_CALL removeVetoableChangeListener( + OUString const &, + css::uno::Reference< css::beans::XVetoableChangeListener > const &) override + {} + + private: + /** Check if LDAP is configured */ + static bool readLdapConfiguration( + uno::Reference const & context, + LdapDefinition * definition, OUString * loggedOnUser); + + static bool getLdapStringParam(uno::Reference const & xAccess, + const OUString& aLdapSetting, + OUString& aServerParameter); + + LdapData data_; +} ; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/commonpagesdbp.cxx b/extensions/source/dbpilots/commonpagesdbp.cxx new file mode 100644 index 000000000..2e133e9c5 --- /dev/null +++ b/extensions/source/dbpilots/commonpagesdbp.cxx @@ -0,0 +1,449 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "commonpagesdbp.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dbp +{ + + + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + 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::task; + using namespace ::comphelper; + + OTableSelectionPage::OTableSelectionPage(weld::Container* pPage, OControlWizard* pWizard) + : OControlWizardPage(pPage, pWizard, "modules/sabpilot/ui/tableselectionpage.ui", "TableSelectionPage") + , m_xTable(m_xBuilder->weld_tree_view("table")) + , m_xDatasource(m_xBuilder->weld_tree_view("datasource")) + , m_xDatasourceLabel(m_xBuilder->weld_label("datasourcelabel")) + , m_xSearchDatabase(m_xBuilder->weld_button("search")) + , m_xSourceBox(m_xBuilder->weld_container("sourcebox")) + { + try + { + m_xDSContext = getContext().xDatasourceContext; + if (m_xDSContext.is()) + fillListBox(*m_xDatasource, m_xDSContext->getElementNames()); + } + catch (const Exception&) + { + OSL_FAIL("OTableSelectionPage::OTableSelectionPage: could not collect the data source names!"); + } + + m_xDatasource->connect_changed(LINK(this, OTableSelectionPage, OnListboxSelection)); + m_xTable->connect_changed(LINK(this, OTableSelectionPage, OnListboxSelection)); + m_xTable->connect_row_activated(LINK(this, OTableSelectionPage, OnListboxDoubleClicked)); + m_xSearchDatabase->connect_clicked(LINK(this, OTableSelectionPage, OnSearchClicked)); + } + + OTableSelectionPage::~OTableSelectionPage() + { + } + + void OTableSelectionPage::Activate() + { + OControlWizardPage::Activate(); + m_xDatasource->grab_focus(); + } + + bool OTableSelectionPage::canAdvance() const + { + if (!OControlWizardPage::canAdvance()) + return false; + + if (0 == m_xDatasource->count_selected_rows()) + return false; + + if (0 == m_xTable->count_selected_rows()) + return false; + + return true; + } + + void OTableSelectionPage::initializePage() + { + OControlWizardPage::initializePage(); + + const OControlWizardContext& rContext = getContext(); + try + { + OUString sDataSourceName; + rContext.xForm->getPropertyValue("DataSourceName") >>= sDataSourceName; + + Reference< XConnection > xConnection; + bool bEmbedded = ::dbtools::isEmbeddedInDatabase( rContext.xForm, xConnection ); + if ( bEmbedded ) + { + m_xSourceBox->hide(); + m_xDatasource->append_text(sDataSourceName); + } + m_xDatasource->select_text(sDataSourceName); + + implFillTables(xConnection); + + OUString sCommand; + OSL_VERIFY( rContext.xForm->getPropertyValue("Command") >>= sCommand ); + sal_Int32 nCommandType = CommandType::TABLE; + OSL_VERIFY( rContext.xForm->getPropertyValue("CommandType") >>= nCommandType ); + + // search the entry of the given type with the given name + for (sal_Int32 nLookup = 0; nLookup < m_xTable->n_children(); ++nLookup) + { + if (sCommand == m_xTable->get_text(nLookup)) + { + if (m_xTable->get_id(nLookup).toInt32() == nCommandType) + { + m_xTable->select( nLookup ); + break; + } + } + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.abpilot", "OTableSelectionPage::initializePage"); + } + } + + bool OTableSelectionPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OControlWizardPage::commitPage(_eReason)) + return false; + + const OControlWizardContext& rContext = getContext(); + try + { + Reference< XConnection > xOldConn; + if ( !rContext.bEmbedded ) + { + xOldConn = getFormConnection(); + + OUString sDataSource = m_xDatasource->get_selected_text(); + rContext.xForm->setPropertyValue("DataSourceName", Any( sDataSource ) ); + } + OUString sCommand = m_xTable->get_selected_text(); + sal_Int32 nCommandType = m_xTable->get_selected_id().toInt32(); + + rContext.xForm->setPropertyValue("Command", Any( sCommand ) ); + rContext.xForm->setPropertyValue("CommandType", Any( nCommandType ) ); + + if ( !rContext.bEmbedded ) + setFormConnection( xOldConn, false ); + + if (!updateContext()) + return false; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", "OTableSelectionPage::commitPage"); + } + + return true; + } + + IMPL_LINK_NOARG( OTableSelectionPage, OnSearchClicked, weld::Button&, void ) + { + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, getDialog()->getDialog()); + aFileDlg.SetDisplayDirectory( SvtPathOptions().GetWorkPath() ); + + std::shared_ptr pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)"); + OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!"); + if ( pFilter ) + { + aFileDlg.AddFilter(pFilter->GetUIName(),pFilter->GetDefaultExtension()); + } + + if (ERRCODE_NONE == aFileDlg.Execute()) + { + OUString sDataSourceName = aFileDlg.GetPath(); + ::svt::OFileNotation aFileNotation(sDataSourceName); + sDataSourceName = aFileNotation.get(::svt::OFileNotation::N_SYSTEM); + m_xDatasource->append_text(sDataSourceName); + m_xDatasource->select_text(sDataSourceName); + LINK(this, OTableSelectionPage, OnListboxSelection).Call(*m_xDatasource); + } + } + + IMPL_LINK(OTableSelectionPage, OnListboxDoubleClicked, weld::TreeView&, _rBox, bool) + { + if (_rBox.count_selected_rows()) + getDialog()->travelNext(); + return true; + } + + IMPL_LINK(OTableSelectionPage, OnListboxSelection, weld::TreeView&, _rBox, void) + { + if (m_xDatasource.get() == &_rBox) + { // new data source selected + implFillTables(); + } + + updateDialogTravelUI(); + } + + namespace + { + void lcl_fillEntries(weld::TreeView& rListBox, const Sequence& rNames, const OUString& rImage, sal_Int32 nCommandType) + { + for (auto const & name : rNames) + { + rListBox.append(OUString::number(nCommandType), name, rImage); + } + } + } + + void OTableSelectionPage::implFillTables(const Reference< XConnection >& _rxConn) + { + m_xTable->clear(); + + weld::WaitObject aWaitCursor(getDialog()->getDialog()); + + // will be the table tables of the selected data source + Sequence< OUString > aTableNames; + Sequence< OUString > aQueryNames; + + // connect to the data source + Any aSQLException; + Reference< XConnection > xConn = _rxConn; + if ( !xConn.is() ) + { + if (!m_xDSContext.is()) + return; + // connect to the data source + try + { + OUString sCurrentDatasource = m_xDatasource->get_selected_text(); + if (!sCurrentDatasource.isEmpty()) + { + // obtain the DS object + Reference< XCompletedConnection > xDatasource; + // check if I know this one otherwise transform it into a file URL + if ( !m_xDSContext->hasByName(sCurrentDatasource) ) + { + ::svt::OFileNotation aFileNotation(sCurrentDatasource); + sCurrentDatasource = aFileNotation.get(::svt::OFileNotation::N_URL); + } + + if (m_xDSContext->getByName(sCurrentDatasource) >>= xDatasource) + { // connect + // get the default SDB interaction handler + Reference< XInteractionHandler > xHandler = getDialog()->getInteractionHandler(getDialog()->getDialog()); + if (!xHandler.is() ) + return; + xConn = xDatasource->connectWithCompletion(xHandler); + setFormConnection( xConn ); + } + else + { + OSL_FAIL("OTableSelectionPage::implFillTables: invalid data source object returned by the context"); + } + } + } + catch(const SQLContext& e) { aSQLException <<= e; } + catch(const SQLWarning& e) { aSQLException <<= e; } + catch(const SQLException& e) { aSQLException <<= e; } + catch (const Exception&) + { + OSL_FAIL("OTableSelectionPage::implFillTables: could not fill the table list!"); + } + } + + // will be the table tables of the selected data source + if ( xConn.is() ) + { + try + { + // get the tables + Reference< XTablesSupplier > xSupplTables(xConn, UNO_QUERY); + if ( xSupplTables.is() ) + { + Reference< XNameAccess > xTables = xSupplTables->getTables(); + if (xTables.is()) + aTableNames = xTables->getElementNames(); + } + + // and the queries + Reference< XQueriesSupplier > xSuppQueries( xConn, UNO_QUERY ); + if ( xSuppQueries.is() ) + { + Reference< XNameAccess > xQueries = xSuppQueries->getQueries(); + if ( xQueries.is() ) + aQueryNames = xQueries->getElementNames(); + } + } + catch(const SQLContext& e) { aSQLException <<= e; } + catch(const SQLWarning& e) { aSQLException <<= e; } + catch(const SQLException& e) { aSQLException <<= e; } + catch (const Exception&) + { + OSL_FAIL("OTableSelectionPage::implFillTables: could not fill the table list!"); + } + } + + + if ( aSQLException.hasValue() ) + { // an SQLException (or derivee) was thrown ... + Reference< XInteractionRequest > xRequest = new OInteractionRequest(aSQLException); + try + { + // get the default SDB interaction handler + Reference< XInteractionHandler > xHandler = getDialog()->getInteractionHandler(getDialog()->getDialog()); + if ( xHandler.is() ) + xHandler->handle(xRequest); + } + catch(const Exception&) { } + return; + } + + lcl_fillEntries(*m_xTable, aTableNames, BMP_TABLE, CommandType::TABLE); + lcl_fillEntries(*m_xTable, aQueryNames, BMP_QUERY, CommandType::QUERY); + } + + OMaybeListSelectionPage::OMaybeListSelectionPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage(pPage, pWizard, rUIXMLDescription, rID) + , m_pYes(nullptr) + , m_pNo(nullptr) + , m_pList(nullptr) + { + } + + OMaybeListSelectionPage::~OMaybeListSelectionPage() + { + } + + void OMaybeListSelectionPage::announceControls(weld::RadioButton& _rYesButton, weld::RadioButton& _rNoButton, weld::ComboBox& _rSelection) + { + m_pYes = &_rYesButton; + m_pNo = &_rNoButton; + m_pList = &_rSelection; + + m_pYes->connect_toggled(LINK(this, OMaybeListSelectionPage, OnRadioSelected)); + m_pNo->connect_toggled(LINK(this, OMaybeListSelectionPage, OnRadioSelected)); + implEnableWindows(); + } + + IMPL_LINK(OMaybeListSelectionPage, OnRadioSelected, weld::Toggleable&, rButton, void) + { + if (!rButton.get_active()) + return; + implEnableWindows(); + } + + void OMaybeListSelectionPage::implInitialize(const OUString& _rSelection) + { + DBG_ASSERT(m_pYes, "OMaybeListSelectionPage::implInitialize: no controls announced!"); + bool bIsSelection = ! _rSelection.isEmpty(); + m_pYes->set_active(bIsSelection); + m_pNo->set_active(!bIsSelection); + m_pList->set_sensitive(bIsSelection); + + m_pList->set_active_text(bIsSelection ? _rSelection : OUString()); + } + + void OMaybeListSelectionPage::implCommit(OUString& _rSelection) + { + _rSelection = m_pYes->get_active() ? m_pList->get_active_text() : OUString(); + } + + void OMaybeListSelectionPage::implEnableWindows() + { + m_pList->set_sensitive(m_pYes->get_active()); + } + + void OMaybeListSelectionPage::Activate() + { + OControlWizardPage::Activate(); + + DBG_ASSERT(m_pYes, "OMaybeListSelectionPage::Activate: no controls announced!"); + if (m_pYes->get_active()) + m_pList->grab_focus(); + else + m_pNo->grab_focus(); + } + + ODBFieldPage::ODBFieldPage(weld::Container* pPage, OControlWizard* pWizard) + : OMaybeListSelectionPage(pPage, pWizard, "modules/sabpilot/ui/optiondbfieldpage.ui", "OptionDBField") + , m_xDescription(m_xBuilder->weld_label("explLabel")) + , m_xStoreYes(m_xBuilder->weld_radio_button("yesRadiobutton")) + , m_xStoreNo(m_xBuilder->weld_radio_button("noRadiobutton")) + , m_xStoreWhere(m_xBuilder->weld_combo_box("storeInFieldCombobox")) + { + SetPageTitle(compmodule::ModuleRes(RID_STR_OPTION_DB_FIELD_TITLE)); + + announceControls(*m_xStoreYes, *m_xStoreNo, *m_xStoreWhere); + } + + ODBFieldPage::~ODBFieldPage() + { + } + + void ODBFieldPage::initializePage() + { + OMaybeListSelectionPage::initializePage(); + + // fill the fields page + fillListBox(*m_xStoreWhere, getContext().aFieldNames); + + implInitialize(getDBFieldSetting()); + } + + bool ODBFieldPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OMaybeListSelectionPage::commitPage(_eReason)) + return false; + + implCommit(getDBFieldSetting()); + + return true; + } + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/commonpagesdbp.hxx b/extensions/source/dbpilots/commonpagesdbp.hxx new file mode 100644 index 000000000..1ae742150 --- /dev/null +++ b/extensions/source/dbpilots/commonpagesdbp.hxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "controlwizard.hxx" +#include +#include + +namespace dbp +{ + class OTableSelectionPage final : public OControlWizardPage + { + std::unique_ptr m_xTable; + std::unique_ptr m_xDatasource; + std::unique_ptr m_xDatasourceLabel; + std::unique_ptr m_xSearchDatabase; + std::unique_ptr m_xSourceBox; + + css::uno::Reference< css::sdb::XDatabaseContext > + m_xDSContext; + + public: + explicit OTableSelectionPage(weld::Container* pPage, OControlWizard* pParent); + virtual ~OTableSelectionPage() override; + + private: + // BuilderPage overridables + void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + DECL_LINK( OnListboxSelection, weld::TreeView&, void ); + DECL_LINK( OnListboxDoubleClicked, weld::TreeView&, bool ); + DECL_LINK( OnSearchClicked, weld::Button&, void ); + + void implFillTables(const css::uno::Reference< css::sdbc::XConnection >& + _rxConn = css::uno::Reference< css::sdbc::XConnection >()); + + // OControlWizardPage overridables + virtual bool canAdvance() const override; + }; + + class OMaybeListSelectionPage : public OControlWizardPage + { + weld::RadioButton* m_pYes; + weld::RadioButton* m_pNo; + weld::ComboBox* m_pList; + + public: + OMaybeListSelectionPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID); + virtual ~OMaybeListSelectionPage() override; + + protected: + DECL_LINK( OnRadioSelected, weld::Toggleable&, void ); + + // BuilderPage overridables + void Activate() override; + + // own helper + void announceControls( + weld::RadioButton& _rYesButton, + weld::RadioButton& _rNoButton, + weld::ComboBox& _rSelection); + + void implEnableWindows(); + + void implInitialize(const OUString& _rSelection); + void implCommit(OUString& _rSelection); + }; + + class ODBFieldPage : public OMaybeListSelectionPage + { + protected: + std::unique_ptr m_xDescription; + std::unique_ptr m_xStoreYes; + std::unique_ptr m_xStoreNo; + std::unique_ptr m_xStoreWhere; + + public: + explicit ODBFieldPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~ODBFieldPage() override; + + protected: + void setDescriptionText(const OUString& rDesc) + { + m_xDescription->set_label(rDesc); + } + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + // own overridables + virtual OUString& getDBFieldSetting() = 0; + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/controlwizard.cxx b/extensions/source/dbpilots/controlwizard.cxx new file mode 100644 index 000000000..20052c4cb --- /dev/null +++ b/extensions/source/dbpilots/controlwizard.cxx @@ -0,0 +1,663 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "controlwizard.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 + +#define WIZARD_SIZE_X 60 +#define WIZARD_SIZE_Y 23 + +namespace dbp +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + 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::drawing; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::sheet; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::task; + using namespace ::comphelper; + using namespace ::dbtools; + + struct OAccessRegulator + { + friend class OControlWizardPage; + + protected: + OAccessRegulator() { } + }; + + OControlWizardPage::OControlWizardPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage_Base(pPage, pWizard, rUIXMLDescription, rID) + , m_pDialog(pWizard) + { + m_xContainer->set_size_request(m_xContainer->get_approximate_digit_width() * WIZARD_SIZE_X, + m_xContainer->get_text_height() * WIZARD_SIZE_Y); + } + + OControlWizardPage::~OControlWizardPage() + { + } + + OControlWizard* OControlWizardPage::getDialog() + { + return m_pDialog; + } + + const OControlWizard* OControlWizardPage::getDialog() const + { + return m_pDialog; + } + + bool OControlWizardPage::updateContext() + { + return m_pDialog->updateContext(OAccessRegulator()); + } + + Reference< XConnection > OControlWizardPage::getFormConnection() const + { + return m_pDialog->getFormConnection(OAccessRegulator()); + } + + void OControlWizardPage::setFormConnection( const Reference< XConnection >& _rxConn, bool _bAutoDispose ) + { + m_pDialog->setFormConnection( OAccessRegulator(), _rxConn, _bAutoDispose ); + } + + const OControlWizardContext& OControlWizardPage::getContext() const + { + return m_pDialog->getContext(); + } + + void OControlWizardPage::fillListBox(weld::TreeView& _rList, const Sequence< OUString >& _rItems) + { + _rList.clear(); + const OUString* pItems = _rItems.getConstArray(); + const OUString* pEnd = pItems + _rItems.getLength(); + sal_Int32 nIndex = 0; + for (;pItems < pEnd; ++pItems, ++nIndex) + { + _rList.append(OUString::number(nIndex), *pItems); + } + } + + void OControlWizardPage::fillListBox(weld::ComboBox& _rList, const Sequence< OUString >& _rItems) + { + _rList.clear(); + const OUString* pItems = _rItems.getConstArray(); + const OUString* pEnd = pItems + _rItems.getLength(); + for (;pItems < pEnd; ++pItems) + { + _rList.append_text(*pItems); + } + } + + void OControlWizardPage::enableFormDatasourceDisplay() + { + if (m_xFormContentType) + // nothing to do + return; + + m_xFrame = m_xBuilder->weld_frame("sourceframe"); + m_xFrame->show(); + m_xFormContentType = m_xBuilder->weld_label("contenttype"); + m_xFormContentTypeLabel = m_xBuilder->weld_label("contenttypelabel"); + m_xFormDatasource = m_xBuilder->weld_label("datasource"); + m_xFormDatasourceLabel = m_xBuilder->weld_label("datasourcelabel"); + m_xFormTable = m_xBuilder->weld_label("formtable"); + m_xFormTableLabel = m_xBuilder->weld_label("formtablelabel"); + + const OControlWizardContext& rContext = getContext(); + if ( rContext.bEmbedded ) + { + m_xFormDatasourceLabel->hide(); + m_xFormDatasource->hide(); + } + } + + void OControlWizardPage::initializePage() + { + if (m_xFormDatasource && m_xFormContentTypeLabel && m_xFormTable) + { + const OControlWizardContext& rContext = getContext(); + OUString sDataSource; + OUString sCommand; + sal_Int32 nCommandType = CommandType::COMMAND; + try + { + rContext.xForm->getPropertyValue("DataSourceName") >>= sDataSource; + rContext.xForm->getPropertyValue("Command") >>= sCommand; + rContext.xForm->getPropertyValue("CommandType") >>= nCommandType; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", "OControlWizardPage::initializePage"); + } + + INetURLObject aURL( sDataSource ); + if( aURL.GetProtocol() != INetProtocol::NotValid ) + sDataSource = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset); + m_xFormDatasource->set_label(sDataSource); + m_xFormTable->set_label(sCommand); + + TranslateId pCommandTypeResourceId; + switch (nCommandType) + { + case CommandType::TABLE: + pCommandTypeResourceId = RID_STR_TYPE_TABLE; + break; + + case CommandType::QUERY: + pCommandTypeResourceId = RID_STR_TYPE_QUERY; + break; + + default: + pCommandTypeResourceId = RID_STR_TYPE_COMMAND; + break; + } + m_xFormContentType->set_label(compmodule::ModuleRes(pCommandTypeResourceId)); + } + + OControlWizardPage_Base::initializePage(); + } + + OControlWizard::OControlWizard(weld::Window* _pParent, + const Reference< XPropertySet >& _rxObjectModel, const Reference< XComponentContext >& _rxContext ) + : WizardMachine(_pParent, WizardButtonFlags::CANCEL | WizardButtonFlags::PREVIOUS | WizardButtonFlags::NEXT | WizardButtonFlags::FINISH) + , m_xContext(_rxContext) + { + m_aContext.xObjectModel = _rxObjectModel; + initContext(); + + defaultButton(WizardButtonFlags::NEXT); + enableButtons(WizardButtonFlags::FINISH, false); + } + + OControlWizard::~OControlWizard() + { + } + + short OControlWizard::run() + { + // get the class id of the control we're dealing with + sal_Int16 nClassId = FormComponentType::CONTROL; + try + { + getContext().xObjectModel->getPropertyValue("ClassId") >>= nClassId; + } + catch(const Exception&) + { + OSL_FAIL("OControlWizard::activate: could not obtain the class id!"); + } + if (!approveControl(nClassId)) + { + // TODO: MessageBox or exception + return RET_CANCEL; + } + + ActivatePage(); + + m_xAssistant->set_current_page(0); + + return OControlWizard_Base::run(); + } + + void OControlWizard::implDetermineShape() + { + Reference< XIndexAccess > xPageObjects = m_aContext.xDrawPage; + DBG_ASSERT(xPageObjects.is(), "OControlWizard::implDetermineShape: invalid page!"); + + // for comparing the model + Reference< XControlModel > xModelCompare(m_aContext.xObjectModel, UNO_QUERY); + + if (!xPageObjects.is()) + return; + + // loop through all objects of the page + sal_Int32 nObjects = xPageObjects->getCount(); + Reference< XControlShape > xControlShape; + Reference< XControlModel > xControlModel; + for (sal_Int32 i=0; igetByIndex(i) >>= xControlShape) + { // it _is_ a control shape + xControlModel = xControlShape->getControl(); + DBG_ASSERT(xControlModel.is(), "OControlWizard::implDetermineShape: control shape without model!"); + if (xModelCompare.get() == xControlModel.get()) + { + m_aContext.xObjectShape = xControlShape; + break; + } + } + } + } + + + void OControlWizard::implDetermineForm() + { + Reference< XChild > xModelAsChild(m_aContext.xObjectModel, UNO_QUERY); + Reference< XInterface > xControlParent; + if (xModelAsChild.is()) + xControlParent = xModelAsChild->getParent(); + + m_aContext.xForm.set(xControlParent, UNO_QUERY); + m_aContext.xRowSet.set(xControlParent, UNO_QUERY); + DBG_ASSERT(m_aContext.xForm.is() && m_aContext.xRowSet.is(), + "OControlWizard::implDetermineForm: missing some interfaces of the control parent!"); + + } + + + void OControlWizard::implDeterminePage() + { + try + { + // get the document model + Reference< XChild > xControlAsChild(m_aContext.xObjectModel, UNO_QUERY); + Reference< XChild > xModelSearch(xControlAsChild->getParent(), UNO_QUERY); + + Reference< XModel > xModel(xModelSearch, UNO_QUERY); + while (xModelSearch.is() && !xModel.is()) + { + xModelSearch.set(xModelSearch->getParent(), UNO_QUERY); + xModel.set(xModelSearch, UNO_QUERY); + } + + Reference< XDrawPage > xPage; + if (xModel.is()) + { + m_aContext.xDocumentModel = xModel; + + Reference< XDrawPageSupplier > xPageSupp(xModel, UNO_QUERY); + if (xPageSupp.is()) + { // it's a document with only one page -> Writer + xPage = xPageSupp->getDrawPage(); + } + else + { + // get the controller currently working on this model + Reference< XController > xController = xModel->getCurrentController(); + DBG_ASSERT(xController.is(), "OControlWizard::implDeterminePage: no current controller!"); + + // maybe it's a spreadsheet + Reference< XSpreadsheetView > xView(xController, UNO_QUERY); + if (xView.is()) + { // okay, it is one + Reference< XSpreadsheet > xSheet = xView->getActiveSheet(); + xPageSupp.set(xSheet, UNO_QUERY); + DBG_ASSERT(xPageSupp.is(), "OControlWizard::implDeterminePage: a spreadsheet which is no page supplier!"); + if (xPageSupp.is()) + xPage = xPageSupp->getDrawPage(); + } + else + { // can be a draw/impress doc only + Reference< XDrawView > xDrawView(xController, UNO_QUERY); + DBG_ASSERT(xDrawView.is(), "OControlWizard::implDeterminePage: no alternatives left ... can't determine the page!"); + if (xDrawView.is()) + xPage = xDrawView->getCurrentPage(); + } + } + } + else + { + DBG_ASSERT(xPage.is(), "OControlWizard::implDeterminePage: can't determine the page (no model)!"); + } + m_aContext.xDrawPage = xPage; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", "OControlWizard::implDeterminePage"); + } + } + + + void OControlWizard::implGetDSContext() + { + try + { + DBG_ASSERT(m_xContext.is(), "OControlWizard::implGetDSContext: invalid service factory!"); + + m_aContext.xDatasourceContext = DatabaseContext::create(m_xContext); + } + catch(const Exception&) + { + OSL_FAIL("OControlWizard::implGetDSContext: invalid database context!"); + } + } + + + Reference< XConnection > OControlWizard::getFormConnection(const OAccessRegulator&) const + { + return getFormConnection(); + } + + Reference< XConnection > OControlWizard::getFormConnection() const + { + Reference< XConnection > xConn; + try + { + if ( !::dbtools::isEmbeddedInDatabase(m_aContext.xForm,xConn) ) + m_aContext.xForm->getPropertyValue("ActiveConnection") >>= xConn; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", "OControlWizard::getFormConnection"); + } + return xConn; + } + + + void OControlWizard::setFormConnection( const OAccessRegulator& _rAccess, const Reference< XConnection >& _rxConn, bool _bAutoDispose ) + { + try + { + Reference< XConnection > xOldConn = getFormConnection(_rAccess); + if (xOldConn.get() == _rxConn.get()) + return; + + disposeComponent(xOldConn); + + // set the new connection + if ( _bAutoDispose ) + { + // for this, use an AutoDisposer (so the conn is cleaned up when the form dies or gets another connection) + Reference< XRowSet > xFormRowSet( m_aContext.xForm, UNO_QUERY ); + new OAutoConnectionDisposer( xFormRowSet, _rxConn ); + } + else + { + m_aContext.xForm->setPropertyValue("ActiveConnection", Any( _rxConn ) ); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OControlWizard::setFormConnection"); + } + } + + + bool OControlWizard::updateContext(const OAccessRegulator&) + { + return initContext(); + } + + Reference< XInteractionHandler > OControlWizard::getInteractionHandler(weld::Window* _pWindow) const + { + Reference< XInteractionHandler > xHandler; + try + { + xHandler.set( InteractionHandler::createWithParent(m_xContext, nullptr), UNO_QUERY_THROW ); + } + catch(const Exception&) { } + if (!xHandler.is()) + { + ShowServiceNotAvailableError(_pWindow, u"com.sun.star.task.InteractionHandler", true); + } + return xHandler; + } + + bool OControlWizard::initContext() + { + DBG_ASSERT(m_aContext.xObjectModel.is(), "OGroupBoxWizard::initContext: have no control model to work with!"); + if (!m_aContext.xObjectModel.is()) + return false; + + // reset the context + m_aContext.xForm.clear(); + m_aContext.xRowSet.clear(); + m_aContext.xDocumentModel.clear(); + m_aContext.xDrawPage.clear(); + m_aContext.xObjectShape.clear(); + m_aContext.aFieldNames.realloc(0); + + m_aContext.xObjectContainer.clear(); + m_aContext.aTypes.clear(); + m_aContext.bEmbedded = false; + + Any aSQLException; + Reference< XPreparedStatement > xStatement; + try + { + // get the datasource context + implGetDSContext(); + + // first, determine the form the control belongs to + implDetermineForm(); + + // need the page, too + implDeterminePage(); + + // the shape of the control + implDetermineShape(); + + // get the columns of the object the settings refer to + Reference< XNameAccess > xColumns; + + if (m_aContext.xForm.is()) + { + // collect some properties of the form + OUString sObjectName = ::comphelper::getString(m_aContext.xForm->getPropertyValue("Command")); + sal_Int32 nObjectType = ::comphelper::getINT32(m_aContext.xForm->getPropertyValue("CommandType")); + + // calculate the connection the rowset is working with + Reference< XConnection > xConnection; + m_aContext.bEmbedded = ::dbtools::isEmbeddedInDatabase( m_aContext.xForm, xConnection ); + if ( !m_aContext.bEmbedded ) + xConnection = ::dbtools::connectRowset( m_aContext.xRowSet, m_xContext, nullptr ); + + // get the fields + if (xConnection.is()) + { + switch (nObjectType) + { + case 0: + { + Reference< XTablesSupplier > xSupplyTables(xConnection, UNO_QUERY); + if (xSupplyTables.is() && xSupplyTables->getTables().is() && xSupplyTables->getTables()->hasByName(sObjectName)) + { + Reference< XColumnsSupplier > xSupplyColumns; + m_aContext.xObjectContainer = xSupplyTables->getTables(); + m_aContext.xObjectContainer->getByName(sObjectName) >>= xSupplyColumns; + DBG_ASSERT(xSupplyColumns.is(), "OControlWizard::initContext: invalid table columns!"); + xColumns = xSupplyColumns->getColumns(); + } + } + break; + case 1: + { + Reference< XQueriesSupplier > xSupplyQueries(xConnection, UNO_QUERY); + if (xSupplyQueries.is() && xSupplyQueries->getQueries().is() && xSupplyQueries->getQueries()->hasByName(sObjectName)) + { + Reference< XColumnsSupplier > xSupplyColumns; + m_aContext.xObjectContainer = xSupplyQueries->getQueries(); + m_aContext.xObjectContainer->getByName(sObjectName) >>= xSupplyColumns; + DBG_ASSERT(xSupplyColumns.is(), "OControlWizard::initContext: invalid query columns!"); + xColumns = xSupplyColumns->getColumns(); + } + } + break; + default: + { + xStatement = xConnection->prepareStatement(sObjectName); + + // not interested in any results, only in the fields + Reference< XPropertySet > xStatementProps(xStatement, UNO_QUERY); + xStatementProps->setPropertyValue("MaxRows", Any(sal_Int32(0))); + + // TODO: think about handling local SQLExceptions here ... + Reference< XColumnsSupplier > xSupplyCols(xStatement->executeQuery(), UNO_QUERY); + if (xSupplyCols.is()) + xColumns = xSupplyCols->getColumns(); + } + } + } + } + + if (xColumns.is()) + { + m_aContext.aFieldNames = xColumns->getElementNames(); + const OUString* pBegin = m_aContext.aFieldNames.getConstArray(); + const OUString* pEnd = pBegin + m_aContext.aFieldNames.getLength(); + for(;pBegin != pEnd;++pBegin) + { + sal_Int32 nFieldType = DataType::OTHER; + try + { + Reference< XPropertySet > xColumn; + xColumns->getByName(*pBegin) >>= xColumn; + xColumn->getPropertyValue("Type") >>= nFieldType; + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( + "extensions.dbpilots", + "unexpected exception while gathering column information!"); + } + m_aContext.aTypes.emplace(*pBegin,nFieldType); + } + } + } + catch(const SQLContext& e) { aSQLException <<= e; } + catch(const SQLWarning& e) { aSQLException <<= e; } + catch(const SQLException& e) { aSQLException <<= e; } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OControlWizard::initContext: could not retrieve the control context"); + } + + ::comphelper::disposeComponent(xStatement); + + if (aSQLException.hasValue()) + { // an SQLException (or derivee) was thrown ... + + // prepend an extra SQLContext explaining what we were doing + SQLContext aContext; + aContext.Message = compmodule::ModuleRes(RID_STR_COULDNOTOPENTABLE); + aContext.NextException = aSQLException; + + // create an interaction handler to display this exception + Reference< XInteractionHandler > xHandler = getInteractionHandler(m_xAssistant.get()); + if ( !xHandler.is() ) + return false; + + Reference< XInteractionRequest > xRequest = new OInteractionRequest(Any(aContext)); + try + { + xHandler->handle(xRequest); + } + catch(const Exception&) { } + return false; + } + + return m_aContext.aFieldNames.hasElements(); + } + + + void OControlWizard::commitControlSettings(OControlWizardSettings const * _pSettings) + { + DBG_ASSERT(m_aContext.xObjectModel.is(), "OControlWizard::commitControlSettings: have no control model to work with!"); + if (!m_aContext.xObjectModel.is()) + return; + + // the only thing we have at the moment is the label + try + { + Reference< XPropertySetInfo > xInfo = m_aContext.xObjectModel->getPropertySetInfo(); + if (xInfo.is() && xInfo->hasPropertyByName("Label")) + { + OUString sControlLabel(_pSettings->sControlLabel); + m_aContext.xObjectModel->setPropertyValue( + "Label", + Any(sControlLabel) + ); + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OControlWizard::commitControlSettings: could not commit the basic control settings!"); + } + } + + + void OControlWizard::initControlSettings(OControlWizardSettings* _pSettings) + { + DBG_ASSERT(m_aContext.xObjectModel.is(), "OControlWizard::initControlSettings: have no control model to work with!"); + if (!m_aContext.xObjectModel.is()) + return; + + // initialize some settings from the control model give + try + { + OUString sLabelPropertyName("Label"); + Reference< XPropertySetInfo > xInfo = m_aContext.xObjectModel->getPropertySetInfo(); + if (xInfo.is() && xInfo->hasPropertyByName(sLabelPropertyName)) + { + OUString sControlLabel; + m_aContext.xObjectModel->getPropertyValue(sLabelPropertyName) >>= sControlLabel; + _pSettings->sControlLabel = sControlLabel; + } + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OControlWizard::initControlSettings: could not retrieve the basic control settings!"); + } + } + + + bool OControlWizard::needDatasourceSelection() + { + // lemme see ... + return !getContext().aFieldNames.hasElements(); + // if we got fields, the data source is valid ... + } + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/controlwizard.hxx b/extensions/source/dbpilots/controlwizard.hxx new file mode 100644 index 000000000..cf55c655e --- /dev/null +++ b/extensions/source/dbpilots/controlwizard.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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include "dbptypes.hxx" +#include +#include +#include "wizardcontext.hxx" + +class ResId; + +namespace dbp +{ + struct OControlWizardSettings + { + OUString sControlLabel; + }; + + class OControlWizard; + typedef ::vcl::OWizardPage OControlWizardPage_Base; + class OControlWizardPage : public OControlWizardPage_Base + { + OControlWizard* m_pDialog; + std::unique_ptr m_xFormDatasourceLabel; + std::unique_ptr m_xFormDatasource; + std::unique_ptr m_xFormContentTypeLabel; + std::unique_ptr m_xFormContentType; + std::unique_ptr m_xFormTableLabel; + std::unique_ptr m_xFormTable; + std::unique_ptr m_xFrame; + + protected: + OControlWizard* getDialog(); + const OControlWizard* getDialog() const; + const OControlWizardContext& getContext() const; + bool updateContext(); + void setFormConnection(const css::uno::Reference< css::sdbc::XConnection >& _rxConn, bool _bAutoDispose = true ); + css::uno::Reference< css::sdbc::XConnection > + getFormConnection() const; + public: + OControlWizardPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID); + virtual ~OControlWizardPage() override; + + protected: + static void fillListBox( + weld::TreeView& _rList, + const css::uno::Sequence< OUString >& _rItems); + static void fillListBox( + weld::ComboBox& _rList, + const css::uno::Sequence< OUString >& _rItems); + + protected: + void enableFormDatasourceDisplay(); + + protected: + // OWizardPage overridables + virtual void initializePage() override; + }; + + struct OAccessRegulator; + + typedef ::vcl::WizardMachine OControlWizard_Base; + class OControlWizard : public OControlWizard_Base + { + private: + OControlWizardContext m_aContext; + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + + public: + OControlWizard( + weld::Window* _pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxObjectModel, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + virtual ~OControlWizard() override; + + // make the same base class methods public + using OControlWizard_Base::travelNext; + + public: + const css::uno::Reference< css::uno::XComponentContext >& + getComponentContext() const { return m_xContext; } + + const OControlWizardContext& getContext() const { return m_aContext; } + bool updateContext(const OAccessRegulator&); + void setFormConnection(const OAccessRegulator&, const css::uno::Reference< css::sdbc::XConnection >& _rxConn, bool _bAutoDispose ); + css::uno::Reference< css::sdbc::XConnection > + getFormConnection(const OAccessRegulator&) const; + + /** returns the com.sun.star.task.InteractionHandler + @param _pWindow The window will be used when an error message has to be shown. + */ + css::uno::Reference< css::task::XInteractionHandler > getInteractionHandler(weld::Window* _pWindow) const; + + protected: + // initialize the derivees settings (which have to be derived from OControlWizardSettings) + // with some common data extracted from the control model + void initControlSettings(OControlWizardSettings* _pSettings); + // commit the control-relevant settings + void commitControlSettings(OControlWizardSettings const * _pSettings); + + bool needDatasourceSelection(); + + css::uno::Reference< css::sdbc::XConnection > + getFormConnection() const; + + virtual bool approveControl(sal_Int16 _nClassId) = 0; + + virtual short run() override; + + private: + bool initContext(); + + void implGetDSContext(); + void implDetermineForm(); + void implDeterminePage(); + void implDetermineShape(); + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/dbp.component b/extensions/source/dbpilots/dbp.component new file mode 100644 index 000000000..5cff1fb3c --- /dev/null +++ b/extensions/source/dbpilots/dbp.component @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + diff --git a/extensions/source/dbpilots/dbptools.cxx b/extensions/source/dbpilots/dbptools.cxx new file mode 100644 index 000000000..1b647e84c --- /dev/null +++ b/extensions/source/dbpilots/dbptools.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 "dbptools.hxx" +#include +#include + + +namespace dbp +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::container; + + + void disambiguateName(const Reference< XNameAccess >& _rxContainer, OUString& _rElementsName) + { + DBG_ASSERT(_rxContainer.is(), "::dbp::disambiguateName: invalid container!"); + if (!_rxContainer.is()) + return; + + try + { + OUString sBase(_rElementsName); + for (sal_Int32 i=1; i<0x7FFFFFFF; ++i) + { + _rElementsName = sBase; + _rElementsName += OUString::number(i); + if (!_rxContainer->hasByName(_rElementsName)) + return; + } + // can't do anything ... no free names + _rElementsName = sBase; + } + catch(const Exception&) + { + OSL_FAIL("::dbp::disambiguateName: something went (strangely) wrong!"); + } + } + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/dbptools.hxx b/extensions/source/dbpilots/dbptools.hxx new file mode 100644 index 000000000..d7577f187 --- /dev/null +++ b/extensions/source/dbpilots/dbptools.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + + +namespace dbp +{ + + + void disambiguateName( + const css::uno::Reference< css::container::XNameAccess >& _rxContainer, + OUString& _rElementsName); + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/dbptypes.hxx b/extensions/source/dbpilots/dbptypes.hxx new file mode 100644 index 000000000..8b86fe506 --- /dev/null +++ b/extensions/source/dbpilots/dbptypes.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include +#include + +namespace dbp +{ +typedef std::set StringBag; +typedef std::map MapInt2String; + +} // namespace dbp + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/gridwizard.cxx b/extensions/source/dbpilots/gridwizard.cxx new file mode 100644 index 000000000..3cf1d0324 --- /dev/null +++ b/extensions/source/dbpilots/gridwizard.cxx @@ -0,0 +1,446 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "gridwizard.hxx" +#include +#include +#include +#include +#include +#include +#include "dbptools.hxx" +#include + +#define GW_STATE_DATASOURCE_SELECTION 0 +#define GW_STATE_FIELDSELECTION 1 + + +namespace dbp +{ + + + 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::container; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::awt; + + OGridWizard::OGridWizard(weld::Window* _pParent, + const Reference< XPropertySet >& _rxObjectModel, const Reference< XComponentContext >& _rxContext ) + : OControlWizard(_pParent, _rxObjectModel, _rxContext) + , m_bHadDataSelection(true) + { + initControlSettings(&m_aSettings); + + m_xPrevPage->set_help_id(HID_GRIDWIZARD_PREVIOUS); + m_xNextPage->set_help_id(HID_GRIDWIZARD_NEXT); + m_xCancel->set_help_id(HID_GRIDWIZARD_CANCEL); + m_xFinish->set_help_id(HID_GRIDWIZARD_FINISH); + setTitleBase(compmodule::ModuleRes(RID_STR_GRIDWIZARD_TITLE)); + + // if we do not need the data source selection page ... + if (!needDatasourceSelection()) + { // ... skip it! + skip(); + m_bHadDataSelection = false; + } + } + + bool OGridWizard::approveControl(sal_Int16 _nClassId) + { + if (FormComponentType::GRIDCONTROL != _nClassId) + return false; + + Reference< XGridColumnFactory > xColumnFactory(getContext().xObjectModel, UNO_QUERY); + return xColumnFactory.is(); + } + + void OGridWizard::implApplySettings() + { + const OControlWizardContext& rContext = getContext(); + + // the factory for the columns + Reference< XGridColumnFactory > xColumnFactory(rContext.xObjectModel, UNO_QUERY); + DBG_ASSERT(xColumnFactory.is(), "OGridWizard::implApplySettings: should never have made it 'til here!"); + // (if we're here, what the hell happened in approveControl??) + + // the container for the columns + Reference< XNameContainer > xColumnContainer(rContext.xObjectModel, UNO_QUERY); + DBG_ASSERT(xColumnContainer.is(), "OGridWizard::implApplySettings: no container!"); + + if (!xColumnFactory.is() || !xColumnContainer.is()) + return; + + static constexpr OUStringLiteral s_sMouseWheelBehavior = u"MouseWheelBehavior"; + static constexpr OUStringLiteral s_sEmptyString = u""; + + // collect "descriptors" for the to-be-created (grid)columns + std::vector< OUString > aColumnServiceNames; // service names to be used with the XGridColumnFactory + std::vector< OUString > aColumnLabelPostfixes; // postfixes to append to the column labels + std::vector< OUString > aFormFieldNames; // data field names + + aColumnServiceNames.reserve(getSettings().aSelectedFields.getLength()); + aColumnLabelPostfixes.reserve(getSettings().aSelectedFields.getLength()); + aFormFieldNames.reserve(getSettings().aSelectedFields.getLength()); + + // loop through the selected field names + const OUString* pSelectedFields = getSettings().aSelectedFields.getConstArray(); + const OUString* pEnd = pSelectedFields + getSettings().aSelectedFields.getLength(); + for (;pSelectedFields < pEnd; ++pSelectedFields) + { + // get the information for the selected column + sal_Int32 nFieldType = DataType::OTHER; + OControlWizardContext::TNameTypeMap::const_iterator aFind = rContext.aTypes.find(*pSelectedFields); + if ( aFind != rContext.aTypes.end() ) + nFieldType = aFind->second; + + aFormFieldNames.push_back(*pSelectedFields); + switch (nFieldType) + { + case DataType::BIT: + case DataType::BOOLEAN: + aColumnServiceNames.push_back(OUString("CheckBox")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::TINYINT: + case DataType::SMALLINT: + case DataType::INTEGER: + aColumnServiceNames.push_back(OUString("NumericField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::FLOAT: + case DataType::REAL: + case DataType::DOUBLE: + case DataType::NUMERIC: + case DataType::DECIMAL: + aColumnServiceNames.push_back(OUString("FormattedField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::DATE: + aColumnServiceNames.push_back(OUString("DateField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::TIME: + aColumnServiceNames.push_back(OUString("TimeField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + break; + + case DataType::TIMESTAMP: + aColumnServiceNames.push_back(OUString("DateField")); + aColumnLabelPostfixes.push_back(compmodule::ModuleRes(RID_STR_DATEPOSTFIX)); + + aFormFieldNames.push_back(*pSelectedFields); + aColumnServiceNames.push_back(OUString("TimeField")); + aColumnLabelPostfixes.push_back(compmodule::ModuleRes(RID_STR_TIMEPOSTFIX)); + break; + + default: + aColumnServiceNames.push_back(OUString("TextField")); + aColumnLabelPostfixes.push_back(s_sEmptyString); + } + } + + DBG_ASSERT( aFormFieldNames.size() == aColumnServiceNames.size() + && aColumnServiceNames.size() == aColumnLabelPostfixes.size(), + "OGridWizard::implApplySettings: inconsistent descriptor sequences!"); + + // now loop through the descriptions and create the (grid)columns out of th descriptors + { + Reference< XNameAccess > xExistenceChecker(xColumnContainer); + + std::vector< OUString >::const_iterator pColumnLabelPostfix = aColumnLabelPostfixes.begin(); + std::vector< OUString >::const_iterator pFormFieldName = aFormFieldNames.begin(); + + for (const auto& rColumnServiceName : aColumnServiceNames) + { + // create a (grid)column for the (resultset)column + try + { + Reference< XPropertySet > xColumn( xColumnFactory->createColumn(rColumnServiceName), UNO_SET_THROW ); + Reference< XPropertySetInfo > xColumnPSI( xColumn->getPropertySetInfo(), UNO_SET_THROW ); + + OUString sColumnName(rColumnServiceName); + disambiguateName(xExistenceChecker, sColumnName); + + // the data field the column should be bound to + xColumn->setPropertyValue("DataField", Any(*pFormFieldName)); + // the label + xColumn->setPropertyValue("Label", Any(*pFormFieldName + *pColumnLabelPostfix)); + // the width ( => column will be auto-sized) + xColumn->setPropertyValue("Width", Any()); + + if ( xColumnPSI->hasPropertyByName( s_sMouseWheelBehavior ) ) + xColumn->setPropertyValue( s_sMouseWheelBehavior, Any( MouseWheelBehavior::SCROLL_DISABLED ) ); + + // insert the column + xColumnContainer->insertByName(sColumnName, Any(xColumn)); + } + catch(const Exception&) + { + SAL_WARN( "extensions.dbpilots", "OGridWizard::implApplySettings: " + "unexpected exception while creating the grid column for field " << + *pFormFieldName ); + } + + ++pColumnLabelPostfix; + ++pFormFieldName; + } + } + } + + std::unique_ptr OGridWizard::createPage(WizardState _nState) + { + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch (_nState) + { + case GW_STATE_DATASOURCE_SELECTION: + return std::make_unique(pPageContainer, this); + case GW_STATE_FIELDSELECTION: + return std::make_unique(pPageContainer, this); + } + + return nullptr; + } + + vcl::WizardTypes::WizardState OGridWizard::determineNextState( WizardState _nCurrentState ) const + { + switch (_nCurrentState) + { + case GW_STATE_DATASOURCE_SELECTION: + return GW_STATE_FIELDSELECTION; + case GW_STATE_FIELDSELECTION: + return WZS_INVALID_STATE; + } + + return WZS_INVALID_STATE; + } + + void OGridWizard::enterState(WizardState _nState) + { + OControlWizard::enterState(_nState); + + enableButtons(WizardButtonFlags::PREVIOUS, m_bHadDataSelection ? (GW_STATE_DATASOURCE_SELECTION < _nState) : GW_STATE_FIELDSELECTION < _nState); + enableButtons(WizardButtonFlags::NEXT, GW_STATE_FIELDSELECTION != _nState); + if (_nState < GW_STATE_FIELDSELECTION) + enableButtons(WizardButtonFlags::FINISH, false); + + if (GW_STATE_FIELDSELECTION == _nState) + defaultButton(WizardButtonFlags::FINISH); + } + + + bool OGridWizard::leaveState(WizardState _nState) + { + if (!OControlWizard::leaveState(_nState)) + return false; + + if (GW_STATE_FIELDSELECTION == _nState) + defaultButton(WizardButtonFlags::NEXT); + + return true; + } + + + bool OGridWizard::onFinish() + { + if ( !OControlWizard::onFinish() ) + return false; + + implApplySettings(); + + return true; + } + + OGridFieldsSelection::OGridFieldsSelection(weld::Container* pPage, OGridWizard* pWizard) + : OGridPage(pPage, pWizard, "modules/sabpilot/ui/gridfieldsselectionpage.ui", "GridFieldsSelection") + , m_xExistFields(m_xBuilder->weld_tree_view("existingfields")) + , m_xSelectOne(m_xBuilder->weld_button("fieldright")) + , m_xSelectAll(m_xBuilder->weld_button("allfieldsright")) + , m_xDeselectOne(m_xBuilder->weld_button("fieldleft")) + , m_xDeselectAll(m_xBuilder->weld_button("allfieldsleft")) + , m_xSelFields(m_xBuilder->weld_tree_view("selectedfields")) + { + enableFormDatasourceDisplay(); + + m_xSelectOne->connect_clicked(LINK(this, OGridFieldsSelection, OnMoveOneEntry)); + m_xSelectAll->connect_clicked(LINK(this, OGridFieldsSelection, OnMoveAllEntries)); + m_xDeselectOne->connect_clicked(LINK(this, OGridFieldsSelection, OnMoveOneEntry)); + m_xDeselectAll->connect_clicked(LINK(this, OGridFieldsSelection, OnMoveAllEntries)); + + m_xExistFields->connect_changed(LINK(this, OGridFieldsSelection, OnEntrySelected)); + m_xSelFields->connect_changed(LINK(this, OGridFieldsSelection, OnEntrySelected)); + m_xExistFields->connect_row_activated(LINK(this, OGridFieldsSelection, OnEntryDoubleClicked)); + m_xSelFields->connect_row_activated(LINK(this, OGridFieldsSelection, OnEntryDoubleClicked)); + } + + OGridFieldsSelection::~OGridFieldsSelection() + { + } + + void OGridFieldsSelection::Activate() + { + OGridPage::Activate(); + m_xExistFields->grab_focus(); + } + + bool OGridFieldsSelection::canAdvance() const + { + return false; + // we're the last page in our wizard + } + + void OGridFieldsSelection::initializePage() + { + OGridPage::initializePage(); + + const OControlWizardContext& rContext = getContext(); + fillListBox(*m_xExistFields, rContext.aFieldNames); + + m_xSelFields->clear(); + const OGridSettings& rSettings = getSettings(); + const OUString* pSelected = rSettings.aSelectedFields.getConstArray(); + const OUString* pEnd = pSelected + rSettings.aSelectedFields.getLength(); + for (; pSelected < pEnd; ++pSelected) + { + m_xSelFields->append_text(*pSelected); + m_xExistFields->remove_text(*pSelected); + } + + implCheckButtons(); + } + + bool OGridFieldsSelection::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OGridPage::commitPage(_eReason)) + return false; + + OGridSettings& rSettings = getSettings(); + const sal_Int32 nSelected = m_xSelFields->n_children(); + + rSettings.aSelectedFields.realloc(nSelected); + OUString* pSelected = rSettings.aSelectedFields.getArray(); + + for (sal_Int32 i=0; iget_text(i); + + return true; + } + + void OGridFieldsSelection::implCheckButtons() + { + m_xSelectOne->set_sensitive(m_xExistFields->count_selected_rows() != 0); + m_xSelectAll->set_sensitive(m_xExistFields->n_children() != 0); + + m_xDeselectOne->set_sensitive(m_xSelFields->count_selected_rows() != 0); + m_xDeselectAll->set_sensitive(m_xSelFields->n_children() != 0); + + getDialog()->enableButtons(WizardButtonFlags::FINISH, 0 != m_xSelFields->n_children()); + } + + IMPL_LINK(OGridFieldsSelection, OnEntryDoubleClicked, weld::TreeView&, rList, bool) + { + weld::Button* pSimulateButton = m_xExistFields.get() == &rList ? m_xSelectOne.get() : m_xDeselectOne.get(); + if (pSimulateButton->get_sensitive()) + OnMoveOneEntry(*pSimulateButton); + return true; + } + + IMPL_LINK_NOARG(OGridFieldsSelection, OnEntrySelected, weld::TreeView&, void) + { + implCheckButtons(); + } + + IMPL_LINK(OGridFieldsSelection, OnMoveOneEntry, weld::Button&, rButton, void) + { + bool bMoveRight = (m_xSelectOne.get() == &rButton); + weld::TreeView& rMoveTo = bMoveRight ? *m_xSelFields : *m_xExistFields; + + // the index of the selected entry + const sal_Int32 nSelected = bMoveRight ? m_xExistFields->get_selected_index() : m_xSelFields->get_selected_index(); + // the (original) relative position of the entry + int nRelativeIndex = bMoveRight ? m_xExistFields->get_id(nSelected).toInt32() : m_xSelFields->get_id(nSelected).toInt32(); + + sal_Int32 nInsertPos = -1; + if (!bMoveRight) + { // need to determine an insert pos which reflects the original + nInsertPos = 0; + while (nInsertPos < rMoveTo.n_children()) + { + if (rMoveTo.get_id(nInsertPos).toInt32() > nRelativeIndex) + break; + ++nInsertPos; + } + } + + // the text of the entry to move + OUString sMovingEntry = bMoveRight ? m_xExistFields->get_text(nSelected) : m_xSelFields->get_text(nSelected); + + // insert the entry preserving it's "relative position" entry data + OUString sId(OUString::number(nRelativeIndex)); + rMoveTo.insert(nullptr, nInsertPos, &sMovingEntry, &sId, nullptr, nullptr, false, nullptr); + + // remove the entry from its old list + if (bMoveRight) + { + sal_Int32 nSelectPos = m_xExistFields->get_selected_index(); + m_xExistFields->remove(nSelected); + if ((nSelectPos != -1) && (nSelectPos < m_xExistFields->n_children())) + m_xExistFields->select(nSelectPos); + + m_xExistFields->grab_focus(); + } + else + { + sal_Int32 nSelectPos = m_xSelFields->get_selected_index(); + m_xSelFields->remove(nSelected); + if ((nSelectPos != -1) && (nSelectPos < m_xSelFields->n_children())) + m_xSelFields->select(nSelectPos); + + m_xSelFields->grab_focus(); + } + + implCheckButtons(); + } + + IMPL_LINK(OGridFieldsSelection, OnMoveAllEntries, weld::Button&, rButton, void) + { + bool bMoveRight = (m_xSelectAll.get() == &rButton); + m_xExistFields->clear(); + m_xSelFields->clear(); + fillListBox(bMoveRight ? *m_xSelFields : *m_xExistFields, getContext().aFieldNames); + + implCheckButtons(); + } + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/gridwizard.hxx b/extensions/source/dbpilots/gridwizard.hxx new file mode 100644 index 000000000..774e6cd69 --- /dev/null +++ b/extensions/source/dbpilots/gridwizard.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "controlwizard.hxx" +#include "commonpagesdbp.hxx" + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace dbp +{ + struct OGridSettings : public OControlWizardSettings + { + css::uno::Sequence< OUString > aSelectedFields; + }; + + class OGridWizard final : public OControlWizard + { + OGridSettings m_aSettings; + bool m_bHadDataSelection : 1; + + public: + OGridWizard(weld::Window* _pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxObjectModel, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + OGridSettings& getSettings() { return m_aSettings; } + + private: + // OWizardMachine overridables + virtual std::unique_ptr createPage( WizardState _nState ) override; + virtual WizardState determineNextState( WizardState _nCurrentState ) const override; + virtual void enterState( WizardState _nState ) override; + virtual bool leaveState( WizardState _nState ) override; + virtual bool onFinish() override; + + virtual bool approveControl(sal_Int16 _nClassId) override; + + void implApplySettings(); + }; + + class OGridPage : public OControlWizardPage + { + public: + OGridPage(weld::Container* pPage, OGridWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage(pPage, pWizard, rUIXMLDescription, rID) + { + } + protected: + OGridSettings& getSettings() { return static_cast(getDialog())->getSettings(); } + }; + + class OGridFieldsSelection final : public OGridPage + { + std::unique_ptr m_xExistFields; + std::unique_ptr m_xSelectOne; + std::unique_ptr m_xSelectAll; + std::unique_ptr m_xDeselectOne; + std::unique_ptr m_xDeselectAll; + std::unique_ptr m_xSelFields; + + public: + explicit OGridFieldsSelection(weld::Container* pPage, OGridWizard* pWizard); + virtual ~OGridFieldsSelection() override; + + private: + // BuilderPage overridables + virtual void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + + DECL_LINK(OnMoveOneEntry, weld::Button&, void); + DECL_LINK(OnMoveAllEntries, weld::Button&, void); + DECL_LINK(OnEntrySelected, weld::TreeView&, void); + DECL_LINK(OnEntryDoubleClicked, weld::TreeView&, bool); + + void implCheckButtons(); + }; +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/groupboxwiz.cxx b/extensions/source/dbpilots/groupboxwiz.cxx new file mode 100644 index 000000000..a093d9154 --- /dev/null +++ b/extensions/source/dbpilots/groupboxwiz.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 "groupboxwiz.hxx" +#include "commonpagesdbp.hxx" +#include +#include +#include "optiongrouplayouter.hxx" +#include +#include + +#define GBW_STATE_OPTIONLIST 0 +#define GBW_STATE_DEFAULTOPTION 1 +#define GBW_STATE_OPTIONVALUES 2 +#define GBW_STATE_DBFIELD 3 +#define GBW_STATE_FINALIZE 4 + +namespace dbp +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::form; + + OGroupBoxWizard::OGroupBoxWizard(weld::Window* _pParent, + const Reference< XPropertySet >& _rxObjectModel, const Reference< XComponentContext >& _rxContext ) + : OControlWizard(_pParent, _rxObjectModel, _rxContext) + , m_bVisitedDefault(false) + , m_bVisitedDB(false) + { + initControlSettings(&m_aSettings); + + m_xPrevPage->set_help_id(HID_GROUPWIZARD_PREVIOUS); + m_xNextPage->set_help_id(HID_GROUPWIZARD_NEXT); + m_xCancel->set_help_id(HID_GROUPWIZARD_CANCEL); + m_xFinish->set_help_id(HID_GROUPWIZARD_FINISH); + setTitleBase(compmodule::ModuleRes(RID_STR_GROUPWIZARD_TITLE)); + } + + bool OGroupBoxWizard::approveControl(sal_Int16 _nClassId) + { + return FormComponentType::GROUPBOX == _nClassId; + } + + std::unique_ptr OGroupBoxWizard::createPage(::vcl::WizardTypes::WizardState _nState) + { + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch (_nState) + { + case GBW_STATE_OPTIONLIST: + return std::make_unique(pPageContainer, this); + + case GBW_STATE_DEFAULTOPTION: + return std::make_unique(pPageContainer, this); + + case GBW_STATE_OPTIONVALUES: + return std::make_unique(pPageContainer, this); + + case GBW_STATE_DBFIELD: + return std::make_unique(pPageContainer, this); + + case GBW_STATE_FINALIZE: + return std::make_unique(pPageContainer, this); + } + + return nullptr; + } + + vcl::WizardTypes::WizardState OGroupBoxWizard::determineNextState( ::vcl::WizardTypes::WizardState _nCurrentState ) const + { + switch (_nCurrentState) + { + case GBW_STATE_OPTIONLIST: + return GBW_STATE_DEFAULTOPTION; + + case GBW_STATE_DEFAULTOPTION: + return GBW_STATE_OPTIONVALUES; + + case GBW_STATE_OPTIONVALUES: + if (getContext().aFieldNames.hasElements()) + return GBW_STATE_DBFIELD; + else + return GBW_STATE_FINALIZE; + + case GBW_STATE_DBFIELD: + return GBW_STATE_FINALIZE; + } + + return WZS_INVALID_STATE; + } + + void OGroupBoxWizard::enterState(::vcl::WizardTypes::WizardState _nState) + { + // some stuff to do before calling the base class (modifying our settings) + switch (_nState) + { + case GBW_STATE_DEFAULTOPTION: + if (!m_bVisitedDefault) + { // assume that the first of the radio buttons should be selected + DBG_ASSERT(m_aSettings.aLabels.size(), "OGroupBoxWizard::enterState: should never have reached this state!"); + m_aSettings.sDefaultField = m_aSettings.aLabels[0]; + } + m_bVisitedDefault = true; + break; + + case GBW_STATE_DBFIELD: + if (!m_bVisitedDB) + { // try to generate a default for the DB field + // (simply use the first field in the DB names collection) + if (getContext().aFieldNames.hasElements()) + m_aSettings.sDBField = getContext().aFieldNames[0]; + } + m_bVisitedDB = true; + break; + } + + // setting the def button... to be done before the base class is called, too, 'cause the base class + // calls the pages, which are allowed to override our def button behaviour + defaultButton(GBW_STATE_FINALIZE == _nState ? WizardButtonFlags::FINISH : WizardButtonFlags::NEXT); + + // allow "finish" on the last page only + enableButtons(WizardButtonFlags::FINISH, GBW_STATE_FINALIZE == _nState); + // allow previous on all pages but the first one + enableButtons(WizardButtonFlags::PREVIOUS, GBW_STATE_OPTIONLIST != _nState); + // allow next on all pages but the last one + enableButtons(WizardButtonFlags::NEXT, GBW_STATE_FINALIZE != _nState); + + OControlWizard::enterState(_nState); + } + + bool OGroupBoxWizard::onFinish() + { + // commit the basic control settings + commitControlSettings(&m_aSettings); + + // create the radio buttons + try + { + OOptionGroupLayouter aLayouter( getComponentContext() ); + aLayouter.doLayout(getContext(), getSettings()); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", + "caught an exception while creating the radio shapes!"); + } + + return OControlWizard::onFinish(); + } + + ORadioSelectionPage::ORadioSelectionPage(weld::Container* pPage, OControlWizard* pWizard) + : OGBWPage(pPage, pWizard, "modules/sabpilot/ui/groupradioselectionpage.ui", "GroupRadioSelectionPage") + , m_xRadioName(m_xBuilder->weld_entry("radiolabels")) + , m_xMoveRight(m_xBuilder->weld_button("toright")) + , m_xMoveLeft(m_xBuilder->weld_button("toleft")) + , m_xExistingRadios(m_xBuilder->weld_tree_view("radiobuttons")) + { + if (getContext().aFieldNames.hasElements()) + { + enableFormDatasourceDisplay(); + } + + m_xMoveLeft->connect_clicked(LINK(this, ORadioSelectionPage, OnMoveEntry)); + m_xMoveRight->connect_clicked(LINK(this, ORadioSelectionPage, OnMoveEntry)); + m_xRadioName->connect_changed(LINK(this, ORadioSelectionPage, OnNameModified)); + m_xExistingRadios->connect_changed(LINK(this, ORadioSelectionPage, OnEntrySelected)); + + implCheckMoveButtons(); + m_xExistingRadios->set_selection_mode(SelectionMode::Multiple); + + getDialog()->defaultButton(m_xMoveRight.get()); + } + + ORadioSelectionPage::~ORadioSelectionPage() + { + } + + void ORadioSelectionPage::Activate() + { + OGBWPage::Activate(); + m_xRadioName->grab_focus(); + } + + void ORadioSelectionPage::initializePage() + { + OGBWPage::initializePage(); + + m_xRadioName->set_text(""); + + // no need to initialize the list of radios here + // (we're the only one affecting this special setting, so it will be in the same state as last time this + // page was committed) + + implCheckMoveButtons(); + } + + bool ORadioSelectionPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OGBWPage::commitPage(_eReason)) + return false; + + // copy the names of the radio buttons to be inserted + // and initialize the values + OOptionGroupSettings& rSettings = getSettings(); + rSettings.aLabels.clear(); + rSettings.aValues.clear(); + rSettings.aLabels.reserve(m_xExistingRadios->n_children()); + rSettings.aValues.reserve(m_xExistingRadios->n_children()); + for (sal_Int32 i=0; in_children(); ++i) + { + rSettings.aLabels.push_back(m_xExistingRadios->get_text(i)); + rSettings.aValues.push_back(OUString::number(i + 1)); + } + + return true; + } + + IMPL_LINK( ORadioSelectionPage, OnMoveEntry, weld::Button&, rButton, void ) + { + bool bMoveLeft = (m_xMoveLeft.get() == &rButton); + if (bMoveLeft) + { + while (m_xExistingRadios->count_selected_rows()) + m_xExistingRadios->remove(m_xExistingRadios->get_selected_index()); + } + else + { + m_xExistingRadios->append_text(m_xRadioName->get_text()); + m_xRadioName->set_text(""); + } + + implCheckMoveButtons(); + + //adjust the focus + if (bMoveLeft) + m_xExistingRadios->grab_focus(); + else + m_xRadioName->grab_focus(); + } + + IMPL_LINK_NOARG( ORadioSelectionPage, OnEntrySelected, weld::TreeView&, void ) + { + implCheckMoveButtons(); + } + + IMPL_LINK_NOARG( ORadioSelectionPage, OnNameModified, weld::Entry&, void ) + { + implCheckMoveButtons(); + } + + bool ORadioSelectionPage::canAdvance() const + { + return 0 != m_xExistingRadios->n_children(); + } + + void ORadioSelectionPage::implCheckMoveButtons() + { + bool bHaveSome = (0 != m_xExistingRadios->n_children()); + bool bSelectedSome = (0 != m_xExistingRadios->count_selected_rows()); + bool bUnfinishedInput = !m_xRadioName->get_text().isEmpty(); + + m_xMoveLeft->set_sensitive(bSelectedSome); + m_xMoveRight->set_sensitive(bUnfinishedInput); + + OControlWizard* pDialogController = getDialog(); + + pDialogController->enableButtons(WizardButtonFlags::NEXT, bHaveSome); + + weld::Dialog* pDialog = pDialogController->getDialog(); + + if (bUnfinishedInput) + { + if (!pDialog->is_default_widget(m_xMoveRight.get())) + pDialogController->defaultButton(m_xMoveRight.get()); + } + else + { + if (pDialog->is_default_widget(m_xMoveRight.get())) + pDialogController->defaultButton(WizardButtonFlags::NEXT); + } + } + + ODefaultFieldSelectionPage::ODefaultFieldSelectionPage(weld::Container* pPage, OControlWizard* pWizard) + : OMaybeListSelectionPage(pPage, pWizard, "modules/sabpilot/ui/defaultfieldselectionpage.ui", "DefaultFieldSelectionPage") + , m_xDefSelYes(m_xBuilder->weld_radio_button("defaultselectionyes")) + , m_xDefSelNo(m_xBuilder->weld_radio_button("defaultselectionno")) + , m_xDefSelection(m_xBuilder->weld_combo_box("defselectionfield")) + { + announceControls(*m_xDefSelYes, *m_xDefSelNo, *m_xDefSelection); + } + + ODefaultFieldSelectionPage::~ODefaultFieldSelectionPage() + { + } + + void ODefaultFieldSelectionPage::initializePage() + { + OMaybeListSelectionPage::initializePage(); + + const OOptionGroupSettings& rSettings = getSettings(); + + // fill the listbox + m_xDefSelection->clear(); + for (auto const& label : rSettings.aLabels) + m_xDefSelection->append_text(label); + + implInitialize(rSettings.sDefaultField); + } + + bool ODefaultFieldSelectionPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OMaybeListSelectionPage::commitPage(_eReason)) + return false; + + OOptionGroupSettings& rSettings = getSettings(); + implCommit(rSettings.sDefaultField); + + return true; + } + + OOptionValuesPage::OOptionValuesPage(weld::Container* pPage, OControlWizard* pWizard) + : OGBWPage(pPage, pWizard, "modules/sabpilot/ui/optionvaluespage.ui", "OptionValuesPage") + , m_xValue(m_xBuilder->weld_entry("optionvalue")) + , m_xOptions(m_xBuilder->weld_tree_view("radiobuttons")) + , m_nLastSelection(::vcl::WizardTypes::WizardState(-1)) + { + m_xOptions->connect_changed(LINK(this, OOptionValuesPage, OnOptionSelected)); + } + + OOptionValuesPage::~OOptionValuesPage() + { + } + + IMPL_LINK_NOARG( OOptionValuesPage, OnOptionSelected, weld::TreeView&, void ) + { + implTraveledOptions(); + } + + void OOptionValuesPage::Activate() + { + OGBWPage::Activate(); + m_xValue->grab_focus(); + } + + void OOptionValuesPage::implTraveledOptions() + { + if (::vcl::WizardTypes::WizardState(-1) != m_nLastSelection) + { + // save the value for the last option + DBG_ASSERT(o3tl::make_unsigned(m_nLastSelection) < m_aUncommittedValues.size(), "OOptionValuesPage::implTraveledOptions: invalid previous selection index!"); + m_aUncommittedValues[m_nLastSelection] = m_xValue->get_text(); + } + + m_nLastSelection = m_xOptions->get_selected_index(); + DBG_ASSERT(o3tl::make_unsigned(m_nLastSelection) < m_aUncommittedValues.size(), "OOptionValuesPage::implTraveledOptions: invalid new selection index!"); + m_xValue->set_text(m_aUncommittedValues[m_nLastSelection]); + } + + void OOptionValuesPage::initializePage() + { + OGBWPage::initializePage(); + + const OOptionGroupSettings& rSettings = getSettings(); + DBG_ASSERT(rSettings.aLabels.size(), "OOptionValuesPage::initializePage: no options!!"); + DBG_ASSERT(rSettings.aLabels.size() == rSettings.aValues.size(), "OOptionValuesPage::initializePage: inconsistent data!"); + + // fill the list with all available options + m_xOptions->clear(); + m_nLastSelection = -1; + for (auto const& label : rSettings.aLabels) + m_xOptions->append_text(label); + + // remember the values ... can't set them directly in the settings without the explicit commit call + // so we need have a copy of the values + m_aUncommittedValues = rSettings.aValues; + + // select the first entry + m_xOptions->select(0); + implTraveledOptions(); + } + + bool OOptionValuesPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OGBWPage::commitPage(_eReason)) + return false; + + OOptionGroupSettings& rSettings = getSettings(); + + // commit the current value + implTraveledOptions(); + // copy the uncommitted values + rSettings.aValues = m_aUncommittedValues; + + return true; + } + + OOptionDBFieldPage::OOptionDBFieldPage(weld::Container* pPage, OControlWizard* pWizard) + : ODBFieldPage(pPage, pWizard) + { + setDescriptionText(compmodule::ModuleRes(RID_STR_GROUPWIZ_DBFIELD)); + } + + OUString& OOptionDBFieldPage::getDBFieldSetting() + { + return static_cast(getDialog())->getSettings().sDBField; + } + + OFinalizeGBWPage::OFinalizeGBWPage(weld::Container* pPage, OControlWizard* pWizard) + : OGBWPage(pPage, pWizard, "modules/sabpilot/ui/optionsfinalpage.ui", "OptionsFinalPage") + , m_xName(m_xBuilder->weld_entry("nameit")) + { + } + + OFinalizeGBWPage::~OFinalizeGBWPage() + { + } + + void OFinalizeGBWPage::Activate() + { + OGBWPage::Activate(); + m_xName->grab_focus(); + } + + bool OFinalizeGBWPage::canAdvance() const + { + return false; + } + + void OFinalizeGBWPage::initializePage() + { + OGBWPage::initializePage(); + + const OOptionGroupSettings& rSettings = getSettings(); + m_xName->set_text(rSettings.sControlLabel); + } + + bool OFinalizeGBWPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OGBWPage::commitPage(_eReason)) + return false; + + getSettings().sControlLabel = m_xName->get_text(); + + return true; + } + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/groupboxwiz.hxx b/extensions/source/dbpilots/groupboxwiz.hxx new file mode 100644 index 000000000..18fa12c7f --- /dev/null +++ b/extensions/source/dbpilots/groupboxwiz.hxx @@ -0,0 +1,180 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "controlwizard.hxx" +#include "commonpagesdbp.hxx" + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace dbp +{ + + struct OOptionGroupSettings : public OControlWizardSettings + { + std::vector aLabels; + std::vector aValues; + OUString sDefaultField; + OUString sDBField; + }; + + class OGroupBoxWizard final : public OControlWizard + { + OOptionGroupSettings m_aSettings; + + bool m_bVisitedDefault : 1; + bool m_bVisitedDB : 1; + + public: + OGroupBoxWizard( + weld::Window* _pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxObjectModel, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + OOptionGroupSettings& getSettings() { return m_aSettings; } + + private: + // OWizardMachine overridables + virtual std::unique_ptr createPage( WizardState _nState ) override; + virtual WizardState determineNextState( WizardState _nCurrentState ) const override; + virtual void enterState( WizardState _nState ) override; + virtual bool onFinish() override; + + virtual bool approveControl(sal_Int16 _nClassId) override; + }; + + class OGBWPage : public OControlWizardPage + { + public: + OGBWPage(weld::Container* pPage, OControlWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage(pPage, pWizard, rUIXMLDescription, rID) + { + } + + protected: + OOptionGroupSettings& getSettings() { return static_cast(getDialog())->getSettings(); } + }; + + class ORadioSelectionPage final : public OGBWPage + { + std::unique_ptr m_xRadioName; + std::unique_ptr m_xMoveRight; + std::unique_ptr m_xMoveLeft; + std::unique_ptr m_xExistingRadios; + + public: + explicit ORadioSelectionPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~ORadioSelectionPage() override; + + private: + // BuilderPage overridables + void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + + DECL_LINK( OnMoveEntry, weld::Button&, void ); + DECL_LINK( OnEntrySelected, weld::TreeView&, void ); + DECL_LINK( OnNameModified, weld::Entry&, void ); + + void implCheckMoveButtons(); + }; + + class ODefaultFieldSelectionPage final : public OMaybeListSelectionPage + { + std::unique_ptr m_xDefSelYes; + std::unique_ptr m_xDefSelNo; + std::unique_ptr m_xDefSelection; + + public: + explicit ODefaultFieldSelectionPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~ODefaultFieldSelectionPage() override; + + private: + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + OOptionGroupSettings& getSettings() { return static_cast(getDialog())->getSettings(); } + }; + + class OOptionValuesPage final : public OGBWPage + { + std::unique_ptr m_xValue; + std::unique_ptr m_xOptions; + + std::vector m_aUncommittedValues; + ::vcl::WizardTypes::WizardState + m_nLastSelection; + + public: + explicit OOptionValuesPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~OOptionValuesPage() override; + + private: + // BuilderPage overridables + void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + + void implTraveledOptions(); + + DECL_LINK( OnOptionSelected, weld::TreeView&, void ); + }; + + class OOptionDBFieldPage : public ODBFieldPage + { + public: + explicit OOptionDBFieldPage(weld::Container* pPage, OControlWizard* pWizard); + + protected: + // ODBFieldPage overridables + virtual OUString& getDBFieldSetting() override; + }; + + class OFinalizeGBWPage final : public OGBWPage + { + std::unique_ptr m_xName; + + public: + explicit OFinalizeGBWPage(weld::Container* pPage, OControlWizard* pWizard); + virtual ~OFinalizeGBWPage() override; + + private: + // BuilderPage overridables + void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/listcombowizard.cxx b/extensions/source/dbpilots/listcombowizard.cxx new file mode 100644 index 000000000..ae27f9553 --- /dev/null +++ b/extensions/source/dbpilots/listcombowizard.cxx @@ -0,0 +1,485 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "listcombowizard.hxx" +#include "commonpagesdbp.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace dbp +{ + + + 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::sdbcx; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::form; + using namespace ::dbtools; + + OListComboWizard::OListComboWizard(weld::Window* _pParent, + const Reference< XPropertySet >& _rxObjectModel, const Reference< XComponentContext >& _rxContext ) + : OControlWizard(_pParent, _rxObjectModel, _rxContext) + , m_bListBox(false) + , m_bHadDataSelection(true) + { + initControlSettings(&m_aSettings); + + m_xPrevPage->set_help_id(HID_LISTWIZARD_PREVIOUS); + m_xNextPage->set_help_id(HID_LISTWIZARD_NEXT); + m_xCancel->set_help_id(HID_LISTWIZARD_CANCEL); + m_xFinish->set_help_id(HID_LISTWIZARD_FINISH); + + // if we do not need the data source selection page ... + if (!needDatasourceSelection()) + { // ... skip it! + skip(); + m_bHadDataSelection = false; + } + } + + bool OListComboWizard::approveControl(sal_Int16 _nClassId) + { + switch (_nClassId) + { + case FormComponentType::LISTBOX: + m_bListBox = true; + setTitleBase(compmodule::ModuleRes(RID_STR_LISTWIZARD_TITLE)); + return true; + case FormComponentType::COMBOBOX: + m_bListBox = false; + setTitleBase(compmodule::ModuleRes(RID_STR_COMBOWIZARD_TITLE)); + return true; + } + return false; + } + + std::unique_ptr OListComboWizard::createPage(WizardState _nState) + { + OString sIdent(OString::number(_nState)); + weld::Container* pPageContainer = m_xAssistant->append_page(sIdent); + + switch (_nState) + { + case LCW_STATE_DATASOURCE_SELECTION: + return std::make_unique(pPageContainer, this); + case LCW_STATE_TABLESELECTION: + return std::make_unique(pPageContainer, this); + case LCW_STATE_FIELDSELECTION: + return std::make_unique(pPageContainer, this); + case LCW_STATE_FIELDLINK: + return std::make_unique(pPageContainer, this); + case LCW_STATE_COMBODBFIELD: + return std::make_unique(pPageContainer, this); + } + + return nullptr; + } + + vcl::WizardTypes::WizardState OListComboWizard::determineNextState( WizardState _nCurrentState ) const + { + switch (_nCurrentState) + { + case LCW_STATE_DATASOURCE_SELECTION: + return LCW_STATE_TABLESELECTION; + case LCW_STATE_TABLESELECTION: + return LCW_STATE_FIELDSELECTION; + case LCW_STATE_FIELDSELECTION: + return getFinalState(); + } + + return WZS_INVALID_STATE; + } + + void OListComboWizard::enterState(WizardState _nState) + { + OControlWizard::enterState(_nState); + + enableButtons(WizardButtonFlags::PREVIOUS, m_bHadDataSelection ? (LCW_STATE_DATASOURCE_SELECTION < _nState) : LCW_STATE_TABLESELECTION < _nState); + enableButtons(WizardButtonFlags::NEXT, getFinalState() != _nState); + if (_nState < getFinalState()) + enableButtons(WizardButtonFlags::FINISH, false); + + if (getFinalState() == _nState) + defaultButton(WizardButtonFlags::FINISH); + } + + + bool OListComboWizard::leaveState(WizardState _nState) + { + if (!OControlWizard::leaveState(_nState)) + return false; + + if (getFinalState() == _nState) + defaultButton(WizardButtonFlags::NEXT); + + return true; + } + + + void OListComboWizard::implApplySettings() + { + try + { + // for quoting identifiers, we need the connection meta data + Reference< XConnection > xConn = getFormConnection(); + DBG_ASSERT(xConn.is(), "OListComboWizard::implApplySettings: no connection, unable to quote!"); + Reference< XDatabaseMetaData > xMetaData; + if (xConn.is()) + xMetaData = xConn->getMetaData(); + + // do some quotings + if (xMetaData.is()) + { + OUString sQuoteString = xMetaData->getIdentifierQuoteString(); + if (isListBox()) // only when we have a listbox this should be not empty + getSettings().sLinkedListField = quoteName(sQuoteString, getSettings().sLinkedListField); + + OUString sCatalog, sSchema, sName; + ::dbtools::qualifiedNameComponents( xMetaData, getSettings().sListContentTable, sCatalog, sSchema, sName, ::dbtools::EComposeRule::InDataManipulation ); + getSettings().sListContentTable = ::dbtools::composeTableNameForSelect( xConn, sCatalog, sSchema, sName ); + + getSettings().sListContentField = quoteName(sQuoteString, getSettings().sListContentField); + } + + // ListSourceType: SQL + getContext().xObjectModel->setPropertyValue("ListSourceType", Any(sal_Int32(ListSourceType_SQL))); + + if (isListBox()) + { + // BoundColumn: 1 + getContext().xObjectModel->setPropertyValue("BoundColumn", Any(sal_Int16(1))); + + // build the statement to set as list source + OUString sStatement = "SELECT " + + getSettings().sListContentField + ", " + getSettings().sLinkedListField + + " FROM " + getSettings().sListContentTable; + Sequence< OUString > aListSource { sStatement }; + getContext().xObjectModel->setPropertyValue("ListSource", Any(aListSource)); + } + else + { + // build the statement to set as list source + OUString sStatement = "SELECT DISTINCT " + + getSettings().sListContentField + + " FROM " + getSettings().sListContentTable; + getContext().xObjectModel->setPropertyValue( "ListSource", Any(sStatement)); + } + + // the bound field + getContext().xObjectModel->setPropertyValue("DataField", Any(getSettings().sLinkedFormField)); + } + catch(const Exception&) + { + OSL_FAIL("OListComboWizard::implApplySettings: could not set the property values for the listbox!"); + } + } + + + bool OListComboWizard::onFinish() + { + if ( !OControlWizard::onFinish() ) + return false; + + implApplySettings(); + return true; + } + + Reference< XNameAccess > OLCPage::getTables() const + { + Reference< XConnection > xConn = getFormConnection(); + DBG_ASSERT(xConn.is(), "OLCPage::getTables: should have an active connection when reaching this page!"); + + Reference< XTablesSupplier > xSuppTables(xConn, UNO_QUERY); + Reference< XNameAccess > xTables; + if (xSuppTables.is()) + xTables = xSuppTables->getTables(); + + DBG_ASSERT(xTables.is() || !xConn.is(), "OLCPage::getTables: got no tables from the connection!"); + + return xTables; + } + + + Sequence< OUString > OLCPage::getTableFields() + { + Reference< XNameAccess > xTables = getTables(); + Sequence< OUString > aColumnNames; + if (xTables.is()) + { + try + { + // the list table as XColumnsSupplier + Reference< XColumnsSupplier > xSuppCols; + xTables->getByName(getSettings().sListContentTable) >>= xSuppCols; + DBG_ASSERT(xSuppCols.is(), "OLCPage::getTableFields: no columns supplier!"); + + // the columns + Reference< XNameAccess > xColumns; + if (xSuppCols.is()) + xColumns = xSuppCols->getColumns(); + + // the column names + if (xColumns.is()) + aColumnNames = xColumns->getElementNames(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.dbpilots", "OLinkFieldsPage::initializePage: caught an exception while retrieving the columns"); + } + } + return aColumnNames; + } + + OContentTableSelection::OContentTableSelection(weld::Container* pPage, OListComboWizard* pWizard) + : OLCPage(pPage, pWizard, "modules/sabpilot/ui/contenttablepage.ui", "TableSelectionPage") + , m_xSelectTable(m_xBuilder->weld_tree_view("table")) + { + enableFormDatasourceDisplay(); + + m_xSelectTable->connect_row_activated(LINK(this, OContentTableSelection, OnTableDoubleClicked)); + m_xSelectTable->connect_changed(LINK(this, OContentTableSelection, OnTableSelected)); + } + + OContentTableSelection::~OContentTableSelection() + { + } + + void OContentTableSelection::Activate() + { + OLCPage::Activate(); + m_xSelectTable->grab_focus(); + } + + bool OContentTableSelection::canAdvance() const + { + if (!OLCPage::canAdvance()) + return false; + + return 0 != m_xSelectTable->count_selected_rows(); + } + + IMPL_LINK_NOARG( OContentTableSelection, OnTableSelected, weld::TreeView&, void ) + { + updateDialogTravelUI(); + } + + IMPL_LINK( OContentTableSelection, OnTableDoubleClicked, weld::TreeView&, _rListBox, bool ) + { + if (_rListBox.count_selected_rows()) + getDialog()->travelNext(); + return true; + } + + void OContentTableSelection::initializePage() + { + OLCPage::initializePage(); + + // fill the list with the table name + m_xSelectTable->clear(); + try + { + Reference< XNameAccess > xTables = getTables(); + Sequence< OUString > aTableNames; + if (xTables.is()) + aTableNames = xTables->getElementNames(); + fillListBox(*m_xSelectTable, aTableNames); + } + catch(const Exception&) + { + OSL_FAIL("OContentTableSelection::initializePage: could not retrieve the table names!"); + } + + m_xSelectTable->select_text(getSettings().sListContentTable); + } + + + bool OContentTableSelection::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OLCPage::commitPage(_eReason)) + return false; + + OListComboSettings& rSettings = getSettings(); + rSettings.sListContentTable = m_xSelectTable->get_selected_text(); + if (rSettings.sListContentTable.isEmpty() && (::vcl::WizardTypes::eTravelBackward != _eReason)) + // need to select a table + return false; + + return true; + } + + OContentFieldSelection::OContentFieldSelection(weld::Container* pPage, OListComboWizard* pWizard) + : OLCPage(pPage, pWizard, "modules/sabpilot/ui/contentfieldpage.ui", "FieldSelectionPage") + , m_xSelectTableField(m_xBuilder->weld_tree_view("selectfield")) + , m_xDisplayedField(m_xBuilder->weld_entry("displayfield")) + , m_xInfo(m_xBuilder->weld_label("info")) + { + m_xInfo->set_label(compmodule::ModuleRes( isListBox() ? RID_STR_FIELDINFO_LISTBOX : RID_STR_FIELDINFO_COMBOBOX)); + m_xSelectTableField->connect_changed(LINK(this, OContentFieldSelection, OnFieldSelected)); + m_xSelectTableField->connect_row_activated(LINK(this, OContentFieldSelection, OnTableDoubleClicked)); + } + + OContentFieldSelection::~OContentFieldSelection() + { + } + + void OContentFieldSelection::initializePage() + { + OLCPage::initializePage(); + + // fill the list of fields + fillListBox(*m_xSelectTableField, getTableFields()); + + m_xSelectTableField->select_text(getSettings().sListContentField); + m_xDisplayedField->set_text(getSettings().sListContentField); + } + + bool OContentFieldSelection::canAdvance() const + { + if (!OLCPage::canAdvance()) + return false; + + return 0 != m_xSelectTableField->count_selected_rows(); + } + + IMPL_LINK_NOARG( OContentFieldSelection, OnTableDoubleClicked, weld::TreeView&, bool ) + { + if (m_xSelectTableField->count_selected_rows()) + getDialog()->travelNext(); + return true; + } + + IMPL_LINK_NOARG( OContentFieldSelection, OnFieldSelected, weld::TreeView&, void ) + { + updateDialogTravelUI(); + m_xDisplayedField->set_text(m_xSelectTableField->get_selected_text()); + } + + bool OContentFieldSelection::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OLCPage::commitPage(_eReason)) + return false; + + getSettings().sListContentField = m_xSelectTableField->get_selected_text(); + + return true; + } + + OLinkFieldsPage::OLinkFieldsPage(weld::Container* pPage, OListComboWizard* pWizard) + : OLCPage(pPage, pWizard, "modules/sabpilot/ui/fieldlinkpage.ui", "FieldLinkPage") + , m_xValueListField(m_xBuilder->weld_combo_box("valuefield")) + , m_xTableField(m_xBuilder->weld_combo_box("listtable")) + { + m_xValueListField->connect_changed(LINK(this, OLinkFieldsPage, OnSelectionModified)); + m_xTableField->connect_changed(LINK(this, OLinkFieldsPage, OnSelectionModified)); + } + + OLinkFieldsPage::~OLinkFieldsPage() + { + } + + void OLinkFieldsPage::Activate() + { + OLCPage::Activate(); + m_xValueListField->grab_focus(); + } + + void OLinkFieldsPage::initializePage() + { + OLCPage::initializePage(); + + // fill the value list + fillListBox(*m_xValueListField, getContext().aFieldNames); + // fill the table field list + fillListBox(*m_xTableField, getTableFields()); + + // the initial selections + m_xValueListField->set_entry_text(getSettings().sLinkedFormField); + m_xTableField->set_entry_text(getSettings().sLinkedListField); + + implCheckFinish(); + } + + bool OLinkFieldsPage::canAdvance() const + { + // we're on the last page here, no travelNext allowed ... + return false; + } + + void OLinkFieldsPage::implCheckFinish() + { + bool bInvalidSelection = (-1 == m_xValueListField->find_text(m_xValueListField->get_active_text())); + bInvalidSelection |= (-1 == m_xTableField->find_text(m_xTableField->get_active_text())); + getDialog()->enableButtons(WizardButtonFlags::FINISH, !bInvalidSelection); + } + + IMPL_LINK_NOARG(OLinkFieldsPage, OnSelectionModified, weld::ComboBox&, void) + { + implCheckFinish(); + } + + bool OLinkFieldsPage::commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) + { + if (!OLCPage::commitPage(_eReason)) + return false; + + getSettings().sLinkedFormField = m_xValueListField->get_active_text(); + getSettings().sLinkedListField = m_xTableField->get_active_text(); + + return true; + } + + OComboDBFieldPage::OComboDBFieldPage(weld::Container* pPage, OControlWizard* pWizard) + : ODBFieldPage(pPage, pWizard) + { + setDescriptionText(compmodule::ModuleRes(RID_STR_COMBOWIZ_DBFIELD)); + } + + OUString& OComboDBFieldPage::getDBFieldSetting() + { + return static_cast(getDialog())->getSettings().sLinkedFormField; + } + + void OComboDBFieldPage::Activate() + { + ODBFieldPage::Activate(); + getDialog()->enableButtons(WizardButtonFlags::FINISH, true); + } + + bool OComboDBFieldPage::canAdvance() const + { + // we're on the last page here, no travelNext allowed ... + return false; + } + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/listcombowizard.hxx b/extensions/source/dbpilots/listcombowizard.hxx new file mode 100644 index 000000000..7ab6a8a21 --- /dev/null +++ b/extensions/source/dbpilots/listcombowizard.hxx @@ -0,0 +1,178 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "controlwizard.hxx" +#include "commonpagesdbp.hxx" + +using vcl::WizardTypes::WizardState; +using vcl::WizardTypes::CommitPageReason; + +namespace dbp +{ + +#define LCW_STATE_DATASOURCE_SELECTION 0 +#define LCW_STATE_TABLESELECTION 1 +#define LCW_STATE_FIELDSELECTION 2 +#define LCW_STATE_FIELDLINK 3 +#define LCW_STATE_COMBODBFIELD 4 + + struct OListComboSettings : public OControlWizardSettings + { + OUString sListContentTable; + OUString sListContentField; + OUString sLinkedFormField; + OUString sLinkedListField; + }; + + class OListComboWizard final : public OControlWizard + { + OListComboSettings m_aSettings; + bool m_bListBox : 1; + bool m_bHadDataSelection : 1; + + public: + OListComboWizard( + weld::Window* pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxObjectModel, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + OListComboSettings& getSettings() { return m_aSettings; } + + bool isListBox() const { return m_bListBox; } + + private: + // OWizardMachine overridables + virtual std::unique_ptr createPage( WizardState _nState ) override; + virtual WizardState determineNextState( WizardState _nCurrentState ) const override; + virtual void enterState( WizardState _nState ) override; + virtual bool leaveState( WizardState _nState ) override; + virtual bool onFinish() override; + + virtual bool approveControl(sal_Int16 _nClassId) override; + + WizardState getFinalState() const { return isListBox() ? LCW_STATE_FIELDLINK : LCW_STATE_COMBODBFIELD; } + + void implApplySettings(); + }; + + class OLCPage : public OControlWizardPage + { + public: + OLCPage(weld::Container* pPage, OListComboWizard* pWizard, const OUString& rUIXMLDescription, const OString& rID) + : OControlWizardPage(pPage, pWizard, rUIXMLDescription, rID) + { + } + + protected: + OListComboSettings& getSettings() { return static_cast(getDialog())->getSettings(); } + bool isListBox() { return static_cast(getDialog())->isListBox(); } + + protected: + css::uno::Reference< css::container::XNameAccess > getTables() const; + css::uno::Sequence< OUString > getTableFields(); + }; + + class OContentTableSelection final : public OLCPage + { + std::unique_ptr m_xSelectTable; + + public: + explicit OContentTableSelection(weld::Container* pPage, OListComboWizard* pWizard); + virtual ~OContentTableSelection() override; + + private: + // BuilderPage overridables + virtual void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + + DECL_LINK( OnTableDoubleClicked, weld::TreeView&, bool ); + DECL_LINK( OnTableSelected, weld::TreeView&, void ); + }; + + class OContentFieldSelection final : public OLCPage + { + std::unique_ptr m_xSelectTableField; + std::unique_ptr m_xDisplayedField; + std::unique_ptr m_xInfo; + + public: + explicit OContentFieldSelection(weld::Container* pPage, OListComboWizard* pWizard); + virtual ~OContentFieldSelection() override; + + private: + DECL_LINK( OnFieldSelected, weld::TreeView&, void ); + DECL_LINK( OnTableDoubleClicked, weld::TreeView&, bool ); + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + }; + + class OLinkFieldsPage final : public OLCPage + { + std::unique_ptr m_xValueListField; + std::unique_ptr m_xTableField; + + public: + explicit OLinkFieldsPage(weld::Container* pPage, OListComboWizard* pWizard); + virtual ~OLinkFieldsPage() override; + + private: + // BuilderPage overridables + virtual void Activate() override; + + // OWizardPage overridables + virtual void initializePage() override; + virtual bool commitPage( ::vcl::WizardTypes::CommitPageReason _eReason ) override; + virtual bool canAdvance() const override; + + void implCheckFinish(); + + DECL_LINK(OnSelectionModified, weld::ComboBox&, void); + }; + + class OComboDBFieldPage : public ODBFieldPage + { + public: + explicit OComboDBFieldPage(weld::Container* pPage, OControlWizard* pWizard); + + protected: + // BuilderPage overridables + virtual void Activate() override; + + // OWizardPage overridables + virtual bool canAdvance() const override; + + // ODBFieldPage overridables + virtual OUString& getDBFieldSetting() override; + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/moduledbp.cxx b/extensions/source/dbpilots/moduledbp.cxx new file mode 100644 index 000000000..0a8f8fd4d --- /dev/null +++ b/extensions/source/dbpilots/moduledbp.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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/optiongrouplayouter.cxx b/extensions/source/dbpilots/optiongrouplayouter.cxx new file mode 100644 index 000000000..f877a1768 --- /dev/null +++ b/extensions/source/dbpilots/optiongrouplayouter.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 "optiongrouplayouter.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include "groupboxwiz.hxx" +#include "dbptools.hxx" +#include + + +namespace dbp +{ + + +#define BUTTON_HEIGHT 300 +#define HEIGHT 450 +#define OFFSET 300 +#define MIN_WIDTH 600 + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::drawing; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::text; + using namespace ::com::sun::star::view; + + OOptionGroupLayouter::OOptionGroupLayouter(const Reference< XComponentContext >& _rxContext) + :mxContext(_rxContext) + { + } + + + void OOptionGroupLayouter::doLayout(const OControlWizardContext& _rContext, const OOptionGroupSettings& _rSettings) + { + Reference< XShapes > xPageShapes = _rContext.xDrawPage; + if (!xPageShapes.is()) + { + OSL_FAIL("OOptionGroupLayouter::OOptionGroupLayouter: missing the XShapes interface for the page!"); + return; + } + + Reference< XMultiServiceFactory > xDocFactory(_rContext.xDocumentModel, UNO_QUERY); + if (!xDocFactory.is()) + { + OSL_FAIL("OOptionGroupLayouter::OOptionGroupLayouter: no document service factory!"); + return; + } + + // no. of buttons to create + sal_Int32 nRadioButtons = _rSettings.aLabels.size(); + + // the shape of the groupbox + css::awt::Size aControlShapeSize = _rContext.xObjectShape->getSize(); + // maybe need to adjust the size if the control shapes + sal_Int32 nMinShapeHeight = BUTTON_HEIGHT*(nRadioButtons+1) + BUTTON_HEIGHT + BUTTON_HEIGHT/4; + if (aControlShapeSize.Height < nMinShapeHeight) + aControlShapeSize.Height = nMinShapeHeight; + if (aControlShapeSize.Width < MIN_WIDTH) + aControlShapeSize.Width = MIN_WIDTH; + _rContext.xObjectShape->setSize(aControlShapeSize); + + // if we're working on a writer document, we need to anchor the shape + implAnchorShape(Reference< XPropertySet >(_rContext.xObjectShape, UNO_QUERY)); + + // shape collection (for grouping the shapes) + Reference< XShapes > xButtonCollection( ShapeCollection::create(mxContext) ); + // first member : the shape of the control + xButtonCollection->add(_rContext.xObjectShape); + + sal_Int32 nTempHeight = (aControlShapeSize.Height - BUTTON_HEIGHT/4) / (nRadioButtons + 1); + + css::awt::Point aShapePosition = _rContext.xObjectShape->getPosition(); + + css::awt::Size aButtonSize(aControlShapeSize); + aButtonSize.Width = aControlShapeSize.Width - OFFSET; + aButtonSize.Height = HEIGHT; + css::awt::Point aButtonPosition; + aButtonPosition.X = aShapePosition.X + OFFSET; + + OUString sElementsName("RadioGroup"); + disambiguateName(Reference< XNameAccess >(_rContext.xForm, UNO_QUERY), sElementsName); + + auto aLabelIter = _rSettings.aLabels.cbegin(); + auto aValueIter = _rSettings.aValues.cbegin(); + for (sal_Int32 i=0; i xRadioModel( + xDocFactory->createInstance("com.sun.star.form.component.RadioButton"), + UNO_QUERY); + + // the label + xRadioModel->setPropertyValue("Label", Any(*aLabelIter)); + // the value + xRadioModel->setPropertyValue("RefValue", Any(*aValueIter)); + + // default selection + if (_rSettings.sDefaultField == *aLabelIter) + xRadioModel->setPropertyValue("DefaultState", Any(sal_Int16(1))); + + // the connection to the database field + if (!_rSettings.sDBField.isEmpty()) + xRadioModel->setPropertyValue("DataField", Any(_rSettings.sDBField)); + + // the name for the model + xRadioModel->setPropertyValue("Name", Any(sElementsName)); + + // create a shape for the radio button + Reference< XControlShape > xRadioShape( + xDocFactory->createInstance("com.sun.star.drawing.ControlShape"), + UNO_QUERY); + Reference< XPropertySet > xShapeProperties(xRadioShape, UNO_QUERY); + + // if we're working on a writer document, we need to anchor the shape + implAnchorShape(xShapeProperties); + + // position it + xRadioShape->setSize(aButtonSize); + xRadioShape->setPosition(aButtonPosition); + // knitting with the model + xRadioShape->setControl(Reference< XControlModel >(xRadioModel, UNO_QUERY)); + + // the name of the shape + // tdf#117282 com.sun.star.drawing.ControlShape *has* no property + // of type 'Name'. In older versions it was an error that this did + // not throw an UnknownPropertyException. Still, it was never set + // at the Shape/SdrObject and was lost. + // Thus - just do no tset it. It is/stays part of the FormControl + // data, so it will be shown in the FormControl dialogs. It is not + // shown/used in SdrObject::Name dialog (e.g. context menu/Name...) + // if (xShapeProperties.is()) + // xShapeProperties->setPropertyValue("Name", makeAny(sElementsName)); + + // add to the page + xPageShapes->add(xRadioShape); + // add to the collection (for the later grouping) + xButtonCollection->add(xRadioShape); + + // set the GroupBox as "LabelControl" for the RadioButton + // (_after_ having inserted the model into the page!) + xRadioModel->setPropertyValue("LabelControl", Any(_rContext.xObjectModel)); + } + + // group the shapes + try + { + Reference< XShapeGrouper > xGrouper(_rContext.xDrawPage, UNO_QUERY); + if (xGrouper.is()) + { + Reference< XShapeGroup > xGroupedOptions = xGrouper->group(xButtonCollection); + Reference< XSelectionSupplier > xSelector(_rContext.xDocumentModel->getCurrentController(), UNO_QUERY); + if (xSelector.is()) + xSelector->select(Any(xGroupedOptions)); + } + } + catch(Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.dbpilots", + "caught an exception while grouping the shapes!"); + } + } + + + void OOptionGroupLayouter::implAnchorShape(const Reference< XPropertySet >& _rxShapeProps) + { + static constexpr OUStringLiteral s_sAnchorPropertyName = u"AnchorType"; + Reference< XPropertySetInfo > xPropertyInfo; + if (_rxShapeProps.is()) + xPropertyInfo = _rxShapeProps->getPropertySetInfo(); + if (xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(s_sAnchorPropertyName)) + _rxShapeProps->setPropertyValue(s_sAnchorPropertyName, Any(TextContentAnchorType_AT_PAGE)); + } + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/optiongrouplayouter.hxx b/extensions/source/dbpilots/optiongrouplayouter.hxx new file mode 100644 index 000000000..64a6998c1 --- /dev/null +++ b/extensions/source/dbpilots/optiongrouplayouter.hxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + + +namespace dbp +{ + + + struct OControlWizardContext; + struct OOptionGroupSettings; + + class OOptionGroupLayouter final + { + css::uno::Reference< css::uno::XComponentContext > + mxContext; + + public: + explicit OOptionGroupLayouter( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + void doLayout( + const OControlWizardContext& _rContext, + const OOptionGroupSettings& _rSettings + ); + + private: + static void implAnchorShape( + const css::uno::Reference< css::beans::XPropertySet >& _rxShapeProps + ); + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/unoautopilot.hxx b/extensions/source/dbpilots/unoautopilot.hxx new file mode 100644 index 000000000..a61df8a6a --- /dev/null +++ b/extensions/source/dbpilots/unoautopilot.hxx @@ -0,0 +1,116 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace dbp +{ + typedef ::svt::OGenericUnoDialog OUnoAutoPilot_Base; + template + class OUnoAutoPilot final + :public OUnoAutoPilot_Base + ,public ::comphelper::OPropertyArrayUsageHelper< OUnoAutoPilot< TYPE > > + { + public: + explicit OUnoAutoPilot(const css::uno::Reference< css::uno::XComponentContext >& _rxORB, + OUString aImplementationName, + const css::uno::Sequence& aSupportedServices) + : OUnoAutoPilot_Base(_rxORB), + m_ImplementationName(aImplementationName), + m_SupportedServices(aSupportedServices) + { + } + + + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override + { + return css::uno::Sequence(); + } + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override + { + return m_ImplementationName; + } + + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override + { + return m_SupportedServices; + } + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override + { + css::uno::Reference< css::beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override + { + return *this->getArrayHelper(); + } + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override + { + css::uno::Sequence< css::beans::Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + } + + private: + // OGenericUnoDialog overridables + virtual std::unique_ptr createDialog(const css::uno::Reference& rParent) override + { + return std::make_unique(Application::GetFrameWeld(rParent), m_xObjectModel, m_aContext); + } + + virtual void implInitialize(const css::uno::Any& _rValue) override + { + css::beans::PropertyValue aArgument; + if (_rValue >>= aArgument) + if (aArgument.Name == "ObjectModel") + { + aArgument.Value >>= m_xObjectModel; + return; + } + + OUnoAutoPilot_Base::implInitialize(_rValue); + } + + css::uno::Reference< css::beans::XPropertySet > m_xObjectModel; + OUString m_ImplementationName; + css::uno::Sequence m_SupportedServices; + + }; + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/wizardcontext.hxx b/extensions/source/dbpilots/wizardcontext.hxx new file mode 100644 index 000000000..65f4c1410 --- /dev/null +++ b/extensions/source/dbpilots/wizardcontext.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace dbp +{ + + struct OControlWizardContext + { + // the global data source context + css::uno::Reference< css::sdb::XDatabaseContext > + xDatasourceContext; + + // the control mode + css::uno::Reference< css::beans::XPropertySet > + xObjectModel; + // the form the control model belongs to + css::uno::Reference< css::beans::XPropertySet > + xForm; + // the form as rowset + css::uno::Reference< css::sdbc::XRowSet > + xRowSet; + + // the model of the document + css::uno::Reference< css::frame::XModel > + xDocumentModel; + // the page where the control mode resides + css::uno::Reference< css::drawing::XDrawPage > + xDrawPage; + // the shape which carries the control + css::uno::Reference< css::drawing::XControlShape > + xObjectShape; + + // the tables or queries of the data source the form is bound to (if any) + css::uno::Reference< css::container::XNameAccess > + xObjectContainer; + // the column types container of the object the form is bound to (table, query or SQL statement) + typedef std::map TNameTypeMap; + TNameTypeMap aTypes; + // the column names of the object the form is bound to (table, query or SQL statement) + css::uno::Sequence< OUString > + aFieldNames; + + bool bEmbedded; + }; + + +} // namespace dbp + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/dbpilots/wizardservices.cxx b/extensions/source/dbpilots/wizardservices.cxx new file mode 100644 index 000000000..25bcf7942 --- /dev/null +++ b/extensions/source/dbpilots/wizardservices.cxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "unoautopilot.hxx" +#include "groupboxwiz.hxx" +#include "listcombowizard.hxx" +#include "gridwizard.hxx" + +// the registration methods + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_dbp_OGroupBoxWizard_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire( + new ::dbp::OUnoAutoPilot< ::dbp::OGroupBoxWizard>( + context, + "org.openoffice.comp.dbp.OGroupBoxWizard", + { "com.sun.star.sdb.GroupBoxAutoPilot" } + )); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_dbp_OListComboWizard_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire( + new ::dbp::OUnoAutoPilot< ::dbp::OListComboWizard>( + context, + "org.openoffice.comp.dbp.OListComboWizard", + { "com.sun.star.sdb.ListComboBoxAutoPilot" } + )); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_dbp_OGridWizard_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire( + new ::dbp::OUnoAutoPilot< ::dbp::OGridWizard>( + context, + "org.openoffice.comp.dbp.OGridWizard", + { "com.sun.star.sdb.GridControlAutoPilot" } + )); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/inc/componentmodule.cxx b/extensions/source/inc/componentmodule.cxx new file mode 100644 index 000000000..e1b29b2ec --- /dev/null +++ b/extensions/source/inc/componentmodule.cxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "componentmodule.hxx" +#include + +namespace compmodule +{ + + OUString ModuleRes(TranslateId pId) + { + return Translate::get(pId, Translate::Create("pcr")); + } + + +} // namespace compmodule + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/inc/componentmodule.hxx b/extensions/source/inc/componentmodule.hxx new file mode 100644 index 000000000..24b5032cd --- /dev/null +++ b/extensions/source/inc/componentmodule.hxx @@ -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 . + */ + +#pragma once + +#include +#include + +namespace compmodule +{ + + // specialized ResId, using the resource locale provided by the global module + OUString ModuleRes(TranslateId pId); + +} // namespace compmodule + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/consolehandler.cxx b/extensions/source/logging/consolehandler.cxx new file mode 100644 index 000000000..d1455baa3 --- /dev/null +++ b/extensions/source/logging/consolehandler.cxx @@ -0,0 +1,264 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "methodguard.hxx" +#include "loghandler.hxx" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace logging +{ + using ::com::sun::star::logging::XConsoleHandler; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::logging::XLogFormatter; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::beans::NamedValue; + + typedef ::cppu::WeakComponentImplHelper < XConsoleHandler + , XServiceInfo + > ConsoleHandler_Base; + + namespace { + + class ConsoleHandler :public ::cppu::BaseMutex + ,public ConsoleHandler_Base + { + private: + LogHandlerHelper m_aHandlerHelper; + sal_Int32 m_nThreshold; + + public: + ConsoleHandler(const Reference &context, + const css::uno::Sequence &arguments); + virtual ~ConsoleHandler() override; + + private: + // XConsoleHandler + virtual ::sal_Int32 SAL_CALL getThreshold() override; + virtual void SAL_CALL setThreshold( ::sal_Int32 _threshold ) override; + + // XLogHandler + virtual OUString SAL_CALL getEncoding() override; + virtual void SAL_CALL setEncoding( const OUString& _encoding ) override; + virtual Reference< XLogFormatter > SAL_CALL getFormatter() override; + virtual void SAL_CALL setFormatter( const Reference< XLogFormatter >& _formatter ) override; + virtual ::sal_Int32 SAL_CALL getLevel() override; + virtual void SAL_CALL setLevel( ::sal_Int32 _level ) override; + virtual void SAL_CALL flush( ) override; + virtual sal_Bool SAL_CALL publish( const LogRecord& Record ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& _rServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + public: + typedef ComponentMethodGuard< ConsoleHandler > MethodGuard; + void enterMethod( MethodGuard::Access ); + void leaveMethod( MethodGuard::Access ); + }; + + } + + ConsoleHandler::ConsoleHandler(const Reference &context, + const css::uno::Sequence &arguments) + :ConsoleHandler_Base( m_aMutex ) + ,m_aHandlerHelper( context, m_aMutex, rBHelper ) + ,m_nThreshold( css::logging::LogLevel::SEVERE ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !arguments.hasElements() ) + { // create() - nothing to init + m_aHandlerHelper.setIsInitialized(); + return; + } + + if ( arguments.getLength() != 1 ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + Sequence< NamedValue > aSettings; + if ( !( arguments[0] >>= aSettings ) ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + // createWithSettings( [in] sequence< css::beans::NamedValue > Settings ) + ::comphelper::NamedValueCollection aTypedSettings( aSettings ); + m_aHandlerHelper.initFromSettings( aTypedSettings ); + + aTypedSettings.get_ensureType( "Threshold", m_nThreshold ); + + m_aHandlerHelper.setIsInitialized(); + } + + ConsoleHandler::~ConsoleHandler() + { + if ( !rBHelper.bDisposed ) + { + acquire(); + dispose(); + } + } + + + void SAL_CALL ConsoleHandler::disposing() + { + m_aHandlerHelper.setFormatter( nullptr ); + } + + + void ConsoleHandler::enterMethod( MethodGuard::Access ) + { + m_aHandlerHelper.enterMethod(); + } + + + void ConsoleHandler::leaveMethod( MethodGuard::Access ) + { + m_aMutex.release(); + } + + + ::sal_Int32 SAL_CALL ConsoleHandler::getThreshold() + { + MethodGuard aGuard( *this ); + return m_nThreshold; + } + + + void SAL_CALL ConsoleHandler::setThreshold( ::sal_Int32 _threshold ) + { + MethodGuard aGuard( *this ); + m_nThreshold = _threshold; + } + + + OUString SAL_CALL ConsoleHandler::getEncoding() + { + MethodGuard aGuard( *this ); + OUString sEncoding; + OSL_VERIFY( m_aHandlerHelper.getEncoding( sEncoding ) ); + return sEncoding; + } + + + void SAL_CALL ConsoleHandler::setEncoding( const OUString& _rEncoding ) + { + MethodGuard aGuard( *this ); + OSL_VERIFY( m_aHandlerHelper.setEncoding( _rEncoding ) ); + } + + + Reference< XLogFormatter > SAL_CALL ConsoleHandler::getFormatter() + { + MethodGuard aGuard( *this ); + return m_aHandlerHelper.getFormatter(); + } + + + void SAL_CALL ConsoleHandler::setFormatter( const Reference< XLogFormatter >& _rxFormatter ) + { + MethodGuard aGuard( *this ); + m_aHandlerHelper.setFormatter( _rxFormatter ); + } + + + ::sal_Int32 SAL_CALL ConsoleHandler::getLevel() + { + MethodGuard aGuard( *this ); + return m_aHandlerHelper.getLevel(); + } + + + void SAL_CALL ConsoleHandler::setLevel( ::sal_Int32 _nLevel ) + { + MethodGuard aGuard( *this ); + m_aHandlerHelper.setLevel( _nLevel ); + } + + + void SAL_CALL ConsoleHandler::flush( ) + { + MethodGuard aGuard( *this ); + fflush( stdout ); + fflush( stderr ); + } + + + sal_Bool SAL_CALL ConsoleHandler::publish( const LogRecord& _rRecord ) + { + MethodGuard aGuard( *this ); + + OString sEntry; + if ( !m_aHandlerHelper.formatForPublishing( _rRecord, sEntry ) ) + return false; + + if ( _rRecord.Level >= m_nThreshold ) + fprintf( stderr, "%s\n", sEntry.getStr() ); + else + fprintf( stdout, "%s\n", sEntry.getStr() ); + + return true; + } + + OUString SAL_CALL ConsoleHandler::getImplementationName() + { + return "com.sun.star.comp.extensions.ConsoleHandler"; + } + + sal_Bool SAL_CALL ConsoleHandler::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL ConsoleHandler::getSupportedServiceNames() + { + return { "com.sun.star.logging.ConsoleHandler" }; + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_ConsoleHandler( + css::uno::XComponentContext *context, + css::uno::Sequence const &arguments) +{ + return cppu::acquire(new logging::ConsoleHandler(context, arguments)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/csvformatter.cxx b/extensions/source/logging/csvformatter.cxx new file mode 100644 index 000000000..8e749db42 --- /dev/null +++ b/extensions/source/logging/csvformatter.cxx @@ -0,0 +1,320 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 logging +{ + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::logging::LogRecord; + + namespace { + + // formats for csv files as defined by RFC4180 + class CsvFormatter : public cppu::WeakImplHelper + { + public: + virtual OUString SAL_CALL formatMultiColumn(const Sequence< OUString>& column_data) override; + + CsvFormatter(); + + private: + // XCsvLogFormatter + virtual sal_Bool SAL_CALL getLogEventNo() override; + virtual sal_Bool SAL_CALL getLogThread() override; + virtual sal_Bool SAL_CALL getLogTimestamp() override; + virtual sal_Bool SAL_CALL getLogSource() override; + virtual Sequence< OUString > SAL_CALL getColumnnames() override; + + virtual void SAL_CALL setLogEventNo( sal_Bool log_event_no ) override; + virtual void SAL_CALL setLogThread( sal_Bool log_thread ) override; + virtual void SAL_CALL setLogTimestamp( sal_Bool log_timestamp ) override; + virtual void SAL_CALL setLogSource( sal_Bool log_source ) override; + virtual void SAL_CALL setColumnnames( const Sequence< OUString>& column_names) override; + + // XLogFormatter + virtual OUString SAL_CALL getHead( ) override; + virtual OUString SAL_CALL format( const LogRecord& Record ) override; + virtual OUString SAL_CALL getTail( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& service_name ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + private: + bool m_LogEventNo; + bool m_LogThread; + bool m_LogTimestamp; + bool m_LogSource; + bool m_MultiColumn; + css::uno::Sequence< OUString > m_Columnnames; + }; + + } +} // namespace logging + +// private helpers +namespace +{ + const sal_Unicode quote_char = '"'; + const sal_Unicode comma_char = ','; + constexpr OUStringLiteral dos_newline = u"\r\n"; + + bool needsQuoting(std::u16string_view str) + { + return str.find_first_of(u"\",\n\r") != std::u16string_view::npos; + }; + + void appendEncodedString(OUStringBuffer& buf, const OUString& str) + { + if(needsQuoting(str)) + { + // each double-quote will get replaced by two double-quotes + buf.append(quote_char); + const sal_Int32 buf_offset = buf.getLength(); + const sal_Int32 str_length = str.getLength(); + buf.append(str); + // special treatment for the last character + if(quote_char==str[str_length-1]) + buf.append(quote_char); + // iterating backwards because the index at which we insert won't be shifted + // when moving that way. + for(sal_Int32 i = str_length; i>=0; ) + { + i=str.lastIndexOf(quote_char, --i); + if(i!=-1) + buf.insert(buf_offset + i, quote_char); + } + buf.append(quote_char); + } + else + buf.append(str); + }; +} + +namespace logging +{ + CsvFormatter::CsvFormatter() + :m_LogEventNo(true), + m_LogThread(true), + m_LogTimestamp(true), + m_LogSource(false), + m_MultiColumn(false), + m_Columnnames({ "message" }) + { } + + sal_Bool CsvFormatter::getLogEventNo() + { + return m_LogEventNo; + } + + sal_Bool CsvFormatter::getLogThread() + { + return m_LogThread; + } + + sal_Bool CsvFormatter::getLogTimestamp() + { + return m_LogTimestamp; + } + + sal_Bool CsvFormatter::getLogSource() + { + return m_LogSource; + } + + Sequence< OUString > CsvFormatter::getColumnnames() + { + return m_Columnnames; + } + + void CsvFormatter::setLogEventNo(sal_Bool log_event_no) + { + m_LogEventNo = log_event_no; + } + + void CsvFormatter::setLogThread(sal_Bool log_thread) + { + m_LogThread = log_thread; + } + + void CsvFormatter::setLogTimestamp(sal_Bool log_timestamp) + { + m_LogTimestamp = log_timestamp; + } + + void CsvFormatter::setLogSource(sal_Bool log_source) + { + m_LogSource = log_source; + } + + void CsvFormatter::setColumnnames(const Sequence< OUString >& columnnames) + { + m_Columnnames = columnnames; + m_MultiColumn = (m_Columnnames.getLength()>1); + } + + OUString SAL_CALL CsvFormatter::getHead( ) + { + OUStringBuffer buf; + if(m_LogEventNo) + buf.append("event no,"); + if(m_LogThread) + buf.append("thread,"); + if(m_LogTimestamp) + buf.append("timestamp,"); + if(m_LogSource) + buf.append("class,method,"); + sal_Int32 columns = m_Columnnames.getLength(); + for(sal_Int32 i=0; i(this), 1); + } + + // ISO 8601 + char buffer[ SAL_N_ELEMENTS("-32768-65535-65535T65535:65535:65535.4294967295") ]; + const size_t buffer_size = sizeof( buffer ); + snprintf( buffer, buffer_size, "%04i-%02u-%02uT%02u:%02u:%02u.%09" SAL_PRIuUINT32, + static_cast(record.LogTime.Year), + static_cast(record.LogTime.Month), + static_cast(record.LogTime.Day), + static_cast(record.LogTime.Hours), + static_cast(record.LogTime.Minutes), + static_cast(record.LogTime.Seconds), + record.LogTime.NanoSeconds ); + aLogEntry.appendAscii( buffer ); + aLogEntry.append(comma_char); + } + + if(m_LogSource) + { + appendEncodedString(aLogEntry, record.SourceClassName); + aLogEntry.append(comma_char); + + appendEncodedString(aLogEntry, record.SourceMethodName); + aLogEntry.append(comma_char); + } + + // if the CsvFormatter has multiple columns set via setColumnnames(), the + // message of the record is expected to be encoded with formatMultiColumn + // if the CsvFormatter has only one column set, the message is expected not + // to be encoded + if(m_MultiColumn) + aLogEntry.append(record.Message); + else + appendEncodedString(aLogEntry, record.Message); + + aLogEntry.append( dos_newline ); + return aLogEntry.makeStringAndClear(); + } + + OUString SAL_CALL CsvFormatter::getTail( ) + { + return OUString(); + } + + OUString SAL_CALL CsvFormatter::formatMultiColumn(const Sequence< OUString>& column_data) + { + sal_Int32 columns = column_data.getLength(); + OUStringBuffer buf; + for(int i=0; i SAL_CALL CsvFormatter::getSupportedServiceNames() + { + return { "com.sun.star.logging.CsvFormatter" }; + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_CsvFormatter( + css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new logging::CsvFormatter()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/filehandler.cxx b/extensions/source/logging/filehandler.cxx new file mode 100644 index 000000000..200a3a64b --- /dev/null +++ b/extensions/source/logging/filehandler.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 +#include + +#include "methodguard.hxx" +#include "loghandler.hxx" + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +namespace logging +{ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::logging::XLogFormatter; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::logging::XLogHandler; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::util::PathSubstitution; + using ::com::sun::star::util::XStringSubstitution; + using ::com::sun::star::beans::NamedValue; + + typedef ::cppu::WeakComponentImplHelper < XLogHandler + , XServiceInfo + > FileHandler_Base; + + namespace { + + class FileHandler :public ::cppu::BaseMutex + ,public FileHandler_Base + { + private: + enum FileValidity + { + /// never attempted to open the file + eUnknown, + /// file is valid + eValid, + /// file is invalid + eInvalid + }; + + Reference m_xContext; + LogHandlerHelper m_aHandlerHelper; + OUString m_sFileURL; + std::unique_ptr< ::osl::File > m_pFile; + FileValidity m_eFileValidity; + + public: + FileHandler(const css::uno::Reference &context, + const css::uno::Sequence &arguments); + virtual ~FileHandler() override; + + private: + // XLogHandler + virtual OUString SAL_CALL getEncoding() override; + virtual void SAL_CALL setEncoding( const OUString& _encoding ) override; + virtual Reference< XLogFormatter > SAL_CALL getFormatter() override; + virtual void SAL_CALL setFormatter( const Reference< XLogFormatter >& _formatter ) override; + virtual ::sal_Int32 SAL_CALL getLevel() override; + virtual void SAL_CALL setLevel( ::sal_Int32 _level ) override; + virtual void SAL_CALL flush( ) override; + virtual sal_Bool SAL_CALL publish( const LogRecord& Record ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& _rServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // OComponentHelper + virtual void SAL_CALL disposing() override; + + public: + typedef ComponentMethodGuard< FileHandler > MethodGuard; + void enterMethod( MethodGuard::Access ); + void leaveMethod( MethodGuard::Access ); + + private: + /** prepares our output file for writing + */ + bool impl_prepareFile_nothrow(); + + /// writes the given string to our file + void impl_writeString_nothrow( const OString& _rEntry ); + + /** does string substitution on a (usually externally provided) file url + */ + void impl_doStringsubstitution_nothrow( OUString& _inout_rURL ); + }; + + } + + FileHandler::FileHandler(const css::uno::Reference &context, + const css::uno::Sequence &arguments) + :FileHandler_Base( m_aMutex ) + ,m_xContext( context ) + ,m_aHandlerHelper( context, m_aMutex, rBHelper ) + ,m_eFileValidity( eUnknown ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( arguments.getLength() != 1 ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + Sequence< NamedValue > aSettings; + if ( arguments[0] >>= m_sFileURL ) + { + // create( [in] string URL ); + impl_doStringsubstitution_nothrow( m_sFileURL ); + } + else if ( arguments[0] >>= aSettings ) + { + // createWithSettings( [in] sequence< css::beans::NamedValue > Settings ) + ::comphelper::NamedValueCollection aTypedSettings( aSettings ); + m_aHandlerHelper.initFromSettings( aTypedSettings ); + + if ( aTypedSettings.get_ensureType( "FileURL", m_sFileURL ) ) + impl_doStringsubstitution_nothrow( m_sFileURL ); + } + else + throw IllegalArgumentException( OUString(), *this, 1 ); + + m_aHandlerHelper.setIsInitialized(); + } + + FileHandler::~FileHandler() + { + if ( !rBHelper.bDisposed ) + { + acquire(); + dispose(); + } + } + + + bool FileHandler::impl_prepareFile_nothrow() + { + if ( m_eFileValidity == eUnknown ) + { + m_pFile.reset( new ::osl::File( m_sFileURL ) ); + // check whether the log file already exists + ::osl::DirectoryItem aFileItem; + if (osl::FileBase::E_None == ::osl::DirectoryItem::get(m_sFileURL, aFileItem)) + { + ::osl::FileStatus aStatus(osl_FileStatus_Mask_Validate); + if (::osl::FileBase::E_None == aFileItem.getFileStatus(aStatus)) + ::osl::File::remove(m_sFileURL); + } + + ::osl::FileBase::RC res = m_pFile->open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); + m_eFileValidity = res == ::osl::FileBase::E_None + ? eValid + : eInvalid; + #if OSL_DEBUG_LEVEL > 0 + if ( m_eFileValidity == eInvalid ) + { + SAL_WARN( "extensions.logging", "FileHandler::impl_prepareFile_nothrow: could not open the designated log file:" + "\nURL: " << m_sFileURL + << "\nerror code: " << static_cast(res) ); + } + #endif + if ( m_eFileValidity == eValid ) + { + OString sHead; + if ( m_aHandlerHelper.getEncodedHead( sHead ) ) + impl_writeString_nothrow( sHead ); + } + } + + return m_eFileValidity == eValid; + } + + + void FileHandler::impl_writeString_nothrow( const OString& _rEntry ) + { + OSL_PRECOND(m_pFile, "FileHandler::impl_writeString_nothrow: no file!"); + + sal_uInt64 nBytesToWrite( _rEntry.getLength() ); + sal_uInt64 nBytesWritten( 0 ); + ::osl::FileBase::RC res = + m_pFile->write( _rEntry.getStr(), nBytesToWrite, nBytesWritten ); + OSL_ENSURE( ( res == ::osl::FileBase::E_None ) && ( nBytesWritten == nBytesToWrite ), + "FileHandler::impl_writeString_nothrow: could not write the log entry!" ); + } + + + void FileHandler::impl_doStringsubstitution_nothrow( OUString& _inout_rURL ) + { + try + { + Reference< XStringSubstitution > xStringSubst(PathSubstitution::create(m_xContext)); + _inout_rURL = xStringSubst->substituteVariables( _inout_rURL, true ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + } + + + void SAL_CALL FileHandler::disposing() + { + if ( m_eFileValidity == eValid ) + { + OString sTail; + if ( m_aHandlerHelper.getEncodedTail( sTail ) ) + impl_writeString_nothrow( sTail ); + } + + m_pFile.reset(); + m_aHandlerHelper.setFormatter( nullptr ); + } + + + void FileHandler::enterMethod( MethodGuard::Access ) + { + m_aHandlerHelper.enterMethod(); + } + + + void FileHandler::leaveMethod( MethodGuard::Access ) + { + m_aMutex.release(); + } + + + OUString SAL_CALL FileHandler::getEncoding() + { + MethodGuard aGuard( *this ); + OUString sEncoding; + OSL_VERIFY( m_aHandlerHelper.getEncoding( sEncoding ) ); + return sEncoding; + } + + + void SAL_CALL FileHandler::setEncoding( const OUString& _rEncoding ) + { + MethodGuard aGuard( *this ); + OSL_VERIFY( m_aHandlerHelper.setEncoding( _rEncoding ) ); + } + + + Reference< XLogFormatter > SAL_CALL FileHandler::getFormatter() + { + MethodGuard aGuard( *this ); + return m_aHandlerHelper.getFormatter(); + } + + + void SAL_CALL FileHandler::setFormatter( const Reference< XLogFormatter >& _rxFormatter ) + { + MethodGuard aGuard( *this ); + m_aHandlerHelper.setFormatter( _rxFormatter ); + } + + + ::sal_Int32 SAL_CALL FileHandler::getLevel() + { + MethodGuard aGuard( *this ); + return m_aHandlerHelper.getLevel(); + } + + + void SAL_CALL FileHandler::setLevel( ::sal_Int32 _nLevel ) + { + MethodGuard aGuard( *this ); + m_aHandlerHelper.setLevel( _nLevel ); + } + + + void SAL_CALL FileHandler::flush( ) + { + MethodGuard aGuard( *this ); + if (!m_pFile) + { + OSL_PRECOND(false, "FileHandler::flush: no file!"); + return; + } + ::osl::FileBase::RC res = m_pFile->sync(); + OSL_ENSURE(res == ::osl::FileBase::E_None, "FileHandler::flush: Could not sync logfile to filesystem."); + } + + + sal_Bool SAL_CALL FileHandler::publish( const LogRecord& _rRecord ) + { + MethodGuard aGuard( *this ); + + if ( !impl_prepareFile_nothrow() ) + return false; + + OString sEntry; + if ( !m_aHandlerHelper.formatForPublishing( _rRecord, sEntry ) ) + return false; + + impl_writeString_nothrow( sEntry ); + return true; + } + + OUString SAL_CALL FileHandler::getImplementationName() + { + return "com.sun.star.comp.extensions.FileHandler"; + } + + sal_Bool SAL_CALL FileHandler::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL FileHandler::getSupportedServiceNames() + { + return { "com.sun.star.logging.FileHandler" }; + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_FileHandler( + css::uno::XComponentContext *context, + css::uno::Sequence const &arguments) +{ + return cppu::acquire(new logging::FileHandler(context, arguments)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/log.component b/extensions/source/logging/log.component new file mode 100644 index 000000000..ae221bb57 --- /dev/null +++ b/extensions/source/logging/log.component @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/source/logging/logger.cxx b/extensions/source/logging/logger.cxx new file mode 100644 index 000000000..322ad7ab9 --- /dev/null +++ b/extensions/source/logging/logger.cxx @@ -0,0 +1,265 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "logrecord.hxx" +#include "loggerconfig.hxx" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +namespace logging +{ + + using ::com::sun::star::logging::XLogger; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::WeakReference; + using ::com::sun::star::logging::XLogHandler; + using ::com::sun::star::logging::LogRecord; + + namespace { + + class EventLogger : public cppu::BaseMutex, + public cppu::WeakImplHelper + { + private: + comphelper::OInterfaceContainerHelper2 m_aHandlers; + oslInterlockedCount m_nEventNumber; + + // + sal_Int32 m_nLogLevel; + OUString m_sName; + // + + public: + EventLogger( const Reference< XComponentContext >& _rxContext, const OUString& _rName ); + + // XLogger + virtual OUString SAL_CALL getName() override; + virtual ::sal_Int32 SAL_CALL getLevel() override; + virtual void SAL_CALL setLevel( ::sal_Int32 _level ) override; + virtual void SAL_CALL addLogHandler( const Reference< XLogHandler >& LogHandler ) override; + virtual void SAL_CALL removeLogHandler( const Reference< XLogHandler >& LogHandler ) override; + virtual sal_Bool SAL_CALL isLoggable( ::sal_Int32 _nLevel ) override; + virtual void SAL_CALL log( ::sal_Int32 Level, const OUString& Message ) override; + virtual void SAL_CALL logp( ::sal_Int32 Level, const OUString& SourceClass, const OUString& SourceMethod, const OUString& Message ) override; + + protected: + virtual ~EventLogger() override; + + private: + /** logs the given log record + */ + void impl_ts_logEvent_nothrow( const LogRecord& _rRecord ); + + /** non-threadsafe impl-version of isLoggable + */ + bool impl_nts_isLoggable_nothrow( ::sal_Int32 _nLevel ); + }; + + /** administrates a pool of XLogger instances, where a logger is keyed by its name, + and subsequent requests for a logger with the same name return the same instance. + */ + class LoggerPool : public cppu::WeakImplHelper + { + private: + ::osl::Mutex m_aMutex; + Reference m_xContext; + std::map< OUString, WeakReference > m_aLoggerMap; + + public: + explicit LoggerPool( const Reference< XComponentContext >& _rxContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& _rServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XLoggerPool + virtual Reference< XLogger > SAL_CALL getNamedLogger( const OUString& Name ) override; + virtual Reference< XLogger > SAL_CALL getDefaultLogger( ) override; + }; + + } + + EventLogger::EventLogger( const Reference< XComponentContext >& _rxContext, const OUString& _rName ) + :m_aHandlers( m_aMutex ) + ,m_nEventNumber( 0 ) + ,m_nLogLevel( css::logging::LogLevel::OFF ) + ,m_sName( _rName ) + { + osl_atomic_increment( &m_refCount ); + { + initializeLoggerFromConfiguration( _rxContext, this ); + } + osl_atomic_decrement( &m_refCount ); + } + + EventLogger::~EventLogger() + { + } + + bool EventLogger::impl_nts_isLoggable_nothrow( ::sal_Int32 _nLevel ) + { + if ( _nLevel < m_nLogLevel ) + return false; + + if ( !m_aHandlers.getLength() ) + return false; + + return true; + } + + void EventLogger::impl_ts_logEvent_nothrow( const LogRecord& _rRecord ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !impl_nts_isLoggable_nothrow( _rRecord.Level ) ) + return; + + m_aHandlers.forEach< XLogHandler >( + [&_rRecord] (Reference const& rxListener) { rxListener->publish(_rRecord); } ); + m_aHandlers.forEach< XLogHandler >( + [] (Reference const& rxListener) { rxListener->flush(); } ); + } + + OUString SAL_CALL EventLogger::getName() + { + return m_sName; + } + + ::sal_Int32 SAL_CALL EventLogger::getLevel() + { + ::osl::MutexGuard aGuard( m_aMutex ); + return m_nLogLevel; + } + + void SAL_CALL EventLogger::setLevel( ::sal_Int32 _level ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_nLogLevel = _level; + } + + void SAL_CALL EventLogger::addLogHandler( const Reference< XLogHandler >& _rxLogHandler ) + { + if ( _rxLogHandler.is() ) + m_aHandlers.addInterface( _rxLogHandler ); + } + + void SAL_CALL EventLogger::removeLogHandler( const Reference< XLogHandler >& _rxLogHandler ) + { + if ( _rxLogHandler.is() ) + m_aHandlers.removeInterface( _rxLogHandler ); + } + + sal_Bool SAL_CALL EventLogger::isLoggable( ::sal_Int32 _nLevel ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return impl_nts_isLoggable_nothrow( _nLevel ); + } + + void SAL_CALL EventLogger::log( ::sal_Int32 _nLevel, const OUString& _rMessage ) + { + impl_ts_logEvent_nothrow( createLogRecord( + m_sName, + _rMessage, + _nLevel, + osl_atomic_increment( &m_nEventNumber ) + ) ); + } + + void SAL_CALL EventLogger::logp( ::sal_Int32 _nLevel, const OUString& _rSourceClass, const OUString& _rSourceMethod, const OUString& _rMessage ) + { + impl_ts_logEvent_nothrow( createLogRecord( + m_sName, + _rSourceClass, + _rSourceMethod, + _rMessage, + _nLevel, + osl_atomic_increment( &m_nEventNumber ) + ) ); + } + + LoggerPool::LoggerPool( const Reference< XComponentContext >& _rxContext ) + :m_xContext( _rxContext ) + { + } + + OUString SAL_CALL LoggerPool::getImplementationName() + { + return "com.sun.star.comp.extensions.LoggerPool"; + } + + sal_Bool SAL_CALL LoggerPool::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + Sequence< OUString > SAL_CALL LoggerPool::getSupportedServiceNames() + { + return { "com.sun.star.logging.LoggerPool" }; + } + + Reference< XLogger > SAL_CALL LoggerPool::getNamedLogger( const OUString& _rName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + WeakReference< XLogger >& rLogger( m_aLoggerMap[ _rName ] ); + Reference< XLogger > xLogger( rLogger ); + if ( !xLogger.is() ) + { + // never requested before, or already dead + xLogger = new EventLogger( m_xContext, _rName ); + rLogger = xLogger; + } + + return xLogger; + } + + Reference< XLogger > SAL_CALL LoggerPool::getDefaultLogger( ) + { + return getNamedLogger( "org.openoffice.logging.DefaultLogger" ); + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_LoggerPool( + css::uno::XComponentContext *context, + css::uno::Sequence const &) +{ + return cppu::acquire(new logging::LoggerPool(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/loggerconfig.cxx b/extensions/source/logging/loggerconfig.cxx new file mode 100644 index 000000000..25ef76e02 --- /dev/null +++ b/extensions/source/logging/loggerconfig.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 "loggerconfig.hxx" +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +namespace logging +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::logging::XLogger; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Any; + using ::com::sun::star::container::XNameContainer; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::lang::XSingleServiceFactory; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::util::XChangesBatch; + using ::com::sun::star::lang::NullPointerException; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::lang::ServiceNotRegisteredException; + using ::com::sun::star::beans::NamedValue; + using ::com::sun::star::logging::XLogHandler; + using ::com::sun::star::logging::XLogFormatter; + using ::com::sun::star::container::XNameAccess; + using ::com::sun::star::uno::XComponentContext; + + namespace LogLevel = ::com::sun::star::logging::LogLevel; + + namespace + { + + typedef void (*SettingTranslation)( const Reference< XLogger >&, const OUString&, Any& ); + + + void lcl_substituteFileHandlerURLVariables_nothrow( const Reference< XLogger >& _rxLogger, OUString& _inout_rFileURL ) + { + struct Variable + { + std::u16string_view pVariablePattern; + OUString sVariableValue; + }; + + OUString sLoggerName; + try { sLoggerName = _rxLogger->getName(); } + catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION("extensions.logging"); } + + TimeValue aTimeValue; + oslDateTime aDateTime; + OSL_VERIFY( osl_getSystemTime( &aTimeValue ) ); + OSL_VERIFY( osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime ) ); + + char buffer[ 30 ]; + const size_t buffer_size = sizeof( buffer ); + + snprintf( buffer, buffer_size, "%04i-%02i-%02i", + static_cast(aDateTime.Year), + static_cast(aDateTime.Month), + static_cast(aDateTime.Day) ); + OUString sDate = OUString::createFromAscii( buffer ); + + snprintf( buffer, buffer_size, "%02i-%02i-%02i.%03i", + static_cast(aDateTime.Hours), + static_cast(aDateTime.Minutes), + static_cast(aDateTime.Seconds), + ::sal::static_int_cast< sal_Int16 >( aDateTime.NanoSeconds / 10000000 ) ); + OUString sTime = OUString::createFromAscii( buffer ); + + OUString sDateTime = sDate + "." + sTime; + + oslProcessIdentifier aProcessId = 0; + oslProcessInfo info; + info.Size = sizeof (oslProcessInfo); + if ( osl_getProcessInfo ( nullptr, osl_Process_IDENTIFIER, &info ) == osl_Process_E_None) + aProcessId = info.Ident; + OUString aPID = OUString::number( aProcessId ); + + Variable const aVariables[] = + { + {std::u16string_view(u"$(loggername)"), sLoggerName}, + {std::u16string_view(u"$(date)"), sDate}, + {std::u16string_view(u"$(time)"), sTime}, + {std::u16string_view(u"$(datetime)"), sDateTime}, + {std::u16string_view(u"$(pid)"), aPID} + }; + + for (Variable const & aVariable : aVariables) + { + sal_Int32 nVariableIndex = _inout_rFileURL.indexOf( aVariable.pVariablePattern ); + if (nVariableIndex >= 0) + { + _inout_rFileURL = _inout_rFileURL.replaceAt( nVariableIndex, aVariable.pVariablePattern.size(), aVariable.sVariableValue ); + } + } + } + + + void lcl_transformFileHandlerSettings_nothrow( const Reference< XLogger >& _rxLogger, const OUString& _rSettingName, Any& _inout_rSettingValue ) + { + if ( _rSettingName != "FileURL" ) + // not interested in this setting + return; + + OUString sURL; + OSL_VERIFY( _inout_rSettingValue >>= sURL ); + lcl_substituteFileHandlerURLVariables_nothrow( _rxLogger, sURL ); + _inout_rSettingValue <<= sURL; + } + + + Reference< XInterface > lcl_createInstanceFromSetting_throw( + const Reference& _rContext, + const Reference< XLogger >& _rxLogger, + const Reference< XNameAccess >& _rxLoggerSettings, + const char* _pServiceNameAsciiNodeName, + const char* _pServiceSettingsAsciiNodeName, + SettingTranslation _pSettingTranslation = nullptr + ) + { + Reference< XInterface > xInstance; + + // read the settings for the to-be-created service + Reference< XNameAccess > xServiceSettingsNode( _rxLoggerSettings->getByName( + OUString::createFromAscii( _pServiceSettingsAsciiNodeName ) ), UNO_QUERY_THROW ); + + Sequence< OUString > aSettingNames( xServiceSettingsNode->getElementNames() ); + size_t nServiceSettingCount( aSettingNames.getLength() ); + Sequence< NamedValue > aSettings( nServiceSettingCount ); + if ( nServiceSettingCount ) + { + const OUString* pSettingNames = aSettingNames.getConstArray(); + const OUString* pSettingNamesEnd = aSettingNames.getConstArray() + aSettingNames.getLength(); + NamedValue* pSetting = aSettings.getArray(); + + for ( ; + pSettingNames != pSettingNamesEnd; + ++pSettingNames, ++pSetting + ) + { + pSetting->Name = *pSettingNames; + pSetting->Value = xServiceSettingsNode->getByName( *pSettingNames ); + + if ( _pSettingTranslation ) + _pSettingTranslation( _rxLogger, pSetting->Name, pSetting->Value ); + } + } + + OUString sServiceName; + _rxLoggerSettings->getByName( OUString::createFromAscii( _pServiceNameAsciiNodeName ) ) >>= sServiceName; + if ( !sServiceName.isEmpty() ) + { + bool bSuccess = false; + if ( aSettings.hasElements() ) + { + Sequence< Any > aConstructionArgs{ Any(aSettings) }; + xInstance = _rContext->getServiceManager()->createInstanceWithArgumentsAndContext(sServiceName, aConstructionArgs, _rContext); + bSuccess = xInstance.is(); + } + else + { + xInstance = _rContext->getServiceManager()->createInstanceWithContext(sServiceName, _rContext); + bSuccess = xInstance.is(); + } + + if ( !bSuccess ) + throw ServiceNotRegisteredException( sServiceName ); + } + + return xInstance; + } + } + + + void initializeLoggerFromConfiguration( const Reference& _rContext, const Reference< XLogger >& _rxLogger ) + { + try + { + if ( !_rxLogger.is() ) + throw NullPointerException(); + + Reference< XMultiServiceFactory > xConfigProvider( + css::configuration::theDefaultProvider::get(_rContext)); + + // write access to the "Settings" node (which includes settings for all loggers) + Sequence aArguments{ Any(NamedValue( + "nodepath", Any(OUString("/org.openoffice.Office.Logging/Settings")))) }; + Reference< XNameContainer > xAllSettings( xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationUpdateAccess", + aArguments + ), UNO_QUERY_THROW ); + + OUString sLoggerName( _rxLogger->getName() ); + if ( !xAllSettings->hasByName( sLoggerName ) ) + { + // no node yet for this logger. Create default settings. + Reference< XSingleServiceFactory > xNodeFactory( xAllSettings, UNO_QUERY_THROW ); + Reference< XInterface > xLoggerSettings( xNodeFactory->createInstance(), css::uno::UNO_SET_THROW ); + xAllSettings->insertByName( sLoggerName, Any( xLoggerSettings ) ); + Reference< XChangesBatch > xChanges( xAllSettings, UNO_QUERY_THROW ); + xChanges->commitChanges(); + } + + // actually read and forward the settings + Reference< XNameAccess > xLoggerSettings( xAllSettings->getByName( sLoggerName ), UNO_QUERY_THROW ); + + // the log level + sal_Int32 nLogLevel( LogLevel::OFF ); + OSL_VERIFY( xLoggerSettings->getByName("LogLevel") >>= nLogLevel ); + _rxLogger->setLevel( nLogLevel ); + + // the default handler, if any + Reference< XInterface > xUntyped( lcl_createInstanceFromSetting_throw( _rContext, _rxLogger, xLoggerSettings, "DefaultHandler", "HandlerSettings", &lcl_transformFileHandlerSettings_nothrow ) ); + if ( !xUntyped.is() ) + // no handler -> we're done + return; + Reference< XLogHandler > xHandler( xUntyped, UNO_QUERY_THROW ); + _rxLogger->addLogHandler( xHandler ); + + // The newly created handler might have an own (default) level. Ensure that it uses + // the same level as the logger. + xHandler->setLevel( nLogLevel ); + + // the default formatter for the handler + xUntyped = lcl_createInstanceFromSetting_throw( _rContext, _rxLogger, xLoggerSettings, "DefaultFormatter", "FormatterSettings" ); + if ( !xUntyped.is() ) + // no formatter -> we're done + return; + Reference< XLogFormatter > xFormatter( xUntyped, UNO_QUERY_THROW ); + xHandler->setFormatter( xFormatter ); + + // TODO: we could first create the formatter, then the handler. This would allow + // passing the formatter as value in the component context, so the handler would + // not create an own default formatter + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + } + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/loggerconfig.hxx b/extensions/source/logging/loggerconfig.hxx new file mode 100644 index 000000000..b08628cf1 --- /dev/null +++ b/extensions/source/logging/loggerconfig.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + + +namespace logging +{ + + + /** initializes the given logger from the configuration + + The configuration node /org.openoffice.Office.Logging/Settings/ + is examined for this. If it does not yet exist, it will be created. + + The function creates a default handler and a default formatter, as specified in the + configuration. + + This function is currently external to the logger instance. Perhaps it can, on the long + run, be moved to the logger implementation - not sure if it's the best place. + */ + void initializeLoggerFromConfiguration( + const css::uno::Reference& _rContext, + const css::uno::Reference< css::logging::XLogger >& _rxLogger + ); + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/loghandler.cxx b/extensions/source/logging/loghandler.cxx new file mode 100644 index 000000000..afc33605b --- /dev/null +++ b/extensions/source/logging/loghandler.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 "loghandler.hxx" + +#include +#include +#include +#include + +#include +#include + + +namespace logging +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::logging::XLogFormatter; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::logging::PlainTextFormatter; + + namespace LogLevel = ::com::sun::star::logging::LogLevel; + + LogHandlerHelper::LogHandlerHelper( const Reference< XComponentContext >& _rxContext, ::osl::Mutex& _rMutex, ::cppu::OBroadcastHelper& _rBHelper ) + :m_eEncoding( RTL_TEXTENCODING_UTF8 ) + ,m_nLevel( LogLevel::SEVERE ) + ,m_xContext( _rxContext ) + ,m_rMutex( _rMutex ) + ,m_rBHelper( _rBHelper ) + ,m_bInitialized( false ) + { + } + + + void LogHandlerHelper::initFromSettings( const ::comphelper::NamedValueCollection& _rSettings ) + { + OUString sEncoding; + if ( _rSettings.get_ensureType( "Encoding", sEncoding ) ) + { + if ( !setEncoding( sEncoding ) ) + throw IllegalArgumentException(); + } + + _rSettings.get_ensureType( "Formatter", m_xFormatter ); + _rSettings.get_ensureType( "Level", m_nLevel ); + } + + + void LogHandlerHelper::enterMethod() + { + m_rMutex.acquire(); + + if ( !m_bInitialized ) + throw DisposedException("component not initialized" ); + + if ( m_rBHelper.bDisposed ) + throw DisposedException("component already disposed" ); + + // fallback settings, in case they weren't passed at construction time + if ( !getFormatter().is() ) + { + try + { + Reference< XLogFormatter > xFormatter( PlainTextFormatter::create( m_xContext ), css::uno::UNO_SET_THROW ); + setFormatter( xFormatter ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + } + } + + + bool LogHandlerHelper::getEncoding( OUString& _out_rEncoding ) const + { + const char* pMimeCharset = rtl_getMimeCharsetFromTextEncoding( m_eEncoding ); + if ( pMimeCharset ) + { + _out_rEncoding = OUString::createFromAscii( pMimeCharset ); + return true; + } + _out_rEncoding.clear(); + return false; + } + + + bool LogHandlerHelper::setEncoding( std::u16string_view _rEncoding ) + { + OString sAsciiEncoding( OUStringToOString( _rEncoding, RTL_TEXTENCODING_ASCII_US ) ); + rtl_TextEncoding eEncoding = rtl_getTextEncodingFromMimeCharset( sAsciiEncoding.getStr() ); + if ( eEncoding != RTL_TEXTENCODING_DONTKNOW ) + { + m_eEncoding = eEncoding; + return true; + } + return false; + } + + + bool LogHandlerHelper::formatForPublishing( const LogRecord& _rRecord, OString& _out_rEntry ) const + { + if ( _rRecord.Level < getLevel() ) + // not to be published due to low level + return false; + + try + { + Reference< XLogFormatter > xFormatter( getFormatter(), css::uno::UNO_SET_THROW ); + OUString sEntry( xFormatter->format( _rRecord ) ); + _out_rEntry = OUStringToOString( sEntry, getTextEncoding() ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + return false; + } + + + bool LogHandlerHelper::getEncodedHead( OString& _out_rHead ) const + { + try + { + Reference< XLogFormatter > xFormatter( getFormatter(), css::uno::UNO_SET_THROW ); + OUString sHead( xFormatter->getHead() ); + _out_rHead = OUStringToOString( sHead, getTextEncoding() ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + return false; + } + + + bool LogHandlerHelper::getEncodedTail( OString& _out_rTail ) const + { + try + { + Reference< XLogFormatter > xFormatter( getFormatter(), css::uno::UNO_SET_THROW ); + OUString sTail( xFormatter->getTail() ); + _out_rTail = OUStringToOString( sTail, getTextEncoding() ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.logging"); + } + return false; + } + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/loghandler.hxx b/extensions/source/logging/loghandler.hxx new file mode 100644 index 000000000..02f4fb773 --- /dev/null +++ b/extensions/source/logging/loghandler.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 . + */ + +#pragma once + +#include + +#include + +#include +#include +#include + +#include +#include +#include + + +namespace logging +{ + + class LogHandlerHelper + { + private: + // + rtl_TextEncoding m_eEncoding; + sal_Int32 m_nLevel; + css::uno::Reference< css::logging::XLogFormatter > + m_xFormatter; + // + + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + ::osl::Mutex& m_rMutex; + ::cppu::OBroadcastHelper& m_rBHelper; + bool m_bInitialized; + + public: + LogHandlerHelper( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + ::osl::Mutex& _rMutex, + ::cppu::OBroadcastHelper& _rBHelper + ); + + public: + void setIsInitialized() { m_bInitialized = true; } + + bool getEncoding( OUString& _out_rEncoding ) const; + bool setEncoding( std::u16string_view _rEncoding ); + + rtl_TextEncoding + getTextEncoding() const { return m_eEncoding; } + + const css::uno::Reference< css::logging::XLogFormatter >& + getFormatter() const { return m_xFormatter; } + void + setFormatter( const css::uno::Reference< css::logging::XLogFormatter >& _rxFormatter ) + { + m_xFormatter = _rxFormatter; + } + + sal_Int32 + getLevel() const { return m_nLevel; } + void + setLevel( const sal_Int32 _nLevel ) + { + m_nLevel = _nLevel; + } + + /** prepares implementation of a public accessible method of a log handler + + enterMethod does the following things: +
  • It acquires the mutex given in the constructor.
  • +
  • It checks whether the component is already initialized, and throws an exception if not os.
  • +
  • It checks whether the component is already disposed, and throws an exception if not os.
  • +
  • It creates a default formatter (PlainTextFormatter), if no formatter exists at this time.
  • +
+ */ + void enterMethod(); + + /** formats a record for publishing it + + The method first checks whether the records log level is greater or equal our own + log level. If not, is returned. + + Second, our formatter is used to create a unicode string from the log record. If an error occurs + during this, e.g. if the formatter is or throws an exception during formatting, + is returned. + + Finally, the unicode string is encoded into a byte string, using our encoding setting. Then, + is returned. + */ + bool formatForPublishing( const css::logging::LogRecord& _rRecord, OString& _out_rEntry ) const; + + /** retrieves our formatter's heading, encoded with our encoding + + @return in case of success, if any error occurred + */ + bool getEncodedHead( OString& _out_rHead ) const; + + /** retrieves our formatter's tail, encoded with our encoding + + @return in case of success, if any error occurred + */ + bool getEncodedTail( OString& _out_rTail ) const; + + /** initializes the instance from a collection of named settings + + The recognized named settings are Encoding, Formatter, and Level, + which initialize the respective attributes. + + Settings which are recognized are remove from the given collection. This allows + the caller to determine whether or not the collection contained any unsupported + items, and react appropriately. + + @throws IllegalArgumentException + if one of the values in the collection is of wrong type. + */ + void initFromSettings( const ::comphelper::NamedValueCollection& _rSettings ); + }; + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/logrecord.cxx b/extensions/source/logging/logrecord.cxx new file mode 100644 index 000000000..26f59e841 --- /dev/null +++ b/extensions/source/logging/logrecord.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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "logrecord.hxx" + +#include +#include +#include +#include + + +namespace logging +{ + + + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::util::DateTime; + + namespace + { + /** returns a string representation of the current thread + + @todo + We need a way to retrieve the current UNO thread ID as string, + which is issue #i77342# + */ + OUString getCurrentThreadID() + { + oslThreadIdentifier nThreadID( osl::Thread::getCurrentIdentifier() ); + return OUString::number( static_cast(nThreadID) ); + } + } + + + LogRecord createLogRecord( const OUString& _rLoggerName, const OUString& _rClassName, + const OUString& _rMethodName, const OUString& _rMessage, + sal_Int32 _nLogLevel, oslInterlockedCount _nEventNumber ) + { + TimeValue aTimeValue; + osl_getSystemTime( &aTimeValue ); + + oslDateTime aDateTime; + OSL_VERIFY( osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime ) ); + + DateTime aTimeStamp; + aTimeStamp.Year = aDateTime.Year; + aTimeStamp.Month = aDateTime.Month; + aTimeStamp.Day = aDateTime.Day; + aTimeStamp.Hours = aDateTime.Hours; + aTimeStamp.Minutes = aDateTime.Minutes; + aTimeStamp.Seconds = aDateTime.Seconds; + aTimeStamp.NanoSeconds = aDateTime.NanoSeconds; + + return LogRecord( + _rLoggerName, + _rClassName, + _rMethodName, + _rMessage, + aTimeStamp, + _nEventNumber, + getCurrentThreadID(), + _nLogLevel + ); + } + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/logrecord.hxx b/extensions/source/logging/logrecord.hxx new file mode 100644 index 000000000..ad6e350cf --- /dev/null +++ b/extensions/source/logging/logrecord.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + + +namespace logging +{ + + css::logging::LogRecord createLogRecord( + const OUString& _rLoggerName, + const OUString& _rClassName, + const OUString& _rMethodName, + const OUString& _rMessage, + sal_Int32 _nLogLevel, + oslInterlockedCount _nEventNumber + ); + + inline css::logging::LogRecord createLogRecord( + const OUString& _rLoggerName, + const OUString& _rMessage, + sal_Int32 _nLogLevel, + oslInterlockedCount _nEventNumber + ) + { + return createLogRecord( _rLoggerName, OUString(), OUString(), _rMessage, _nLogLevel, _nEventNumber ); + } + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/methodguard.hxx b/extensions/source/logging/methodguard.hxx new file mode 100644 index 000000000..189462eae --- /dev/null +++ b/extensions/source/logging/methodguard.hxx @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + + +namespace logging +{ + template < class COMPONENT > + class ComponentMethodGuard + { + private: + COMPONENT& m_rHandler; + + public: + class Access + { + private: + friend class ComponentMethodGuard; + Access() { } + }; + + public: + explicit ComponentMethodGuard( COMPONENT& _rHandler ) + :m_rHandler( _rHandler ) + { + m_rHandler.enterMethod( Access() ); + } + ~ComponentMethodGuard() + { + m_rHandler.leaveMethod( Access() ); + } + }; + + +} // namespace logging + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/plaintextformatter.cxx b/extensions/source/logging/plaintextformatter.cxx new file mode 100644 index 000000000..23392b61c --- /dev/null +++ b/extensions/source/logging/plaintextformatter.cxx @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace logging +{ + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::logging::LogRecord; + using ::com::sun::star::uno::XInterface; + + namespace { + + class PlainTextFormatter : public cppu::WeakImplHelper + { + public: + PlainTextFormatter(); + + private: + // XLogFormatter + virtual OUString SAL_CALL getHead( ) override; + virtual OUString SAL_CALL format( const LogRecord& Record ) override; + virtual OUString SAL_CALL getTail( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& _rServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + }; + + } + + PlainTextFormatter::PlainTextFormatter() + { + } + + OUString SAL_CALL PlainTextFormatter::getHead( ) + { + return + " event no" // column 1: the event number + " " + "thread " // column 2: the thread ID + " " + "date " // column 3: date + " " + "time " // column 4: time + " " + "(class/method:) message" // column 5: class/method/message + "\n"; + } + + + OUString SAL_CALL PlainTextFormatter::format( const LogRecord& _rRecord ) + { + char buffer[ sizeof("-32768-65535-65535 65535:65535:65535.4294967295") ]; + // reserve enough space for hypothetical max length + const int buffer_size = sizeof( buffer ); + int used = snprintf( buffer, buffer_size, "%10i", static_cast(_rRecord.SequenceNumber) ); + if ( used >= buffer_size || used < 0 ) + buffer[ buffer_size - 1 ] = 0; + + OUStringBuffer aLogEntry; + aLogEntry.appendAscii( buffer ); + aLogEntry.append( " " ); + + OString sThreadID( OUStringToOString( _rRecord.ThreadID, osl_getThreadTextEncoding() ) ); + snprintf( buffer, buffer_size, "%8s", sThreadID.getStr() ); + aLogEntry.appendAscii( buffer ); + aLogEntry.append( " " ); + + snprintf( buffer, buffer_size, "%04" SAL_PRIdINT32 "-%02" SAL_PRIuUINT32 "-%02" SAL_PRIuUINT32 " %02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ":%02" SAL_PRIuUINT32 ".%09" SAL_PRIuUINT32, + static_cast(_rRecord.LogTime.Year), static_cast(_rRecord.LogTime.Month), static_cast(_rRecord.LogTime.Day), + static_cast(_rRecord.LogTime.Hours), static_cast(_rRecord.LogTime.Minutes), static_cast(_rRecord.LogTime.Seconds), _rRecord.LogTime.NanoSeconds ); + aLogEntry.appendAscii( buffer ); + aLogEntry.append( " " ); + + if ( !(_rRecord.SourceClassName.isEmpty() || _rRecord.SourceMethodName.isEmpty()) ) + { + aLogEntry.append( _rRecord.SourceClassName ); + aLogEntry.append( "::" ); + aLogEntry.append( _rRecord.SourceMethodName ); + aLogEntry.append( ": " ); + } + + aLogEntry.append( _rRecord.Message ); + aLogEntry.append( "\n" ); + + return aLogEntry.makeStringAndClear(); + } + + + OUString SAL_CALL PlainTextFormatter::getTail( ) + { + // no tail + return OUString(); + } + + sal_Bool SAL_CALL PlainTextFormatter::supportsService( const OUString& _rServiceName ) + { + return cppu::supportsService(this, _rServiceName); + } + + + OUString SAL_CALL PlainTextFormatter::getImplementationName() + { + return "com.sun.star.comp.extensions.PlainTextFormatter"; + } + + Sequence< OUString > SAL_CALL PlainTextFormatter::getSupportedServiceNames() + { + return { "com.sun.star.logging.PlainTextFormatter" }; + } + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_extensions_PlainTextFormatter( + css::uno::XComponentContext *, + css::uno::Sequence const &) +{ + return cppu::acquire(new logging::PlainTextFormatter()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/logging/simpletextformatter.cxx b/extensions/source/logging/simpletextformatter.cxx new file mode 100644 index 000000000..b54fea5a6 --- /dev/null +++ b/extensions/source/logging/simpletextformatter.cxx @@ -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 . + */ + +#include + +#include +#include +#include +#include + +#include +#include + +namespace logging +{ +using css::logging::LogRecord; +using namespace css::uno; + +namespace +{ +class SimpleTextFormatter + : public cppu::WeakImplHelper +{ +public: + SimpleTextFormatter(); + +private: + // XLogFormatter + virtual OUString SAL_CALL getHead() override; + virtual OUString SAL_CALL format(const LogRecord& Record) override; + virtual OUString SAL_CALL getTail() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& _rServiceName) override; + virtual Sequence SAL_CALL getSupportedServiceNames() override; +}; +} + +SimpleTextFormatter::SimpleTextFormatter() {} + +OUString SAL_CALL SimpleTextFormatter::getHead() { return OUString(); } + +OUString SAL_CALL SimpleTextFormatter::format(const LogRecord& _rRecord) +{ + OUString aLogEntry; + // Highlight warnings + if (_rRecord.Level == css::logging::LogLevel::SEVERE) + aLogEntry = "ERROR: "; + else if (_rRecord.Level == css::logging::LogLevel::WARNING) + aLogEntry = "WARNING: "; + + return aLogEntry + _rRecord.Message + "\n"; +} + +OUString SAL_CALL SimpleTextFormatter::getTail() { return OUString(); } + +sal_Bool SAL_CALL SimpleTextFormatter::supportsService(const OUString& _rServiceName) +{ + return cppu::supportsService(this, _rServiceName); +} + +OUString SAL_CALL SimpleTextFormatter::getImplementationName() +{ + return "com.sun.star.comp.extensions.SimpleTextFormatter"; +} + +Sequence SAL_CALL SimpleTextFormatter::getSupportedServiceNames() +{ + return { "com.sun.star.logging.SimpleTextFormatter" }; +} + +} // namespace logging + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_extensions_SimpleTextFormatter(css::uno::XComponentContext*, + css::uno::Sequence const&) +{ + return cppu::acquire(new logging::SimpleTextFormatter()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/GetMetadataForFile.h b/extensions/source/macosx/spotlight/GetMetadataForFile.h new file mode 100644 index 000000000..51086827e --- /dev/null +++ b/extensions/source/macosx/spotlight/GetMetadataForFile.h @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +Boolean GetMetadataForFile( + void * thisInterface, CFMutableDictionaryRef attributes, + CFStringRef contentTypeUTI, CFStringRef pathToFile); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/GetMetadataForFile.m b/extensions/source/macosx/spotlight/GetMetadataForFile.m new file mode 100644 index 000000000..a1dcdbe61 --- /dev/null +++ b/extensions/source/macosx/spotlight/GetMetadataForFile.m @@ -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 . + */ + +#include +#include +#include + +#include "GetMetadataForFile.h" +#import "OOoSpotlightImporter.h" + +/* ----------------------------------------------------------------------------- + Get metadata attributes from file + + This function's job is to extract useful information your file format supports + and return it as a dictionary + ----------------------------------------------------------------------------- */ + +Boolean GetMetadataForFile(void* thisInterface, + CFMutableDictionaryRef attributes, + CFStringRef contentTypeUTI, + CFStringRef pathToFile) +{ + (void) thisInterface; /* unused */ + /* Pull any available metadata from the file at the specified path */ + /* Return the attribute keys and attribute values in the dict */ + /* Return TRUE if successful, FALSE if there was no data provided */ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + OOoSpotlightImporter *importer = [OOoSpotlightImporter new]; + + Boolean importOK = NO; + @try { + importOK = [importer importDocument:(NSString*)pathToFile + contentType:(NSString*)contentTypeUTI + attributes:(NSMutableDictionary*)attributes]; + } + @catch (NSException *exception) { + NSLog(@"main: Caught %@: %@", [exception name], [exception reason]); + } + + [importer release]; + + [pool release]; + + return importOK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/OOoContentDataParser.h b/extensions/source/macosx/spotlight/OOoContentDataParser.h new file mode 100644 index 000000000..dc07a3166 --- /dev/null +++ b/extensions/source/macosx/spotlight/OOoContentDataParser.h @@ -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 . + */ + +#import + +@interface OOoContentDataParser : NSObject { + // indicates if we are interested in an element's content + BOOL shouldReadCharacters; + + // the MD importer's values + NSMutableDictionary *mdiValues; + + // all of the text inside a document + NSMutableString *textContent; + + // the current element's content + NSMutableString *runningTextContent; +} + +- (void)parseXML:(NSData*)data intoDictionary:(NSMutableDictionary*)dict; + +// delegates +- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict; + +- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName; + +- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string; + +- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError; + +- (void)parserDidEndDocument:(NSXMLParser *)parser; + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/OOoContentDataParser.m b/extensions/source/macosx/spotlight/OOoContentDataParser.m new file mode 100644 index 000000000..e1f51e5b9 --- /dev/null +++ b/extensions/source/macosx/spotlight/OOoContentDataParser.m @@ -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 + +#import "OOoContentDataParser.h" + +@implementation OOoContentDataParser + +- (id)init +{ + if ((self = [super init]) != nil) { + shouldReadCharacters = NO; + textContent = nil; + runningTextContent = nil; + + return self; + } + + return nil; +} + +- (void)parseXML:(NSData*)data intoDictionary:(NSMutableDictionary*)dict +{ + mdiValues = dict; + + //NSLog(@"data: %@ %d", data, [data length]); + + //init parser settings + shouldReadCharacters = NO; + + NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; + + [parser setDelegate:self]; + + [parser setShouldResolveExternalEntities:NO]; + [parser parse]; + + [parser release]; + + //NSLog(@"finished"); +} + +- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict +{ + (void) parser; // unused + (void) namespaceURI; // FIXME this should not be ignored but should be used + // instead of text: prefix in the comparison below! + (void) qualifiedName; // unused + (void) attributeDict; // unused + // all text content is stored inside elements + if ([elementName isEqualToString:@"text:p"] == YES) { + runningTextContent = [NSMutableString new]; + shouldReadCharacters = YES; + //NSLog(@"start"); + } else { + return; + } + + //NSLog(@"start element %@", elementName); +} + +- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName +{ + (void) parser; // unused + (void) elementName; // unused + (void) namespaceURI; // unused + (void) qName; // unused + if (shouldReadCharacters == TRUE) { + if (textContent == nil) { + textContent = [NSMutableString new]; + } else if ([runningTextContent isEqualToString:@""] == NO) { + // separate by whitespace + [textContent appendString:@" "]; + } + //NSLog(@"end"); + + [textContent appendString:[NSString stringWithString:runningTextContent]]; + [runningTextContent release]; + runningTextContent = nil; + } + shouldReadCharacters = NO; +} + +- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string +{ + (void) parser; // unused + if (shouldReadCharacters == NO) { + return; + } + //NSLog(string); + + [runningTextContent appendString:string]; + + //NSLog(@"read: %@", string); + +} + +- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError +{ + //NSLog(@"parsing finished with error"); + NSLog(@"An error occurred parsing the document. (Error %li, Description: %@, Line: %li, Column: %li)", (long) [parseError code], + [[parser parserError] localizedDescription], (long) [parser lineNumber], + (long) [parser columnNumber]); + + if (runningTextContent != nil) { + [runningTextContent release]; + runningTextContent = nil; + } + if (textContent != nil) { + [textContent release]; + textContent = nil; + } +} + +- (void)parserDidEndDocument:(NSXMLParser *)parser +{ + (void) parser; // unused + if (textContent != nil && [textContent length] > 0) { + [mdiValues setObject:[NSString stringWithString:textContent] forKey:(NSString*)kMDItemTextContent]; + [textContent release]; + textContent = nil; + } +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/OOoMetaDataParser.h b/extensions/source/macosx/spotlight/OOoMetaDataParser.h new file mode 100644 index 000000000..85d48b173 --- /dev/null +++ b/extensions/source/macosx/spotlight/OOoMetaDataParser.h @@ -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 . + */ + +#import + + +@interface OOoMetaDataParser : NSObject { + //indicates if content should be read + BOOL shouldReadCharacters; + //indicates if the current element is a custom metadata tag + BOOL isCustom; + + NSMutableDictionary *metaValues; + NSMutableString *textCurrentElement; + NSString *customAttribute; +} + +- (void)parseXML:(NSData*)data intoDictionary:(NSMutableDictionary*)dict; + +//delegates +- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict; + +- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName; + +- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string; + +- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError; +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/OOoMetaDataParser.m b/extensions/source/macosx/spotlight/OOoMetaDataParser.m new file mode 100644 index 000000000..1e7cac685 --- /dev/null +++ b/extensions/source/macosx/spotlight/OOoMetaDataParser.m @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#import "OOoMetaDataParser.h" + +static NSSet *singleValueXMLElements; +static NSSet *multiValueXMLElements; +static NSDictionary *metaXML2MDIKeys; + +@implementation OOoMetaDataParser + ++ (void)initialize +{ + static BOOL isInitialized = NO; + + if (isInitialized == NO) { + //set up the meta elements with only one value + NSMutableSet *temp = [NSMutableSet new]; +//FIXME these should use namespace URIs and not prefixes + [temp addObject:@"dc:title"]; + [temp addObject:@"dc:description"]; + [temp addObject:@"meta:user-defined"]; + singleValueXMLElements = [[NSSet setWithSet:temp] retain]; + + //set up the meta elements that can have more than one value + [temp removeAllObjects]; + [temp addObject:@"dc:subject"]; + [temp addObject:@"meta:keyword"]; + [temp addObject:@"meta:initial-creator"]; + [temp addObject:@"dc:creator"]; + multiValueXMLElements = [[NSSet setWithSet:temp] retain]; + [temp release]; + + //set up the map to store the values with the correct MDI keys + NSMutableDictionary *tempDict = [NSMutableDictionary new]; + [tempDict setObject:(NSString*)kMDItemTitle forKey:@"dc:title"]; + [tempDict setObject:(NSString*)kMDItemDescription forKey:@"dc:description"]; + [tempDict setObject:(NSString*)kMDItemKeywords forKey:@"dc:subject"]; + [tempDict setObject:(NSString*)kMDItemAuthors forKey:@"meta:initial-creator"]; + [tempDict setObject:(NSString*)kMDItemAuthors forKey:@"dc:creator"]; + [tempDict setObject:(NSString*)kMDItemKeywords forKey:@"meta:keyword"]; + [tempDict setObject:@"org_openoffice_opendocument_custominfo1" forKey:@"Info 1"]; + [tempDict setObject:@"org_openoffice_opendocument_custominfo2" forKey:@"Info 2"]; + [tempDict setObject:@"org_openoffice_opendocument_custominfo3" forKey:@"Info 3"]; + [tempDict setObject:@"org_openoffice_opendocument_custominfo4" forKey:@"Info 4"]; + metaXML2MDIKeys = [[NSDictionary dictionaryWithDictionary:tempDict] retain]; + [tempDict release]; + + isInitialized = YES; + } +} + +- (id)init +{ + if ((self = [super init]) != nil) { + shouldReadCharacters = NO; + textCurrentElement = nil; + + return self; + } + + return nil; +} + +- (void)parseXML:(NSData*)data intoDictionary:(NSMutableDictionary*)dict +{ + metaValues = dict; + + //NSLog(@"data: %@ %d", data, [data length]); + + //init parser settings + shouldReadCharacters = NO; + + NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; + + [parser setDelegate:self]; + + [parser setShouldResolveExternalEntities:NO]; + [parser parse]; + + [parser release]; + + //NSLog(@"finished parsing meta"); +} + +- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict +{ + (void) parser; // unused + (void) namespaceURI; // FIXME this should not be ignored but should be used + // instead of meta: prefix in the comparison below! + (void) qualifiedName; // unused +// NSLog(@"<%@>", elementName); + if ([singleValueXMLElements containsObject:elementName] == YES) { + shouldReadCharacters = YES; + } else if ([multiValueXMLElements containsObject:elementName] == YES) { + shouldReadCharacters = YES; + } else { + //we are not interested in this element + shouldReadCharacters = NO; + return; + } + + if (shouldReadCharacters == YES) { + textCurrentElement = [NSMutableString new]; + isCustom = [elementName isEqualToString:@"meta:user-defined"]; + if (isCustom == YES) { + customAttribute = [[attributeDict objectForKey:@"meta:name"] retain]; + //NSLog(customAttribute); + } + } + + //NSLog(@"start element %@", elementName); +} + +- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName +{ + (void) parser; // unused + (void) namespaceURI; // unused + (void) qName; // unused +// NSLog(@"", elementName); + if (shouldReadCharacters == YES) { + NSString *mdiName = nil; + if (isCustom == YES) { + mdiName = (NSString*)[metaXML2MDIKeys objectForKey:customAttribute]; + } else { + mdiName = (NSString*)[metaXML2MDIKeys objectForKey:elementName]; + } + //NSLog(@"mdiName: %@", mdiName); + + if (mdiName == nil) { + return; + } + + if ([singleValueXMLElements containsObject:elementName] == YES) { + [metaValues setObject:textCurrentElement forKey:mdiName]; + } else { + // must be multi-value + NSMutableArray *arr = [metaValues objectForKey:mdiName]; + if (arr == nil) { + // we have no array yet, create it + arr = [[NSMutableArray new] autorelease]; + // and store it + [metaValues setObject:arr forKey:mdiName]; + } + // only store an element once, no need for duplicates + if ([arr containsObject:textCurrentElement] == NO) { + [arr addObject:textCurrentElement]; + } + } + // cleanup part 1 + [textCurrentElement release]; + if (isCustom == YES) { + [customAttribute release]; + } + } + + //cleanup part 2 + shouldReadCharacters = NO; + isCustom = NO; +} + +- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string +{ + (void) parser; // unused +// NSLog(@"%@", string); + if (shouldReadCharacters == NO) { + return; + } + + // this delegate method might be called several times for a single element, + // so we have to collect the received data + [textCurrentElement appendString:string]; + + //NSLog(@"chars read: %@", string); +} + +- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError +{ + //NSLog(@"parsing finished with error"); + NSLog(@"Error %li, Description: %@, Line: %li, Column: %li", (long) [parseError code], + [[parser parserError] localizedDescription], (long) [parser lineNumber], + (long) [parser columnNumber]); +} + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/OOoSpotlightImporter.h b/extensions/source/macosx/spotlight/OOoSpotlightImporter.h new file mode 100644 index 000000000..947f8dbf1 --- /dev/null +++ b/extensions/source/macosx/spotlight/OOoSpotlightImporter.h @@ -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 . + */ + +#import + +@interface OOoSpotlightImporter : NSObject +{ +} + +- (BOOL)importDocument:(NSString*)pathToFile + contentType:(NSString*)contentTypeUTI + attributes:(NSMutableDictionary*)attributes; + +- (NSFileHandle*)openZipFileAtPath:(NSString*)pathToFile; + +- (NSData*)metaDataFileFromZip:(NSFileHandle*)unzipFile; + +- (NSData*)contentDataFileFromZip:(NSFileHandle*)unzipFile; +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/OOoSpotlightImporter.m b/extensions/source/macosx/spotlight/OOoSpotlightImporter.m new file mode 100644 index 000000000..a144fe259 --- /dev/null +++ b/extensions/source/macosx/spotlight/OOoSpotlightImporter.m @@ -0,0 +1,487 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#import + +#import "OOoSpotlightImporter.h" +#import "OOoMetaDataParser.h" +#import "OOoContentDataParser.h" + +/* a dictionary to hold the UTIs */ +static NSDictionary *uti2kind; + +typedef struct { + unsigned short min_version; + unsigned short general_flag; + unsigned short compression; + unsigned short lastmod_time; + unsigned short lastmod_date; + unsigned crc32; + unsigned compressed_size; + unsigned uncompressed_size; + unsigned short filename_size; + unsigned short extra_field_size; + NSString *filename; + NSString *extra_field; +} LocalFileHeader; + +typedef struct { + unsigned short creator_version; + unsigned short min_version; + unsigned short general_flag; + unsigned short compression; + unsigned short lastmod_time; + unsigned short lastmod_date; + unsigned crc32; + unsigned compressed_size; + unsigned uncompressed_size; + unsigned short filename_size; + unsigned short extra_field_size; + unsigned short file_comment_size; + unsigned short disk_num; + unsigned short internal_attr; + unsigned external_attr; + unsigned offset; + NSString *filename; + NSString *extra_field; + NSString *file_comment; +} CentralDirectoryEntry; + +typedef struct { + unsigned short disk_num; + unsigned short cdir_disk; + unsigned short disk_entries; + unsigned short cdir_entries; + unsigned cdir_size; + unsigned cdir_offset; + unsigned short comment_size; + NSString *comment; +} CentralDirectoryEnd; + +#define CDIR_ENTRY_SIG (0x02014b50) +#define LOC_FILE_HEADER_SIG (0x04034b50) +#define CDIR_END_SIG (0x06054b50) + +static unsigned char readByte(NSFileHandle *file) +{ + if (file == nil) + return 0; + NSData* tmpBuf = [file readDataOfLength: 1]; + if (tmpBuf == nil) + return 0; + unsigned char *d = (unsigned char*)[tmpBuf bytes]; + if (d == nil) + return 0; + return *d; +} + +static unsigned short readShort(NSFileHandle *file) +{ + unsigned short p0 = (unsigned short)readByte(file); + unsigned short p1 = (unsigned short)readByte(file); + return (unsigned short)(p0|(p1<<8)); +} + +static unsigned readInt(NSFileHandle *file) +{ + unsigned p0 = (unsigned)readByte(file); + unsigned p1 = (unsigned)readByte(file); + unsigned p2 = (unsigned)readByte(file); + unsigned p3 = (unsigned)readByte(file); + return (unsigned)(p0|(p1<<8)|(p2<<16)|(p3<<24)); +} + +static bool readCentralDirectoryEnd(NSFileHandle *file, CentralDirectoryEnd *end) +{ + unsigned signature = readInt(file); + if (signature != CDIR_END_SIG) + return false; + + end->disk_num = readShort(file); + end->cdir_disk = readShort(file); + end->disk_entries = readShort(file); + end->cdir_entries = readShort(file); + end->cdir_size = readInt(file); + end->cdir_offset = readInt(file); + end->comment_size = readShort(file); + NSData *data = [file readDataOfLength: end->comment_size]; + end->comment = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return true; +} + +static bool readCentralDirectoryEntry(NSFileHandle *file, CentralDirectoryEntry *entry) +{ + unsigned signature = readInt(file); + if (signature != CDIR_ENTRY_SIG) + return false; + + entry->creator_version = readShort(file); + entry->min_version = readShort(file); + entry->general_flag = readShort(file); + entry->compression = readShort(file); + entry->lastmod_time = readShort(file); + entry->lastmod_date = readShort(file); + entry->crc32 = readInt(file); + entry->compressed_size = readInt(file); + entry->uncompressed_size = readInt(file); + entry->filename_size = readShort(file); + entry->extra_field_size = readShort(file); + entry->file_comment_size = readShort(file); + entry->disk_num = readShort(file); + entry->internal_attr = readShort(file); + entry->external_attr = readInt(file); + entry->offset = readInt(file); + NSData *data = [file readDataOfLength: entry->filename_size]; + entry->filename = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + data = [file readDataOfLength: entry->extra_field_size]; + entry->extra_field = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + data = [file readDataOfLength: entry->file_comment_size]; + entry->file_comment = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return true; +} + +static bool readLocalFileHeader(NSFileHandle *file, LocalFileHeader *header) +{ + unsigned signature = readInt(file); + if (signature != LOC_FILE_HEADER_SIG) + return false; + + header->min_version = readShort(file); + header->general_flag = readShort(file); + header->compression = readShort(file); + header->lastmod_time = readShort(file); + header->lastmod_date = readShort(file); + header->crc32 = readInt(file); + header->compressed_size = readInt(file); + header->uncompressed_size = readInt(file); + header->filename_size = readShort(file); + header->extra_field_size = readShort(file); + NSData *data = [file readDataOfLength: header->filename_size]; + header->filename = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + data = [file readDataOfLength: header->extra_field_size]; + header->extra_field = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return true; +} + +static bool areHeadersConsistent(const LocalFileHeader *header, const CentralDirectoryEntry *entry) +{ + if (header->min_version != entry->min_version) + return false; + if (header->general_flag != entry->general_flag) + return false; + if (header->compression != entry->compression) + return false; + if (!(header->general_flag & 0x08)) + { + if (header->crc32 != entry->crc32) + return false; + if (header->compressed_size != entry->compressed_size) + return false; + if (header->uncompressed_size != entry->uncompressed_size) + return false; + } + return true; +} + +static bool findCentralDirectoryEnd(NSFileHandle *file) +{ + // Assume the cdir end is in the last 1024 bytes + // Scan backward from end of file for the end signature + + [file seekToEndOfFile]; + unsigned long long fileLength = [file offsetInFile]; + + if (fileLength < 10) + return false; + + [file seekToFileOffset: (fileLength - 4)]; + + unsigned long long limit; + if (fileLength > 1024) + limit = fileLength - 1024; + else + limit = 0; + + unsigned long long offset; + while ((offset = [file offsetInFile]) > limit) + { + unsigned signature = readInt(file); + if (signature == CDIR_END_SIG) + { + // Seek back over the CDIR_END_SIG + [file seekToFileOffset: offset]; + return true; + } + else + { + // Seek one byte back + [file seekToFileOffset: (offset - 1)]; + } + } + return false; +} + +static bool isZipFile(NSFileHandle *file) +{ + if (!findCentralDirectoryEnd(file)) + return false; + CentralDirectoryEnd end; + if (!readCentralDirectoryEnd(file, &end)) + return false; + [file seekToFileOffset: end.cdir_offset]; + CentralDirectoryEntry entry; + if (!readCentralDirectoryEntry(file, &entry)) + return false; + [file seekToFileOffset: entry.offset]; + LocalFileHeader header; + if (!readLocalFileHeader(file, &header)) + return false; + if (!areHeadersConsistent(&header, &entry)) + return false; + return true; +} + +static bool findDataStream(NSFileHandle *file, CentralDirectoryEntry *entry, NSString *name) +{ + [file seekToEndOfFile]; + unsigned long long fileLength = [file offsetInFile]; + if (!findCentralDirectoryEnd(file)) + return false; + CentralDirectoryEnd end; + if (!readCentralDirectoryEnd(file, &end)) + return false; + [file seekToFileOffset: end.cdir_offset]; + do + { + if (!readCentralDirectoryEntry(file, entry)) + return false; + if ([entry->filename compare: name] == NSOrderedSame) + break; + } + while ( [file offsetInFile] < fileLength && [file offsetInFile] < end.cdir_offset + end.cdir_size); + if ([entry->filename compare: name] != NSOrderedSame) + return false; + [file seekToFileOffset: entry->offset]; + LocalFileHeader header; + if (!readLocalFileHeader(file, &header)) + return false; + if (!areHeadersConsistent(&header, entry)) + return false; + return true; +} + +static NSData *getUncompressedData(NSFileHandle *file, NSString *name) +{ + CentralDirectoryEntry entry; + if (!findDataStream(file, &entry, name)) + return nil; + if (!entry.compression) + return [file readDataOfLength: entry.compressed_size]; + else + { + int ret; + z_stream strm; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm,-MAX_WBITS); + if (ret != Z_OK) + return nil; + + NSData *compressedData = [file readDataOfLength: entry.compressed_size]; + + strm.avail_in = [compressedData length]; + strm.next_in = (Bytef *)[compressedData bytes]; + + Bytef *uncompressedData = (Bytef *)malloc(entry.uncompressed_size); + if (!uncompressedData) + { + (void)inflateEnd(&strm); + return nil; + } + strm.avail_out = entry.uncompressed_size; + strm.next_out = uncompressedData; + ret = inflate(&strm, Z_FINISH); + switch (ret) + { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + free(uncompressedData); + return nil; + } + (void)inflateEnd(&strm); + NSData *returnBuffer = [NSData dataWithBytes:(const void *)uncompressedData length:entry.uncompressed_size]; + free(uncompressedData); + return returnBuffer; + } +} + +@implementation OOoSpotlightImporter + +/* initialize is only called once the first time this class is loaded */ ++ (void)initialize +{ + static BOOL isInitialized = NO; + if (isInitialized == NO) { + NSMutableDictionary *temp = [NSMutableDictionary new]; + [temp setObject:@"OpenOffice.org 1.0 Text" forKey:@"org.openoffice.text"]; + [temp setObject:@"OpenDocument Text" forKey:@"org.oasis.opendocument.text"]; + [temp setObject:@"OpenOffice.org 1.0 Spreadsheet" forKey:@"org.openoffice.spreadsheet"]; + [temp setObject:@"OpenDocument Spreadsheet" forKey:@"org.oasis.opendocument.spreadsheet"]; + [temp setObject:@"OpenOffice.org 1.0 Presentation" forKey:@"org.openoffice.presentation"]; + [temp setObject:@"OpenDocument Presentation" forKey:@"org.oasis.opendocument.presentation"]; + [temp setObject:@"OpenOffice.org 1.0 Drawing" forKey:@"org.openoffice.graphics"]; + [temp setObject:@"OpenDocument Drawing" forKey:@"org.oasis.opendocument.graphics"]; + [temp setObject:@"OpenOffice.org 1.0 Master" forKey:@"org.openoffice.text-master"]; + [temp setObject:@"OpenDocument Master" forKey:@"org.oasis.opendocument.text-master"]; + [temp setObject:@"OpenOffice.org 1.0 Formula" forKey:@"org.openoffice.formula"]; + [temp setObject:@"OpenDocument Formula" forKey:@"org.oasis.opendocument.formula"]; + [temp setObject:@"OpenOffice.org 1.0 Text Template" forKey:@"org.openoffice.text-template"]; + [temp setObject:@"OpenDocument Text Template" forKey:@"org.oasis.opendocument.text-template"]; + [temp setObject:@"OpenOffice.org 1.0 Spreadsheet Template" forKey:@"org.openoffice.spreadsheet-template"]; + [temp setObject:@"OpenDocument Spreadsheet Template" forKey:@"org.oasis.opendocument.spreadsheet-template"]; + [temp setObject:@"OpenOffice.org 1.0 Presentation Template" forKey:@"org.openoffice.presentation-template"]; + [temp setObject:@"OpenDocument Presentation Template" forKey:@"org.oasis.opendocument.presentation-template"]; + [temp setObject:@"OpenOffice.org 1.0 Drawing Template" forKey:@"org.openoffice.graphics-template"]; + [temp setObject:@"OpenDocument Drawing Template" forKey:@"org.oasis.opendocument.graphics-template"]; + [temp setObject:@"OpenOffice.org 1.0 Database" forKey:@"org.openoffice.database"]; + [temp setObject:@"OpenDocument Chart" forKey:@"org.oasis.opendocument.chart"]; + + uti2kind = [[NSDictionary dictionaryWithDictionary:temp] retain]; + [temp release]; + + isInitialized = YES; + } +} + +/* importDocument is the real starting point for our plugin */ +- (BOOL)importDocument:(NSString*)pathToFile contentType:(NSString*)contentTypeUTI attributes:(NSMutableDictionary*)attributes +{ + //NSLog(contentTypeUTI); + //NSLog(pathToFile); + + NSString *itemKind = [uti2kind objectForKey:contentTypeUTI]; + if (itemKind != nil) { + [attributes setObject:itemKind forKey:(NSString*)kMDItemKind]; + } + + //first check to see if this is a valid zipped file that contains a file "meta.xml" + NSFileHandle *unzipFile = [self openZipFileAtPath:pathToFile]; + + + if (unzipFile == nil) { + //NSLog(@"zip file not open"); + return NO; + } + + //first get the metadata + NSData *metaData = [self metaDataFileFromZip:unzipFile]; + if (metaData == nil) { + [unzipFile closeFile]; + return YES; + } + + [metaData retain]; + + OOoMetaDataParser *parser = [OOoMetaDataParser new]; + if (parser != nil) { + //parse and extract the data + [parser parseXML:metaData intoDictionary:attributes]; + } + + [metaData release]; + [parser release]; + + //and now get the content + NSData *contentData = [self contentDataFileFromZip:unzipFile]; + if (contentData == nil) { + [unzipFile closeFile]; + return YES; + } + + [contentData retain]; + + OOoContentDataParser *parser2 = [OOoContentDataParser new]; + if (parser2 != nil) { + //parse and extract the data + [parser2 parseXML:contentData intoDictionary:attributes]; + } + + [contentData release]; + [parser2 release]; + + [unzipFile closeFile]; + + return YES; +} + +/* openZipFileAtPath returns the file as a valid data structure or nil otherwise*/ +- (NSFileHandle*)openZipFileAtPath:(NSString*)pathToFile +{ + NSFileHandle* unzipFile = nil; + + if ([pathToFile length] != 0) + { + unzipFile = [NSFileHandle fileHandleForReadingAtPath: pathToFile]; + } + + if (unzipFile == nil) + { + //NSLog(@"Cannot open %s",zipfilename); + return nil; + } + + if (!isZipFile(unzipFile)) + { + [unzipFile closeFile]; + return nil; + } + //NSLog(@"%s opened",zipfilename); + + return unzipFile; +} + +/* metaDataFileFromZip extracts the file meta.xml from the zip file and returns it as an NSData* structure + or nil if the metadata is not present */ +- (NSData*) metaDataFileFromZip:(NSFileHandle*)unzipFile +{ + if (unzipFile == nil) + return nil; + return getUncompressedData(unzipFile, @"meta.xml"); +} + +/* contentDataFileFromZip extracts the file content.xml from the zip file and returns it as an NSData* structure + or nil if the metadata is not present */ +- (NSData*) contentDataFileFromZip:(NSFileHandle*)unzipFile +{ + if (unzipFile == nil) + return nil; + return getUncompressedData(unzipFile, @"content.xml"); +} + + +@end + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/.gitignore b/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/.gitignore new file mode 100644 index 000000000..96c4e5542 --- /dev/null +++ b/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/.gitignore @@ -0,0 +1 @@ +project.xcworkspace diff --git a/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/project.pbxproj b/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/project.pbxproj new file mode 100644 index 000000000..a577eeb1d --- /dev/null +++ b/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/project.pbxproj @@ -0,0 +1,308 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + BE9A7AC823590D9500931013 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BE9A7AC723590D9500931013 /* main.m */; }; + BE9A7AD723590E5D00931013 /* OOoSpotlightImporter.m in Sources */ = {isa = PBXBuildFile; fileRef = BE9A7ACE23590E5D00931013 /* OOoSpotlightImporter.m */; }; + BE9A7AD823590E5D00931013 /* OOoMetaDataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = BE9A7AD223590E5D00931013 /* OOoMetaDataParser.m */; }; + BE9A7AD923590E5D00931013 /* OOoContentDataParser.m in Sources */ = {isa = PBXBuildFile; fileRef = BE9A7AD323590E5D00931013 /* OOoContentDataParser.m */; }; + BE9A7ADA23590E5D00931013 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BE9A7AD423590E5D00931013 /* main.m */; }; + BE9A7ADB23590E5D00931013 /* GetMetadataForFile.m in Sources */ = {isa = PBXBuildFile; fileRef = BE9A7AD623590E5D00931013 /* GetMetadataForFile.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + BE9A7AC223590D9400931013 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + BE9A7AC423590D9500931013 /* SpotlightImporterTester */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SpotlightImporterTester; sourceTree = BUILT_PRODUCTS_DIR; }; + BE9A7AC723590D9500931013 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + BE9A7ACE23590E5D00931013 /* OOoSpotlightImporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OOoSpotlightImporter.m; path = ../../OOoSpotlightImporter.m; sourceTree = ""; }; + BE9A7ACF23590E5D00931013 /* OOoSpotlightImporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OOoSpotlightImporter.h; path = ../../OOoSpotlightImporter.h; sourceTree = ""; }; + BE9A7AD023590E5D00931013 /* GetMetadataForFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GetMetadataForFile.h; path = ../../GetMetadataForFile.h; sourceTree = ""; }; + BE9A7AD123590E5D00931013 /* OOoMetaDataParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OOoMetaDataParser.h; path = ../../OOoMetaDataParser.h; sourceTree = ""; }; + BE9A7AD223590E5D00931013 /* OOoMetaDataParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OOoMetaDataParser.m; path = ../../OOoMetaDataParser.m; sourceTree = ""; }; + BE9A7AD323590E5D00931013 /* OOoContentDataParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OOoContentDataParser.m; path = ../../OOoContentDataParser.m; sourceTree = ""; }; + BE9A7AD423590E5D00931013 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ../../main.m; sourceTree = ""; }; + BE9A7AD523590E5D00931013 /* OOoContentDataParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OOoContentDataParser.h; path = ../../OOoContentDataParser.h; sourceTree = ""; }; + BE9A7AD623590E5D00931013 /* GetMetadataForFile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GetMetadataForFile.m; path = ../../GetMetadataForFile.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + BE9A7AC123590D9400931013 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + BE9A7ABB23590D9400931013 = { + isa = PBXGroup; + children = ( + BE9A7AC623590D9500931013 /* SpotlightImporterTester */, + BE9A7AC523590D9500931013 /* Products */, + ); + sourceTree = ""; + }; + BE9A7AC523590D9500931013 /* Products */ = { + isa = PBXGroup; + children = ( + BE9A7AC423590D9500931013 /* SpotlightImporterTester */, + ); + name = Products; + sourceTree = ""; + }; + BE9A7AC623590D9500931013 /* SpotlightImporterTester */ = { + isa = PBXGroup; + children = ( + BE9A7AD023590E5D00931013 /* GetMetadataForFile.h */, + BE9A7AD623590E5D00931013 /* GetMetadataForFile.m */, + BE9A7AD423590E5D00931013 /* main.m */, + BE9A7AD523590E5D00931013 /* OOoContentDataParser.h */, + BE9A7AD323590E5D00931013 /* OOoContentDataParser.m */, + BE9A7AD123590E5D00931013 /* OOoMetaDataParser.h */, + BE9A7AD223590E5D00931013 /* OOoMetaDataParser.m */, + BE9A7ACF23590E5D00931013 /* OOoSpotlightImporter.h */, + BE9A7ACE23590E5D00931013 /* OOoSpotlightImporter.m */, + BE9A7AC723590D9500931013 /* main.m */, + ); + path = SpotlightImporterTester; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + BE9A7AC323590D9400931013 /* SpotlightImporterTester */ = { + isa = PBXNativeTarget; + buildConfigurationList = BE9A7ACB23590D9500931013 /* Build configuration list for PBXNativeTarget "SpotlightImporterTester" */; + buildPhases = ( + BE9A7AC023590D9400931013 /* Sources */, + BE9A7AC123590D9400931013 /* Frameworks */, + BE9A7AC223590D9400931013 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SpotlightImporterTester; + productName = SpotlightImporterTester; + productReference = BE9A7AC423590D9500931013 /* SpotlightImporterTester */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + BE9A7ABC23590D9400931013 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1110; + ORGANIZATIONNAME = Collabora; + TargetAttributes = { + BE9A7AC323590D9400931013 = { + CreatedOnToolsVersion = 11.1; + }; + }; + }; + buildConfigurationList = BE9A7ABF23590D9400931013 /* Build configuration list for PBXProject "SpotlightImporterTester" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = BE9A7ABB23590D9400931013; + productRefGroup = BE9A7AC523590D9500931013 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + BE9A7AC323590D9400931013 /* SpotlightImporterTester */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + BE9A7AC023590D9400931013 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + BE9A7ADA23590E5D00931013 /* main.m in Sources */, + BE9A7AD923590E5D00931013 /* OOoContentDataParser.m in Sources */, + BE9A7AD823590E5D00931013 /* OOoMetaDataParser.m in Sources */, + BE9A7ADB23590E5D00931013 /* GetMetadataForFile.m in Sources */, + BE9A7AD723590E5D00931013 /* OOoSpotlightImporter.m in Sources */, + BE9A7AC823590D9500931013 /* main.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + BE9A7AC923590D9500931013 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + LO_CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + LO_CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + BE9A7ACA23590D9500931013 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + LO_CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + LO_CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + BE9A7ACC23590D9500931013 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = NO; + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + BE9A7ACD23590D9500931013 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = NO; + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + BE9A7ABF23590D9400931013 /* Build configuration list for PBXProject "SpotlightImporterTester" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE9A7AC923590D9500931013 /* Debug */, + BE9A7ACA23590D9500931013 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + BE9A7ACB23590D9500931013 /* Build configuration list for PBXNativeTarget "SpotlightImporterTester" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BE9A7ACC23590D9500931013 /* Debug */, + BE9A7ACD23590D9500931013 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = BE9A7ABC23590D9400931013 /* Project object */; +} diff --git a/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/xcshareddata/xcschemes/SpotlightImporterTester.xcscheme b/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/xcshareddata/xcschemes/SpotlightImporterTester.xcscheme new file mode 100644 index 000000000..d2aab1a01 --- /dev/null +++ b/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester.xcodeproj/xcshareddata/xcschemes/SpotlightImporterTester.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester/main.m b/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester/main.m new file mode 100644 index 000000000..f9b6bbb5f --- /dev/null +++ b/extensions/source/macosx/spotlight/SpotlightImporterTester/SpotlightImporterTester/main.m @@ -0,0 +1,30 @@ +/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ + +#import + +#import +#import +#import + +#import "GetMetadataForFile.h" + +int main(int argc, const char* argv[]) +{ + @autoreleasepool + { + if (argc != 3) + { + fprintf(stderr, "Usage: %s UTI path\n", argv[0]); + return 1; + } + NSMutableDictionary* attributes = [NSMutableDictionary dictionaryWithCapacity:10]; + NSString* contentTypeUTI = [NSString stringWithUTF8String:argv[1]]; + NSString* pathToFile = [NSString stringWithUTF8String:argv[2]]; + + GetMetadataForFile(NULL, (__bridge CFMutableDictionaryRef)attributes, + (__bridge CFStringRef)contentTypeUTI, (__bridge CFStringRef)pathToFile); + } + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/main.m b/extensions/source/macosx/spotlight/main.m new file mode 100644 index 000000000..b1a6381a7 --- /dev/null +++ b/extensions/source/macosx/spotlight/main.m @@ -0,0 +1,211 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// +// main.m +// SpotlightTester +// +// Created by Florian Heckl on 10.07.07. +// +//============================================================================== +// +// DO NOT MODIFY THE CONTENTS OF THIS FILE +// +// This file contains the generic CFPlug-in code necessary for your importer +// To complete your importer implement the function in GetMetadataForFile.c +// +//============================================================================== + +#include +#include +#include + +#include "GetMetadataForFile.h" + +// constants + + +#define PLUGIN_ID "A3FCC88D-B9A6-4364-8B93-92123C8A2D18" + +// +// Below is the generic glue code for all plug-ins. +// +// You should not have to modify this code aside from changing +// names if you decide to change the names defined in the Info.plist +// + + +// typedefs + +// The layout for an instance of MetaDataImporterPlugIn +typedef struct +{ + MDImporterInterfaceStruct *conduitInterface; + CFUUIDRef factoryID; + UInt32 refCount; +} MetadataImporterPluginType; + +// prototypes +// Forward declaration for the IUnknown implementation. +// + +static MetadataImporterPluginType *AllocMetadataImporterPluginType(CFUUIDRef inFactoryID); +static void DeallocMetadataImporterPluginType(MetadataImporterPluginType *thisInstance); +static HRESULT MetadataImporterQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv); +static ULONG MetadataImporterPluginAddRef(void *thisInstance); +static ULONG MetadataImporterPluginRelease(void *thisInstance); +// testInterfaceFtbl definition +// The TestInterface function table. +// + +static MDImporterInterfaceStruct testInterfaceFtbl = { + NULL, + MetadataImporterQueryInterface, + MetadataImporterPluginAddRef, + MetadataImporterPluginRelease, + GetMetadataForFile +}; + + +// AllocMetadataImporterPluginType +// Utility function that allocates a new instance. +// You can do some initial setup for the importer here if you wish +// like allocating globals etc... +// +MetadataImporterPluginType *AllocMetadataImporterPluginType(CFUUIDRef inFactoryID) +{ + MetadataImporterPluginType *theNewInstance; + + theNewInstance = (MetadataImporterPluginType *)malloc(sizeof(MetadataImporterPluginType)); + memset(theNewInstance,0,sizeof(MetadataImporterPluginType)); + + /* Point to the function table */ + theNewInstance->conduitInterface = &testInterfaceFtbl; + + /* Retain and keep an open instance refcount for each factory. */ + theNewInstance->factoryID = CFRetain(inFactoryID); + CFPlugInAddInstanceForFactory(inFactoryID); + + /* This function returns the IUnknown interface so set the refCount to one. */ + theNewInstance->refCount = 1; + return theNewInstance; +} + +// DeallocSpotlightTesterMDImporterPluginType +// Utility function that deallocates the instance when +// the refCount goes to zero. +// In the current implementation importer interfaces are never deallocated +// but implement this as this might change in the future +// +void DeallocMetadataImporterPluginType(MetadataImporterPluginType *thisInstance) +{ + CFUUIDRef theFactoryID; + + theFactoryID = thisInstance->factoryID; + free(thisInstance); + if (theFactoryID){ + CFPlugInRemoveInstanceForFactory(theFactoryID); + CFRelease(theFactoryID); + } +} + +// MetadataImporterQueryInterface +// Implementation of the IUnknown QueryInterface function. +// +HRESULT MetadataImporterQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv) +{ + CFUUIDRef interfaceID; + + interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault,iid); + + if (CFEqual(interfaceID,kMDImporterInterfaceID)){ + /* If the Right interface was requested, bump the ref count, + * set the ppv parameter equal to the instance, and + * return good status. + */ + ((MetadataImporterPluginType*)thisInstance)->conduitInterface->AddRef(thisInstance); + *ppv = thisInstance; + CFRelease(interfaceID); + return S_OK; + }else{ + if (CFEqual(interfaceID,IUnknownUUID)){ + /* If the IUnknown interface was requested, same as above. */ + ((MetadataImporterPluginType*)thisInstance )->conduitInterface->AddRef(thisInstance); + *ppv = thisInstance; + CFRelease(interfaceID); + return S_OK; + }else{ + /* Requested interface unknown, bail with error. */ + *ppv = NULL; + CFRelease(interfaceID); + return E_NOINTERFACE; + } + } +} + +// MetadataImporterPluginAddRef +// Implementation of reference counting for this type. Whenever an interface +// is requested, bump the refCount for the instance. NOTE: returning the +// refcount is a convention but is not required so don't rely on it. +// +ULONG MetadataImporterPluginAddRef(void *thisInstance) +{ + ((MetadataImporterPluginType *)thisInstance )->refCount += 1; + return ((MetadataImporterPluginType*) thisInstance)->refCount; +} + +// SampleCMPluginRelease +// When an interface is released, decrement the refCount. +// If the refCount goes to zero, deallocate the instance. +// +ULONG MetadataImporterPluginRelease(void *thisInstance) +{ + ((MetadataImporterPluginType*)thisInstance)->refCount -= 1; + if (((MetadataImporterPluginType*)thisInstance)->refCount == 0){ + DeallocMetadataImporterPluginType((MetadataImporterPluginType*)thisInstance ); + return 0; + }else{ + return ((MetadataImporterPluginType*) thisInstance )->refCount; + } +} + +// SpotlightTesterMDImporterPluginFactory +// Implementation of the factory function for this type. +// +__attribute__ ((visibility("default"))) +void * +MetadataImporterPluginFactory(CFAllocatorRef allocator, CFUUIDRef typeID) +{ + (void) allocator; /* unused */ + MetadataImporterPluginType *result; + CFUUIDRef uuid; + + /* If correct type is being requested, allocate an + * instance of TestType and return the IUnknown interface. + */ + if (CFEqual(typeID,kMDImporterTypeID)){ + uuid = CFUUIDCreateFromString(kCFAllocatorDefault,CFSTR(PLUGIN_ID)); + result = AllocMetadataImporterPluginType(uuid); + CFRelease(uuid); + return result; + } + /* If the requested type is incorrect, return NULL. */ + return NULL; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/macosx/spotlight/mdimporter/Info.plist b/extensions/source/macosx/spotlight/mdimporter/Info.plist new file mode 100644 index 000000000..5a60493cb --- /dev/null +++ b/extensions/source/macosx/spotlight/mdimporter/Info.plist @@ -0,0 +1,87 @@ + + + + + + CFBundleDevelopmentRegion + English + CFBundleDocumentTypes + + + CFBundleTypeRole + MDImporter + LSItemContentTypes + + org.openoffice.text + org.oasis-open.opendocument.text + org.openoffice.spreadsheet + org.oasis-open.opendocument.spreadsheet + org.openoffice.presentation + org.oasis-open.opendocument.presentation + org.openoffice.graphics + org.oasis-open.opendocument.graphics + org.openoffice.text-master + org.oasis-open.opendocument.text-master + org.openoffice.formula + org.oasis-open.opendocument.formula + org.openoffice.text-template + org.oasis-open.opendocument.text-template + org.openoffice.spreadsheet-template + org.oasis-open.opendocument.spreadsheet-template + org.openoffice.presentation-template + org.oasis-open.opendocument.presentation-template + org.openoffice.graphics-template + org.oasis-open.opendocument.graphics-template + org.oasis-open.opendocument.database + + + + CFBundleExecutable + OOoSpotlightImporter + CFBundleName + OOoSpotlightImporter + CFBundleIconFile + + CFBundleIdentifier + org.libreoffice.mdimporter + CFBundleInfoDictionaryVersion + 6.0 + CFBundleVersion + 1.0 + CFPlugInDynamicRegisterFunction + + CFPlugInDynamicRegistration + NO + CFPlugInFactories + + A3FCC88D-B9A6-4364-8B93-92123C8A2D18 + MetadataImporterPluginFactory + + CFPlugInTypes + + 8B08C4BF-415B-11D8-B3F9-0003936726FC + + A3FCC88D-B9A6-4364-8B93-92123C8A2D18 + + + CFPlugInUnloadFunction + + + + diff --git a/extensions/source/macosx/spotlight/mdimporter/en.lproj/schema.strings b/extensions/source/macosx/spotlight/mdimporter/en.lproj/schema.strings new file mode 100644 index 000000000..355998783 --- /dev/null +++ b/extensions/source/macosx/spotlight/mdimporter/en.lproj/schema.strings @@ -0,0 +1 @@ +ÿþ \ No newline at end of file diff --git a/extensions/source/macosx/spotlight/mdimporter/schema.xml b/extensions/source/macosx/spotlight/mdimporter/schema.xml new file mode 100644 index 000000000..f17aa8c6c --- /dev/null +++ b/extensions/source/macosx/spotlight/mdimporter/schema.xml @@ -0,0 +1,413 @@ + + + + + OpenOffice.org allows the user to enter 4 pieces of custom information in the document's metadata. + These metadata fields are described here for Spotlight's use. + + + + + + + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + + The custom metadata info. + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + org_openoffice_opendocument_custominfo1 + org_openoffice_opendocument_custominfo2 + org_openoffice_opendocument_custominfo3 + org_openoffice_opendocument_custominfo4 + + + + + diff --git a/extensions/source/macosx/spotlight/version.plist b/extensions/source/macosx/spotlight/version.plist new file mode 100644 index 000000000..d91342841 --- /dev/null +++ b/extensions/source/macosx/spotlight/version.plist @@ -0,0 +1,33 @@ + + + + + + BuildVersion + 266 + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + ProjectName + DevToolsWizardTemplates + SourceVersion + 3070000 + + diff --git a/extensions/source/ole/comifaces.hxx b/extensions/source/ole/comifaces.hxx new file mode 100644 index 000000000..51e955dd6 --- /dev/null +++ b/extensions/source/ole/comifaces.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +using namespace com::sun::star::uno; + +MIDL_INTERFACE("e40a2331-3bc1-11d4-8321-005004526ab4") +IJScriptValueObject: public IUnknown +{ + STDMETHOD( Set)( VARIANT type, VARIANT value)= 0; + STDMETHOD( Get)( VARIANT *val)= 0; + STDMETHOD( InitOutParam)()= 0; + STDMETHOD( InitInOutParam)( VARIANT type, VARIANT value)= 0; + STDMETHOD( IsOutParam)( VARIANT_BOOL * flag)= 0; + STDMETHOD( IsInOutParam)( VARIANT_BOOL * flag)= 0; + STDMETHOD( GetValue)( BSTR* type, VARIANT *value)= 0; + +protected: + ~IJScriptValueObject() {} +}; + +MIDL_INTERFACE("7B5C3410-66FA-11d4-832A-005004526AB4") +IUnoObjectWrapper: public IUnknown +{ + STDMETHOD( getWrapperXInterface)( Reference* pInt)=0; + STDMETHOD( getOriginalUnoObject)( Reference* pInt)=0; + STDMETHOD( getOriginalUnoStruct)( Any * pStruct)=0; + +protected: + ~IUnoObjectWrapper() {} +}; + +MIDL_INTERFACE("8BB66591-A544-4de9-822C-57AB57BCED1C") +IUnoTypeWrapper: public IUnknown +{ + STDMETHOD(put_Name)(BSTR val) = 0; + STDMETHOD(get_Name)(BSTR* pVal) = 0; + +protected: + ~IUnoTypeWrapper() {} +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/jscriptclasses.cxx b/extensions/source/ole/jscriptclasses.cxx new file mode 100644 index 000000000..8fc371c4c --- /dev/null +++ b/extensions/source/ole/jscriptclasses.cxx @@ -0,0 +1,312 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "jscriptclasses.hxx" + + +// JScriptValue + +JScriptValue::JScriptValue(): m_bOutParam(false), m_bInOutParam(false) +{ +} + +JScriptValue::~JScriptValue() +{ +} + + +// JScriptValue, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::GetTypeInfoCount(UINT* /*pctinfo*/) +{ + return E_NOTIMPL; +} + +// JScriptValue, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::GetTypeInfo( UINT /*iTInfo*/, + LCID /*lcid*/, + ITypeInfo** /*ppTInfo*/) +{ + return E_NOTIMPL; +} + +// JScriptValue, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::GetIDsOfNames( REFIID /*riid*/, + LPOLESTR *rgszNames, + UINT /*cNames*/, + LCID /*lcid*/, + DISPID *rgDispId) +{ + if( !rgDispId) + return E_POINTER; + + + HRESULT ret= S_OK; + CComBSTR name(*rgszNames); + name.ToLower(); + + if( name == CComBSTR( L"set") ) + *rgDispId= 1; + else if( name == CComBSTR( L"get") ) + *rgDispId= 2; + else if( name == CComBSTR( L"initoutparam") ) + *rgDispId= 3; + else if( name == CComBSTR( L"initinoutparam") ) + *rgDispId= 4; + else + ret= DISP_E_UNKNOWNNAME; + + return ret; +} + +// JScriptValue, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::Invoke( DISPID dispIdMember, + REFIID /*riid*/, + LCID /*lcid*/, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO* /*pExcepInfo*/, + UINT* /*puArgErr*/) +{ + if( pDispParams->cNamedArgs) + return DISP_E_NONAMEDARGS; + + + HRESULT ret= S_OK; + switch( dispIdMember) + { + case 0: // DISPID_VALUE + if( wFlags & DISPATCH_PROPERTYGET && pVarResult) + { + if( FAILED( VariantCopy( pVarResult, &m_varValue))) + ret= E_FAIL; + } + else + ret= E_POINTER; + break; + case 1: + if( wFlags & DISPATCH_METHOD) + ret= Set( pDispParams->rgvarg[1], pDispParams->rgvarg[0]); + if( FAILED( ret)) + ret= DISP_E_EXCEPTION; + break; + case 2: + if( wFlags & DISPATCH_METHOD) + ret= Get( pVarResult); + if( FAILED( ret)) + ret= DISP_E_EXCEPTION; + break; + case 3: + if( wFlags & DISPATCH_METHOD) + ret= InitOutParam(); + if( FAILED( ret)) + ret= DISP_E_EXCEPTION; + break; + case 4: + if( wFlags & DISPATCH_METHOD) + ret= InitInOutParam( pDispParams->rgvarg[1], pDispParams->rgvarg[0]); + if( FAILED( ret)) + ret= DISP_E_EXCEPTION; + break; + default: + ret= DISP_E_MEMBERNOTFOUND; + break; + } + + return ret; +} + +// JScriptValue, IScriptOutParam----------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::Set( VARIANT type, VARIANT value) +{ + Lock(); + m_varValue.Clear(); + HRESULT hr= VariantCopyInd( &m_varValue, &value); + VARIANT var; + VariantInit( &var); + if( SUCCEEDED( hr= VariantChangeType( &var, &type, 0, VT_BSTR))) + m_bstrType= var.bstrVal; + Unlock(); + return hr; +} +// JScriptValue, IScriptOutParam----------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::Get( VARIANT *val) +{ + Lock(); + if( !val) + return E_POINTER; + HRESULT hr= VariantCopy( val, &m_varValue); + Unlock(); + return hr; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::InitOutParam() +{ + Lock(); + m_varValue.Clear(); + m_bOutParam= true; + m_bInOutParam= false; + Unlock(); + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::InitInOutParam( VARIANT type, VARIANT value) +{ + Lock(); + m_bInOutParam= true; + m_bOutParam= false; + Unlock(); + return Set( type, value); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::IsOutParam( VARIANT_BOOL * flag) +{ + Lock(); + if( !flag) + return E_POINTER; + *flag= m_bOutParam ? VARIANT_TRUE : VARIANT_FALSE; + Unlock(); + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::IsInOutParam( VARIANT_BOOL * flag) +{ + Lock(); + if( !flag) + return E_POINTER; + *flag= m_bInOutParam ? VARIANT_TRUE : VARIANT_FALSE; + Unlock(); + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptValue::GetValue( BSTR* type, VARIANT *value) +{ + Lock(); + if( !type || !value) + return E_POINTER; + HRESULT hr; + if( SUCCEEDED( hr= m_bstrType.CopyTo( type))) + hr= VariantCopy( value, &m_varValue); + Unlock(); + return hr; +} + + +// JScriptOutValue + + +JScriptOutParam::JScriptOutParam() +{ +} + +JScriptOutParam::~JScriptOutParam() +{ +} + + +// JScriptOutParam, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptOutParam::GetTypeInfoCount(UINT* /*pctinfo*/) +{ + return E_NOTIMPL; +} + +// JScriptOutParam, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptOutParam::GetTypeInfo( UINT /*iTInfo*/, + LCID /*lcid*/, + ITypeInfo** /*ppTInfo*/) +{ + return E_NOTIMPL; +} + +// JScriptOutParam, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptOutParam::GetIDsOfNames( REFIID /*riid*/, + LPOLESTR *rgszNames, + UINT /*cNames*/, + LCID /*lcid*/, + DISPID *rgDispId) +{ + if( !rgDispId) + return E_POINTER; + + + HRESULT ret= S_OK; + CComBSTR name(*rgszNames); + name.ToLower(); + + if( name == CComBSTR( L"0") ) + *rgDispId= 1; + else + ret= DISP_E_UNKNOWNNAME; + + return ret; +} + +// JScriptOutParam, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP JScriptOutParam::Invoke( DISPID dispIdMember, + REFIID /*riid*/, + LCID /*lcid*/, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO* /*pExcepInfo*/, + UINT* /*puArgErr*/) +{ + HRESULT ret= S_OK; + switch( dispIdMember) + { + case 0: // DISPID_VALUE + if( wFlags & DISPATCH_PROPERTYGET && pVarResult) + { + if( FAILED( VariantCopy( pVarResult, &m_varValue))) + ret= E_FAIL; + } + else if( wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF) + { + m_varValue.Clear(); + if( FAILED( VariantCopyInd( &m_varValue, &pDispParams->rgvarg[0]))) + ret= E_FAIL; + } + else + ret= E_POINTER; + break; + case 1: + if( wFlags & DISPATCH_PROPERTYGET && pVarResult) + { + if( FAILED( VariantCopy( pVarResult, &m_varValue))) + ret= E_FAIL; + } + else if( wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF) + { + m_varValue.Clear(); + if( FAILED( VariantCopyInd( &m_varValue, &pDispParams->rgvarg[0]))) + ret= E_FAIL; + } + else + ret= E_POINTER; + break; + + default: + ret= DISP_E_MEMBERNOTFOUND; + break; + } + + return ret; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/jscriptclasses.hxx b/extensions/source/ole/jscriptclasses.hxx new file mode 100644 index 000000000..cef993ed0 --- /dev/null +++ b/extensions/source/ole/jscriptclasses.hxx @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "wincrap.hxx" + +#include "comifaces.hxx" + + +// Sequences are represented by prepending "[]", e.g. []char, [][]byte, [][][]object, etc. + +// To make a JScriptValue object to an out parameter, call +// "InitOutParam" and to make it a in/out parameter call +// "InitInOutParam" + +// If the object represents an out parameter then the value can after the call +// be retrieved by "Get". + +// From JavaScript the functions Get, Set, InitOutParam and InitInOutParam are +// used, that is they are accessible through IDispatch. The functions are used +// by the bridge. + +class JScriptValue: + public CComObjectRootEx, + public IJScriptValueObject, + public IDispatch +{ +public: + JScriptValue(); + virtual ~JScriptValue(); + + BEGIN_COM_MAP(JScriptValue) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IJScriptValueObject) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + // IDispatch ------------------------------------------- + STDMETHOD( GetTypeInfoCount)(UINT *pctinfo) override; + + STDMETHOD( GetTypeInfo)( UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo) override; + + STDMETHOD( GetIDsOfNames)( REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId) override; + + STDMETHOD( Invoke)( DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr) override; + // IJScriptOutParam -------------------------------------- + + STDMETHOD( Set)( VARIANT type, VARIANT value) override; + STDMETHOD( Get)( VARIANT *val) override; + STDMETHOD( InitOutParam)() override; + STDMETHOD( InitInOutParam)( VARIANT type, VARIANT value) override; + STDMETHOD( IsOutParam)( VARIANT_BOOL * flag) override; + STDMETHOD( IsInOutParam)( VARIANT_BOOL * flag) override; + STDMETHOD( GetValue)( BSTR* type, VARIANT *value) override; + + + CComVariant m_varValue; + CComBSTR m_bstrType; + bool m_bOutParam: 1; + bool m_bInOutParam: 1; + +}; + +// If a class is implemented in JScript, then its method +class JScriptOutParam: + public CComObjectRootEx, + public IDispatch +{ +public: + JScriptOutParam(); + virtual ~JScriptOutParam(); + + BEGIN_COM_MAP(JScriptOutParam) + COM_INTERFACE_ENTRY(IDispatch) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + // IDispatch ------------------------------------------- + STDMETHOD( GetTypeInfoCount)(UINT *pctinfo) override; + + STDMETHOD( GetTypeInfo)( UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo) override; + + STDMETHOD( GetIDsOfNames)( REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId) override; + + STDMETHOD( Invoke)( DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr) override; + + +private: + CComVariant m_varValue; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/ole2uno.cxx b/extensions/source/ole/ole2uno.cxx new file mode 100644 index 000000000..f9eef5125 --- /dev/null +++ b/extensions/source/ole/ole2uno.cxx @@ -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 . + */ + + +#include +#include +#include "ole2uno.hxx" + +using namespace osl; + +namespace { + +struct MutexInit +{ + Mutex * operator () () + { + static Mutex aInstance; + return &aInstance; + } +}; + +} + +Mutex * getBridgeMutex() +{ + return rtl_Instance< Mutex, MutexInit, ::osl::MutexGuard, + ::osl::GetGlobalMutex >::create( + MutexInit(), ::osl::GetGlobalMutex()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/ole2uno.hxx b/extensions/source/ole/ole2uno.hxx new file mode 100644 index 000000000..5fcf2fd96 --- /dev/null +++ b/extensions/source/ole/ole2uno.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "wincrap.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define UNO_2_OLE_EXCEPTIONCODE 1001 +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::registry; +using namespace com::sun::star::reflection; +using namespace com::sun::star::beans; +using namespace osl; + +VARTYPE getVarType(const Any& val); +/* creates a Type object for a given type name. + + The function returns false if the name does not represent + a valid type. +*/ +bool getType(BSTR name, Type& type); +void o2u_attachCurrentThread(); + +class BridgeRuntimeError +{ +public: + explicit BridgeRuntimeError(const OUString& sMessage) + : message(sMessage) + { + } + OUString message; +}; + +Mutex* getBridgeMutex(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/oleautobridge.component b/extensions/source/ole/oleautobridge.component new file mode 100644 index 000000000..09f7621c2 --- /dev/null +++ b/extensions/source/ole/oleautobridge.component @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/source/ole/oledll.cxx b/extensions/source/ole/oledll.cxx new file mode 100644 index 000000000..1275f4dc6 --- /dev/null +++ b/extensions/source/ole/oledll.cxx @@ -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 . + */ + +#define STRICT +#define _WIN32_DCOM + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wall" +#pragma clang diagnostic ignored "-Wattributes" +#pragma clang diagnostic ignored "-Wdelete-incomplete" +#pragma clang diagnostic ignored "-Wextra" +#pragma clang diagnostic ignored "-Wint-to-pointer-cast" +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#pragma clang diagnostic ignored "-Wmicrosoft" +#pragma clang diagnostic ignored "-Wnon-pod-varargs" +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif + +#include +static CComModule _Module; +#include + +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +BEGIN_OBJECT_MAP(ObjectMap) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-field-initializers" +#endif +END_OBJECT_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +// DLL Entry Point + +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + { + _Module.Term(); + } + return TRUE; // ok +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/oleobjw.cxx b/extensions/source/ole/oleobjw.cxx new file mode 100644 index 000000000..85f410c54 --- /dev/null +++ b/extensions/source/ole/oleobjw.cxx @@ -0,0 +1,2513 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "ole2uno.hxx" +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "jscriptclasses.hxx" + +#include "oleobjw.hxx" +#include "unoobjw.hxx" +#include +using namespace osl; +using namespace cppu; +using namespace com::sun::star::script; +using namespace com::sun::star::lang; +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::oleautomation; +using namespace com::sun::star::bridge::ModelDependent; +using namespace ::com::sun::star; + + +#define JSCRIPT_ID_PROPERTY L"_environment" +#define JSCRIPT_ID L"jscript" + +// key: XInterface pointer created by Invocation Adapter Factory +// value: XInterface pointer to the wrapper class. +// Entries to the map are made within +// Any createOleObjectWrapper(IUnknown* pUnknown, const Type& aType); +// Entries are being deleted if the wrapper class's destructor has been +// called. +// Before UNO object is wrapped to COM object this map is checked +// to see if the UNO object is already a wrapper. +std::unordered_map AdapterToWrapperMap; +// key: XInterface of the wrapper object. +// value: XInterface of the Interface created by the Invocation Adapter Factory. +// A COM wrapper is responsible for removing the corresponding entry +// in AdapterToWrapperMap if it is being destroyed. Because the wrapper does not +// know about its adapted interface it uses WrapperToAdapterMap to get the +// adapted interface which is then used to locate the entry in AdapterToWrapperMap. +std::unordered_map WrapperToAdapterMap; + +std::unordered_map > ComPtrToWrapperMap; + +IUnknownWrapper::IUnknownWrapper( Reference const & xFactory, + sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass): + UnoConversionUtilities( xFactory, unoWrapperClass, comWrapperClass), + m_pxIdlClass( nullptr), m_eJScript( JScriptUndefined), + m_bComTlbIndexInit(false), m_bHasDfltMethod(false), m_bHasDfltProperty(false) +{ +} + + +IUnknownWrapper::~IUnknownWrapper() +{ + o2u_attachCurrentThread(); + MutexGuard guard(getBridgeMutex()); + XInterface * xIntRoot = static_cast(this); +#if OSL_DEBUG_LEVEL > 0 + acquire(); // make sure we don't delete us twice because of Reference + OSL_ASSERT( Reference( static_cast(this), UNO_QUERY).get() == xIntRoot ); +#endif + + // remove entries in global maps + auto it= WrapperToAdapterMap.find( reinterpret_cast(xIntRoot)); + if( it != WrapperToAdapterMap.end()) + { + sal_uIntPtr adapter= it->second; + + AdapterToWrapperMap.erase( adapter); + WrapperToAdapterMap.erase( it); + } + + auto it_c= ComPtrToWrapperMap.find( reinterpret_cast(m_spUnknown.p)); + if(it_c != ComPtrToWrapperMap.end()) + ComPtrToWrapperMap.erase(it_c); +} + +Any IUnknownWrapper::queryInterface(const Type& t) +{ + if (t == cppu::UnoType::get() && !m_bHasDfltMethod ) + return Any(); + if (t == cppu::UnoType::get() && !m_bHasDfltProperty ) + return Any(); + if ( ( t == cppu::UnoType::get() || t == cppu::UnoType::get() ) && !m_spDispatch) + return Any(); + // XDirectInvocation seems to be an oracle replacement for XAutomationInvocation, however it is flawed especially wrt. assumptions about whether to invoke a + // Put or Get property, the implementation code has no business guessing that, it's up to the caller to decide that. Worse XDirectInvocation duplicates lots of code. + // XAutomationInvocation provides separate calls for put& get + // properties. Note: Currently the basic runtime doesn't call put properties directly, it should... after all the basic runtime should know whether it is calling a put or get property. + // For the moment for ease of merging we will let the XDirectInvoke and XAuthomationInvocation interfaces stay side by side (and for the moment at least I would prefer the basic + // runtime to call XAutomationInvocation instead of XDirectInvoke + return WeakImplHelper::queryInterface(t); +} + +Reference SAL_CALL IUnknownWrapper::getIntrospection() +{ + Reference ret; + + return ret; +} + +Any SAL_CALL IUnknownWrapper::invokeGetProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) +{ + Any aResult; + try + { + o2u_attachCurrentThread(); + ITypeInfo * pInfo = getTypeInfo(); + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); + if ( !aDescGet ) + { + OUString msg("[automation bridge]Property \"" + aPropertyName + + "\" is not supported"); + throw UnknownPropertyException(msg); + } + aResult = invokeWithDispIdComTlb( aDescGet, aPropertyName, aParams, aOutParamIndex, aOutParam ); + } + catch ( const Exception& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::invokeGetProperty ! Message : \n " + + e.Message, + nullptr, anyEx ); + } + return aResult; +} + +Any SAL_CALL IUnknownWrapper::invokePutProperty( const OUString& aPropertyName, const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, Sequence< Any >& aOutParam ) +{ + Any aResult; + try + { + o2u_attachCurrentThread(); + ITypeInfo * pInfo = getTypeInfo(); + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); + if ( !aDescPut ) + { + OUString msg("[automation bridge]Property \"" + aPropertyName + + "\" is not supported"); + throw UnknownPropertyException(msg); + } + aResult = invokeWithDispIdComTlb( aDescPut, aPropertyName, aParams, aOutParamIndex, aOutParam ); + } + catch ( const Exception& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::invokePutProperty ! Message : \n" + + e.Message, + nullptr, anyEx ); + } + return aResult; +} + + +Any SAL_CALL IUnknownWrapper::invoke( const OUString& aFunctionName, + const Sequence< Any >& aParams, Sequence< sal_Int16 >& aOutParamIndex, + Sequence< Any >& aOutParam ) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + "[automation bridge] The object does not have an IDispatch interface"); + } + + Any ret; + + try + { + o2u_attachCurrentThread(); + + TypeDescription methodDesc; + getMethodInfo(aFunctionName, methodDesc); + if( methodDesc.is()) + { + ret = invokeWithDispIdUnoTlb(aFunctionName, + aParams, + aOutParamIndex, + aOutParam); + } + else + { + ret= invokeWithDispIdComTlb( aFunctionName, + aParams, + aOutParamIndex, + aOutParam); + } + } + catch (const IllegalArgumentException &) + { + throw; + } + catch (const CannotConvertException &) + { + throw; + } + catch (const BridgeRuntimeError & e) + { + throw RuntimeException(e.message); + } + catch (const Exception & e) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::invoke ! Message : \n" + + e.Message, + nullptr, anyEx ); + + } + catch(...) + { + throw RuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::Invoke !"); + } + return ret; +} + +void SAL_CALL IUnknownWrapper::setValue( const OUString& aPropertyName, + const Any& aValue ) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + "[automation bridge] The object does not have an IDispatch interface"); + } + try + { + o2u_attachCurrentThread(); + + ITypeInfo * pInfo = getTypeInfo(); + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); + //check if there is such a property at all or if it is read only + if ( ! aDescPut && ! aDescGet && ! aVarDesc) + { + OUString msg("[automation bridge]Property \"" + aPropertyName + + "\" is not supported"); + throw UnknownPropertyException(msg); + } + + if ( (! aDescPut && aDescGet) + || (aVarDesc && aVarDesc->wVarFlags == VARFLAG_FREADONLY) ) + { + //read-only + SAL_WARN( "extensions.olebridge", "[automation bridge] Property " << aPropertyName << " is read-only"); + // ignore silently + return; + } + + HRESULT hr= S_OK; + DISPPARAMS dispparams; + CComVariant varArg; + CComVariant varRefArg; + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr; + + // converting UNO value to OLE variant + DISPID dispidPut= DISPID_PROPERTYPUT; + dispparams.rgdispidNamedArgs = &dispidPut; + dispparams.cArgs = 1; + dispparams.cNamedArgs = 1; + dispparams.rgvarg = & varArg; + + OSL_ASSERT(aDescPut || aVarDesc); + + VARTYPE vt = 0; + DISPID dispid = 0; + INVOKEKIND invkind = INVOKE_PROPERTYPUT; + //determine the expected type, dispid, invoke kind (DISPATCH_PROPERTYPUT, + //DISPATCH_PROPERTYPUTREF) + if (aDescPut) + { + vt = getElementTypeDesc(& aDescPut->lprgelemdescParam[0].tdesc); + dispid = aDescPut->memid; + invkind = aDescPut->invkind; + } + else + { + vt = getElementTypeDesc( & aVarDesc->elemdescVar.tdesc); + dispid = aVarDesc->memid; + if (vt == VT_UNKNOWN || vt == VT_DISPATCH || + (vt & VT_ARRAY) || (vt & VT_BYREF)) + { + invkind = INVOKE_PROPERTYPUTREF; + } + } + + // convert the uno argument + if (vt & VT_BYREF) + { + anyToVariant( & varRefArg, aValue, ::sal::static_int_cast< VARTYPE, int >( vt ^ VT_BYREF ) ); + varArg.vt = vt; + if( (vt & VT_TYPEMASK) == VT_VARIANT) + varArg.byref = & varRefArg; + else if ((vt & VT_TYPEMASK) == VT_DECIMAL) + varArg.byref = & varRefArg.decVal; + else + varArg.byref = & varRefArg.byref; + } + else + { + anyToVariant(& varArg, aValue, vt); + } + // call to IDispatch + hr = m_spDispatch->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, ::sal::static_int_cast< WORD, INVOKEKIND >( invkind ), + &dispparams, & varResult, & excepinfo, &uArgErr); + + // lookup error code + switch (hr) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + throw RuntimeException(); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException(); + break; + case DISP_E_EXCEPTION: + throw InvocationTargetException(); + break; + case DISP_E_MEMBERNOTFOUND: + throw UnknownPropertyException(); + break; + case DISP_E_NONAMEDARGS: + throw RuntimeException(); + break; + case DISP_E_OVERFLOW: + throw CannotConvertException("call to OLE object failed", static_cast( + static_cast(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); + break; + case DISP_E_PARAMNOTFOUND: + throw IllegalArgumentException("call to OLE object failed", static_cast( + static_cast(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )) ; + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException("call to OLE object failed", static_cast( + static_cast(this)), TypeClass_UNKNOWN, FailReason::UNKNOWN, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException(); + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException(); + break; + case DISP_E_PARAMNOTOPTIONAL: + throw CannotConvertException("call to OLE object failed",static_cast( + static_cast(this)) , TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); + break; + default: + throw RuntimeException(); + break; + } + } + catch (const CannotConvertException &) + { + throw; + } + catch (const UnknownPropertyException &) + { + throw; + } + catch (const BridgeRuntimeError& e) + { + throw RuntimeException(e.message); + } + catch (const Exception & e) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::setValue ! Message : \n" + + e.Message, + nullptr, anyEx ); + + } + catch (...) + { + throw RuntimeException( + "[automation bridge] unexpected exception in " + "IUnknownWrapper::setValue !"); + } +} + +Any SAL_CALL IUnknownWrapper::getValue( const OUString& aPropertyName ) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + "[automation bridge] The object does not have an IDispatch interface"); + } + Any ret; + try + { + o2u_attachCurrentThread(); + ITypeInfo * pInfo = getTypeInfo(); + // I was going to implement an XServiceInfo interface to allow the type + // of the automation object to be exposed... but it seems + // from looking at comments in the code that it is possible for + // this object to actually wrap a UNO object ( I guess if automation is + // used from MSO to create Openoffice objects ) Therefore, those objects + // will more than likely already have their own XServiceInfo interface. + // Instead here I chose a name that should be illegal both in COM and + // UNO ( from an IDL point of view ) therefore I think this is a safe + // hack + if ( aPropertyName == "$GetTypeName" ) + { + if ( pInfo && m_sTypeName.getLength() == 0 ) + { + m_sTypeName = "IDispatch"; + CComBSTR sName; + + if ( SUCCEEDED( pInfo->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr ) ) ) + { + OUString sTmp( o3tl::toU(LPCOLESTR(sName))); + if ( sTmp.startsWith("_") ) + sTmp = sTmp.copy(1); + // do we own the memory for pTypeLib, msdn doc is vague + // I'll assume we do + CComPtr< ITypeLib > pTypeLib; + unsigned int index; + if ( SUCCEEDED( pInfo->GetContainingTypeLib( &pTypeLib.p, &index )) ) + { + if ( SUCCEEDED( pTypeLib->GetDocumentation( -1, &sName, nullptr, nullptr, nullptr ) ) ) + { + OUString sLibName( o3tl::toU(LPCOLESTR(sName))); + m_sTypeName = sLibName + "." + sTmp; + + } + } + } + + } + ret <<= m_sTypeName; + return ret; + } + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aPropertyName, & aDescGet, & aDescPut, & aVarDesc); + if ( ! aDescGet && ! aDescPut && ! aVarDesc) + { + //property not found + OUString msg("[automation bridge]Property \"" + aPropertyName + + "\" is not supported"); + throw UnknownPropertyException(msg); + } + // write-only should not be possible + OSL_ASSERT( aDescGet || ! aDescPut); + + HRESULT hr; + DISPPARAMS dispparams = {nullptr, nullptr, 0, 0}; + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr; + DISPID dispid; + if (aDescGet) + dispid = aDescGet->memid; + else if (aVarDesc) + dispid = aVarDesc->memid; + else + dispid = aDescPut->memid; + + hr = m_spDispatch->Invoke(dispid, + IID_NULL, + LOCALE_USER_DEFAULT, + DISPATCH_PROPERTYGET, + &dispparams, + &varResult, + &excepinfo, + &uArgErr); + + // converting return value and out parameter back to UNO + if (hr == S_OK) + { + // If the com object implements uno interfaces then we have + // to convert the attribute into the expected type. + TypeDescription attrInfo; + getAttributeInfo(aPropertyName, attrInfo); + if( attrInfo.is() ) + variantToAny( &varResult, ret, Type( attrInfo.get()->pWeakRef)); + else + variantToAny(&varResult, ret); + } + + // lookup error code + switch (hr) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + case DISP_E_BADVARTYPE: + case DISP_E_EXCEPTION: + throw RuntimeException(OUString(o3tl::toU(excepinfo.bstrDescription))); + break; + case DISP_E_MEMBERNOTFOUND: + throw UnknownPropertyException(OUString(o3tl::toU(excepinfo.bstrDescription))); + break; + default: + throw RuntimeException(OUString(o3tl::toU(excepinfo.bstrDescription))); + break; + } + } + catch ( const UnknownPropertyException& ) + { + throw; + } + catch (const BridgeRuntimeError& e) + { + throw RuntimeException(e.message); + } + catch (const Exception & e) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::getValue ! Message : \n" + + e.Message, + nullptr, anyEx ); + } + catch (...) + { + throw RuntimeException( + "[automation bridge] unexpected exception in " + "IUnknownWrapper::getValue !"); + } + return ret; +} + +sal_Bool SAL_CALL IUnknownWrapper::hasMethod( const OUString& aName ) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + "[automation bridge] The object does not have an IDispatch interface"); + } + bool ret = false; + + try + { + o2u_attachCurrentThread(); + ITypeInfo* pInfo = getTypeInfo(); + FuncDesc aDesc(pInfo); + getFuncDesc(aName, & aDesc); + // Automation properties can have arguments. Those are treated as methods and + //are called through XInvocation::invoke. + if ( ! aDesc) + { + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc( aName, & aDescGet, & aDescPut, & aVarDesc); + if ((aDescGet && aDescGet->cParams > 0) + || (aDescPut && aDescPut->cParams > 0)) + ret = true; + } + else + ret = true; + } + catch (const BridgeRuntimeError& e) + { + throw RuntimeException(e.message); + } + catch (const Exception & e) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::hasMethod ! Message : \n" + + e.Message, + nullptr, anyEx ); + } + catch (...) + { + throw RuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::hasMethod !"); + } + return ret; +} + +sal_Bool SAL_CALL IUnknownWrapper::hasProperty( const OUString& aName ) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException("[automation bridge] The object does not have an " + "IDispatch interface"); + } + bool ret = false; + try + { + o2u_attachCurrentThread(); + + ITypeInfo * pInfo = getTypeInfo(); + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(aName, & aDescGet, & aDescPut, & aVarDesc); + + // we should probably just check the func kind + // basic has been modified to handle properties ( 'get' ) props at + // least with parameters + // additionally you can call invoke(Get|Set)Property on the bridge + // you can determine if a property has parameter is hasMethod + // returns true for the name + if (aVarDesc + || aDescPut + || aDescGet ) + { + ret = true; + } + } + catch (const BridgeRuntimeError& e) + { + throw RuntimeException(e.message); + } + catch (const Exception & e) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::hasProperty ! Message : \n" + + e.Message, + nullptr, anyEx ); + + } + catch (...) + { + throw RuntimeException("[automation bridge] unexpected exception in " + "IUnknownWrapper::hasProperty !"); + } + return ret; +} + +Any SAL_CALL IUnknownWrapper::createBridge( const Any& modelDepObject, + const Sequence< sal_Int8 >& /*aProcessId*/, sal_Int16 sourceModelType, + sal_Int16 destModelType ) +{ + Any ret; + o2u_attachCurrentThread(); + + if ( + (sourceModelType == UNO) && + (destModelType == OLE) && + (modelDepObject.getValueTypeClass() == TypeClass_INTERFACE) + ) + { + Reference xInt( *static_cast(modelDepObject.getValue())); + Reference xSelf( static_cast(this)); + + if (xInt == xSelf) + { + VARIANT* pVariant = static_cast(CoTaskMemAlloc(sizeof(VARIANT))); + + VariantInit(pVariant); + if (m_bOriginalDispatch) + { + pVariant->vt = VT_DISPATCH; + pVariant->pdispVal = m_spDispatch; + pVariant->pdispVal->AddRef(); + } + else + { + pVariant->vt = VT_UNKNOWN; + pVariant->punkVal = m_spUnknown; + pVariant->punkVal->AddRef(); + } + + ret.setValue(static_cast(&pVariant), cppu::UnoType::get()); + } + } + + return ret; +} +/** @internal + @exception IllegalArgumentException + @exception CannotConvertException + @exception InvocationTargetException + @RuntimeException +*/ +Any IUnknownWrapper::invokeWithDispIdUnoTlb(const OUString& sFunctionName, + const Sequence< Any >& Params, + Sequence< sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam) +{ + Any ret; + HRESULT hr= S_OK; + + sal_Int32 parameterCount= Params.getLength(); + sal_Int32 outParameterCount= 0; + typelib_InterfaceMethodTypeDescription* pMethod= nullptr; + TypeDescription methodDesc; + getMethodInfo(sFunctionName, methodDesc); + + // We need to know whether the IDispatch is from a JScript object. + // Then out and in/out parameters have to be treated differently than + // with common COM objects. + bool bJScriptObject= isJScriptObject(); + std::unique_ptr sarParams; + std::unique_ptr sarParamsRef; + CComVariant *pVarParams= nullptr; + CComVariant *pVarParamsRef= nullptr; + bool bConvRet= true; + + if( methodDesc.is()) + { + pMethod = reinterpret_cast(methodDesc.get()); + parameterCount = pMethod->nParams; + // Create the Array for the array being passed in DISPPARAMS + // the array also contains the outparameter (but not the values) + if( pMethod->nParams > 0) + { + sarParams.reset(new CComVariant[ parameterCount]); + pVarParams = sarParams.get(); + } + + // Create the Array for the out an in/out parameter. These values + // are referenced by the VT_BYREF VARIANTs in DISPPARAMS. + // We need to find out the number of out and in/out parameter. + for( sal_Int32 i=0; i < parameterCount; i++) + { + if( pMethod->pParams[i].bOut) + outParameterCount++; + } + + if( !bJScriptObject) + { + sarParamsRef.reset(new CComVariant[outParameterCount]); + pVarParamsRef = sarParamsRef.get(); + // build up the parameters for IDispatch::Invoke + sal_Int32 outParamIndex=0; + int i = 0; + try + { + for( i= 0; i < parameterCount; i++) + { + // In parameter + if( pMethod->pParams[i].bIn && ! pMethod->pParams[i].bOut) + { + anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]); + } + // Out parameter + in/out parameter + else if( pMethod->pParams[i].bOut ) + { + CComVariant var; + if(pMethod->pParams[i].bIn) + { + anyToVariant( & var,Params[i]); + pVarParamsRef[outParamIndex] = var; + } + + switch( pMethod->pParams[i].pTypeRef->eTypeClass) + { + case typelib_TypeClass_INTERFACE: + case typelib_TypeClass_STRUCT: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt= VT_DISPATCH; + pVarParamsRef[ outParamIndex].pdispVal= nullptr; + } + pVarParams[parameterCount - i -1].vt = VT_DISPATCH | VT_BYREF; + pVarParams[parameterCount - i -1].ppdispVal= &pVarParamsRef[outParamIndex].pdispVal; + break; + case typelib_TypeClass_ENUM: + case typelib_TypeClass_LONG: + case typelib_TypeClass_UNSIGNED_LONG: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_I4; + pVarParamsRef[ outParamIndex].lVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_I4 | VT_BYREF; + pVarParams[parameterCount - i -1].plVal= &pVarParamsRef[outParamIndex].lVal; + break; + case typelib_TypeClass_SEQUENCE: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_ARRAY| VT_VARIANT; + pVarParamsRef[ outParamIndex].parray= nullptr; + } + pVarParams[parameterCount - i -1].vt = VT_ARRAY| VT_BYREF | VT_VARIANT; + pVarParams[parameterCount - i -1].pparray= &pVarParamsRef[outParamIndex].parray; + break; + case typelib_TypeClass_ANY: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_EMPTY; + pVarParamsRef[ outParamIndex].lVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF; + pVarParams[parameterCount - i -1].pvarVal = &pVarParamsRef[outParamIndex]; + break; + case typelib_TypeClass_BOOLEAN: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_BOOL; + pVarParamsRef[ outParamIndex].boolVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_BOOL| VT_BYREF; + pVarParams[parameterCount - i -1].pboolVal = + & pVarParamsRef[outParamIndex].boolVal; + break; + + case typelib_TypeClass_STRING: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_BSTR; + pVarParamsRef[ outParamIndex].bstrVal= nullptr; + } + pVarParams[parameterCount - i -1].vt = VT_BSTR| VT_BYREF; + pVarParams[parameterCount - i -1].pbstrVal= + & pVarParamsRef[outParamIndex].bstrVal; + break; + + case typelib_TypeClass_FLOAT: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_R4; + pVarParamsRef[ outParamIndex].fltVal= 0; + } + pVarParams[parameterCount - i -1].vt = VT_R4| VT_BYREF; + pVarParams[parameterCount - i -1].pfltVal = + & pVarParamsRef[outParamIndex].fltVal; + break; + case typelib_TypeClass_DOUBLE: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_R8; + pVarParamsRef[ outParamIndex].dblVal= 0; + } + pVarParams[parameterCount - i -1].vt = VT_R8| VT_BYREF; + pVarParams[parameterCount - i -1].pdblVal= + & pVarParamsRef[outParamIndex].dblVal; + break; + case typelib_TypeClass_BYTE: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_UI1; + pVarParamsRef[ outParamIndex].bVal= 0; + } + pVarParams[parameterCount - i -1].vt = VT_UI1| VT_BYREF; + pVarParams[parameterCount - i -1].pbVal= + & pVarParamsRef[outParamIndex].bVal; + break; + case typelib_TypeClass_CHAR: + case typelib_TypeClass_SHORT: + case typelib_TypeClass_UNSIGNED_SHORT: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_I2; + pVarParamsRef[ outParamIndex].iVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_I2| VT_BYREF; + pVarParams[parameterCount - i -1].piVal= + & pVarParamsRef[outParamIndex].iVal; + break; + + default: + if( ! pMethod->pParams[i].bIn) + { + pVarParamsRef[ outParamIndex].vt = VT_EMPTY; + pVarParamsRef[ outParamIndex].lVal = 0; + } + pVarParams[parameterCount - i -1].vt = VT_VARIANT | VT_BYREF; + pVarParams[parameterCount - i -1].pvarVal = + & pVarParamsRef[outParamIndex]; + } + outParamIndex++; + } // end else if + } // end for + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i ); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = i; + throw; + } + } + else // it is a JScriptObject + { + int i = 0; + try + { + for( ; i< parameterCount; i++) + { + // In parameter + if( pMethod->pParams[i].bIn && ! pMethod->pParams[i].bOut) + { + anyToVariant( &pVarParams[parameterCount - i -1], Params.getConstArray()[i]); + } + // Out parameter + in/out parameter + else if( pMethod->pParams[i].bOut ) + { + CComObject* pParamObject; + if( !SUCCEEDED( CComObject::CreateInstance( &pParamObject))) + { + throw BridgeRuntimeError( + "[automation bridge]IUnknownWrapper::" + "invokeWithDispIdUnoTlb\n" + "Could not create out parameter at index: " + + OUString::number(static_cast(i))); + } + + CComPtr pUnk(pParamObject->GetUnknown()); + CComQIPtr pDisp( pUnk); + + pVarParams[ parameterCount - i -1].vt= VT_DISPATCH; + pVarParams[ parameterCount - i -1].pdispVal= pDisp; + pVarParams[ parameterCount - i -1].pdispVal->AddRef(); + // if the param is in/out then put the parameter on index 0 + if( pMethod->pParams[i].bIn ) // in / out + { + CComVariant varParam; + anyToVariant( &varParam, Params.getConstArray()[i]); + CComDispatchDriver dispDriver( pDisp); + if(FAILED( dispDriver.PutPropertyByName( L"0", &varParam))) + throw BridgeRuntimeError( + "[automation bridge]IUnknownWrapper::" + "invokeWithDispIdUnoTlb\n" + "Could not set property \"0\" for the in/out " + "param!"); + + } + } + } + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i ); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = i; + throw; + } + } + } + // No type description Available, that is we have to deal with a COM component, + // that does not implements UNO interfaces ( IDispatch based) + else + { + //We should not run into this block, because invokeWithDispIdComTlb should + //have been called instead. + OSL_ASSERT(false); + } + + + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr; + DISPPARAMS dispparams= { pVarParams, nullptr, static_cast(parameterCount), 0}; + + // Get the DISPID + FuncDesc aDesc(getTypeInfo()); + getFuncDesc(sFunctionName, & aDesc); + // invoking OLE method + hr = m_spDispatch->Invoke(aDesc->memid, + IID_NULL, + LOCALE_USER_DEFAULT, + DISPATCH_METHOD, + &dispparams, + &varResult, + &excepinfo, + &uArgErr); + + // converting return value and out parameter back to UNO + if (hr == S_OK) + { + if( outParameterCount && pMethod) + { + OutParamIndex.realloc( outParameterCount); + auto pOutParamIndex = OutParamIndex.getArray(); + OutParam.realloc( outParameterCount); + auto pOutParam = OutParam.getArray(); + sal_Int32 outIndex=0; + int i = 0; + try + { + for( ; i < parameterCount; i++) + { + if( pMethod->pParams[i].bOut ) + { + pOutParamIndex[outIndex]= static_cast(i); + Any outAny; + if( !bJScriptObject) + { + variantToAny( &pVarParamsRef[outIndex], outAny, + Type(pMethod->pParams[i].pTypeRef), false); + pOutParam[outIndex++]= outAny; + } + else //JScriptObject + { + if( pVarParams[i].vt == VT_DISPATCH) + { + CComDispatchDriver pDisp( pVarParams[i].pdispVal); + if( pDisp) + { + CComVariant varOut; + if( SUCCEEDED( pDisp.GetPropertyByName( L"0", &varOut))) + { + variantToAny( &varOut, outAny, + Type(pMethod->pParams[parameterCount - 1 - i].pTypeRef), false); + pOutParam[outParameterCount - 1 - outIndex++]= outAny; + } + else + bConvRet= false; + } + else + bConvRet= false; + } + else + bConvRet= false; + } + } + if( !bConvRet) break; + } + } + catch(IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, int >( i ); + throw; + } + catch(CannotConvertException & e) + { + e.ArgumentIndex = i; + throw; + } + } + // return value, no type information available + if ( bConvRet) + { + try + { + if( pMethod ) + variantToAny(&varResult, ret, Type( pMethod->pReturnTypeRef), false); + else + variantToAny(&varResult, ret, false); + } + catch (IllegalArgumentException & e) + { + e.Message = + "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n" + "Could not convert return value! \n Message: \n" + e.Message; + throw; + } + catch (CannotConvertException & e) + { + e.Message = + "[automation bridge]IUnknownWrapper::invokeWithDispIdUnoTlb\n" + "Could not convert return value! \n Message: \n" + e.Message; + throw; + } + } + } + + if( !bConvRet) // conversion of return or out parameter failed + throw CannotConvertException("Call to COM object failed. Conversion of return or out value failed", + Reference( static_cast(this), UNO_QUERY ), TypeClass_UNKNOWN, + FailReason::UNKNOWN, 0);// lookup error code + // conversion of return or out parameter failed + switch (hr) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + throw IllegalArgumentException(); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException(); + break; + case DISP_E_EXCEPTION: + throw InvocationTargetException(); + break; + case DISP_E_MEMBERNOTFOUND: + throw IllegalArgumentException(); + break; + case DISP_E_NONAMEDARGS: + throw IllegalArgumentException(); + break; + case DISP_E_OVERFLOW: + throw CannotConvertException("call to OLE object failed", static_cast( + static_cast(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); + break; + case DISP_E_PARAMNOTFOUND: + throw IllegalArgumentException("call to OLE object failed", static_cast( + static_cast(this)), ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException("call to OLE object failed",static_cast( + static_cast(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException() ; + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException() ; + break; + case DISP_E_PARAMNOTOPTIONAL: + throw CannotConvertException("call to OLE object failed", static_cast( + static_cast(this)), TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); + break; + default: + throw RuntimeException(); + break; + } + + return ret; +} + + +// XInitialization +void SAL_CALL IUnknownWrapper::initialize( const Sequence< Any >& aArguments ) +{ + // 1.parameter is IUnknown + // 2.parameter is a boolean which indicates if the COM pointer was an IUnknown or IDispatch + // 3.parameter is a Sequence + o2u_attachCurrentThread(); + OSL_ASSERT(aArguments.getLength() == 3); + + m_spUnknown= *static_cast(aArguments[0].getValue()); + m_spUnknown.QueryInterface( & m_spDispatch.p); + + aArguments[1] >>= m_bOriginalDispatch; + aArguments[2] >>= m_seqTypes; + + ITypeInfo* pType = nullptr; + try + { + // a COM object implementation that has no TypeInfo is still a legal COM object; + // such objects can at least be transported through UNO using the bridge + // so we should allow to create wrappers for them as well + pType = getTypeInfo(); + } + catch( const BridgeRuntimeError& ) + {} + catch( const Exception& ) + {} + + if ( pType ) + { + try + { + // Get Default member + CComBSTR defaultMemberName; + if ( SUCCEEDED( pType->GetDocumentation(0, &defaultMemberName, nullptr, nullptr, nullptr ) ) ) + { + OUString usName(o3tl::toU(LPCOLESTR(defaultMemberName))); + FuncDesc aDescGet(pType); + FuncDesc aDescPut(pType); + VarDesc aVarDesc(pType); + // see if this is a property first ( more likely to be a property then a method ) + getPropDesc( usName, & aDescGet, & aDescPut, & aVarDesc); + + if ( !aDescGet && !aDescPut ) + { + getFuncDesc( usName, &aDescGet ); + if ( !aDescGet ) + throw BridgeRuntimeError( "[automation bridge]IUnknownWrapper::initialize() Failed to get Function or Property desc. for " + usName ); + } + // now for some funny heuristics to make basic understand what to do + // a single aDescGet ( that doesn't take any params ) would be + // a read only ( defaultmember ) property e.g. this object + // should implement XDefaultProperty + // a single aDescGet ( that *does* ) take params is basically a + // default method e.g. implement XDefaultMethod + + // a DescPut ( I guess we only really support a default param with '1' param ) as a setValue ( but I guess we can leave it through, the object will fail if we don't get it right anyway ) + if ( aDescPut || ( aDescGet && aDescGet->cParams == 0 ) ) + m_bHasDfltProperty = true; + if ( aDescGet->cParams > 0 ) + m_bHasDfltMethod = true; + if ( m_bHasDfltProperty || m_bHasDfltMethod ) + m_sDefaultMember = usName; + } + } + catch ( const BridgeRuntimeError & e ) + { + throw RuntimeException( e.message ); + } + catch( const Exception& e ) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw css::lang::WrappedTargetRuntimeException( + "[automation bridge] unexpected exception in IUnknownWrapper::initialize() error message: \n" + e.Message, + nullptr, anyEx ); + } + } +} + + +// XDirectInvocation +uno::Any SAL_CALL IUnknownWrapper::directInvoke( const OUString& aName, const uno::Sequence< uno::Any >& aParams ) +{ + Any aResult; + + if ( !m_spDispatch ) + { + throw RuntimeException( + "[automation bridge] The object does not have an IDispatch interface"); + } + + o2u_attachCurrentThread(); + DISPID dispid; + if ( !getDispid( aName, &dispid ) ) + throw IllegalArgumentException( + "[automation bridge] The object does not have a function or property " + + aName, Reference(), 0); + + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr = 0; + INVOKEKIND pInvkinds[2]; + pInvkinds[0] = INVOKE_FUNC; + pInvkinds[1] = aParams.getLength() ? INVOKE_PROPERTYPUT : INVOKE_PROPERTYGET; + HRESULT hInvRes = E_FAIL; + + // try Invoke first, if it does not work, try put/get property + for ( sal_Int32 nStep = 0; FAILED( hInvRes ) && nStep < 2; nStep++ ) + { + DISPPARAMS dispparams = {nullptr, nullptr, 0, 0}; + + std::unique_ptr arDispidNamedArgs; + std::unique_ptr ptrArgs; + std::unique_ptr ptrRefArgs; // referenced arguments + CComVariant * arArgs = nullptr; + CComVariant * arRefArgs = nullptr; + + dispparams.cArgs = aParams.getLength(); + + // Determine the number of named arguments + for ( uno::Any const & any : aParams ) + if ( any.getValueType() == cppu::UnoType::get() ) + dispparams.cNamedArgs ++; + + // fill the named arguments + if ( dispparams.cNamedArgs > 0 + && ( dispparams.cNamedArgs != 1 || pInvkinds[nStep] != INVOKE_PROPERTYPUT ) ) + { + int nSizeAr = dispparams.cNamedArgs + 1; + if ( pInvkinds[nStep] == INVOKE_PROPERTYPUT ) + nSizeAr = dispparams.cNamedArgs; + + std::unique_ptr saNames(new OLECHAR*[nSizeAr]); + OLECHAR ** pNames = saNames.get(); + pNames[0] = const_cast(o3tl::toW(aName.getStr())); + + int cNamedArg = 0; + for ( size_t nInd = 0; nInd < dispparams.cArgs; nInd++ ) + { + if (auto v = o3tl::tryAccess(aParams[nInd])) + { + const NamedArgument& arg = *v; + + //We put the parameter names in reverse order into the array, + //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs + //The first name in the array is the method name + pNames[nSizeAr - 1 - cNamedArg++] = const_cast(o3tl::toW(arg.Name.getStr())); + } + } + + arDispidNamedArgs.reset( new DISPID[nSizeAr] ); + HRESULT hr = getTypeInfo()->GetIDsOfNames( pNames, nSizeAr, arDispidNamedArgs.get() ); + if ( hr == E_NOTIMPL ) + hr = m_spDispatch->GetIDsOfNames(IID_NULL, pNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() ); + + if ( SUCCEEDED( hr ) ) + { + if ( pInvkinds[nStep] == DISPATCH_PROPERTYPUT ) + { + DISPID* arIDs = arDispidNamedArgs.get(); + arIDs[0] = DISPID_PROPERTYPUT; + dispparams.rgdispidNamedArgs = arIDs; + } + else + { + DISPID* arIDs = arDispidNamedArgs.get(); + dispparams.rgdispidNamedArgs = & arIDs[1]; + } + } + else if (hr == DISP_E_UNKNOWNNAME) + { + throw IllegalArgumentException( + "[automation bridge]One of the named arguments is wrong!", + Reference(), 0); + } + else + { + throw InvocationTargetException( + "[automation bridge] ITypeInfo::GetIDsOfNames returned error " + + OUString::number(static_cast(hr), 16), Reference(), Any()); + } + } + + //Convert arguments + ptrArgs.reset(new CComVariant[dispparams.cArgs]); + ptrRefArgs.reset(new CComVariant[dispparams.cArgs]); + arArgs = ptrArgs.get(); + arRefArgs = ptrRefArgs.get(); + + sal_Int32 nInd = 0; + try + { + sal_Int32 revIndex = 0; + for ( nInd = 0; nInd < sal_Int32(dispparams.cArgs); nInd++) + { + revIndex = dispparams.cArgs - nInd - 1; + arRefArgs[revIndex].byref = nullptr; + Any anyArg; + if ( nInd < aParams.getLength() ) + anyArg = aParams.getConstArray()[nInd]; + + // Property Put arguments + if ( anyArg.getValueType() == cppu::UnoType::get() ) + { + PropertyPutArgument arg; + anyArg >>= arg; + anyArg = arg.Value; + } + // named argument + if (anyArg.getValueType() == cppu::UnoType::get()) + { + NamedArgument aNamedArgument; + anyArg >>= aNamedArgument; + anyArg = aNamedArgument.Value; + } + + if ( nInd < aParams.getLength() && anyArg.getValueTypeClass() != TypeClass_VOID ) + { + anyToVariant( &arArgs[revIndex], anyArg, VT_VARIANT ); + } + else + { + arArgs[revIndex].vt = VT_ERROR; + arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; + } + } + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( nInd ); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = nInd; + throw; + } + + dispparams.rgvarg = arArgs; + // invoking OLE method + hInvRes = m_spDispatch->Invoke( dispid, + IID_NULL, + LOCALE_USER_DEFAULT, + ::sal::static_int_cast< WORD, INVOKEKIND >( pInvkinds[nStep] ), + &dispparams, + &varResult, + &excepinfo, + &uArgErr); + } + + // converting return value and out parameter back to UNO + if ( SUCCEEDED( hInvRes ) ) + variantToAny( &varResult, aResult, false ); + else + { + // map error codes to exceptions + OUString message; + switch ( hInvRes ) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + throw IllegalArgumentException("[automation bridge] Wrong " + "number of arguments. Object returned DISP_E_BADPARAMCOUNT.", + nullptr, 0); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException("[automation bridge] One or more " + "arguments have the wrong type. Object returned " + "DISP_E_BADVARTYPE.", nullptr); + break; + case DISP_E_EXCEPTION: + message = OUString::Concat("[automation bridge]: ") + + std::u16string_view(o3tl::toU(excepinfo.bstrDescription), + ::SysStringLen(excepinfo.bstrDescription)); + throw InvocationTargetException(message, Reference(), Any()); + break; + case DISP_E_MEMBERNOTFOUND: + message = "[automation bridge]: A function with the name \"" + + aName + "\" is not supported. Object returned " + "DISP_E_MEMBERNOTFOUND."; + throw IllegalArgumentException(message, nullptr, 0); + break; + case DISP_E_NONAMEDARGS: + throw IllegalArgumentException("[automation bridge] Object " + "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_OVERFLOW: + throw CannotConvertException("[automation bridge] Call failed.", + static_cast( + static_cast(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); + break; + case DISP_E_PARAMNOTFOUND: + throw IllegalArgumentException("[automation bridge]Call failed." + "Object returned DISP_E_PARAMNOTFOUND.", + nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException("[automation bridge] Call failed. " + "Object returned DISP_E_TYPEMISMATCH", + static_cast( + static_cast(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException("[automation bridge] Call failed. " + "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr); + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException("[automation bridge] Call failed. " + "Object returned DISP_E_UNKNOWNLCID.",nullptr); + break; + case DISP_E_PARAMNOTOPTIONAL: + throw CannotConvertException("[automation bridge] Call failed." + "Object returned DISP_E_PARAMNOTOPTIONAL", + static_cast(static_cast(this)), + TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); + break; + default: + throw RuntimeException(); + break; + } + } + + return aResult; +} + +sal_Bool SAL_CALL IUnknownWrapper::hasMember( const OUString& aName ) +{ + if ( ! m_spDispatch ) + { + throw RuntimeException( + "[automation bridge] The object does not have an IDispatch interface"); + } + + o2u_attachCurrentThread(); + DISPID dispid; + return getDispid( aName, &dispid ); +} + + +// UnoConversionUtilities -------------------------------------------------------------------------------- +Reference< XInterface > IUnknownWrapper::createUnoWrapperInstance() +{ + if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL) + { + Reference xWeak= static_cast( new InterfaceOleWrapper( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); + } + else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT) + { + Reference xWeak= static_cast( new UnoObjectWrapperRemoteOpt( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); + } + else + return Reference(); +} +Reference IUnknownWrapper::createComWrapperInstance() +{ + Reference xWeak= static_cast( new IUnknownWrapper( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); +} + + +void IUnknownWrapper::getMethodInfo(std::u16string_view sName, TypeDescription& methodInfo) +{ + TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName); + if( desc.is()) + { + typelib_TypeDescription* pMember= desc.get(); + if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_METHOD ) + methodInfo= pMember; + } +} + +void IUnknownWrapper::getAttributeInfo(std::u16string_view sName, TypeDescription& attributeInfo) +{ + TypeDescription desc= getInterfaceMemberDescOfCurrentCall(sName); + if( desc.is()) + { + typelib_TypeDescription* pMember= desc.get(); + if( pMember->eTypeClass == typelib_TypeClass_INTERFACE_ATTRIBUTE ) + { + attributeInfo= reinterpret_cast(pMember)->pAttributeTypeRef; + } + } +} +TypeDescription IUnknownWrapper::getInterfaceMemberDescOfCurrentCall(std::u16string_view sName) +{ + TypeDescription ret; + + for( auto const & rType : std::as_const(m_seqTypes) ) + { + TypeDescription _curDesc( rType ); + _curDesc.makeComplete(); + typelib_InterfaceTypeDescription * pInterface= reinterpret_cast(_curDesc.get()); + if( pInterface) + { + typelib_InterfaceMemberTypeDescription* pMember= nullptr; + //find the member description of the current call + for( int j=0; j < pInterface->nAllMembers; j++) + { + typelib_TypeDescriptionReference* pTypeRefMember = pInterface->ppAllMembers[j]; + typelib_TypeDescription* pDescMember= nullptr; + TYPELIB_DANGER_GET( &pDescMember, pTypeRefMember); + + typelib_InterfaceMemberTypeDescription* pInterfaceMember= + reinterpret_cast(pDescMember); + if( OUString( pInterfaceMember->pMemberName) == sName) + { + pMember= pInterfaceMember; + break; + } + TYPELIB_DANGER_RELEASE( pDescMember); + } + + if( pMember) + { + ret= &pMember->aBase; + TYPELIB_DANGER_RELEASE( &pMember->aBase); + } + } + if( ret.is()) + break; + } + return ret; +} + +bool IUnknownWrapper::isJScriptObject() +{ + if( m_eJScript == JScriptUndefined) + { + CComDispatchDriver disp( m_spDispatch); + if( disp) + { + CComVariant result; + if( SUCCEEDED( disp.GetPropertyByName( JSCRIPT_ID_PROPERTY, &result))) + { + if(result.vt == VT_BSTR) + { + CComBSTR name( result.bstrVal); + name.ToLower(); + if( name == CComBSTR(JSCRIPT_ID)) + m_eJScript= IsJScript; + } + } + } + if( m_eJScript == JScriptUndefined) + m_eJScript= NoJScript; + } + + return m_eJScript != NoJScript; +} + + +/** @internal + The function ultimately calls IDispatch::Invoke on the wrapped COM object. + The COM object does not implement UNO Interfaces ( via IDispatch). This + is the case when the OleObjectFactory service has been used to create a + component. + @exception IllegalArgumentException + @exception CannotConvertException + @InvocationTargetException + @RuntimeException + @BridgeRuntimeError +*/ +Any IUnknownWrapper::invokeWithDispIdComTlb(const OUString& sFuncName, + const Sequence< Any >& Params, + Sequence< sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam) +{ + // Get type info for the call. It can be a method call or property put or + // property get operation. + FuncDesc aFuncDesc(getTypeInfo()); + getFuncDescForInvoke(sFuncName, Params, & aFuncDesc); + return invokeWithDispIdComTlb( aFuncDesc, sFuncName, Params, OutParamIndex, OutParam ); +} + +Any IUnknownWrapper::invokeWithDispIdComTlb(FuncDesc& aFuncDesc, + const OUString& sFuncName, + const Sequence< Any >& Params, + Sequence< sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam) +{ + Any ret; + HRESULT result; + + DISPPARAMS dispparams = {nullptr, nullptr, 0, 0}; + CComVariant varResult; + ExcepInfo excepinfo; + unsigned int uArgErr; + sal_Int32 i = 0; + sal_Int32 nUnoArgs = Params.getLength(); + DISPID idPropertyPut = DISPID_PROPERTYPUT; + std::unique_ptr arDispidNamedArgs; + std::unique_ptr ptrArgs; + std::unique_ptr ptrRefArgs; // referenced arguments + CComVariant * arArgs = nullptr; + CComVariant * arRefArgs = nullptr; + sal_Int32 revIndex = 0; + + //Set the array of DISPIDs for named args if it is a property put operation. + //If there are other named arguments another array is set later on. + if (aFuncDesc->invkind == INVOKE_PROPERTYPUT + || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF) + dispparams.rgdispidNamedArgs = & idPropertyPut; + + //Determine the number of named arguments + for (int iParam = 0; iParam < nUnoArgs; iParam ++) + { + const Any & curArg = Params[iParam]; + if (curArg.getValueType() == cppu::UnoType::get()) + dispparams.cNamedArgs ++; + } + //In a property put operation a property value is a named argument (DISPID_PROPERTYPUT). + //Therefore the number of named arguments is increased by one. + //Although named, the argument is not named in an actual language, such as Basic, + //therefore it is never a com.sun.star.bridge.oleautomation.NamedArgument + if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT + || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF) + dispparams.cNamedArgs ++; + + //Determine the number of all arguments and named arguments + if (aFuncDesc->cParamsOpt == -1) + { + //Attribute vararg is set on this method. "Unlimited" number of args + //supported. There can be no optional or defaultvalue on any of the arguments. + dispparams.cArgs = nUnoArgs; + } + else + { + //If there are named arguments, then the dispparams.cArgs + //is the number of supplied args, otherwise it is the expected number. + if (dispparams.cNamedArgs) + dispparams.cArgs = nUnoArgs; + else + dispparams.cArgs = aFuncDesc->cParams; + } + + //check if there are not too many arguments supplied + if (::sal::static_int_cast< sal_uInt32, int >( nUnoArgs ) > dispparams.cArgs) + { + throw IllegalArgumentException( + "[automation bridge] There are too many arguments for this method", + Reference(), static_cast(dispparams.cArgs)); + } + + //Set up the array of DISPIDs (DISPPARAMS::rgdispidNamedArgs) + //for the named arguments. + //If there is only one named arg and if it is because of a property put + //operation, then we need not set up the DISPID array. + if (dispparams.cNamedArgs > 0 && + ! (dispparams.cNamedArgs == 1 && + (aFuncDesc->invkind == INVOKE_PROPERTYPUT || + aFuncDesc->invkind == INVOKE_PROPERTYPUTREF))) + { + //set up an array containing the member and parameter names + //which is then used in ITypeInfo::GetIDsOfNames + //First determine the size of the array of names which is passed to + //ITypeInfo::GetIDsOfNames. It must hold the method names + the named + //args. + int nSizeAr = dispparams.cNamedArgs + 1; + if (aFuncDesc->invkind == INVOKE_PROPERTYPUT + || aFuncDesc->invkind == INVOKE_PROPERTYPUTREF) + { + nSizeAr = dispparams.cNamedArgs; //counts the DISID_PROPERTYPUT + } + + std::unique_ptr saNames(new OLECHAR*[nSizeAr]); + OLECHAR ** arNames = saNames.get(); + arNames[0] = const_cast(o3tl::toW(sFuncName.getStr())); + + int cNamedArg = 0; + for (size_t iParams = 0; iParams < dispparams.cArgs; iParams ++) + { + const Any & curArg = Params[iParams]; + if (auto v = o3tl::tryAccess(curArg)) + { + const NamedArgument& arg = *v; + //We put the parameter names in reverse order into the array, + //so we can use the DISPID array for DISPPARAMS::rgdispidNamedArgs + //The first name in the array is the method name + arNames[nSizeAr - 1 - cNamedArg++] = const_cast(o3tl::toW(arg.Name.getStr())); + } + } + + //Prepare the array of DISPIDs for ITypeInfo::GetIDsOfNames + //it must be big enough to contain the DISPIDs of the member + parameters + arDispidNamedArgs.reset(new DISPID[nSizeAr]); + HRESULT hr = getTypeInfo()->GetIDsOfNames(arNames, nSizeAr, + arDispidNamedArgs.get()); + if ( hr == E_NOTIMPL ) + hr = m_spDispatch->GetIDsOfNames(IID_NULL, arNames, nSizeAr, LOCALE_USER_DEFAULT, arDispidNamedArgs.get() ); + + if (hr == S_OK) + { + // In a "property put" operation, the property value is a named param with the + //special DISPID DISPID_PROPERTYPUT + if (aFuncDesc->invkind == DISPATCH_PROPERTYPUT + || aFuncDesc->invkind == DISPATCH_PROPERTYPUTREF) + { + //Element at index 0 in the DISPID array must be DISPID_PROPERTYPUT + //The first item in the array arDispidNamedArgs is the DISPID for + //the method. We replace it with DISPID_PROPERTYPUT. + DISPID* arIDs = arDispidNamedArgs.get(); + arIDs[0] = DISPID_PROPERTYPUT; + dispparams.rgdispidNamedArgs = arIDs; + } + else + { + //The first item in the array arDispidNamedArgs is the DISPID for + //the method. It must be removed + DISPID* arIDs = arDispidNamedArgs.get(); + dispparams.rgdispidNamedArgs = & arIDs[1]; + } + } + else if (hr == DISP_E_UNKNOWNNAME) + { + throw IllegalArgumentException( + "[automation bridge]One of the named arguments is wrong!", + Reference(), 0); + } + else + { + throw InvocationTargetException( + "[automation bridge] ITypeInfo::GetIDsOfNames returned error " + + OUString::number(static_cast(hr), 16), Reference(), Any()); + } + } + + //Convert arguments + ptrArgs.reset(new CComVariant[dispparams.cArgs]); + ptrRefArgs.reset(new CComVariant[dispparams.cArgs]); + arArgs = ptrArgs.get(); + arRefArgs = ptrRefArgs.get(); + try + { + for (i = 0; i < static_cast(dispparams.cArgs); i++) + { + revIndex= dispparams.cArgs - i -1; + arRefArgs[revIndex].byref=nullptr; + Any anyArg; + if ( i < nUnoArgs) + anyArg= Params.getConstArray()[i]; + + unsigned short paramFlags = PARAMFLAG_FOPT | PARAMFLAG_FIN; + VARTYPE varType = VT_VARIANT; + if (aFuncDesc->cParamsOpt != -1 || aFuncDesc->cParams != (i + 1)) + { + paramFlags = aFuncDesc->lprgelemdescParam[i].paramdesc.wParamFlags; + varType = getElementTypeDesc(&aFuncDesc->lprgelemdescParam[i].tdesc); + } + + // Make sure that there is a UNO parameter for every + // expected parameter. If there is no UNO parameter where the + // called function expects one, then it must be optional. Otherwise + // it's a UNO programming error. + if (i >= nUnoArgs && !(paramFlags & PARAMFLAG_FOPT)) + { + throw IllegalArgumentException( + ("ole automation bridge: The called function expects an argument at position: " + + OUString::number(i) + " (index starting at 0)."), + Reference(), static_cast(i)); + } + + // Property Put arguments + if (anyArg.getValueType() == cppu::UnoType::get()) + { + PropertyPutArgument arg; + anyArg >>= arg; + anyArg = arg.Value; + } + // named argument + if (anyArg.getValueType() == cppu::UnoType::get()) + { + NamedArgument aNamedArgument; + anyArg >>= aNamedArgument; + anyArg = aNamedArgument.Value; + } + // out param + if (paramFlags & PARAMFLAG_FOUT && + ! (paramFlags & PARAMFLAG_FIN) ) + { + VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF ); + if (i < nUnoArgs) + { + arRefArgs[revIndex].vt= type; + } + else + { + //optional arg + arRefArgs[revIndex].vt = VT_ERROR; + arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; + } + if( type == VT_VARIANT ) + { + arArgs[revIndex].vt= VT_VARIANT | VT_BYREF; + arArgs[revIndex].byref= &arRefArgs[revIndex]; + } + else + { + arArgs[revIndex].vt= varType; + if (type == VT_DECIMAL) + arArgs[revIndex].byref= & arRefArgs[revIndex].decVal; + else + arArgs[revIndex].byref= & arRefArgs[revIndex].byref; + } + } + // in/out + in byref params + else if (varType & VT_BYREF) + { + VARTYPE type = ::sal::static_int_cast< VARTYPE, int >( varType ^ VT_BYREF ); + CComVariant var; + + if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID) + { + anyToVariant( & arRefArgs[revIndex], anyArg, type); + } + else if (paramFlags & PARAMFLAG_FHASDEFAULT) + { + //optional arg with default + VariantCopy( & arRefArgs[revIndex], + & aFuncDesc->lprgelemdescParam[i].paramdesc. + pparamdescex->varDefaultValue); + } + else + { + //optional arg + //e.g: call func(x) in basic : func() ' no arg supplied + OSL_ASSERT(paramFlags & PARAMFLAG_FOPT); + arRefArgs[revIndex].vt = VT_ERROR; + arRefArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; + } + + // Set the converted arguments in the array which will be + // DISPPARAMS::rgvarg + // byref arg VT_XXX |VT_BYREF + arArgs[revIndex].vt = varType; + if (revIndex == 0 && aFuncDesc->invkind == INVOKE_PROPERTYPUT) + { + arArgs[revIndex] = arRefArgs[revIndex]; + } + else if (type == VT_DECIMAL) + { + arArgs[revIndex].byref= & arRefArgs[revIndex].decVal; + } + else if (type == VT_VARIANT) + { + if ( ! (paramFlags & PARAMFLAG_FOUT)) + arArgs[revIndex] = arRefArgs[revIndex]; + else + arArgs[revIndex].byref = & arRefArgs[revIndex]; + } + else + { + arArgs[revIndex].byref = & arRefArgs[revIndex].byref; + arArgs[revIndex].vt = ::sal::static_int_cast< VARTYPE, int >( arRefArgs[revIndex].vt | VT_BYREF ); + } + + } + // in parameter no VT_BYREF except for array, interfaces + else + { // void any stands for optional param + if (i < nUnoArgs && anyArg.getValueTypeClass() != TypeClass_VOID) + { + anyToVariant( & arArgs[revIndex], anyArg, varType); + } + //optional arg but no void any supplied + //Basic: obj.func() ' first parameter left out because it is optional + else if (paramFlags & PARAMFLAG_FHASDEFAULT) + { + //optional arg with default either as direct arg : VT_XXX or + VariantCopy( & arArgs[revIndex], + & aFuncDesc->lprgelemdescParam[i].paramdesc. + pparamdescex->varDefaultValue); + } + else if (paramFlags & PARAMFLAG_FOPT) + { + arArgs[revIndex].vt = VT_ERROR; + arArgs[revIndex].scode = DISP_E_PARAMNOTFOUND; + } + else + { + arArgs[revIndex].vt = VT_EMPTY; + arArgs[revIndex].lVal = 0; + } + } + } + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = ::sal::static_int_cast< sal_Int16, sal_Int32 >( i ); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = i; + throw; + } + dispparams.rgvarg= arArgs; + // invoking OLE method + result = m_spDispatch->Invoke(aFuncDesc->memid, + IID_NULL, + LOCALE_USER_DEFAULT, + ::sal::static_int_cast< WORD, INVOKEKIND >( aFuncDesc->invkind ), + &dispparams, + &varResult, + &excepinfo, + &uArgErr); + + // converting return value and out parameter back to UNO + if (result == S_OK) + { + + // allocate space for the out param Sequence and indices Sequence + int outParamsCount= 0; // includes in/out parameter + for (int j = 0; j < aFuncDesc->cParams; j++) + { + if (aFuncDesc->lprgelemdescParam[j].paramdesc.wParamFlags & + PARAMFLAG_FOUT) + outParamsCount++; + } + + OutParamIndex.realloc(outParamsCount); + OutParam.realloc(outParamsCount); + // Convert out params + if (outParamsCount) + { + auto pOutParamIndex = OutParamIndex.getArray(); + auto pOutParam = OutParam.getArray(); + int outParamIndex=0; + for (int paramIndex = 0; paramIndex < nUnoArgs; paramIndex ++) + { + //Determine the index within the method signature + int realParamIndex = paramIndex; + int revParamIndex = dispparams.cArgs - paramIndex - 1; + if (Params[paramIndex].getValueType() + == cppu::UnoType::get()) + { + //dispparams.rgdispidNamedArgs contains the mapping from index + //of named args list to index of parameter list + realParamIndex = dispparams.rgdispidNamedArgs[revParamIndex]; + } + + // no named arg, always come before named args + if (! (aFuncDesc->lprgelemdescParam[realParamIndex].paramdesc.wParamFlags + & PARAMFLAG_FOUT)) + continue; + Any outAny; + // variantToAny is called with the "reduce range" parameter set to sal_False. + // That causes VT_I4 values not to be converted down to a "lower" type. That + // feature exist for JScript only because it only uses VT_I4 for integer types. + try + { + variantToAny( & arRefArgs[revParamIndex], outAny, false ); + } + catch (IllegalArgumentException & e) + { + e.ArgumentPosition = static_cast(paramIndex); + throw; + } + catch (CannotConvertException & e) + { + e.ArgumentIndex = paramIndex; + throw; + } + pOutParam[outParamIndex] = outAny; + pOutParamIndex[outParamIndex] = ::sal::static_int_cast< sal_Int16, int >( paramIndex ); + outParamIndex++; + } + OutParam.realloc(outParamIndex); + OutParamIndex.realloc(outParamIndex); + } + // Return value + variantToAny(&varResult, ret, false); + } + + // map error codes to exceptions + OUString message; + switch (result) + { + case S_OK: + break; + case DISP_E_BADPARAMCOUNT: + throw IllegalArgumentException("[automation bridge] Wrong " + "number of arguments. Object returned DISP_E_BADPARAMCOUNT.", + nullptr, 0); + break; + case DISP_E_BADVARTYPE: + throw RuntimeException("[automation bridge] One or more " + "arguments have the wrong type. Object returned " + "DISP_E_BADVARTYPE.", nullptr); + break; + case DISP_E_EXCEPTION: + message = OUString::Concat("[automation bridge]: ") + + std::u16string_view(o3tl::toU(excepinfo.bstrDescription), + ::SysStringLen(excepinfo.bstrDescription)); + + throw InvocationTargetException(message, Reference(), Any()); + break; + case DISP_E_MEMBERNOTFOUND: + message = "[automation bridge]: A function with the name \"" + + sFuncName + "\" is not supported. Object returned " + "DISP_E_MEMBERNOTFOUND."; + throw IllegalArgumentException(message, nullptr, 0); + break; + case DISP_E_NONAMEDARGS: + throw IllegalArgumentException("[automation bridge] Object " + "returned DISP_E_NONAMEDARGS",nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_OVERFLOW: + throw CannotConvertException("[automation bridge] Call failed.", + static_cast( + static_cast(this)), TypeClass_UNKNOWN, FailReason::OUT_OF_RANGE, uArgErr); + break; + case DISP_E_PARAMNOTFOUND: + throw IllegalArgumentException("[automation bridge]Call failed." + "Object returned DISP_E_PARAMNOTFOUND.", + nullptr, ::sal::static_int_cast< sal_Int16, unsigned int >( uArgErr )); + break; + case DISP_E_TYPEMISMATCH: + throw CannotConvertException("[automation bridge] Call failed. " + "Object returned DISP_E_TYPEMISMATCH", + static_cast( + static_cast(this)) , TypeClass_UNKNOWN, FailReason::UNKNOWN, uArgErr); + break; + case DISP_E_UNKNOWNINTERFACE: + throw RuntimeException("[automation bridge] Call failed. " + "Object returned DISP_E_UNKNOWNINTERFACE.",nullptr); + break; + case DISP_E_UNKNOWNLCID: + throw RuntimeException("[automation bridge] Call failed. " + "Object returned DISP_E_UNKNOWNLCID.",nullptr); + break; + case DISP_E_PARAMNOTOPTIONAL: + throw CannotConvertException("[automation bridge] Call failed." + "Object returned DISP_E_PARAMNOTOPTIONAL", + static_cast(static_cast(this)), + TypeClass_UNKNOWN, FailReason::NO_DEFAULT_AVAILABLE, uArgErr); + break; + default: + throw RuntimeException(); + break; + } + + return ret; +} + +void IUnknownWrapper::getFuncDescForInvoke(const OUString & sFuncName, + const Sequence & seqArgs, + FUNCDESC** pFuncDesc) +{ + int nUnoArgs = seqArgs.getLength(); + const Any * arArgs = seqArgs.getConstArray(); + ITypeInfo* pInfo = getTypeInfo(); + + //If the last of the positional arguments is a PropertyPutArgument + //then obtain the type info for the property put operation. + + //The property value is always the last argument, in a positional argument list + //or in a list of named arguments. A PropertyPutArgument is actually a named argument + //hence it must not be put in an extra NamedArgument structure + if (nUnoArgs > 0 && + arArgs[nUnoArgs - 1].getValueType() == cppu::UnoType::get()) + { + // DISPATCH_PROPERTYPUT + FuncDesc aDescGet(pInfo); + FuncDesc aDescPut(pInfo); + VarDesc aVarDesc(pInfo); + getPropDesc(sFuncName, & aDescGet, & aDescPut, & aVarDesc); + if ( ! aDescPut) + { + throw IllegalArgumentException( + "[automation bridge] The object does not have a writeable property: " + + sFuncName, Reference(), 0); + } + *pFuncDesc = aDescPut.Detach(); + } + else + { // DISPATCH_METHOD + FuncDesc aFuncDesc(pInfo); + getFuncDesc(sFuncName, & aFuncDesc); + if ( ! aFuncDesc) + { + // Fallback: DISPATCH_PROPERTYGET can mostly be called as + // DISPATCH_METHOD + ITypeInfo * pTypeInfo = getTypeInfo(); + FuncDesc aDescPut(pTypeInfo); + VarDesc aVarDesc(pTypeInfo); + getPropDesc(sFuncName, & aFuncDesc, & aDescPut, & aVarDesc); + if ( ! aFuncDesc ) + { + throw IllegalArgumentException( + "[automation bridge] The object does not have a function" + " or readable property \"" + + sFuncName + "\"", Reference(), 0); + } + } + *pFuncDesc = aFuncDesc.Detach(); + } +} +bool IUnknownWrapper::getDispid(const OUString& sFuncName, DISPID * id) +{ + OSL_ASSERT(m_spDispatch); + LPOLESTR lpsz = const_cast (o3tl::toW(sFuncName.getStr())); + HRESULT hr = m_spDispatch->GetIDsOfNames(IID_NULL, &lpsz, 1, LOCALE_USER_DEFAULT, id); + return hr == S_OK; +} +void IUnknownWrapper::getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc) + +{ + OSL_ASSERT( * pFuncDesc == nullptr); + buildComTlbIndex(); + typedef TLBFuncIndexMap::const_iterator cit; + //We assume there is only one entry with the function name. A property + //would have two entries. + cit itIndex= m_mapComFunc.find(sFuncName); + if (itIndex == m_mapComFunc.end()) + { + //try case insensitive with IDispatch::GetIDsOfNames + DISPID id; + if (getDispid(sFuncName, &id)) + { + CComBSTR memberName; + unsigned int pcNames=0; + // get the case sensitive name + if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames))) + { + //get the associated index and add an entry to the map + //with the name sFuncName which differs in the casing of the letters to + //the actual name as obtained from ITypeInfo + OUString sRealName(o3tl::toU(LPCOLESTR(memberName))); + cit itOrg = m_mapComFunc.find(sRealName); + OSL_ASSERT(itOrg != m_mapComFunc.end()); + // maybe this is a property, if so we need + // to store either both id's ( put/get ) or + // just the get. Storing both is more consistent + std::pair pItems = m_mapComFunc.equal_range( sRealName ); + for ( ;pItems.first != pItems.second; ++pItems.first ) + m_mapComFunc.insert( TLBFuncIndexMap::value_type ( std::make_pair(sFuncName, pItems.first->second ) )); + itIndex = + m_mapComFunc.find( sFuncName ); + } + } + } + +#if OSL_DEBUG_LEVEL >= 1 + // There must only be one entry if sFuncName represents a function or two + // if it is a property + std::pair p = m_mapComFunc.equal_range(sFuncName.toAsciiLowerCase()); + int numEntries = 0; + for ( ;p.first != p.second; p.first ++, numEntries ++); + OSL_ASSERT( ! (numEntries > 3) ); +#endif + if( itIndex != m_mapComFunc.end()) + { + ITypeInfo* pType= getTypeInfo(); + FUNCDESC * pDesc = nullptr; + if (!SUCCEEDED(pType->GetFuncDesc(itIndex->second, & pDesc))) + { + throw BridgeRuntimeError("[automation bridge] Could not get " + "FUNCDESC for " + sFuncName); + } + if (pDesc->invkind == INVOKE_FUNC) + { + (*pFuncDesc) = pDesc; + } + else + { + pType->ReleaseFuncDesc(pDesc); + } + } + //else no entry found for sFuncName, pFuncDesc will not be filled in +} + +void IUnknownWrapper::getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet, + FUNCDESC** pFuncDescPut, VARDESC** pVarDesc) +{ + OSL_ASSERT( * pFuncDescGet == nullptr && * pFuncDescPut == nullptr); + buildComTlbIndex(); + typedef TLBFuncIndexMap::const_iterator cit; + std::pair p = m_mapComFunc.equal_range(sFuncName); + if (p.first == m_mapComFunc.end()) + { + //try case insensitive with IDispatch::GetIDsOfNames + DISPID id; + if (getDispid(sFuncName, &id)) + { + CComBSTR memberName; + unsigned int pcNames=0; + // get the case sensitive name + if( SUCCEEDED(getTypeInfo()->GetNames( id, & memberName, 1, &pcNames))) + { + //As opposed to getFuncDesc, we do not add the value because we would + // need to find the get and set description for the property. This would + //mean to iterate over all FUNCDESCs again. + p = m_mapComFunc.equal_range(OUString(o3tl::toU(LPCOLESTR(memberName)))); + } + } + } + + for ( int i = 0 ;p.first != p.second; p.first ++, i ++) + { + // There are a maximum of two entries, property put and property get + OSL_ASSERT( ! (i > 2) ); + ITypeInfo* pType= getTypeInfo(); + FUNCDESC * pFuncDesc = nullptr; + if (SUCCEEDED( pType->GetFuncDesc(p.first->second, & pFuncDesc))) + { + if (pFuncDesc->invkind == INVOKE_PROPERTYGET) + { + (*pFuncDescGet) = pFuncDesc; + } + else if (pFuncDesc->invkind == INVOKE_PROPERTYPUT || + pFuncDesc->invkind == INVOKE_PROPERTYPUTREF) + { + //a property can have 3 entries, put, put ref, get + // If INVOKE_PROPERTYPUTREF or INVOKE_PROPERTYPUT is used + //depends on what is found first. + if ( * pFuncDescPut) + { + //we already have found one + pType->ReleaseFuncDesc(pFuncDesc); + } + else + { + (*pFuncDescPut) = pFuncDesc; + } + } + else + { + pType->ReleaseFuncDesc(pFuncDesc); + } + } + //ITypeInfo::GetFuncDesc may even provide a funcdesc for a VARDESC + // with invkind = INVOKE_FUNC. Since this function should only return + //a value for a real property (XInvokation::hasMethod, ..::hasProperty + //we need to make sure that sFuncName represents a real property. + VARDESC * pVD = nullptr; + if (SUCCEEDED(pType->GetVarDesc(p.first->second, & pVD))) + (*pVarDesc) = pVD; + } + //else no entry for sFuncName, pFuncDesc will not be filled in +} + +VARTYPE IUnknownWrapper::getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType ) +{ + VARTYPE _type( VT_NULL ); + if ( pTypeInfo ) + { + CComPtr spRefInfo; + pTypeInfo->GetRefTypeInfo( nHrefType, &spRefInfo.p ); + if ( spRefInfo ) + { + TypeAttr attr( spRefInfo ); + spRefInfo->GetTypeAttr( &attr ); + if ( attr->typekind == TKIND_ENUM ) + { + // We use the type of the first enum value. + if ( attr->cVars == 0 ) + { + throw BridgeRuntimeError("[automation bridge] Could not obtain type description"); + } + VarDesc var( spRefInfo ); + spRefInfo->GetVarDesc( 0, &var ); + _type = var->lpvarValue->vt; + } + else if ( attr->typekind == TKIND_INTERFACE ) + { + _type = VT_UNKNOWN; + } + else if ( attr->typekind == TKIND_DISPATCH ) + { + _type = VT_DISPATCH; + } + else if ( attr->typekind == TKIND_ALIAS ) + { + // TKIND_ALIAS is a type that is an alias for another type. So get that alias type. + _type = getUserDefinedElementType( pTypeInfo, attr->tdescAlias.hreftype ); + } + else + { + throw BridgeRuntimeError( "[automation bridge] Unhandled user defined type." ); + } + } + } + return _type; +} + +VARTYPE IUnknownWrapper::getElementTypeDesc(const TYPEDESC *desc) +{ + VARTYPE _type( VT_NULL ); + + if (desc->vt == VT_PTR) + { + _type = getElementTypeDesc(desc->lptdesc); + _type |= VT_BYREF; + } + else if (desc->vt == VT_SAFEARRAY) + { + _type = getElementTypeDesc(desc->lptdesc); + _type |= VT_ARRAY; + } + else if (desc->vt == VT_USERDEFINED) + { + ITypeInfo* thisInfo = getTypeInfo(); //kept by this instance + _type = getUserDefinedElementType( thisInfo, desc->hreftype ); + } + else + { + _type = desc->vt; + } + return _type; +} + +void IUnknownWrapper::buildComTlbIndex() +{ + if ( ! m_bComTlbIndexInit) + { + MutexGuard guard(getBridgeMutex()); + { + if ( ! m_bComTlbIndexInit) + { + OUString sError; + ITypeInfo* pType= getTypeInfo(); + TypeAttr typeAttr(pType); + if( SUCCEEDED( pType->GetTypeAttr( &typeAttr))) + { + for( WORD i= 0; i < typeAttr->cFuncs; i++) + { + FuncDesc funcDesc(pType); + if( SUCCEEDED( pType->GetFuncDesc( i, &funcDesc))) + { + CComBSTR memberName; + unsigned int pcNames=0; + if( SUCCEEDED(pType->GetNames( funcDesc->memid, & memberName, 1, &pcNames))) + { + OUString usName(o3tl::toU(LPCOLESTR(memberName))); + m_mapComFunc.emplace(usName, i); + } + else + { + sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " + "ITypeInfo::GetNames failed."; + } + } + else + sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " + "ITypeInfo::GetFuncDesc failed."; + } + + //If we create an Object in JScript and a property then it + //has VARDESC instead of FUNCDESC + for (WORD i = 0; i < typeAttr->cVars; i++) + { + VarDesc varDesc(pType); + if (SUCCEEDED(pType->GetVarDesc(i, & varDesc))) + { + CComBSTR memberName; + unsigned int pcNames = 0; + if (SUCCEEDED(pType->GetNames(varDesc->memid, & memberName, 1, &pcNames))) + { + if (varDesc->varkind == VAR_DISPATCH) + { + OUString usName(o3tl::toU(LPCOLESTR(memberName))); + m_mapComFunc.emplace(usName, i); + } + } + else + { + sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " + "ITypeInfo::GetNames failed."; + } + } + else + sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " + "ITypeInfo::GetVarDesc failed."; + + } + } + else + sError = "[automation bridge] IUnknownWrapper::buildComTlbIndex, " + "ITypeInfo::GetTypeAttr failed."; + + if (sError.getLength()) + { + throw BridgeRuntimeError(sError); + } + + m_bComTlbIndexInit = true; + } + } + } +} + +ITypeInfo* IUnknownWrapper::getTypeInfo() +{ + if( !m_spDispatch) + { + throw BridgeRuntimeError("The object has no IDispatch interface!"); + } + + if( !m_spTypeInfo ) + { + MutexGuard guard(getBridgeMutex()); + if( ! m_spTypeInfo) + { + CComPtr< ITypeInfo > spType; + if( !SUCCEEDED( m_spDispatch->GetTypeInfo( 0, LOCALE_USER_DEFAULT, &spType.p))) + { + throw BridgeRuntimeError("[automation bridge]The dispatch object does not " + "support ITypeInfo!"); + } + + OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER(); + + //If this is a dual interface then TYPEATTR::typekind is usually TKIND_INTERFACE + //We need to get the type description for TKIND_DISPATCH + TypeAttr typeAttr(spType.p); + if( SUCCEEDED(spType->GetTypeAttr( &typeAttr))) + { + if (typeAttr->typekind == TKIND_INTERFACE && + typeAttr->wTypeFlags & TYPEFLAG_FDUAL) + { + HREFTYPE refDispatch; + if (!SUCCEEDED(spType->GetRefTypeOfImplType(::sal::static_int_cast< UINT, int >( -1 ), &refDispatch))) + { + throw BridgeRuntimeError( + "[automation bridge] Could not obtain type information " + "for dispatch interface." ); + } + CComPtr spTypeDisp; + if (SUCCEEDED(spType->GetRefTypeInfo(refDispatch, & spTypeDisp))) + m_spTypeInfo= spTypeDisp; + } + else if (typeAttr->typekind == TKIND_DISPATCH) + { + m_spTypeInfo= spType; + } + else + { + throw BridgeRuntimeError( + "[automation bridge] Automation object does not " + "provide type information."); + } + } + } + } + return m_spTypeInfo; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/oleobjw.hxx b/extensions/source/ole/oleobjw.hxx new file mode 100644 index 000000000..d1a1d0ed8 --- /dev/null +++ b/extensions/source/ole/oleobjw.hxx @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "ole2uno.hxx" +#include "wincrap.hxx" + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "unoconversionutilities.hxx" +#include "windata.hxx" +using namespace cppu; +using namespace com::sun::star::lang; +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::oleautomation; + +typedef std::unordered_map> DispIdMap; + +typedef std::unordered_multimap TLBFuncIndexMap; + +// This class wraps an IDispatch and maps XInvocation calls to IDispatch calls on the wrapped object. +// If m_TypeDescription is set then this class represents a UNO interface implemented in a COM component. +// The interface is not a real interface in terms of an abstract class but is realized through IDispatch. +class IUnknownWrapper : public WeakImplHelper< XBridgeSupplier2, XInitialization, XAutomationObject, XDefaultProperty, XDefaultMethod, XDirectInvocation, XAutomationInvocation >, + + public UnoConversionUtilities + +{ +public: + IUnknownWrapper(Reference const &xFactory, + sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass); + + ~IUnknownWrapper() override; + + //XInterface + Any SAL_CALL queryInterface(const Type& t) override; + + // XInvokation + virtual Reference< XIntrospectionAccess > SAL_CALL getIntrospection( ) override; + virtual Any SAL_CALL invoke( const OUString& aFunctionName, + const Sequence< Any >& aParams, + Sequence< sal_Int16 >& aOutParamIndex, + Sequence< Any >& aOutParam ) override; + virtual void SAL_CALL setValue( const OUString& aPropertyName, + const Any& aValue ) override; + virtual Any SAL_CALL getValue( const OUString& aPropertyName ) override; + virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) override; + virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) override; + + // XBridgeSupplier2 + // This interface is implemented to provide a safe way to obtain the original + // IUnknown or IDispatch within the function anyToVariant. The function asks + // every UNO object for its XBridgeSupplier2 and if it is available uses it to convert + // the object with its own supplier. + virtual Any SAL_CALL createBridge( const Any& modelDepObject, + const Sequence< sal_Int8 >& aProcessId, + sal_Int16 sourceModelType, + sal_Int16 destModelType ) override; + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XDefaultProperty + virtual OUString SAL_CALL getDefaultPropertyName( ) override { return m_sDefaultMember; } + + // XDefaultMethod + virtual OUString SAL_CALL getDefaultMethodName( ) override { return m_sDefaultMember; } + + virtual css::uno::Any SAL_CALL invokeGetProperty( const OUString& aFunctionName, const css::uno::Sequence< css::uno::Any >& aParams, css::uno::Sequence< ::sal_Int16 >& aOutParamIndex, css::uno::Sequence< css::uno::Any >& aOutParam ) override; + virtual css::uno::Any SAL_CALL invokePutProperty( const OUString& aFunctionName, const css::uno::Sequence< css::uno::Any >& aParams, css::uno::Sequence< ::sal_Int16 >& aOutParamIndex, css::uno::Sequence< css::uno::Any >& aOutParam ) override; + + // XDirectInvocation + virtual css::uno::Any SAL_CALL directInvoke( const OUString& aName, const css::uno::Sequence< css::uno::Any >& aParams ) override; + virtual sal_Bool SAL_CALL hasMember( const OUString& aName ) override; + + + Any invokeWithDispIdComTlb(FuncDesc& aFuncDesc, + const OUString& sFuncName, + const Sequence< Any >& Params, + Sequence< sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam); + + +protected: + + virtual Any invokeWithDispIdUnoTlb(const OUString& sFunctionName, + const Sequence< Any >& Params, + Sequence& OutParamIndex, + Sequence< Any >& OutParam); + // Is used for OleObjectFactory service + virtual Any invokeWithDispIdComTlb(const OUString& sFuncName, + const Sequence< Any >& Params, + Sequence< sal_Int16 >& OutParamIndex, + Sequence< Any >& OutParam); + + // UnoConversionUtilities ------------------------------------------------------------------------------- + virtual Reference createUnoWrapperInstance() override; + virtual Reference createComWrapperInstance() override; + + /**Obtains a FUNCDESC structure for a function. + Fills the FUNCDESC structure if ITypeInfo provides information for + the function of name sFuncName or pFuncDesc will not be filled in. + May throw a BridgeRuntimeError. + */ + void getFuncDesc(const OUString & sFuncName, FUNCDESC ** pFuncDesc); + /**Obtains a FUNCDESC structures or a VARDESC structure + for a property. pFuncDescPut may also contain + a structure for a "propertyputref" operation. If pFuncDesc contains a + "put ref" or "put" FUNCDESC depends on what was found first in the type + description. + Fills the FUNCDESC structure if ITypeInfo provides information for + the respective property functions or the structures will not be filled in. + May throw a BridgeRuntimeError. + */ + void getPropDesc(const OUString & sFuncName, FUNCDESC ** pFuncDescGet, + FUNCDESC** pFuncDescPut, VARDESC ** pVarDesc); + // These functions are for the case if an object of this class wraps an IDispatch + // object that implements UNO interfaces. In that case the member m_seqTypes + // is set through XInitialization::initialize. + void getMethodInfo(std::u16string_view sName, TypeDescription& methodDescription); + // After return attributInfo contains typelib_InterfaceAttributeTypeDescription::pAttributeTypeRef + void getAttributeInfo(std::u16string_view sName, TypeDescription& attributeInfo); + // used by get MethodInfo + TypeDescription getInterfaceMemberDescOfCurrentCall(std::u16string_view sName); + /** Returns always a valid ITypeInfo interface or throws a BridgeRuntimeError. + The returned interface does not need to be AddRef'ed as long as it is locally + used. The interface is kept in the instance of this class. + */ + ITypeInfo* getTypeInfo(); + + /** Returns the DISPID for a function or property name. If true is returned then + id contains a valid DISPID. + */ + + bool getDispid(const OUString& sFuncName, DISPID * id); + + VARTYPE getUserDefinedElementType( ITypeInfo* pTypeInfo, const DWORD nHrefType ); + + /** Gets the element type in a VARIANT like style. E.g. if desc->lptdesc contains + a VT_PTR than it is replaced by VT_BYREF and VT_SAFEARRAY is replaced by VT_ARRAY + If the TYPEDESC describes an SAFEARRAY then varType is a combination of VT_ARRAY + and the element type. + The argument desc must be obtained from FUNCDESC::lprgelemdescParam[i].tdesc where + FUNCDESC was obtained from the ITypeInfo belonging to wrapped IDispatch. + */ + VARTYPE getElementTypeDesc( const TYPEDESC *desc); + /** Iterates over all functions and put the names and indices into the map + m_mapComFunc of type TLBFuncIndexMap. + Call the function every time before accessing the map. + Throws a BridgeRuntimeError on failure. + */ + void buildComTlbIndex(); + + /** Returns a FUNCDESC structure which contains type information about the + current XInvocation::invoke call. The FUNCDESC either describes a method, + a property put or a property get operation. + It uses the types com.sun.star.bridge.oleautomation.PropertyPutArgument + which can be + contained in the sequence of in-arguments of invoke to determine if the call is + a property put or property get operation. + If no adequate FUNCDESC was found, an IllegalArgumentException is thrown. + Therefore it is safe to assume that the returned FUNCDESC* is not NULL. + + @exception IllegalArgumentException + Thrown if no adequate FUNCDESC could be found. + */ + void getFuncDescForInvoke(const OUString & sFuncName, + const Sequence & seqArgs, FUNCDESC** pFuncDesc); + + // Finds out whether the wrapped IDispatch is a JScript Object. This is + // done by + // asking for the property "_environment". If it has the value "JScript" + // (case insensitive) then the IDispatch is considered a JScript object. + bool isJScriptObject(); + + + // If UNO interfaces are implemented in JScript objects, VB or C++ COM objects + // and those are passed as parameter to a UNO interface function, then + // the IDispatch* are wrapped by objects of this class. Assuming that the functions + // implemented by the IDispatch object returns another UNO interface then + // it has to be wrapped to this type. But this is only possible if an object of this + // wrapper class knows what type it is represting. The member m_TypeDescription holds this + // information. + // m_TypeDescription is only useful when an object wraps an IDispatch object that implements + // a UNO interface. The value is set during a call to XInitialization::initialize. + Sequence m_seqTypes; + CComPtr m_spUnknown; + CComPtr m_spDispatch; + OUString m_sTypeName; // is "" ( not initialised ), "IDispatch" ( we have no idea ) or "SomeLibrary.SomeTypeName" if we managed to get a type + /** This value is set during XInitialization::initialize. It indicates that the COM interface + was transported as VT_DISPATCH in a VARIANT rather than a VT_UNKNOWN + */ + bool m_bOriginalDispatch; + DispIdMap m_dispIdMap; + Reference* m_pxIdlClass; + + + // used by isJScriptObject + enum JScriptDetermination{ JScriptUndefined=0, NoJScript, IsJScript}; + JScriptDetermination m_eJScript; + // The map is filled by buildComTlbIndex + // It maps Uno Function names to an index which is used in ITypeInfo::GetFuncDesc + TLBFuncIndexMap m_mapComFunc; + // used for synchronizing the computation of the content for m_mapComFunc + bool m_bComTlbIndexInit; + // Keeps the ITypeInfo obtained from IDispatch::GetTypeInfo + CComPtr< ITypeInfo > m_spTypeInfo; + OUString m_sDefaultMember; + bool m_bHasDfltMethod; + bool m_bHasDfltProperty; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/olethread.cxx b/extensions/source/ole/olethread.cxx new file mode 100644 index 000000000..1580c0b7d --- /dev/null +++ b/extensions/source/ole/olethread.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 "ole2uno.hxx" + +#include +#include +#include + +void o2u_attachCurrentThread() +{ + static osl::ThreadData oleThreadData; + + if (!bool(reinterpret_cast(oleThreadData.getData()))) + { + HRESULT hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED); + if (!SUCCEEDED(hr)) + { // FIXME: is it a problem that this ends up in STA currently? + assert(RPC_E_CHANGED_MODE == hr); + // Let's find out explicitly what apartment mode we are in. + SAL_WARN("extensions.olebridge", "CoInitializeEx failed" + << (hr == RPC_E_CHANGED_MODE ? " (expectedly)" : "") + << ": " << WindowsErrorStringFromHRESULT(hr)); + APTTYPE nAptType; + APTTYPEQUALIFIER nAptTypeQualifier; + if (SUCCEEDED(CoGetApartmentType(&nAptType, &nAptTypeQualifier))) + { + SAL_WARN("extensions.olebridge", + " Thread is in a " + << (nAptType == APTTYPE_STA ? OUString("single-threaded") : + (nAptType == APTTYPE_MTA ? OUString("multi-threaded") : + (nAptType == APTTYPE_NA ? OUString("neutral") : + (nAptType == APTTYPE_MAINSTA ? OUString("main single-threaded") : + ("unknown (") + OUString::number(nAptType) + ")")))) + << " apartment" + << (nAptTypeQualifier == APTTYPEQUALIFIER_NONE ? OUString() : + (nAptTypeQualifier == APTTYPEQUALIFIER_IMPLICIT_MTA ? OUString(" (implicit)") : + (nAptTypeQualifier == APTTYPEQUALIFIER_NA_ON_MTA ? OUString(" (on MTA)") : + (nAptTypeQualifier == APTTYPEQUALIFIER_NA_ON_STA ? OUString(" (on STA)") : + (nAptTypeQualifier == APTTYPEQUALIFIER_NA_ON_IMPLICIT_MTA ? OUString(" (on implicit MTA)") : + (nAptTypeQualifier == APTTYPEQUALIFIER_NA_ON_MAINSTA ? OUString(" (on main STA)") : + (" (with unknown qualifier (" + OUString::number(nAptTypeQualifier) + "))"))))))) + << "."); + } + } + oleThreadData.setData(reinterpret_cast(true)); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/servprov.cxx b/extensions/source/ole/servprov.cxx new file mode 100644 index 000000000..ea69be1d9 --- /dev/null +++ b/extensions/source/ole/servprov.cxx @@ -0,0 +1,548 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "ole2uno.hxx" +#include "unoconversionutilities.hxx" +#include "servprov.hxx" +#include "unoobjw.hxx" +#include "oleobjw.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace cppu; +using namespace osl; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::ModelDependent; + +#include + +// GUID used since 5.2 ( src569 m) +// {82154420-0FBF-11d4-8313-005004526AB4} +DEFINE_GUID(OID_ServiceManager, 0x82154420, 0xfbf, 0x11d4, 0x83, 0x13, 0x0, 0x50, 0x4, 0x52, 0x6a, 0xb4); + +// FIXME: This GUID is just the above OID_ServiceManager with the +// initial part bumped by one. Is that good enough? +// {82154421-0FBF-11d4-8313-005004526AB4} +DEFINE_GUID(OID_LibreOfficeWriterApplication, 0x82154421, 0xfbf, 0x11d4, 0x83, 0x13, 0x0, 0x50, 0x4, 0x52, 0x6a, 0xb4); + +// For Calc +// {82154425-0FBF-11d4-8313-005004526AB4} +DEFINE_GUID(OID_LibreOfficeCalcApplication, 0x82154425, 0xfbf, 0x11d4, 0x83, 0x13, 0x0, 0x50, 0x4, 0x52, 0x6a, 0xb4); + +OneInstanceOleWrapper::OneInstanceOleWrapper( const Reference& smgr, + std::function()> xInstFunction ) + : m_refCount(0) + , m_xInstFunction(xInstFunction) + , m_factoryHandle(0) + , m_smgr(smgr) +{ + Reference xInt = m_smgr->createInstance("com.sun.star.bridge.oleautomation.BridgeSupplier"); + + if (xInt.is()) + { + Any a= xInt->queryInterface( cppu::UnoType::get() ); + a >>= m_bridgeSupplier; + } +} + +OneInstanceOleWrapper::~OneInstanceOleWrapper() +{ +} + +bool OneInstanceOleWrapper::registerClass(GUID const * pGuid) +{ + HRESULT hresult; + + o2u_attachCurrentThread(); + + hresult = CoRegisterClassObject( + *pGuid, + this, + CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, + REGCLS_MULTIPLEUSE, + &m_factoryHandle); + + SAL_INFO("extensions.olebridge", "CoRegisterClassObject(" << *pGuid << "): " << WindowsErrorStringFromHRESULT(hresult)); + + return (hresult == NOERROR); +} + +bool OneInstanceOleWrapper::deregisterClass() +{ + return CoRevokeClassObject(m_factoryHandle) == NOERROR; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP OneInstanceOleWrapper::QueryInterface(REFIID riid, void ** ppv) +{ + if(IsEqualIID(riid, IID_IUnknown)) + { + AddRef(); + *ppv = static_cast(static_cast(this)); + return NOERROR; + } + else if (IsEqualIID(riid, IID_IClassFactory)) + { + AddRef(); + *ppv = static_cast(this); + return NOERROR; + } + + *ppv = nullptr; + return ResultFromScode(E_NOINTERFACE); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) OneInstanceOleWrapper::AddRef() +{ + return osl_atomic_increment( &m_refCount); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) OneInstanceOleWrapper::Release() +{ + MutexGuard oGuard( Mutex::getGlobalMutex()); + ULONG refCount = --m_refCount; + if ( m_refCount == 0) + { + delete this; + } + + return refCount; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP OneInstanceOleWrapper::CreateInstance(IUnknown*, + REFIID riid, void** ppv) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", "OneInstanceOleWrapper::CreateInstance(" << riid << ")"); + + HRESULT ret = ResultFromScode(E_UNEXPECTED); + + const Reference& xInst = m_xInstFunction(); + if (xInst.is()) + { + Any usrAny(&xInst, cppu::UnoType::get()); + sal_uInt8 arId[16]; + rtl_getGlobalProcessId( arId); + Any oleAny = m_bridgeSupplier->createBridge(usrAny, + Sequence( reinterpret_cast(arId), 16), + UNO, + OLE); + + + if (auto v = o3tl::tryAccess(oleAny)) + { + VARIANT* pVariant = reinterpret_cast(*v); + + if ((pVariant->vt == VT_UNKNOWN) || (pVariant->vt == VT_DISPATCH)) + { + SAL_INFO("extensions.olebridge", "OneInstanceOleWrapper::Createbridge: punkVal=" << pVariant->punkVal); + ret = pVariant->punkVal->QueryInterface(riid, ppv); + } + + VariantClear(pVariant); + CoTaskMemFree(pVariant); + } + } + + return ret; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP OneInstanceOleWrapper::LockServer(BOOL /*fLock*/) +{ + return NOERROR; +} + +OleConverter::OleConverter( const Reference &smgr): + UnoConversionUtilities( smgr) + +{ +} + +// The XMultiServiceFactory is later set by XInitialization +OleConverter::OleConverter( const Reference& smgr, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass ): + UnoConversionUtilities( smgr, unoWrapperClass, comWrapperClass ) + +{ +} + +OleConverter::~OleConverter() +{ +} + +// XBridgeSupplier -------------------------------------------------------------- +Any SAL_CALL OleConverter::createBridge(const Any& modelDepObject, + const Sequence< sal_Int8 >& ProcessId, + sal_Int16 sourceModelType, + sal_Int16 destModelType) +{ + Any ret; + sal_uInt8 arId[16]; + rtl_getGlobalProcessId( arId ); + + Sequence< sal_Int8 > seqProcessId( reinterpret_cast(arId), 16); + + if ( seqProcessId == ProcessId) + { + if (sourceModelType == UNO) + { + if (destModelType == UNO) + { + // same model -> copy value only + ret = modelDepObject; + } + else if (destModelType == OLE) + { + // convert UNO any into variant + VARIANT* pVariant = static_cast(CoTaskMemAlloc(sizeof(VARIANT))); + VariantInit( pVariant); + try + { + anyToVariant( pVariant, modelDepObject); + } + catch(...) + { + CoTaskMemFree(pVariant); + throw IllegalArgumentException(); + } + ret.setValue(static_cast(&pVariant), cppu::UnoType::get()); + } + else + throw IllegalArgumentException(); + } + else if (sourceModelType == OLE) + { + auto v = o3tl::tryAccess(modelDepObject); + if (!v) + { + throw IllegalArgumentException(); + } + else if (destModelType == OLE) + { + // same model -> copy value only + VARIANT* pVariant = static_cast(CoTaskMemAlloc(sizeof(VARIANT))); + + if (NOERROR != VariantCopy(pVariant, reinterpret_cast(*v))) + { + CoTaskMemFree(pVariant); + throw(IllegalArgumentException()); + } + else + { + ret.setValue(static_cast(&pVariant), cppu::UnoType::get()); + } + } + else if (destModelType == UNO) + { + // convert variant into UNO any + VARIANT* pVariant = reinterpret_cast(*v); + try + { + variantToAny(pVariant, ret); + } + catch (const CannotConvertException & e) + { + throw IllegalArgumentException( + e.Message, nullptr, -1); + } + } + else + throw IllegalArgumentException(); + + } + else + throw IllegalArgumentException(); + } + + return ret; +} + +OUString OleConverter::getImplementationName() +{ + return m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL + ? OUString("com.sun.star.comp.ole.OleConverter2") + : OUString("com.sun.star.comp.ole.OleConverterVar1"); +} + +sal_Bool OleConverter::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence OleConverter::getSupportedServiceNames() +{ + if (m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL) + { + return css::uno::Sequence{ + "com.sun.star.bridge.OleBridgeSupplier2", + "com.sun.star.bridge.oleautomation.BridgeSupplier"}; + } + return css::uno::Sequence{ + "com.sun.star.bridge.OleBridgeSupplierVar1"}; +} + +// XInitialize ------------------------------------------------------------------------------ +// the first argument is an XMultiServiceFactory if at all +void SAL_CALL OleConverter::initialize( const Sequence< Any >& aArguments ) +{ + if( aArguments.getLength() == 1 && aArguments[0].getValueTypeClass() == TypeClass_INTERFACE) + { + Reference < XInterface > xInt; + aArguments[0] >>= xInt; + Reference xMulti( xInt, UNO_QUERY); + m_smgrRemote= xMulti; + } +} + +// UnoConversionUtilities ------------------------------------------------------------------- +Reference< XInterface > OleConverter::createUnoWrapperInstance() +{ + if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL) + { + Reference xWeak= static_cast( new InterfaceOleWrapper( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); + } + else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT) + { + Reference xWeak= static_cast( new UnoObjectWrapperRemoteOpt( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); + } + else + return Reference(); +} + +Reference< XInterface > OleConverter::createComWrapperInstance() +{ + Reference xWeak= static_cast( new IUnknownWrapper( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); +} + +OleClient::OleClient( const Reference& smgr): + UnoConversionUtilities( smgr) +{ + Reference xInt;// = m_smgr->createInstance(L"com.sun.star.bridge.OleBridgeSupplier2"); + + if (xInt.is()) + { + Any a= xInt->queryInterface(cppu::UnoType::get() ); + a >>= m_bridgeSupplier; + } +} + +OleClient::~OleClient() +{ +} + +Sequence< OUString > SAL_CALL OleClient::getAvailableServiceNames() +{ + Sequence< OUString > ret; + + return ret; +} + +OUString OleClient::getImplementationName() +{ + return "com.sun.star.comp.ole.OleClient"; +} + +sal_Bool OleClient::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence OleClient::getSupportedServiceNames() +{ + return css::uno::Sequence{ + "com.sun.star.bridge.OleObjectFactory", + "com.sun.star.bridge.oleautomation.Factory"}; +} + +Reference SAL_CALL OleClient::createInstance(const OUString& ServiceSpecifier) +{ + Reference ret; + HRESULT result; + IUnknown* pUnknown = nullptr; + CLSID classId; + + o2u_attachCurrentThread(); + + result = CLSIDFromProgID( + o3tl::toW(ServiceSpecifier.getStr()), //Pointer to the ProgID + &classId); //Pointer to the CLSID + + + if (result == NOERROR) + { + result = CoCreateInstance( + classId, //Class identifier (CLSID) of the object + nullptr, //Pointer to whether object is or isn't part of an aggregate + CLSCTX_SERVER, //Context for running executable code + IID_IUnknown, //Reference to the identifier of the interface + reinterpret_cast(&pUnknown)); //Address of output variable that receives + // the interface pointer requested in riid + } + + if (pUnknown != nullptr) + { + Any any; + CComVariant variant; + + V_VT(&variant) = VT_UNKNOWN; + V_UNKNOWN(&variant) = pUnknown; + // AddRef for Variant + pUnknown->AddRef(); + + // When the object is wrapped, then its refcount is increased + variantToAny(&variant, any); + if (any.getValueTypeClass() == TypeClass_INTERFACE) + { + any >>= ret; + } + pUnknown->Release(); // CoCreateInstance + } + + return ret; +} + +Reference SAL_CALL OleClient::createInstanceWithArguments(const OUString& ServiceSpecifier, const Sequence< Any >& /*Arguments*/) +{ + return createInstance( ServiceSpecifier); +} + +// UnoConversionUtilities ----------------------------------------------------------------------------- +Reference< XInterface > OleClient::createUnoWrapperInstance() +{ + if( m_nUnoWrapperClass == INTERFACE_OLE_WRAPPER_IMPL) + { + Reference xWeak= static_cast( new InterfaceOleWrapper( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); + } + else if( m_nUnoWrapperClass == UNO_OBJECT_WRAPPER_REMOTE_OPT) + { + Reference xWeak= static_cast( new UnoObjectWrapperRemoteOpt( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); + } + else + return Reference< XInterface>(); +} +// UnoConversionUtilities ----------------------------------------------------------------------------- +Reference< XInterface > OleClient::createComWrapperInstance( ) +{ + Reference xWeak= static_cast( new IUnknownWrapper( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); +} + +OleServer::OleServer( const Reference& smgr): + m_smgr( smgr) +{ + Reference xInt = m_smgr->createInstance("com.sun.star.bridge.oleautomation.BridgeSupplier"); + + if (xInt.is()) + { + Any a= xInt->queryInterface( cppu::UnoType::get() ); + a >>= m_bridgeSupplier; + } + + (void) provideInstance( [&] + { + return m_smgr; + }, + &OID_ServiceManager ); + + (void) provideInstance( [&] + { + // We want just one SwVbaGlobals for all Automation clients + static const Reference xWordGlobals = m_smgr->createInstance("ooo.vba.word.Globals"); + const Reference xHelperInterface(xWordGlobals, UNO_QUERY); + Any aApplication = xHelperInterface->Application(); + Reference xApplication; + aApplication >>= xApplication; + return xApplication; + }, + &OID_LibreOfficeWriterApplication ); + + (void) provideInstance( [&] + { + // Ditto for sc + static const Reference xCalcGlobals = m_smgr->createInstance("ooo.vba.excel.Globals"); + const Reference xHelperInterface(xCalcGlobals, UNO_QUERY); + Any aApplication = xHelperInterface->Application(); + Reference xApplication; + aApplication >>= xApplication; + return xApplication; + }, + &OID_LibreOfficeCalcApplication ); +} + +OleServer::~OleServer() +{ + for (auto const& elem : m_wrapperList) + { + elem->deregisterClass(); + elem->Release(); + } + m_wrapperList.clear(); +} + +OUString OleServer::getImplementationName() +{ + return "com.sun.star.comp.ole.OleServer"; +} + +sal_Bool OleServer::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence OleServer::getSupportedServiceNames() +{ + return css::uno::Sequence{ + "com.sun.star.bridge.OleApplicationRegistration", + "com.sun.star.bridge.oleautomation.ApplicationRegistration"}; +} + +bool OleServer::provideInstance(std::function()> xInstFunction, GUID const * guid) +{ + OneInstanceOleWrapper* pWrapper = new OneInstanceOleWrapper( m_smgr, xInstFunction ); + + pWrapper->AddRef(); + m_wrapperList.push_back(pWrapper); + + return pWrapper->registerClass(guid); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/servprov.hxx b/extensions/source/ole/servprov.hxx new file mode 100644 index 000000000..8871f28cf --- /dev/null +++ b/extensions/source/ole/servprov.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 . + */ + +#pragma once + +#include + +#include +#include +#include + +#include "ole2uno.hxx" +#include "unoconversionutilities.hxx" + +using namespace com::sun::star::bridge; +using namespace cppu; + +/// @throws Exception +Reference< XInterface> ConverterProvider_CreateInstance2( const Reference & xSMgr); +/// @throws Exception +Reference< XInterface> ConverterProvider_CreateInstanceVar1( const Reference & xSMgr); +/// @throws Exception +Reference OleClient_CreateInstance( const Reference & xSMgr); +/// @throws Exception +Reference OleServer_CreateInstance( const Reference & xSMgr); + +/***************************************************************************** + + OneInstanceOleWrapper + + Provides a single UNO object as OLE object. + + Acts as a COM class factory. When IClassFactory::CreateInstance is being called + then it maps the XInstance member it to a COM object. + +*****************************************************************************/ + +class OneInstanceOleWrapper : public IClassFactory +{ +public: + + OneInstanceOleWrapper( const Reference& smgr, + std::function()> xInstFunction ); + virtual ~OneInstanceOleWrapper(); + + bool registerClass(GUID const * pGuid); + bool deregisterClass(); + + /* IUnknown methods */ + STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj) override; + STDMETHOD_(ULONG, AddRef)() override; + STDMETHOD_(ULONG, Release)() override; + + /* IClassFactory methods */ + STDMETHOD(CreateInstance)(IUnknown* punkOuter, REFIID riid, void** ppv) override; + STDMETHOD(LockServer)(BOOL fLock) override; + +protected: + oslInterlockedCount m_refCount; + std::function()> m_xInstFunction; + DWORD m_factoryHandle; + Reference m_bridgeSupplier; + Reference m_smgr; +}; + +// Implementation of the UNO service com.sun.star.bridge.OleBridgeSupplier2. + +// This class realizes the service com.sun.star.bridge.OleBridgeSupplier2 and +// com.sun.star.bridge.OleBridgeSupplierVar1. The class implements XBridgeSupplier2 which +// interface does not need a Machine Id in its createBridge function anymore, +// If a UNO interface is to be converted then the member m_nUnoWrapperClass determines +// what wrapper class is to be used. There are currently InterfaceOleWrapper and +// UnoObjectWrapperRemoteOpt. The first is used for the OleBridgeSupplier2 and the +// latter for OleBridgeSupplierVar1. +// The m_nComWrapperClass specifies the class which is used as wrapper for COM interfaces. +// Currently there is only one class available (IUnknownWrapper). +class OleConverter : public WeakImplHelper, + public UnoConversionUtilities +{ +public: + explicit OleConverter( const Reference& smgr); + OleConverter( const Reference& smgr, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass ); + virtual ~OleConverter() override; + + // XBridgeSupplier2 --------------------------------------------------- + + Any SAL_CALL createBridge(const Any& modelDepObject, + const Sequence& ProcessId, + sal_Int16 sourceModelType, + sal_Int16 destModelType) override; + + // XInitialization + void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + OUString SAL_CALL getImplementationName() override; + + sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // UnoConversionUtilities + Reference< XInterface > createUnoWrapperInstance() override; + Reference< XInterface > createComWrapperInstance() override; +protected: + +}; + +// Implementation of the UNO service com.sun.star.bridge.OleObjectFactory. + +class OleClient : public WeakImplHelper, + public UnoConversionUtilities +{ +public: + explicit OleClient( const Reference& smgr); + ~OleClient() override; + + // XMultiServiceFactory + Reference SAL_CALL createInstance(const OUString& ServiceSpecifier) override; + Reference SAL_CALL createInstanceWithArguments(const OUString& ServiceSpecifier, const Sequence< Any >& Arguments) override; + Sequence< OUString > SAL_CALL getAvailableServiceNames() override; + + OUString SAL_CALL getImplementationName() override; + + sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // UnoConversionUtilities + Reference< XInterface > createUnoWrapperInstance() override; + Reference< XInterface > createComWrapperInstance() override; + +protected: + Reference m_bridgeSupplier; +}; + +/***************************************************************************** + + OleServer + + Implementation of the UNO service com.sun.star.bridge.OleApplicationRegistration. + Register the calling application as OLE automation server for + standard OLE object. The objects will be registered while instantiating + this implementation and deregistered, if this implementation is destroyed. + +*****************************************************************************/ + +class OleServer : public cppu::WeakImplHelper +{ +public: + explicit OleServer( const Reference &smgr); + ~OleServer() override; + + OUString SAL_CALL getImplementationName() override; + + sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + +protected: + bool provideInstance(std::function()> xInstFunction, GUID const * guid); + + std::list< OneInstanceOleWrapper* > m_wrapperList; + Reference< XBridgeSupplier2 > m_bridgeSupplier; + + Reference m_smgr; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/servreg.cxx b/extensions/source/ole/servreg.cxx new file mode 100644 index 000000000..66928137b --- /dev/null +++ b/extensions/source/ole/servreg.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 +#include "ole2uno.hxx" +#include "servprov.hxx" +#include +#include + +using namespace cppu; + +Reference ConverterProvider_CreateInstance2( const Reference & xSMgr) +{ + Reference xService = *new OleConverter( xSMgr); + return xService; +} + +Reference ConverterProvider_CreateInstanceVar1( const Reference & xSMgr) +{ + Reference xService = *new OleConverter( xSMgr, UNO_OBJECT_WRAPPER_REMOTE_OPT, IUNKNOWN_WRAPPER_IMPL); + return xService; +} + +Reference OleClient_CreateInstance( const Reference & xSMgr) +{ + Reference xService = *new OleClient( xSMgr); + return xService; +} + +Reference OleServer_CreateInstance( const Reference & xSMgr) +{ + Reference xService = *new OleServer(xSMgr); + return xService; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void * oleautobridge_component_getFactory( + const char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + void * pRet = nullptr; + + OUString aImplName( OUString::createFromAscii( pImplName ) ); + Reference< XSingleServiceFactory > xFactory; + Sequence seqServiceNames; + if (pServiceManager && aImplName == "com.sun.star.comp.ole.OleConverter2") + { + xFactory= createSingleFactory( static_cast< XMultiServiceFactory*>(pServiceManager), + aImplName, + ConverterProvider_CreateInstance2, seqServiceNames ); + } + else if (pServiceManager && aImplName == "com.sun.star.comp.ole.OleConverterVar1") + { + xFactory= createSingleFactory( static_cast(pServiceManager), + aImplName, + ConverterProvider_CreateInstanceVar1, seqServiceNames ); + } + else if(pServiceManager && aImplName == "com.sun.star.comp.ole.OleClient") + { + xFactory= createSingleFactory( static_cast< XMultiServiceFactory*>(pServiceManager), + aImplName, + OleClient_CreateInstance, seqServiceNames ); + } + else if(pServiceManager && aImplName == "com.sun.star.comp.ole.OleServer") + { + xFactory= createOneInstanceFactory( static_cast< XMultiServiceFactory*>(pServiceManager), + aImplName, + OleServer_CreateInstance, seqServiceNames ); + } + + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + + return pRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unoconversionutilities.hxx b/extensions/source/ole/unoconversionutilities.hxx new file mode 100644 index 000000000..a73a714ab --- /dev/null +++ b/extensions/source/ole/unoconversionutilities.hxx @@ -0,0 +1,2363 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ole2uno.hxx" +#include + +#include "unotypewrapper.hxx" +#include + +// for some reason DECIMAL_NEG (wtypes.h) which contains BYTE is not resolved. +typedef unsigned char BYTE; +// classes for wrapping uno objects +#define INTERFACE_OLE_WRAPPER_IMPL 1 +#define UNO_OBJECT_WRAPPER_REMOTE_OPT 2 + +#define INVOCATION_SERVICE "com.sun.star.script.Invocation" + + +// classes for wrapping ole objects +#define IUNKNOWN_WRAPPER_IMPL 1 + +#define INTERFACE_ADAPTER_FACTORY "com.sun.star.script.InvocationAdapterFactory" +// COM or JScript objects implementing UNO interfaces have to implement this property +#define SUPPORTED_INTERFACES_PROP L"_implementedInterfaces" +// Second property without leading underscore for use in VB +#define SUPPORTED_INTERFACES_PROP2 L"Bridge_ImplementedInterfaces" + +using namespace com::sun::star::script; +using namespace com::sun::star::beans; +using namespace com::sun::star::uno; +using namespace com::sun::star::bridge::oleautomation; + +extern std::unordered_map AdapterToWrapperMap; +extern std::unordered_map WrapperToAdapterMap; + +//Maps IUnknown pointers to a weak reference of the respective wrapper class (e.g. +// IUnknownWrapperImpl. It is the responsibility of the wrapper to remove the entry when +// it is being destroyed. +// Used to ensure that an Automation object is always mapped to the same UNO objects. +extern std::unordered_map > ComPtrToWrapperMap; + +// Maps XInterface pointers to a weak reference of its wrapper class (i.e. +// InterfaceOleWrapper). It is the responsibility of the wrapper to remove the entry when +// it is being destroyed. It is used to ensure the identity of objects. That is, a UNO interface +// is mapped to IDispatch which is kept alive in the COM environment. If the same +// UNO interface is mapped again to COM then the IDispach of the first mapped instance +// must be returned. +extern std::unordered_map > UnoObjToWrapperMap; + +// This function tries to the change the type of a value (contained in the Any) +// to the smallest possible that can hold the value. This is actually done only +// for types of VT_I4 (see o2u_variantToAny). The reason is the following: +// JavaScript passes integer values always as VT_I4. If there is a parameter or +// property of type any then the bridge converts the any's content according +// to "o2u_variantToAny". Because the VARTYPE is VT_I4 the value would be converted +// to TypeClass_LONG. Say the method XPropertySet::setPropertyValue( string name, any value) +// would be called on an object and the property actually is of TypeClass_SHORT. +// After conversion of the VARIANT parameter the Any would contain type +// TypeClass_LONG. Because the corereflection does not cast from long to short +// the "setPropertValue" would fail as the value has not the right type. + +// The corereflection does convert small integer types to bigger types. +// Therefore we can reduce the type if possible and avoid the above mentioned +// problem. + +// The function is not used when elements are to be converted for Sequences. + +inline void reduceRange( Any& any) +{ + OSL_ASSERT( any.getValueTypeClass() == TypeClass_LONG); + + sal_Int32 value= *o3tl::doAccess(any); + if( value <= 0x7f && value >= -0x80) + {// -128 bis 127 + sal_Int8 charVal= static_cast( value); + any.setValue( &charVal, cppu::UnoType::get()); + } + else if( value <= 0x7fff && value >= -0x8000) + {// -32768 bis 32767 + sal_Int16 shortVal= static_cast( value); + any.setValue( &shortVal, cppu::UnoType::get()); + } +} + +// createUnoObjectWrapper gets a wrapper instance by calling createUnoWrapperInstance + // and initializes it via XInitialization. The wrapper object is required to implement + // XBridgeSupplier so that it can convert itself to IDispatch. + // class T: Deriving class ( must implement XInterface ) +/** All methods are allowed to throw at least a BridgeRuntimeError. + */ +template< class > +class UnoConversionUtilities +{ +public: + explicit UnoConversionUtilities( const Reference & smgr): + m_nUnoWrapperClass( INTERFACE_OLE_WRAPPER_IMPL), + m_nComWrapperClass( IUNKNOWN_WRAPPER_IMPL), + m_smgr( smgr) + {} + + UnoConversionUtilities( const Reference & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass ) + : m_nUnoWrapperClass(unoWrapperClass), + m_nComWrapperClass(comWrapperClass), m_smgr(xFactory) + {} + + virtual ~UnoConversionUtilities() {} + /** converts only into oleautomation types, that is there is no VT_I1, VT_UI2, VT_UI4 + a sal_Unicode character is converted into a BSTR. + @exception com.sun.star.lang.IllegalArgumentException + If the any was inappropriate for conversion. + @exception com.sun.star.script.CannotConvertException + The any contains a type class for which no conversion is provided. + */ + void anyToVariant(VARIANT* pVariant, const Any& rAny); + void anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type); + + /** @exception com.sun.star.lang.IllegalArgumentException + If rSeq does not contain a sequence then the exception is thrown. + */ + SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq); + /** @exception com.sun.star.lang.IllegalArgumentException + If rSeq does not contain a sequence or elemtype has no proper value + then the exception is thrown. + */ + SAFEARRAY* createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype); + /** + @exception com.sun.star.lang.IllegalArgumentException + If rObj does not contain a struct or interface + */ + void createUnoObjectWrapper(const Any & rObj, VARIANT * pVar); + /** @exception CannotConvertException + Thrown if the VARIANT contains a type that cannot be coerced in the expected Any. + ArgumentIndex is 0. + @IllegalArgumentException + Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1, + */ + void variantToAny(const VARIANT* pVariant, Any& rAny, bool bReduceValueRange = true); + /** This method converts variants arguments in calls from COM -> UNO. Only then + the expected UNO type is known. + @exception CannotConvertException + Thrown if the VARIANT contains a type that cannot be coerced in the expected Any. + ArgumentIndex is 0. + @IllegalArgumentException + Thrown if the VARIANT is inappropriate for conversion. ArgumentPosition is -1, + */ + void variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, bool bReduceValueRange = true); + + /** + @exception IllegalArgumentException + -if pVar does not contain VT_UNKNOWN or VT_DISPATCH or + pVar is used for a particular UNO type which is not supported by pVar + */ + Any createOleObjectWrapper(VARIANT* pVar, const Type& aType= Type()); + + /* + Return true means var contained a ValueObject, and it was successfully converted. + The result is in any. It an error occurred a BridgeRuntimeError will be thrown. + */ + bool convertValueObject( const VARIANTARG *var, Any& any); + void dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type); + + Sequence createOleArrayWrapperOfDim(SAFEARRAY* pArray, unsigned int dimCount, unsigned int actDim, LONG* index, + VARTYPE type, const Type& unotype); + Sequence createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unotype= Type()); + + + VARTYPE mapTypeClassToVartype( TypeClass type); + Reference< XSingleServiceFactory > getInvocationFactory(const Any& anyObject); + + + virtual Reference< XInterface > createUnoWrapperInstance()=0; + virtual Reference< XInterface > createComWrapperInstance()=0; + + static bool isJScriptArray(const VARIANT* pvar); + + Sequence getImplementedInterfaces(IUnknown* pUnk); + +protected: + Reference createAdapter(const Sequence& types, const Reference& receiver); + + // helper function for Sequence conversion + void getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc); + // helper function for Sequence conversion + static bool incrementMultidimensionalIndex(sal_Int32 dimensions, const sal_Int32 * parDimensionLength, + sal_Int32 * parMultidimensionalIndex); + // helper function for Sequence conversion + static size_t getOleElementSize( VARTYPE type); + + static Type getElementTypeOfSequence( const Type& seqType); + + //Provides a typeconverter + Reference getTypeConverter(); + + // This member determines what class is used to convert a UNO object + // or struct to a COM object. It is passed along to the anyToVariant + // function in the createBridge function implementation + const sal_uInt8 m_nUnoWrapperClass; + const sal_uInt8 m_nComWrapperClass; + + // The servicemanager is either a local smgr or remote when the service + // com.sun.star.bridge.OleBridgeSupplierVar1 is used. This service can be + // created by createInstanceWithArguments where one can supply a service + // manager that is to be used. + // Local service manager as supplied by the loader when the creator function + // of the service is being called. + Reference m_smgr; + // An explicitly supplied service manager when the service + // com.sun.star.bridge.OleBridgeSupplierVar1 is used. That can be a remote + // manager. + Reference m_smgrRemote; + Reference m_xInvocationFactoryLocal; + Reference m_xInvocationFactoryRemote; + +private: + // Holds the type converter which is used for sequence conversion etc. + // Use the getTypeConverter function to obtain the interface. + Reference m_typeConverter; + + +}; + +// ask the object for XBridgeSupplier2 and on success bridges +// the uno object to IUnknown or IDispatch. +// return true the UNO object supports +template < class T > +bool convertSelfToCom( T& unoInterface, VARIANT * pVar) +{ + bool ret = false; + Reference< XInterface > xInt( unoInterface, UNO_QUERY); + if( xInt.is()) + { + Reference< css::bridge::XBridgeSupplier2 > xSupplier( xInt, UNO_QUERY); + if( xSupplier.is()) + { + sal_Int8 arId[16]; + rtl_getGlobalProcessId( reinterpret_cast(arId)); + Sequence seqId( arId, 16); + Any anySource; + anySource <<= xInt; + Any anyDisp = xSupplier->createBridge( + anySource, seqId, css::bridge::ModelDependent::UNO, + css::bridge::ModelDependent::OLE); + + // due to global-process-id check this must be in-process pointer + if (auto v = o3tl::tryAccess(anyDisp)) + { + VARIANT* pvariant= reinterpret_cast(*v); + HRESULT hr; + if (FAILED(hr = VariantCopy(pVar, pvariant))) + throw BridgeRuntimeError( + "[automation bridge] convertSelfToCom\n" + "VariantCopy failed! Error: " + + OUString::number(hr)); + VariantClear( pvariant); + CoTaskMemFree( pvariant); + ret = true; + } + } + } + return ret; +} + + +// Gets the invocation factory depending on the Type in the Any. +// The factory can be created by a local or remote multi service factory. +// In case there is a remote multi service factory available there are +// some services or types for which the local factory is used. The exceptions +// are: all structs. +// Param anyObject - contains the object ( interface, struct) for what we need an invocation object. + +template +Reference< XSingleServiceFactory > UnoConversionUtilities::getInvocationFactory(const Any& anyObject) +{ + Reference< XSingleServiceFactory > retVal; + MutexGuard guard( getBridgeMutex()); + if( anyObject.getValueTypeClass() != TypeClass_STRUCT && + m_smgrRemote.is() ) + { + if( ! m_xInvocationFactoryRemote.is() ) + m_xInvocationFactoryRemote.set(m_smgrRemote->createInstance( INVOCATION_SERVICE), UNO_QUERY); + retVal= m_xInvocationFactoryRemote; + } + else + { + if( ! m_xInvocationFactoryLocal.is() ) + m_xInvocationFactoryLocal.set(m_smgr->createInstance(INVOCATION_SERVICE ), UNO_QUERY); + retVal= m_xInvocationFactoryLocal; + } + return retVal; +} + +template +void UnoConversionUtilities::variantToAny( const VARIANTARG* pArg, Any& rAny, const Type& ptype, bool bReduceValueRange /* = sal_True */) +{ + try + { + HRESULT hr; + bool bFail = false; + bool bCannotConvert = false; + CComVariant var; + + // There is no need to support indirect values, since they're not supported by UNO + if( FAILED(hr= VariantCopyInd( &var, pArg))) // remove VT_BYREF + throw BridgeRuntimeError( + "[automation bridge] UnoConversionUtilities::variantToAny \n" + "VariantCopyInd failed for reason : " + OUString::number(hr)); + bool bHandled = convertValueObject( & var, rAny); + if( bHandled) + OSL_ENSURE( rAny.getValueType() == ptype, "type in Value Object must match the type parameter"); + + if( ! bHandled) + { + // convert into a variant type that is the equivalent to the type + // the sequence expects. Thus variantToAny produces the correct type + // E.g. An Array object contains VT_I4 and the sequence expects shorts + // than the vartype must be changed. The reason is, you can't specify the + // type in JavaScript and the script engine determines the type being used. + switch( ptype.getTypeClass()) + { + case TypeClass_CHAR: // could be: new Array( 12, 'w', "w") + if( var.vt == VT_BSTR) + { + if(SUCCEEDED( hr= VariantChangeType( &var, &var, 0, VT_BSTR))) + rAny.setValue( V_BSTR( &var), ptype); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + } + else + { + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2))) + rAny.setValue(& var.iVal, ptype); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + } + break; + case TypeClass_INTERFACE: // could also be an IUnknown + case TypeClass_STRUCT: + { + rAny = createOleObjectWrapper( & var, ptype); + break; + } + case TypeClass_ENUM: + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I4))) + rAny.setValue(& var.lVal, ptype); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_SEQUENCE: + // There are different ways of receiving a sequence: + // 1: JScript, VARTYPE: VT_DISPATCH + // 2. VBScript simple arraysVT_VARIANT|VT_BYREF the referenced VARIANT contains + // a VT_ARRAY| + // 3. VBScript multi dimensional arrays: VT_ARRAY|VT_BYREF + if( pArg->vt == VT_DISPATCH) + { + dispatchExObject2Sequence( pArg, rAny, ptype); + } + else + { + if ((var.vt & VT_ARRAY) != 0) + { + VARTYPE oleType = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY ); + Sequence unoSeq = createOleArrayWrapper( var.parray, oleType, ptype); + Reference conv = getTypeConverter(); + if (conv.is()) + { + try + { + Any anySeq(unoSeq); + Any convAny = conv->convertTo(anySeq, ptype); + rAny = convAny; + } + catch (const IllegalArgumentException& e) + { + throw BridgeRuntimeError( + "[automation bridge]com.sun.star.lang.IllegalArgumentException " + "in UnoConversionUtilities::variantToAny! Message: " + + e.Message); + } + catch (const CannotConvertException& e) + { + throw BridgeRuntimeError( + "[automation bridge]com.sun.star.script.CannotConvertException " + "in UnoConversionUtilities::variantToAny! Message: " + + e.Message); + } + } + } + } + break; + case TypeClass_VOID: + rAny.setValue(nullptr,Type()); + break; + case TypeClass_ANY: // Any + // There could be a JScript Array that needs special handling + // If an Any is expected and this Any must contain a Sequence + // then we cannot figure out what element type is required. + // Therefore we convert to Sequence< Any > + if( pArg->vt == VT_DISPATCH && isJScriptArray( pArg)) + { + dispatchExObject2Sequence( pArg, rAny, + cppu::UnoType>::get()); + } + else if (pArg->vt == VT_DECIMAL) + { + //Decimal maps to hyper in calls from COM -> UNO + // It does not matter if we create a sal_uInt64 or sal_Int64, + // because the UNO object is called through invocation which + //will do a type conversion if necessary + if (var.decVal.sign == 0) + { + // positive value + variantToAny( & var, rAny, cppu::UnoType::get(), + bReduceValueRange); + } + else + { + //negative value + variantToAny( & var, rAny, cppu::UnoType::get(), + bReduceValueRange); + } + } + else + { + variantToAny( & var, rAny); + } + break; + case TypeClass_BOOLEAN: // VARIANT could be VARIANT_BOOL or other + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BOOL))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_STRING: // UString + if(var.vt == VT_NULL) + var = CComBSTR(""); + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_BSTR))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_FLOAT: // float + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R4))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_DOUBLE: // double + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_R8))) + variantToAny(& var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_BYTE: // BYTE + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I1))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_SHORT: // INT16 + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_I2))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_LONG: + if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_I4))) + variantToAny( & var, rAny, bReduceValueRange); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_HYPER: + if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL))) + { + if (var.decVal.Lo64 > SAL_CONST_UINT64(0x8000000000000000) + || var.decVal.Hi32 > 0 + || var.decVal.scale > 0) + { + bFail = true; + break; + } + sal_Int64 value = var.decVal.Lo64; + if (var.decVal.sign == DECIMAL_NEG) + value |= SAL_CONST_UINT64(0x8000000000000000); + rAny <<= value; + } + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_UNSIGNED_SHORT: // UINT16 + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI2))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_UNSIGNED_LONG: + if(SUCCEEDED(hr = VariantChangeType( & var, &var, 0, VT_UI4))) + variantToAny( & var, rAny, bReduceValueRange); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_UNSIGNED_HYPER: + if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_DECIMAL))) + { + if (var.decVal.Hi32 > 0 || var.decVal.scale > 0) + { + bFail = true; + break; + } + rAny <<= var.decVal.Lo64; + } + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + case TypeClass_TYPE: + if(SUCCEEDED(hr = VariantChangeType(& var, &var, 0, VT_UNKNOWN))) + variantToAny( & var, rAny); + else if (hr == DISP_E_TYPEMISMATCH) + bCannotConvert = true; + else + bFail = true; + break; + default: + bCannotConvert = true; + break; + } + } + if (bCannotConvert) + throw CannotConvertException( + "[automation bridge]UnoConversionUtilities::variantToAny \n" + "Cannot convert the value of vartype :\"" + + OUString::number(static_cast(var.vt)) + + "\" to the expected UNO type of type class: " + + OUString::number(static_cast(ptype.getTypeClass())), + nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0); + + if (bFail) + throw IllegalArgumentException( + "[automation bridge]UnoConversionUtilities:variantToAny\n" + "The provided VARIANT of type\" " + OUString::number(static_cast(var.vt)) + + "\" is unappropriate for conversion!", Reference(), -1); + } + catch (const CannotConvertException &) + { + throw; + } + catch (const IllegalArgumentException &) + { + throw; + } + catch (const BridgeRuntimeError &) + { + throw; + } + catch (const Exception & e) + { + throw BridgeRuntimeError("[automation bridge] unexpected exception in " + "UnoConversionUtilities::variantToAny ! Message : \n" + + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + "[automation bridge] unexpected exception in " + "UnoConversionUtilities::variantToAny !"); + } +} + +// The function only converts Sequences to SAFEARRAYS with elements of the type +// specified by the parameter type. Everything else is forwarded to +// anyToVariant(VARIANT* pVariant, const Any& rAny) +// Param type must not be VT_BYREF +template +void UnoConversionUtilities::anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type) +{ + try + { + HRESULT hr= S_OK; + + OSL_ASSERT( (type & VT_BYREF) == 0); + if (type & VT_ARRAY) + { + type ^= VT_ARRAY; + SAFEARRAY* ar= createUnoSequenceWrapper( rAny, type); + if( ar) + { + VariantClear( pVariant); + pVariant->vt= ::sal::static_int_cast< VARTYPE, int >( VT_ARRAY | type ); + pVariant->byref= ar; + } + } + else if(type == VT_VARIANT) + { + anyToVariant(pVariant, rAny); + } + else + { + CComVariant var; + anyToVariant( &var, rAny); + if(FAILED(hr = VariantChangeType(&var, &var, 0, type))) + { + if (hr == DISP_E_TYPEMISMATCH) + throw CannotConvertException( + "[automation bridge]UnoConversionUtilities::anyToVariant \n" + "Cannot convert the value of type :\"" + + rAny.getValueTypeName() + + "\" to the expected Automation type of VARTYPE: " + + OUString::number(static_cast(type)), + nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0); + + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::anyToVariant \n" + "Conversion of any with " + + rAny.getValueType().getTypeName() + + " to VARIANT with type: " + OUString::number(static_cast(type)) + + " failed! Error code: " + OUString::number(hr)); + + } + if(FAILED(hr = VariantCopy(pVariant, &var))) + { + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::anyToVariant \n" + "VariantCopy failed for reason: " + OUString::number(hr)); + } + } + } + catch (const IllegalArgumentException &) + { + throw; + } + catch (const CannotConvertException &) + { + throw; + } + catch (const BridgeRuntimeError&) + { + throw; + } + catch(const Exception & e) + { + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::anyToVariant \n" + "Unexpected exception occurred. Message: " + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::anyToVariant \n" + "Unexpected exception occurred."); + } +} + +template +void UnoConversionUtilities::anyToVariant(VARIANT* pVariant, const Any& rAny) +{ + try + { + bool bIllegal = false; + switch (rAny.getValueTypeClass()) + { + case TypeClass_INTERFACE: + { + Reference xInt; + if (rAny >>= xInt) + { + createUnoObjectWrapper(rAny, pVariant); + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_STRUCT: + { + if (rAny.getValueType() == cppu::UnoType::get() ) + { + Date d; + if (rAny >>= d) + { + pVariant->vt = VT_DATE; + pVariant->date = d.Value; + } + else + { + bIllegal = true; + } + } + else if(rAny.getValueType() == cppu::UnoType::get()) + { + Decimal d; + if (rAny >>= d) + { + pVariant->vt = VT_DECIMAL; + pVariant->decVal.scale = d.Scale; + pVariant->decVal.sign = d.Sign; + pVariant->decVal.Lo32 = d.LowValue; + pVariant->decVal.Mid32 = d.MiddleValue; + pVariant->decVal.Hi32 = d.HighValue; + } + else + { + bIllegal = true; + } + } + else if (rAny.getValueType() == cppu::UnoType::get()) + { + Currency c; + if (rAny >>= c) + { + pVariant->vt = VT_CY; + pVariant->cyVal.int64 = c.Value; + } + else + { + bIllegal = true; + } + } + else if(rAny.getValueType() == cppu::UnoType::get()) + { + SCode s; + if (rAny >>= s) + { + pVariant->vt = VT_ERROR; + pVariant->scode = s.Value; + } + else + { + bIllegal = true; + } + } + else + { + createUnoObjectWrapper(rAny, pVariant); + } + break; + } + case TypeClass_SEQUENCE: // sequence ??? SafeArray descriptor + { + SAFEARRAY* pArray = createUnoSequenceWrapper(rAny); + if (pArray) + { + V_VT(pVariant) = VT_ARRAY | VT_VARIANT; + V_ARRAY(pVariant) = pArray; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_VOID: + { + HRESULT hr = S_OK; + if (FAILED(hr = VariantClear(pVariant))) + { + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::anyToVariant\n" + "VariantClear failed with error:" + OUString::number(hr)); + } + break; + } + case TypeClass_BOOLEAN: + { + bool value; + if (rAny >>= value) + { + pVariant->vt = VT_BOOL; + pVariant->boolVal = value ? VARIANT_TRUE: VARIANT_FALSE; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_CHAR: + { + // Because VT_UI2 does not conform to oleautomation we convert into VT_I2 instead + sal_uInt16 value = *o3tl::forceAccess(rAny); + pVariant->vt = VT_I2; + pVariant->iVal = value; + break; + } + case TypeClass_STRING: + { + OUString value; + if (rAny >>= value) + { + pVariant->vt = VT_BSTR; + pVariant->bstrVal = SysAllocString(o3tl::toW(value.getStr())); + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_FLOAT: + { + float value; + if (rAny >>= value) + { + pVariant->vt = VT_R4; + pVariant->fltVal = value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_DOUBLE: + { + double value; + if (rAny >>= value) + { + pVariant->vt = VT_R8; + pVariant->dblVal = value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_BYTE: + { + // ole automation does not know a signed char but only unsigned char + sal_Int8 value; + if (rAny >>= value) + { + pVariant->vt = VT_UI1; + pVariant->bVal = value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_SHORT: // INT16 + case TypeClass_UNSIGNED_SHORT: // UINT16 + { + sal_Int16 value; + if (rAny >>= value) + { + pVariant->vt = VT_I2; + pVariant->iVal = value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_ENUM: + { + sal_Int32 value = *static_cast(rAny.getValue()); + pVariant->vt = VT_I4; + pVariant->lVal= value; + break; + } + case TypeClass_LONG: + case TypeClass_UNSIGNED_LONG: + { + sal_Int32 value; + if (rAny >>= value) + { + pVariant->vt = VT_I4; + pVariant->lVal= value; + } + else + { + bIllegal = true; + } + break; + } + case TypeClass_HYPER: + { + + pVariant->vt = VT_DECIMAL; + pVariant->decVal.scale = 0; + pVariant->decVal.sign = 0; + pVariant->decVal.Hi32 = 0; + + sal_Int64 value; + rAny >>= value; + + if (value & SAL_CONST_UINT64(0x8000000000000000)) + pVariant->decVal.sign = DECIMAL_NEG; + + pVariant->decVal.Lo64 = value; + break; + } + case TypeClass_UNSIGNED_HYPER: + { + pVariant->vt = VT_DECIMAL; + pVariant->decVal.scale = 0; + pVariant->decVal.sign = 0; + pVariant->decVal.Hi32 = 0; + + sal_uInt64 value; + rAny >>= value; + pVariant->decVal.Lo64 = value; + break; + } + case TypeClass_TYPE: + { + Type type; + rAny >>= type; + CComVariant var; + if (!createUnoTypeWrapper(type.getTypeName(), & var)) + throw BridgeRuntimeError( + "[automation bridge] UnoConversionUtilities::anyToVariant \n" + "Error during conversion of UNO type to Automation object!"); + + if (FAILED(VariantCopy(pVariant, &var))) + throw BridgeRuntimeError( + "[automation bridge] UnoConversionUtilities::anyToVariant \n" + "Unexpected error!"); + break; + } + default: + //TypeClass_SERVICE: + //TypeClass_EXCEPTION: + //When an InvocationTargetException is thrown when calling XInvocation::invoke + //on a UNO object, then the target exception is directly used to create a + //EXEPINFO structure + //TypeClass_TYPEDEF + //TypeClass_ANY: + //TypeClass_UNKNOWN: + //TypeClass_MODULE: + throw CannotConvertException( + "[automation bridge]UnoConversionUtilities::anyToVariant\n" + "There is no conversion for this UNO type to an Automation type." + "The destination type class is the type class of the UNO " + "argument which was to be converted.", + Reference(), rAny.getValueTypeClass(), + FailReason::TYPE_NOT_SUPPORTED, 0); + + break; + } + if (bIllegal) + { + throw IllegalArgumentException( + "[automation bridge]UnoConversionUtilities::anyToVariant\n" + "The provided any of type\" " + rAny.getValueType().getTypeName() + + "\" is unappropriate for conversion!", Reference(), -1); + + } + } + catch (const CannotConvertException &) + { + throw; + } + catch (const IllegalArgumentException &) + { + throw; + } + catch(const BridgeRuntimeError&) + { + throw; + } + catch(const Exception & e) + { + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::anyToVariant \n" + "Unexpected exception occurred. Message: " + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::anyToVariant \n" + "Unexpected exception occurred. " ); + } +} + +// Creates an SAFEARRAY of the specified element and if necessary +// creates a SAFEARRAY with multiple dimensions. +// Used by sal_Bool anyToVariant(VARIANT* pVariant, const Any& rAny, VARTYPE type); +template +SAFEARRAY* UnoConversionUtilities::createUnoSequenceWrapper(const Any& rSeq, VARTYPE elemtype) +{ + if (rSeq.getValueTypeClass() != TypeClass_SEQUENCE) + throw IllegalArgumentException( + "[automation bridge]UnoConversionUtilities::createUnoSequenceWrapper \n" + "The any does not contain a sequence!", nullptr, 0); + if (elemtype == VT_NULL || elemtype == VT_EMPTY) + throw IllegalArgumentException( + "[automation bridge]UnoConversionUtilities::createUnoSequenceWrapper \n" + "No element type supplied!",nullptr, -1); + SAFEARRAY* pArray= nullptr; + // Get the dimensions. This is done by examining the type name string + // The count of brackets determines the dimensions. + OUString sTypeName= rSeq.getValueType().getTypeName(); + sal_Int32 dims=0; + for(sal_Int32 lastIndex=0;(lastIndex= sTypeName.indexOf( L'[', lastIndex)) != -1; lastIndex++,dims++); + + //get the maximum number of elements per dimensions and the typedescription of the elements + Sequence seqElementCounts( dims); + TypeDescription elementTypeDesc; + getElementCountAndTypeOfSequence( rSeq, 1, seqElementCounts, elementTypeDesc ); + + if( elementTypeDesc.is() ) + { + // set up the SAFEARRAY + std::unique_ptr sarSafeArrayBound(new SAFEARRAYBOUND[dims]); + SAFEARRAYBOUND* prgsabound= sarSafeArrayBound.get(); + for( sal_Int32 i=0; i < dims; i++) + { + //prgsabound[0] is the right most dimension + prgsabound[dims - i - 1].lLbound = 0; + prgsabound[dims - i - 1].cElements = seqElementCounts[i]; + } + + typelib_TypeDescription* rawTypeDesc= elementTypeDesc.get(); + sal_Int32 elementSize= rawTypeDesc->nSize; + size_t oleElementSize= getOleElementSize( elemtype); + // SafeArrayCreate clears the memory for the data itself. + pArray = SafeArrayCreate(elemtype, dims, prgsabound); + + // convert the Sequence's elements and populate the SAFEARRAY + if( pArray) + { + // Iterate over every Sequence that contains the actual elements + void* pSAData; + if( SUCCEEDED( SafeArrayAccessData( pArray, &pSAData))) + { + const sal_Int32* parElementCount= seqElementCounts.getConstArray(); + uno_Sequence * pMultiSeq= *static_cast(rSeq.getValue()); + sal_Int32 dimsSeq= dims - 1; + + // arDimSeqIndices contains the current index of a block of data. + // E.g. Sequence> , the index would refer to Sequence + // In this case arDimSeqIndices would have the size 1. That is the elements are not counted + // but the Sequences that contain those elements. + // The indices are 0 based + std::unique_ptr sarDimsSeqIndices; + sal_Int32* arDimsSeqIndices= nullptr; + if( dimsSeq > 0) + { + sarDimsSeqIndices.reset(new sal_Int32[dimsSeq]); + arDimsSeqIndices = sarDimsSeqIndices.get(); + memset( arDimsSeqIndices, 0, sizeof( sal_Int32 ) * dimsSeq); + } + + char* psaCurrentData= static_cast(pSAData); + + do + { + // Get the Sequence at the current index , see arDimsSeqIndices + uno_Sequence * pCurrentSeq= pMultiSeq; + sal_Int32 curDim=1; // 1 based + bool skipSeq= false; + while( curDim <= dimsSeq ) + { + // get the Sequence at the index if valid + if( pCurrentSeq->nElements > arDimsSeqIndices[ curDim - 1] ) // don't point to Nirvana + { + // size of Sequence is 4 + sal_Int32 offset= arDimsSeqIndices[ curDim - 1] * 4; + pCurrentSeq= *reinterpret_cast(&pCurrentSeq->elements[ offset]); + curDim++; + } + else + { + // There is no Sequence at this index, so skip this index + skipSeq= true; + break; + } + } + + if( skipSeq) + continue; + + // Calculate the current position within the datablock of the SAFEARRAY + // for the next Sequence. + sal_Int32 memOffset= 0; + sal_Int32 dimWeight= parElementCount[ dims - 1]; // size of the rightmost dimension + for(sal_Int32 idims=0; idims < dimsSeq; idims++ ) + { + memOffset+= arDimsSeqIndices[dimsSeq - 1 - idims] * dimWeight; + // now determine the weight of the dimension to the left of the current. + if( dims - 2 - idims >=0) + dimWeight*= parElementCount[dims - 2 - idims]; + } + psaCurrentData= static_cast(pSAData) + memOffset * oleElementSize; + // convert the Sequence and put the elements into the Safearray + for( sal_Int32 i= 0; i < pCurrentSeq->nElements; i++) + { + Any unoElement( pCurrentSeq->elements + i * elementSize, rawTypeDesc ); + // The any is being converted into a VARIANT which value is then copied + // to the SAFEARRAY's data block. When copying one has to follow the rules for + // copying certain types, as are VT_DISPATCH, VT_UNKNOWN, VT_VARIANT, VT_BSTR. + // To increase performance, we just do a memcpy of VARIANT::byref. This is possible + // because anyToVariant has already followed the copying rules. To make this + // work there must not be a VariantClear. + // One Exception is VARIANT because I don't know how VariantCopy works. + + VARIANT var; + VariantInit( &var); + anyToVariant( &var, unoElement); + if( elemtype == VT_VARIANT ) + { + VariantCopy( reinterpret_cast(psaCurrentData), &var); + VariantClear( &var); + } + else + memcpy( psaCurrentData, &var.byref, oleElementSize); + + psaCurrentData+= oleElementSize; + } + } + while( incrementMultidimensionalIndex( dimsSeq, parElementCount, arDimsSeqIndices)); + + SafeArrayUnaccessData( pArray); + } + } + } + return pArray; +} + +// Increments a multi dimensional index. +// Returns true as long as the index has been successfully incremented, false otherwise. +// False is also returned if an overflow of the most significant dimension occurs. E.g. +// assume an array with the dimensions (2,2), then the lowest index is (0,0) and the highest +// index is (1,1). If the function is being called with the index (1,1) then the overflow would +// occur, with the result (0,0) and a sal_False as return value. +// Param dimensions - number of dimensions +// Param parDimensionsLength - The array contains the size of each dimension, that is the +// size of the array equals the parameter dimensions. +// The rightmost dimensions is the least significant one +// ( parDimensionsLengths[ dimensions -1 ] ). +// Param parMultiDimensionalIndex - The array contains the index. Each dimension index is +// 0 based. +template +bool UnoConversionUtilities::incrementMultidimensionalIndex(sal_Int32 dimensions, + const sal_Int32 * parDimensionLengths, + sal_Int32 * parMultidimensionalIndex) +{ + if( dimensions < 1) + return false; + + bool ret= true; + bool carry= true; // to get into the while loop + + sal_Int32 currentDimension= dimensions; //most significant is 1 + while( carry) + { + parMultidimensionalIndex[ currentDimension - 1]++; + // if carryover, set index to 0 and handle carry on a level above + if( parMultidimensionalIndex[ currentDimension - 1] > (parDimensionLengths[ currentDimension - 1] - 1)) + parMultidimensionalIndex[ currentDimension - 1]= 0; + else + carry= false; + + currentDimension --; + // if dimensions drops below 1 and carry is set than then all indices are 0 again + // this is signalled by returning sal_False + if( currentDimension < 1 && carry) + { + carry= false; + ret= false; + } + } + return ret; +} + +// Determines the size of a certain OLE type. The function takes +// only those types into account which are oleautomation types and +// can have a value ( unless VT_NULL, VT_EMPTY, VT_ARRAY, VT_BYREF). +// Currently used in createUnoSequenceWrapper to calculate addresses +// for data within a SAFEARRAY. +template +size_t UnoConversionUtilities::getOleElementSize( VARTYPE type) +{ + size_t size; + switch( type) + { + case VT_BOOL: size= sizeof( VARIANT_BOOL);break; + case VT_UI1: size= sizeof( unsigned char);break; + case VT_R8: size= sizeof( double);break; + case VT_R4: size= sizeof( float);break; + case VT_I2: size= sizeof( short);break; + case VT_I4: size= sizeof( long);break; + case VT_BSTR: size= sizeof( BSTR); break; + case VT_ERROR: size= sizeof( SCODE); break; + case VT_DISPATCH: + case VT_UNKNOWN: size= sizeof( IUnknown*); break; + case VT_VARIANT: size= sizeof( VARIANT);break; + default: size= 0; + } + return size; +} + +//If a Sequence is being converted into a SAFEARRAY then we possibly have +// to create a SAFEARRAY with multiple dimensions. This is the case when a +// Sequence contains Sequences ( Sequence< Sequence < XXX > > ). The leftmost +// Sequence in the declaration is assumed to represent dimension 1. Because +// all Sequence elements of a Sequence can have different length, we have to +// determine the maximum length which is then the length of the respective +// dimension. +// getElementCountAndTypeOfSequence determines the length of each dimension and calls itself recursively +// in the process. +// param rSeq - an Any that has to contain a Sequence +// param dim - the dimension for which the number of elements is being determined, +// must be one. +// param seqElementCounts - contains the maximum number of elements for each +// dimension. Index 0 contains the number of dimension one. +// After return the Sequence contains the maximum number of +// elements for each dimension. +// The length of the Sequence must equal the number of dimensions. +// param typeClass - TypeClass of the element type that is no Sequence, e.g. +// Sequence< Sequence > > - type is sal_Int32) +template +void UnoConversionUtilities::getElementCountAndTypeOfSequence( const Any& rSeq, sal_Int32 dim, + Sequence< sal_Int32 >& seqElementCounts, TypeDescription& typeDesc) +{ + sal_Int32 dimCount= (*static_cast(rSeq.getValue()))->nElements; + if( dimCount > seqElementCounts[ dim-1]) + seqElementCounts.getArray()[ dim-1]= dimCount; + + // we need the element type to construct the any that is + // passed into getElementCountAndTypeOfSequence again + typelib_TypeDescription* pSeqDesc= nullptr; + rSeq.getValueTypeDescription( &pSeqDesc); + typelib_TypeDescriptionReference* pElementDescRef= reinterpret_cast(pSeqDesc)->pType; + + // if the elements are Sequences then do recursion + if( dim < seqElementCounts.getLength() ) + { + uno_Sequence* pSeq = *static_cast(rSeq.getValue()); + uno_Sequence** arSequences= reinterpret_cast(pSeq->elements); + for( sal_Int32 i=0; i < dimCount; i++) + { + uno_Sequence* arElement= arSequences[ i]; + getElementCountAndTypeOfSequence( Any( &arElement, pElementDescRef), dim + 1 , seqElementCounts, typeDesc); + } + } + else + { + // determine the element type ( e.g. Sequence< Sequence > > - type is sal_Int32) + typeDesc= pElementDescRef; + } + typelib_typedescription_release( pSeqDesc); +} + + +template +SAFEARRAY* UnoConversionUtilities::createUnoSequenceWrapper(const Any& rSeq) +{ + SAFEARRAY* pArray = nullptr; + sal_uInt32 n = 0; + + if( rSeq.getValueTypeClass() != TypeClass_SEQUENCE ) + throw IllegalArgumentException( + "[automation bridge]UnoConversionUtilities::createUnoSequenceWrapper\n" + "The UNO argument is not a sequence", nullptr, -1); + + uno_Sequence * punoSeq= *static_cast(rSeq.getValue()); + + typelib_TypeDescriptionReference* pSeqTypeRef= rSeq.getValueTypeRef(); + typelib_TypeDescription* pSeqType= nullptr; + TYPELIB_DANGER_GET( &pSeqType, pSeqTypeRef); + typelib_IndirectTypeDescription * pSeqIndDec= reinterpret_cast(pSeqType); + + + typelib_TypeDescriptionReference * pSeqElementTypeRef= pSeqIndDec->pType; + TYPELIB_DANGER_RELEASE( pSeqType); + + typelib_TypeDescription* pSeqElementDesc= nullptr; + TYPELIB_DANGER_GET( &pSeqElementDesc, pSeqElementTypeRef); + sal_Int32 nElementSize= pSeqElementDesc->nSize; + n= punoSeq->nElements; + + SAFEARRAYBOUND rgsabound[1]; + rgsabound[0].lLbound = 0; + rgsabound[0].cElements = n; + VARIANT oleElement; + LONG safeI[1]; + + pArray = SafeArrayCreate(VT_VARIANT, 1, rgsabound); + + Any unoElement; + char * pSeqData= punoSeq->elements; + + for (sal_uInt32 i = 0; i < n; i++) + { + unoElement.setValue( pSeqData + i * nElementSize, pSeqElementDesc); + VariantInit(&oleElement); + + anyToVariant(&oleElement, unoElement); + + safeI[0] = i; + SafeArrayPutElement(pArray, safeI, &oleElement); + + VariantClear(&oleElement); + } + TYPELIB_DANGER_RELEASE( pSeqElementDesc); + + return pArray; +} + +/* The argument rObj can contain +- UNO struct +- UNO interface +- UNO interface created by this bridge (adapter factory) +- UNO interface created by this bridge ( COM Wrapper) + +pVar must be initialized. +*/ +template +void UnoConversionUtilities::createUnoObjectWrapper(const Any & rObj, VARIANT * pVar) +{ + MutexGuard guard(getBridgeMutex()); + + Reference xInt; + + TypeClass tc = rObj.getValueTypeClass(); + if (tc != TypeClass_INTERFACE && tc != TypeClass_STRUCT) + throw IllegalArgumentException( + "[automation bridge]UnoConversionUtilities::createUnoObjectWrapper \n" + "Cannot create an Automation interface for a UNO type which is not " + "a struct or interface!", nullptr, -1); + + if (rObj.getValueTypeClass() == TypeClass_INTERFACE) + { + if (! (rObj >>= xInt)) + throw IllegalArgumentException( + "[automation bridge] UnoConversionUtilities::createUnoObjectWrapper\n " + "Could not create wrapper object for UNO object!", nullptr, -1); + //If XInterface is NULL, which is a valid value, then simply return NULL. + if ( ! xInt.is()) + { + pVar->vt = VT_UNKNOWN; + pVar->punkVal = nullptr; + return; + } + //make sure we have the main XInterface which is used with a map + xInt.set(xInt, UNO_QUERY); + //If there is already a wrapper for the UNO object then use it + + Reference xIntWrapper; + // Does a UNO wrapper exist already ? + auto it_uno = UnoObjToWrapperMap.find( reinterpret_cast(xInt.get())); + if(it_uno != UnoObjToWrapperMap.end()) + { + xIntWrapper = it_uno->second; + if (xIntWrapper.is()) + { + convertSelfToCom(xIntWrapper, pVar); + return; + } + } + // Is the object a COM wrapper ( either XInvocation, or Adapter object) + // or does it supply an IDispatch by its own ? + else + { + Reference xIntComWrapper = xInt; + + // Adapter? then get the COM wrapper to which the adapter delegates its calls + auto it = AdapterToWrapperMap.find( reinterpret_cast(xInt.get())); + if( it != AdapterToWrapperMap.end() ) + xIntComWrapper= reinterpret_cast(it->second); + + if (convertSelfToCom(xIntComWrapper, pVar)) + return; + } + } + // If we have no UNO wrapper nor the IDispatch yet then we have to create + // a wrapper. For that we need an XInvocation. + + // create an XInvocation using the invocation service + Reference xInv; + Reference xInvFactory= getInvocationFactory(rObj); + if (xInvFactory.is()) + { + Sequence params(2); + params.getArray()[0] = rObj; + params.getArray()[1] <<= OUString("FromOLE"); + Reference xInt2 = xInvFactory->createInstanceWithArguments(params); + xInv.set(xInt2, UNO_QUERY); + } + + if (xInv.is()) + { + Reference xNewWrapper = createUnoWrapperInstance(); + Reference xInitWrapper(xNewWrapper, UNO_QUERY); + if (xInitWrapper.is()) + { + VARTYPE vartype= getVarType( rObj); + + if (xInt.is()) + { + Any params[3]; + params[0] <<= xInv; + params[1] <<= xInt; + params[2] <<= vartype; + xInitWrapper->initialize( Sequence(params, 3)); + } + else + { + Any params[2]; + params[0] <<= xInv; + params[1] <<= vartype; + xInitWrapper->initialize( Sequence(params, 2)); + } + + // put the newly created object into a map. If the same object will + // be mapped again and there is already a wrapper then the old wrapper + // will be used. + if(xInt.is()) // only interfaces + UnoObjToWrapperMap[reinterpret_cast(xInt.get())]= xNewWrapper; + convertSelfToCom(xNewWrapper, pVar); + return; + } + } +} + +template +void UnoConversionUtilities::variantToAny( const VARIANT* pVariant, Any& rAny, + bool bReduceValueRange /* = sal_True */) +{ + HRESULT hr = S_OK; + try + { + CComVariant var; + + // There is no need to support indirect values, since they're not supported by UNO + if( FAILED(hr= VariantCopyInd( &var, pVariant))) // remove VT_BYREF + throw BridgeRuntimeError( + "[automation bridge] UnoConversionUtilities::variantToAny \n" + "VariantCopyInd failed for reason : " + OUString::number(hr)); + + if ( ! convertValueObject( & var, rAny)) + { + if ((var.vt & VT_ARRAY) > 0) + { + VARTYPE oleTypeFlags = ::sal::static_int_cast< VARTYPE, int >( var.vt ^ VT_ARRAY ); + + Sequence unoSeq = createOleArrayWrapper(var.parray, oleTypeFlags); + rAny.setValue( &unoSeq, cppu::UnoType::get()); + } + else + { + switch (var.vt) + { + case VT_EMPTY: + rAny.setValue(nullptr, Type()); + break; + case VT_NULL: + rAny.setValue(nullptr, Type()); + break; + case VT_I2: + rAny.setValue( & var.iVal, cppu::UnoType::get()); + break; + case VT_I4: + rAny.setValue( & var.lVal, cppu::UnoType::get()); + // necessary for use in JavaScript ( see "reduceRange") + if( bReduceValueRange) + reduceRange(rAny); + break; + case VT_R4: + rAny.setValue( & var.fltVal, cppu::UnoType::get()); + break; + case VT_R8: + rAny.setValue(& var.dblVal, cppu::UnoType::get()); + break; + case VT_CY: + { + Currency cy(var.cyVal.int64); + rAny <<= cy; + break; + } + case VT_DATE: + { + Date d(var.date); + rAny <<= d; + break; + } + case VT_BSTR: + { + OUString b(o3tl::toU(var.bstrVal)); + rAny.setValue( &b, cppu::UnoType::get()); + break; + } + case VT_UNKNOWN: + case VT_DISPATCH: + { + //check if it is a UNO type + CComQIPtr spType(static_cast(var.byref)); + if (spType) + { + CComBSTR sName; + if (FAILED(spType->get_Name(&sName))) + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::variantToAny \n" + "Failed to get the type name from a UnoTypeWrapper!"); + Type type; + if (!getType(sName, type)) + { + throw CannotConvertException( + OUString::Concat("[automation bridge]UnoConversionUtilities::variantToAny \n" + "A UNO type with the name: ") + o3tl::toU(LPCOLESTR(sName)) + + "does not exist!", + nullptr, TypeClass_UNKNOWN, FailReason::TYPE_NOT_SUPPORTED,0); + } + rAny <<= type; + } + else + { + rAny = createOleObjectWrapper( & var); + } + break; + } + case VT_ERROR: + { + SCode scode(var.scode); + rAny <<= scode; + break; + } + case VT_BOOL: + { + rAny <<= (var.boolVal == VARIANT_TRUE); + break; + } + case VT_I1: + rAny.setValue( & var.cVal, cppu::UnoType::get()); + break; + case VT_UI1: // there is no unsigned char in UNO + rAny <<= sal_Int8(var.bVal); + break; + case VT_UI2: + rAny.setValue( & var.uiVal, cppu::UnoType::get() ); + break; + case VT_UI4: + rAny.setValue( & var.ulVal, cppu::UnoType::get()); + break; + case VT_INT: + rAny.setValue( & var.intVal, cppu::UnoType::get()); + break; + case VT_UINT: + rAny.setValue( & var.uintVal, cppu::UnoType::get()); + break; + case VT_VOID: + rAny.setValue( nullptr, Type()); + break; + case VT_DECIMAL: + { + Decimal dec; + dec.Scale = var.decVal.scale; + dec.Sign = var.decVal.sign; + dec.LowValue = var.decVal.Lo32; + dec.MiddleValue = var.decVal.Mid32; + dec.HighValue = var.decVal.Hi32; + rAny <<= dec; + break; + } + + default: + break; + } + } + } + } + catch (const IllegalArgumentException &) + { + throw; + } + catch (const CannotConvertException &) + { + throw; + } + catch (const BridgeRuntimeError &) + { + throw; + } + catch (const Exception & e) + { + throw BridgeRuntimeError("[automation bridge] unexpected exception in " + "UnoConversionUtilities::variantToAny ! Message : \n" + + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + "[automation bridge] unexpected exception in " + "UnoConversionUtilities::variantToAny !"); + } + +} +// The function converts an IUnknown* into a UNO interface or struct. The +// IUnknown pointer can constitute different kind of objects: +// 1. a wrapper of a UNO struct (the wrapper was created by this bridge) +// 2. a wrapper of a UNO interface (created by this bridge) +// 3. a dispatch object that implements UNO interfaces +// 4. a dispatch object. + +// If the parameter "aType" has a value then the COM object ( pUnknown) is supposed to +// implement the interface described by "aType". Moreover it ( pUnknown) can implement +// several other +// UNO interfaces in which case it has to support the SUPPORTED_INTERFACES_PROP (see +// #define) property. That property contains all names of interfaces. +// "pUnknown" is wrapped by a COM wrapper object that implements XInvocation, e.g. +// IUnknownWrapper. Additionally an object of type "aType" is created by help +// of the INTERFACE_ADAPTER_FACTORY (see #define) service. The implementation of +// "aType" calls on the COM wrapper's XInvocation::invoke. If the COM object supports +// more than one UNO interfaces, as can be determined by the property +// SUPPORTED_INTERFACES_PROP, then the INTERFACE_ADAPTER_FACTORY creates an object that +// implements all these interfaces. +// This is only done if "pUnknown" is not already a UNO wrapper, +// that is it is actually NOT a UNO object that was converted to a COM object. If it is an +// UNO wrapper than the original UNO object is being extracted, queried for "aType" (if +// it is no struct) and returned. +template +Any UnoConversionUtilities::createOleObjectWrapper(VARIANT* pVar, const Type& aType) +{ + //To allow passing "Nothing" in VS 2008 we need to accept VT_EMPTY + if (pVar->vt != VT_UNKNOWN && pVar->vt != VT_DISPATCH && pVar->vt != VT_EMPTY) + throw IllegalArgumentException( + "[automation bridge]UnoConversionUtilities::createOleObjectWrapper \n" + "The VARIANT does not contain an object type! ", nullptr, -1); + + MutexGuard guard( getBridgeMutex()); + + CComPtr spUnknown; + CComPtr spDispatch; + + if (pVar->vt == VT_UNKNOWN) + { + spUnknown = pVar->punkVal; + if (spUnknown) + spUnknown.QueryInterface( & spDispatch.p); + } + else if (pVar->vt == VT_DISPATCH && pVar->pdispVal != nullptr) + { + CComPtr spDispatch2(pVar->pdispVal); + if (spDispatch2) + spDispatch2.QueryInterface( & spUnknown.p); + } + + static Type VOID_TYPE; + Any ret; + //If no Type is provided and pVar contains IUnknown then we return a XInterface. + //If pVar contains an IDispatch then we return a XInvocation. + Type desiredType = aType; + + if (aType == VOID_TYPE) + { + switch (pVar->vt) + { + case VT_EMPTY: + case VT_UNKNOWN: + desiredType = cppu::UnoType::get(); + break; + case VT_DISPATCH: + desiredType = cppu::UnoType::get(); + break; + default: + desiredType = aType; + } + } + + // COM pointer are NULL, no wrapper required + if (spUnknown == nullptr) + { + Reference xInt; + if( aType.getTypeClass() == TypeClass_INTERFACE) + ret.setValue( &xInt, aType); + else if( aType.getTypeClass() == TypeClass_STRUCT) + ret.setValue( nullptr, aType); + else + ret <<= xInt; + return ret; + } + + + // Check if "spUnknown" is a UNO wrapper, that is a UNO object that has been + // passed to COM. Then it supports IUnoObjectWrapper + // and we extract the original UNO object. + CComQIPtr spUno( spUnknown); + if( spUno) + { // it is a wrapper + Reference xInt; + if( SUCCEEDED( spUno->getOriginalUnoObject( &xInt))) + { + ret <<= xInt; + } + else + { + Any any; + if( SUCCEEDED( spUno->getOriginalUnoStruct(&any))) + ret= any; + } + return ret; + } + + // "spUnknown" is a real COM object. + // Before we create a new wrapper object we check if there is an existing wrapper + // There can be two kinds of wrappers, those who wrap dispatch - UNO objects, and those who + // wrap ordinary dispatch objects. The dispatch-UNO objects usually are adapted to represent + // particular UNO interfaces. + Reference xIntWrapper; + auto cit_currWrapper= ComPtrToWrapperMap.find( reinterpret_cast(spUnknown.p)); + if(cit_currWrapper != ComPtrToWrapperMap.end()) + xIntWrapper = cit_currWrapper->second; + if (xIntWrapper.is()) + { + //Try to find an adapter for the wrapper + //find the proper Adapter. The pointer in the WrapperToAdapterMap are valid as long as + //we get a pointer to the wrapper from ComPtrToWrapperMap, because the Adapter hold references + //to the wrapper. + auto it = WrapperToAdapterMap.find(reinterpret_cast(xIntWrapper.get())); + if (it == WrapperToAdapterMap.end()) + { + // No adapter available. + //The COM component could be a UNO object. Then we need to provide + // a proxy that implements all interfaces + Sequence seqTypes= getImplementedInterfaces(spUnknown); + Reference xIntAdapter; + if (seqTypes.getLength() > 0) + { + //It is a COM UNO object + xIntAdapter = createAdapter(seqTypes, xIntWrapper); + } + else + { + // Some ordinary COM object + xIntAdapter = xIntWrapper; + } + // return the wrapper directly, return XInterface or XInvocation + ret = xIntWrapper->queryInterface(desiredType); + if ( ! ret.hasValue()) + throw IllegalArgumentException( + "[automation bridge]UnoConversionUtilities::createOleObjectWrapper \n" + "The COM object is not suitable for the UNO type: " + + desiredType.getTypeName(), nullptr, -1); + } + else + { + //There is an adapter available + Reference xIntAdapter(reinterpret_cast(it->second)); + ret = xIntAdapter->queryInterface( desiredType); + if ( ! ret.hasValue()) + throw IllegalArgumentException( + "[automation bridge]UnoConversionUtilities::createOleObjectWrapper \n" + "The COM object is not suitable for the UNO type: " + + desiredType.getTypeName(), nullptr, -1); + } + + return ret; + } + // No existing wrapper. Therefore create a new proxy. + // If the object implements UNO interfaces then get the types. + Sequence seqTypes = getImplementedInterfaces(spUnknown); + if (seqTypes.getLength() == 0 && + aType != VOID_TYPE && aType != cppu::UnoType::get()) + { + seqTypes = Sequence( & aType, 1); + } + + //There is no existing wrapper, therefore we create one for the real COM object + Reference xIntNewProxy= createComWrapperInstance(); + if ( ! xIntNewProxy.is()) + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::createOleObjectWrapper \n" + "Could not create proxy object for COM object!"); + + // initialize the COM wrapper + Reference xInit( xIntNewProxy, UNO_QUERY); + OSL_ASSERT( xInit.is()); + + Any params[3]; + params[0] <<= reinterpret_cast(spUnknown.p); + params[1] <<= (pVar->vt == VT_DISPATCH); + params[2] <<= seqTypes; + + xInit->initialize( Sequence( params, 3)); + ComPtrToWrapperMap[reinterpret_cast(spUnknown.p)] = xIntNewProxy; + + // we have a wrapper object + //The wrapper implements already XInvocation and XInterface. If + //param aType is void then the object is supposed to have XInvocation. + if (aType == cppu::UnoType::get()|| + (aType == VOID_TYPE && seqTypes.getLength() == 0 )) + { + ret = xIntNewProxy->queryInterface(desiredType); + } + else + { + Reference xIntAdapter = + createAdapter(seqTypes, xIntNewProxy); + ret = xIntAdapter->queryInterface(desiredType); + } + return ret; +} +template +Reference UnoConversionUtilities::createAdapter(const Sequence& seqTypes, + const Reference& receiver) +{ + Reference< XInterface> xIntAdapterFac; + xIntAdapterFac= m_smgr->createInstance(INTERFACE_ADAPTER_FACTORY); + // We create an adapter object that does not only implement the required type but also + // all types that the COM object pretends to implement. A COM object must therefore + // support the property "_implementedInterfaces". + Reference xIntAdapted; + Reference xInv(receiver, UNO_QUERY); + Reference xAdapterFac( xIntAdapterFac, UNO_QUERY); + if( xAdapterFac.is()) + xIntAdapted= xAdapterFac->createAdapter( xInv, seqTypes); + + if( !xIntAdapted.is()) + { + throw BridgeRuntimeError( + "[automation bridge]UnoConversionUtilities::createOleObjectWrapper \n" + "Could not create a proxy for COM object! Creation of adapter failed."); + } + + // Put the pointer to the wrapper object and the interface pointer of the adapted interface + // in a global map. Thus we can determine in a call to createUnoObjectWrapper whether the UNO + // object is a wrapped COM object. In that case we extract the original COM object rather than + // creating a wrapper around the UNO object. + typedef std::unordered_map::value_type VALUE; + AdapterToWrapperMap.insert( VALUE( reinterpret_cast(xIntAdapted.get()), reinterpret_cast(receiver.get()))); + WrapperToAdapterMap.insert( VALUE( reinterpret_cast(receiver.get()), reinterpret_cast(xIntAdapted.get()))); + + return xIntAdapted; +} +// "convertValueObject" converts a JScriptValue object contained in "var" into +// an any. The type contained in the any is stipulated by a "type value" thas +// was set within the JScript script on the value object ( see JScriptValue). +template +bool UnoConversionUtilities::convertValueObject( const VARIANTARG *var, Any& any) +{ + bool ret = false; + try + { + bool bFail = false; + HRESULT hr= S_OK; + CComVariant varDisp; + + if(SUCCEEDED(hr = varDisp.ChangeType( VT_DISPATCH, var))) + { + CComPtr spValue; + VARIANT_BOOL varBool; + CComBSTR bstrType; + CComVariant varValue; + CComPtr spDisp( varDisp.pdispVal); + if(spDisp) + { + if(SUCCEEDED( spDisp->QueryInterface( __uuidof( IJScriptValueObject), + reinterpret_cast (&spValue)))) + { + ret = true; // is a ValueObject + //If it is an out - param then it does not need to be converted. In/out and + // in params does so. + if (SUCCEEDED(hr= spValue->IsOutParam( &varBool))) + { + // if varBool == true then no conversion needed because out param + if (varBool == VARIANT_FALSE) + { + if(SUCCEEDED(hr = spValue->GetValue( & bstrType, & varValue))) + { + Type type; + if (getType(bstrType, type)) + variantToAny( & varValue, any, type); + else + bFail = true; + } + else + bFail = true; + } + } + else + bFail = true; + } + } + } + else if( hr != DISP_E_TYPEMISMATCH && hr != E_NOINTERFACE) + bFail = true; + + if (bFail) + throw BridgeRuntimeError( + "[automation bridge] Conversion of ValueObject failed "); + } + catch (const BridgeRuntimeError &) + { + throw; + } + catch (const Exception & e) + { + throw BridgeRuntimeError("[automation bridge] unexpected exception in " + "UnoConversionUtilities::convertValueObject ! Message : \n" + + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + "[automation bridge] unexpected exception in " + "UnoConversionUtilities::convertValueObject !"); + } + return ret; +} + +template +void UnoConversionUtilities::dispatchExObject2Sequence( const VARIANTARG* pvar, Any& anySeq, const Type& type) +{ + try + { + if( pvar->vt != VT_DISPATCH) + throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!"); + IDispatchEx* pdispEx; + HRESULT hr; + if( FAILED( hr= pvar->pdispVal->QueryInterface( IID_IDispatchEx, + reinterpret_cast( &pdispEx)))) + throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!"); + + DISPID dispid; + DISPPARAMS param= {nullptr,nullptr,0,0}; + CComVariant result; + + OLECHAR const * sLength= L"length"; + + // Get the length of the array. Can also be obtained through GetNextDispID. The + // method only returns DISPIDs of the array data. Their names are like "0", "1" etc. + if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, const_cast(&sLength), 1, LOCALE_USER_DEFAULT, &dispid))) + throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!"); + if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, + ¶m, &result, nullptr, nullptr))) + throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!"); + if( FAILED( VariantChangeType( &result, &result, 0, VT_I4))) + throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!"); + LONG length= result.lVal; + + result.Clear(); + + // get a few basic facts about the sequence, and reallocate: + // create the Sequences + // get the size of the elements + typelib_TypeDescription *pDesc= nullptr; + type.getDescription( &pDesc); + + typelib_IndirectTypeDescription *pSeqDesc= reinterpret_cast(pDesc); + typelib_TypeDescriptionReference *pSeqElemDescRef= pSeqDesc->pType; // type of the Sequence' elements + Type elemType( pSeqElemDescRef); + _typelib_TypeDescription* pSeqElemDesc=nullptr; + TYPELIB_DANGER_GET( &pSeqElemDesc, pSeqElemDescRef); + sal_uInt32 nelementSize= pSeqElemDesc->nSize; + TYPELIB_DANGER_RELEASE( pSeqElemDesc); + + uno_Sequence *p_uno_Seq; + uno_sequence_construct( &p_uno_Seq, pDesc, nullptr, length, cpp_acquire); + + typelib_TypeClass typeElement= pSeqDesc->pType->eTypeClass; + char *pArray= p_uno_Seq->elements; + + // Get All properties in the object, convert their values to the expected type and + // put them into the passed in sequence + for( sal_Int32 i= 0; i< length; i++) + { + OUString ousIndex=OUString::number( i); + OLECHAR* sindex = const_cast(o3tl::toW(ousIndex.getStr())); + + if( FAILED( hr= pdispEx->GetIDsOfNames(IID_NULL, &sindex , 1, LOCALE_USER_DEFAULT, &dispid))) + { + throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!"); + } + if( FAILED( hr= pdispEx->InvokeEx(dispid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, + ¶m, &result, nullptr, nullptr))) + { + throw BridgeRuntimeError("[automation bridge] UnoConversionUtilities::dispatchExObject2Sequence \n" + "Conversion of dispatch object to Sequence failed!"); + } + + // If the result is VT_DISPATCH than the Sequence's element type could be Sequence + // Look that up in the CoreReflection to make clear. + // That requires a recursiv conversion + Any any; + // Destination address within the out-Sequence "anySeq" where to copy the next converted element + void* pDest= pArray + (i * nelementSize); + + if( result.vt & VT_DISPATCH && typeElement == typelib_TypeClass_SEQUENCE) + { + variantToAny( &result, any, elemType, false); + // copy the converted VARIANT, that is a Sequence to the Sequence + uno_Sequence * p_unoSeq= *static_cast(any.getValue()); + // just copy the pointer of the uno_Sequence + // nelementSize should be 4 !!!! + memcpy( pDest, &p_unoSeq, nelementSize); + osl_atomic_increment( &p_unoSeq->nRefCount); + } + else // Element type is no Sequence -> do one conversion + { + variantToAny( &result, any, elemType, false); + if( typeElement == typelib_TypeClass_ANY) + { + // copy the converted VARIANT to the Sequence + uno_type_assignData( pDest, pSeqElemDescRef , &any, pSeqElemDescRef,cpp_queryInterface, + cpp_acquire, cpp_release); + } + else + { + // type after conversion must be the element type of the sequence + OSL_ENSURE(any.getValueTypeClass() == css::uno::TypeClass(typeElement), "wrong conversion"); + uno_type_assignData( pDest, pSeqElemDescRef,const_cast( any.getValue()), any.getValueTypeRef(), + cpp_queryInterface, cpp_acquire, cpp_release); + } + } + } // else + result.Clear(); + anySeq.setValue( &p_uno_Seq, pDesc); + uno_destructData( &p_uno_Seq, pDesc, cpp_release); + typelib_typedescription_release( pDesc); + } + catch (const BridgeRuntimeError &) + { + throw; + } + catch (const Exception & e) + { + throw BridgeRuntimeError("[automation bridge] unexpected exception in " + "UnoConversionUtilities::convertValueObject ! Message : \n" + + e.Message); + } + catch(...) + { + throw BridgeRuntimeError( + "[automation bridge] unexpected exception in " + "UnoConversionUtilities::convertValueObject !"); + } +} + +/* The argument unotype is the type that is expected by the currently called UNO function. + For example: []long, [][]long. If the function calls itself recursively then the element type + is passed on. For example a two dimensional SAFEARRAY of type VT_I4 is to be converted. Then + unotype has to be either void or [][]long. When the function calls itself recursively then + it passes the element type which is []long. +*/ +template +Sequence UnoConversionUtilities::createOleArrayWrapperOfDim(SAFEARRAY* pArray, + unsigned int dimCount, unsigned int actDim, LONG* index, VARTYPE type, const Type& unotype) +{ + LONG lBound; + LONG uBound; + LONG nCountElements; + + SafeArrayGetLBound(pArray, actDim, &lBound); + SafeArrayGetUBound(pArray, actDim, &uBound); + nCountElements= uBound - lBound +1; + + Sequence anySeq(nCountElements); + Any* pUnoArray = anySeq.getArray(); + + for (index[actDim - 1] = lBound; index[actDim - 1] <= uBound; index[actDim - 1]++) + { + if (actDim > 1 ) + { + Sequence element = createOleArrayWrapperOfDim(pArray, dimCount, + actDim - 1, index, type, getElementTypeOfSequence(unotype)); + + pUnoArray[index[actDim - 1] - lBound].setValue(&element, cppu::UnoType::get()); + } + else + { + VARIANT variant; + + VariantInit(&variant); + + V_VT(&variant) = type; + + switch (type) + { + case VT_I2: + SafeArrayGetElement(pArray, index, &V_I2(&variant)); + break; + case VT_I4: + SafeArrayGetElement(pArray, index, &V_I4(&variant)); + break; + case VT_R4: + SafeArrayGetElement(pArray, index, &V_R4(&variant)); + break; + case VT_R8: + SafeArrayGetElement(pArray, index, &V_R8(&variant)); + break; + case VT_CY: + SafeArrayGetElement(pArray, index, &V_CY(&variant)); + break; + case VT_DATE: + SafeArrayGetElement(pArray, index, &V_DATE(&variant)); + break; + case VT_BSTR: + SafeArrayGetElement(pArray, index, &V_BSTR(&variant)); + break; + case VT_DISPATCH: + SafeArrayGetElement(pArray, index, &V_DISPATCH(&variant)); + break; + case VT_ERROR: + SafeArrayGetElement(pArray, index, &V_ERROR(&variant)); + break; + case VT_BOOL: + SafeArrayGetElement(pArray, index, &V_BOOL(&variant)); + break; + case VT_VARIANT: + SafeArrayGetElement(pArray, index, &variant); + break; + case VT_UNKNOWN: + SafeArrayGetElement(pArray, index, &V_UNKNOWN(&variant)); + break; + case VT_I1: + SafeArrayGetElement(pArray, index, &V_I1(&variant)); + break; + case VT_UI1: + SafeArrayGetElement(pArray, index, &V_UI1(&variant)); + break; + case VT_UI2: + SafeArrayGetElement(pArray, index, &V_UI2(&variant)); + break; + case VT_UI4: + SafeArrayGetElement(pArray, index, &V_UI4(&variant)); + break; + default: + break; + } + + if( unotype.getTypeClass() == TypeClass_VOID) + // the function was called without specifying the destination type + variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], false); + else + variantToAny(&variant, pUnoArray[index[actDim - 1] - lBound], + getElementTypeOfSequence(unotype), false); + + VariantClear(&variant); + } + } + return anySeq; +} + +template +Type UnoConversionUtilities::getElementTypeOfSequence( const Type& seqType) +{ + Type retValue; + if( seqType.getTypeClass() != TypeClass_VOID) + { + OSL_ASSERT( seqType.getTypeClass() == TypeClass_SEQUENCE); + typelib_TypeDescription* pDescSeq= nullptr; + seqType.getDescription(& pDescSeq); + retValue = Type(reinterpret_cast(pDescSeq)->pType); + typelib_typedescription_release(pDescSeq); + } + return retValue; +} +template +Sequence UnoConversionUtilities::createOleArrayWrapper(SAFEARRAY* pArray, VARTYPE type, const Type& unoType) +{ + sal_uInt32 dim = SafeArrayGetDim(pArray); + + Sequence ret; + + if (dim > 0) + { + std::unique_ptr sarIndex(new LONG[dim]); + LONG * index = sarIndex.get(); + + for (unsigned int i = 0; i < dim; i++) + { + index[i] = 0; + } + + ret = createOleArrayWrapperOfDim(pArray, dim, dim, index, type, unoType); + } + + return ret; +} + +// If a VARIANT has the type VT_DISPATCH it can either be a JScript Array +// or some other object. This function finds out if it is such an array or +// not. Currently there's no way to make sure it's an array +// so we assume that when the object has a property "0" then it is an Array. +// A JScript has property like "0", "1", "2" etc. which represent the +// value at the corresponding index of the array +template +bool UnoConversionUtilities::isJScriptArray(const VARIANT* rvar) +{ + OSL_ENSURE( rvar->vt == VT_DISPATCH, "param is not a VT_DISPATCH"); + HRESULT hr; + OLECHAR const * sindex= L"0"; + DISPID id; + if ( rvar->vt == VT_DISPATCH && rvar->pdispVal ) + { + hr= rvar->pdispVal->GetIDsOfNames( + IID_NULL, const_cast(&sindex), 1, LOCALE_USER_DEFAULT, + &id); + + if( SUCCEEDED ( hr) ) + return true; + } + + return false; +} + +template +VARTYPE UnoConversionUtilities::mapTypeClassToVartype( TypeClass type) +{ + VARTYPE ret; + switch( type) + { + case TypeClass_INTERFACE: ret= VT_DISPATCH; + break; + case TypeClass_STRUCT: ret= VT_DISPATCH; + break; + case TypeClass_ENUM: ret= VT_I4; + break; + case TypeClass_SEQUENCE: ret= VT_ARRAY; + break; + case TypeClass_ANY: ret= VT_VARIANT; + break; + case TypeClass_BOOLEAN: ret= VT_BOOL; + break; + case TypeClass_CHAR: ret= VT_I2; + break; + case TypeClass_STRING: ret= VT_BSTR; + break; + case TypeClass_FLOAT: ret= VT_R4; + break; + case TypeClass_DOUBLE: ret= VT_R8; + break; + case TypeClass_BYTE: ret= VT_UI1; + break; + case TypeClass_SHORT: ret= VT_I2; + break; + case TypeClass_LONG: ret= VT_I4; + break; + case TypeClass_UNSIGNED_SHORT: ret= VT_UI2; + break; + case TypeClass_UNSIGNED_LONG: ret= VT_UI4; + break; + default: + ret= VT_EMPTY; + } + return ret; +} + +template +Sequence UnoConversionUtilities::getImplementedInterfaces(IUnknown* pUnk) +{ + Sequence seqTypes; + CComDispatchDriver disp( pUnk); + if( disp) + { + CComVariant var; + HRESULT hr= S_OK; + // There are two different property names possible. + if( FAILED( hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP, &var))) + { + hr= disp.GetPropertyByName( SUPPORTED_INTERFACES_PROP2, &var); + } + if (SUCCEEDED( hr)) + { + // we expect an array( SafeArray or IDispatch) of Strings. + Any anyNames; + variantToAny( &var, anyNames, cppu::UnoType>::get()); + Sequence seqAny; + if( anyNames >>= seqAny) + { + seqTypes.realloc( seqAny.getLength()); + auto pseqTypes = seqTypes.getArray(); + for( sal_Int32 i=0; i < seqAny.getLength(); i++) + { + OUString typeName; + seqAny[i] >>= typeName; + pseqTypes[i]= Type( TypeClass_INTERFACE, typeName); + } + } + } + } + return seqTypes; +} +template +Reference UnoConversionUtilities::getTypeConverter() +{ + if ( ! m_typeConverter.is()) + { + MutexGuard guard(getBridgeMutex()); + if ( ! m_typeConverter.is()) + { + Reference xIntConverter = + m_smgr->createInstance("com.sun.star.script.Converter"); + if (xIntConverter.is()) + m_typeConverter.set(xIntConverter, UNO_QUERY); + } + } + return m_typeConverter; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unoobjw.cxx b/extensions/source/ole/unoobjw.cxx new file mode 100644 index 000000000..28286bddb --- /dev/null +++ b/extensions/source/ole/unoobjw.cxx @@ -0,0 +1,3437 @@ +/* -*- 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// Documentation pointers for recent work: +// +// https://www.codeproject.com/Articles/9014/Understanding-COM-Event-Handling +// https://blogs.msdn.microsoft.com/ericlippert/2005/02/15/why-does-wscript-connectobject-not-always-work/ + +#include "ole2uno.hxx" + +#include +#include +#include +#include +#include + +#if defined _MSC_VER && defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wall" +#pragma clang diagnostic ignored "-Wattributes" +#pragma clang diagnostic ignored "-Wdelete-incomplete" +#pragma clang diagnostic ignored "-Wdynamic-class-memaccess" +#pragma clang diagnostic ignored "-Wextra" +#pragma clang diagnostic ignored "-Wint-to-pointer-cast" +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#pragma clang diagnostic ignored "-Wmicrosoft" +#pragma clang diagnostic ignored "-Wnon-pod-varargs" +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#pragma clang diagnostic ignored "-Wnonportable-include-path" +#pragma clang diagnostic ignored "-Wsequence-point" +#pragma clang diagnostic ignored "-Wtypename-missing" +#endif +#include +#include +#if defined _MSC_VER && defined __clang__ +#pragma clang diagnostic pop +#endif +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "comifaces.hxx" +#include "jscriptclasses.hxx" +#include "unotypewrapper.hxx" +#include "oleobjw.hxx" +#include "unoobjw.hxx" +#include "servprov.hxx" + +using namespace osl; +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; +using namespace com::sun::star::container; +using namespace com::sun::star::script; +using namespace com::sun::star::lang; +using namespace com::sun::star::bridge::ModelDependent; +using namespace com::sun::star::reflection; + +std::unordered_map > UnoObjToWrapperMap; +static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource); +static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource); +static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr); + +/* Does not throw any exceptions. + Param pInfo can be NULL. + */ +static void writeExcepinfo(EXCEPINFO * pInfo, const OUString& message) +{ + if (pInfo != nullptr) + { + pInfo->wCode = UNO_2_OLE_EXCEPTIONCODE; + pInfo->bstrSource = SysAllocString(L"[automation bridge] "); + pInfo->bstrDescription = SysAllocString(o3tl::toW(message.getStr())); + } +} + +InterfaceOleWrapper::InterfaceOleWrapper( Reference const & xFactory, + sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass): + UnoConversionUtilities( xFactory, unoWrapperClass, comWrapperClass), + m_defaultValueType( 0) +{ +} + +InterfaceOleWrapper::~InterfaceOleWrapper() +{ + MutexGuard guard(getBridgeMutex()); + // remove entries in global map + auto it = UnoObjToWrapperMap.find( reinterpret_cast(m_xOrigin.get())); + if(it != UnoObjToWrapperMap.end()) + UnoObjToWrapperMap.erase(it); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::QueryInterface(REFIID riid, void ** ppv) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::QueryInterface(" << riid << ")"); + + HRESULT ret= S_OK; + + if( !ppv) + return E_POINTER; + + if(IsEqualIID(riid, IID_IUnknown)) + { + AddRef(); + *ppv = static_cast(static_cast(this)); + SAL_INFO("extensions.olebridge", " " << *ppv); + } + else if (IsEqualIID(riid, IID_IDispatch)) + { + AddRef(); + *ppv = static_cast(this); + SAL_INFO("extensions.olebridge", " " << *ppv); + } + else if (IsEqualIID(riid, IID_IProvideClassInfo)) + { + Reference xConnectable(m_xOrigin, UNO_QUERY); + if (!xConnectable.is()) + return E_NOINTERFACE; + AddRef(); + *ppv = static_cast(this); + SAL_INFO("extensions.olebridge", " " << *ppv); + } + else if (IsEqualIID(riid, IID_IConnectionPointContainer)) + { + Reference xConnectable(m_xOrigin, UNO_QUERY); + if (!xConnectable.is()) + return E_NOINTERFACE; + AddRef(); + *ppv = static_cast(this); + SAL_INFO("extensions.olebridge", " " << *ppv); + } + else if( IsEqualIID( riid, __uuidof( IUnoObjectWrapper))) + { + AddRef(); + *ppv= static_cast(this); + SAL_INFO("extensions.olebridge", " " << *ppv); + } + else + ret= E_NOINTERFACE; + return ret; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::AddRef() +{ + acquire(); + // does not need to guard because one should not rely on the return value of + // AddRef anyway + return m_refCount; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP_(ULONG) InterfaceOleWrapper::Release() +{ + ULONG n= m_refCount; + release(); + return n - 1; +} + +// IUnoObjectWrapper -------------------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getWrapperXInterface( Reference* pXInt) +{ + pXInt->set( static_cast( this), UNO_QUERY); + return pXInt->is() ? S_OK : E_FAIL; +} +COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoObject( Reference* pXInt) +{ + *pXInt= m_xOrigin; + return m_xOrigin.is() ? S_OK : E_FAIL; +} +COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::getOriginalUnoStruct( Any * pStruct) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + HRESULT ret= E_FAIL; + if( !m_xOrigin.is()) + { + Reference xMatHolder( m_xInvocation, UNO_QUERY); + if( xMatHolder.is()) + { + Any any = xMatHolder->getMaterial(); + if( any.getValueTypeClass() == TypeClass_STRUCT) + { + *pStruct= any; + ret= S_OK; + } + } + } + return ret; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfoCount( UINT *pctinfo ) +{ + SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfoCount"); + + if (!pctinfo) + return E_POINTER; + + *pctinfo = 1; + + return S_OK; +} + +namespace { + +class CXTypeInfo : public ITypeInfo, + public CComObjectRoot +{ +public: + enum class Kind { COCLASS, MAIN, OUTGOING }; + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + BEGIN_COM_MAP(CXTypeInfo) +#if defined __clang__ +#pragma clang diagnostic pop +#endif + COM_INTERFACE_ENTRY(ITypeInfo) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#pragma clang diagnostic ignored "-Wunused-function" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + DECLARE_NOT_AGGREGATABLE(CXTypeInfo) + + virtual ~CXTypeInfo() {} + + void InitForCoclass(Reference xOrigin, + const OUString& sImplementationName, + const IID& rIID, + Reference xMSF); + void InitForClassItself(Reference xOrigin, + const OUString& sImplementationName, + const IID& rIID, + Reference xMSF); + void InitForOutgoing(Reference xOrigin, + const OUString& sInterfaceName, + const IID& rIID, + Reference xMSF, + Type aType); + virtual HRESULT STDMETHODCALLTYPE GetTypeAttr(TYPEATTR **ppTypeAttr) override; + virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **ppTComp) override; + virtual HRESULT STDMETHODCALLTYPE GetFuncDesc(UINT index, + FUNCDESC **ppFuncDesc) override; + virtual HRESULT STDMETHODCALLTYPE GetVarDesc(UINT index, + VARDESC **ppVarDesc) override; + virtual HRESULT STDMETHODCALLTYPE GetNames(MEMBERID memid, + BSTR *rgBstrNames, + UINT cMaxNames, + UINT *pcNames) override; + virtual HRESULT STDMETHODCALLTYPE GetRefTypeOfImplType(UINT index, + HREFTYPE *pRefType) override; + virtual HRESULT STDMETHODCALLTYPE GetImplTypeFlags(UINT index, + INT *pImplTypeFlags) override; + virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(LPOLESTR *rgszNames, + UINT cNames, + MEMBERID *pMemId) override; + virtual HRESULT STDMETHODCALLTYPE Invoke(PVOID pvInstance, + MEMBERID memid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr) override; + virtual HRESULT STDMETHODCALLTYPE GetDocumentation(MEMBERID memid, + BSTR *pBstrName, + BSTR *pBstrDocString, + DWORD *pdwHelpContext, + BSTR *pBstrHelpFile) override; + virtual HRESULT STDMETHODCALLTYPE GetDllEntry(MEMBERID memid, + INVOKEKIND invKind, + BSTR *pBstrDllName, + BSTR *pBstrName, + WORD *pwOrdinal) override; + virtual HRESULT STDMETHODCALLTYPE GetRefTypeInfo(HREFTYPE hRefType, + ITypeInfo **ppTInfo) override; + virtual HRESULT STDMETHODCALLTYPE AddressOfMember(MEMBERID memid, + INVOKEKIND invKind, + PVOID *ppv) override; + virtual HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown *pUnkOuter, + REFIID riid, + PVOID *ppvObj) override; + virtual HRESULT STDMETHODCALLTYPE GetMops(MEMBERID memid, + BSTR *pBstrMops) override; + virtual HRESULT STDMETHODCALLTYPE GetContainingTypeLib(ITypeLib **ppTLib, + UINT *pIndex) override; + virtual void STDMETHODCALLTYPE ReleaseTypeAttr(TYPEATTR *pTypeAttr) override; + virtual void STDMETHODCALLTYPE ReleaseFuncDesc(FUNCDESC *pFuncDesc) override; + virtual void STDMETHODCALLTYPE ReleaseVarDesc(VARDESC *pVarDesc) override; + +private: + Kind meKind; + Reference mxOrigin; + OUString msImplementationName; + OUString msInterfaceName; + IID maIID; + Reference mxMSF; + Type maType; +}; + +class CXTypeLib : public ITypeLib, + public CComObjectRoot +{ +public: +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + BEGIN_COM_MAP(CXTypeLib) +#if defined __clang__ +#pragma clang diagnostic pop +#endif + COM_INTERFACE_ENTRY(ITypeLib) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#pragma clang diagnostic ignored "-Wunused-function" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + DECLARE_NOT_AGGREGATABLE(CXTypeLib) + + virtual ~CXTypeLib() {} + + void Init(Reference xOrigin, + const OUString& sImplementationName, + Reference xMSF) + { + SAL_INFO("extensions.olebridge", this << "@CXTypeLib::Init for " << sImplementationName); + mxOrigin = xOrigin; + msImplementationName = sImplementationName; + mxMSF = xMSF; + } + + virtual UINT STDMETHODCALLTYPE GetTypeInfoCount() override + { + SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoCount"); + return 1; + } + + virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT, + ITypeInfo **) override + { + SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfo: E_NOTIMPL"); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoType(UINT, + TYPEKIND *) override + { + SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoType: E_NOTIMPL"); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoOfGuid(REFGUID guid, + ITypeInfo **ppTInfo) override + { + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@CXTypeLib::GetTypeInfoOfGuid(" << guid << ")"); + if (!ppTInfo) + return E_POINTER; + + Reference xConnectable(mxOrigin, UNO_QUERY); + if (!xConnectable.is()) + return TYPE_E_ELEMENTNOTFOUND; + + IID aIID; + if (SUCCEEDED(IIDFromString(reinterpret_cast(xConnectable->getIID().pData->buffer), &aIID))) + { + if (IsEqualIID(guid, aIID)) + { + HRESULT ret; + + CComObject* pTypeInfo; + + ret = CComObject::CreateInstance(&pTypeInfo); + if (FAILED(ret)) + return ret; + + pTypeInfo->AddRef(); + + pTypeInfo->InitForCoclass(mxOrigin, msImplementationName, aIID, mxMSF); + + *ppTInfo = pTypeInfo; + + return S_OK; + } + } + +#if 0 + ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint(); + + IID aIID; + if (SUCCEEDED(IIDFromString((LPOLESTR)aTypeAndIID.IID.pData->buffer, &aIID))) + { + HRESULT ret; + + CComObject* pTypeInfo; + + ret = CComObject::CreateInstance(&pTypeInfo); + if (FAILED(ret)) + return ret; + + pTypeInfo->AddRef(); + + pTypeInfo->InitForOutgoing(mxOrigin, msImplementationName, aIID, mxMSF); + + *ppTInfo = pTypeInfo; + + return S_OK; + } +#else + SAL_WARN("extensions.olebridge", "Not implemented: GetTypeInfoOfGuid(" << guid << ")"); +#endif + + return TYPE_E_ELEMENTNOTFOUND; + + } + + virtual HRESULT STDMETHODCALLTYPE GetLibAttr(TLIBATTR **) override + { + SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetLibAttr: E_NOTIMPL"); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetTypeComp(ITypeComp **) override + { + SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetTypeComp: E_NOTIMPL"); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetDocumentation(INT, + BSTR *, + BSTR *, + DWORD *, + BSTR *) override + { + SAL_WARN("extensions.olebridge", this << "@CXTypeLib::GetDocumentation: E_NOTIMPL"); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE IsName(LPOLESTR, + ULONG, + BOOL *) override + { + SAL_WARN("extensions.olebridge", this << "@CXTypeLib:IsName: E_NOTIMPL"); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE FindName(LPOLESTR, + ULONG, + ITypeInfo **, + MEMBERID *, + USHORT *) override + { + SAL_WARN("extensions.olebridge", this << "@CXTypeLib::FindName: E_NOTIMPL"); + return E_NOTIMPL; + } + + virtual void STDMETHODCALLTYPE ReleaseTLibAttr(TLIBATTR *) override + { + SAL_WARN("extensions.olebridge", this << "@CXTypeLib::ReleaseTLibAttr: E_NOTIMPL"); + } + +private: + Reference mxOrigin; + OUString msImplementationName; + Reference mxMSF; +}; + +} + +void CXTypeInfo::InitForCoclass(Reference xOrigin, + const OUString& sImplementationName, + const IID& rIID, + Reference xMSF) +{ + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForCoclass(" << sImplementationName << "," << rIID << ")"); + meKind = Kind::COCLASS; + mxOrigin = xOrigin; + msImplementationName = sImplementationName; + maIID = rIID; + mxMSF = xMSF; +} + +void CXTypeInfo::InitForClassItself(Reference xOrigin, + const OUString& sImplementationName, + const IID& rIID, + Reference xMSF) +{ + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForClassItself(" << sImplementationName << "," << rIID << ")"); + meKind = Kind::MAIN; + mxOrigin = xOrigin; + msImplementationName = sImplementationName; + maIID = rIID; + mxMSF = xMSF; +} + +void CXTypeInfo::InitForOutgoing(Reference xOrigin, + const OUString& sInterfaceName, + const IID& rIID, + Reference xMSF, + Type aType) +{ + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::InitForOutgoing(" << sInterfaceName << "," << rIID << ")"); + meKind = Kind::OUTGOING; + mxOrigin = xOrigin; + msInterfaceName = sInterfaceName; + maIID = rIID; + mxMSF = xMSF; + maType = aType; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeAttr(TYPEATTR **ppTypeAttr) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr"); + + if (!ppTypeAttr) + return E_POINTER; + + assert(!IsEqualIID(maIID, IID_NULL)); + + TYPEATTR *pTypeAttr = new TYPEATTR; + memset(pTypeAttr, 0, sizeof(*pTypeAttr)); + + pTypeAttr->guid = maIID; + + if (meKind == Kind::COCLASS) + { + pTypeAttr->typekind = TKIND_COCLASS; + pTypeAttr->cFuncs = 0; + pTypeAttr->cVars = 0; + pTypeAttr->cImplTypes = 3; + pTypeAttr->cbSizeVft = 0; + pTypeAttr->cbAlignment = 8; + pTypeAttr->wTypeFlags = TYPEFLAG_FCANCREATE; + } + else if (meKind == Kind::MAIN) + { + pTypeAttr->typekind = TKIND_DISPATCH; + pTypeAttr->cFuncs = 10; // FIXME, dummy + pTypeAttr->cVars = 0; + pTypeAttr->cImplTypes = 1; + // FIXME: I think this is always supposed to be as if just for the seven methods in + // IDIspatch? + pTypeAttr->cbSizeVft = 7 * sizeof(void*); + pTypeAttr->cbAlignment = 8; + pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FDISPATCHABLE; + } + else if (meKind == Kind::OUTGOING) + { + pTypeAttr->typekind = TKIND_DISPATCH; + + Reference xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF)); + assert(xRefl.is()); + + Reference xClass = xRefl->forName(maType.getTypeName()); + assert(xClass.is()); + + auto aMethods = xClass->getMethods(); + assert(xClass->getTypeClass() == TypeClass_INTERFACE && + aMethods.getLength() > 0); + + // Drop the three XInterface methods, add the three corresponding IUnknown ones plus the + // four IDispatch ones on top of that. + pTypeAttr->cFuncs = aMethods.getLength() - 3 + 3 + 4; + pTypeAttr->cVars = 0; + pTypeAttr->cImplTypes = 1; + // FIXME: I think this, too, is always supposed to be as if just for the seven methods in + // IDIspatch? + pTypeAttr->cbSizeVft = 7 * sizeof(void*); + pTypeAttr->cbAlignment = 8; + pTypeAttr->wTypeFlags = TYPEFLAG_FHIDDEN|TYPEFLAG_FNONEXTENSIBLE|TYPEFLAG_FDISPATCHABLE; + } + else + assert(false); + + pTypeAttr->lcid = LOCALE_USER_DEFAULT; + pTypeAttr->memidConstructor = MEMBERID_NIL; + pTypeAttr->memidDestructor = MEMBERID_NIL; + // FIXME: Is this correct, just the vtable pointer, right? + pTypeAttr->cbSizeInstance = sizeof(void*); + pTypeAttr->wMajorVerNum = 0; + pTypeAttr->wMinorVerNum = 0; + pTypeAttr->idldescType.wIDLFlags = IDLFLAG_NONE; + + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetTypeAttr: " << pTypeAttr); + + *ppTypeAttr = pTypeAttr; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetTypeComp(ITypeComp **) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetTypeComp: E_NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetFuncDesc(UINT index, + FUNCDESC **ppFuncDesc) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + if (!ppFuncDesc) + return E_POINTER; + + if (meKind != Kind::OUTGOING) + return E_NOTIMPL; + + if (index <= 6) + { + *ppFuncDesc = new FUNCDESC; + (*ppFuncDesc)->memid = 0x60000000 + index; + (*ppFuncDesc)->lprgscode = nullptr; + (*ppFuncDesc)->lprgelemdescParam = nullptr; + (*ppFuncDesc)->funckind = FUNC_DISPATCH; + (*ppFuncDesc)->invkind = INVOKE_FUNC; + (*ppFuncDesc)->callconv = CC_STDCALL; + switch (index) + { + case 0: // QueryInterface + (*ppFuncDesc)->cParams = 2; + (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; + (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; + break; + case 1: // AddRef + (*ppFuncDesc)->cParams = 0; + (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; + (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4; + break; + case 2: // Release + (*ppFuncDesc)->cParams = 1; + (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; + (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_UI4; + break; + case 3: // GetTypeInfoCount + (*ppFuncDesc)->cParams = 1; + (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; + (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; + break; + case 4: // GetTypeInfo + (*ppFuncDesc)->cParams = 3; + (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; + (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; + break; + case 5: // GetIDsOfNames + (*ppFuncDesc)->cParams = 5; + (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; + (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; + break; + case 6: // Invoke + (*ppFuncDesc)->cParams = 8; + (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; + (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; + break; + } + (*ppFuncDesc)->cParamsOpt = 0; + (*ppFuncDesc)->oVft = index * sizeof(void*); + (*ppFuncDesc)->cScodes = 0; + (*ppFuncDesc)->wFuncFlags = FUNCFLAG_FRESTRICTED; + + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc); + + return S_OK; + } + + Reference xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF)); + assert(xRefl.is()); + + Reference xClass = xRefl->forName(maType.getTypeName()); + assert(xClass.is()); + + auto aMethods = xClass->getMethods(); + assert(xClass->getTypeClass() == TypeClass_INTERFACE && + aMethods.getLength() > 0); + + if (index > o3tl::make_unsigned(aMethods.getLength() - 3 + 3 + 4)) + return E_INVALIDARG; + + *ppFuncDesc = new FUNCDESC; + + (*ppFuncDesc)->memid = index - 6; + (*ppFuncDesc)->lprgscode = nullptr; + (*ppFuncDesc)->lprgelemdescParam = nullptr; + (*ppFuncDesc)->funckind = FUNC_DISPATCH; + (*ppFuncDesc)->invkind = INVOKE_FUNC; + (*ppFuncDesc)->callconv = CC_STDCALL; + (*ppFuncDesc)->cParams = aMethods[index - 4]->getParameterInfos().getLength(); + (*ppFuncDesc)->cParamsOpt = 0; + (*ppFuncDesc)->oVft = index * sizeof(void*); + (*ppFuncDesc)->cScodes = 0; + (*ppFuncDesc)->elemdescFunc.tdesc.lptdesc = nullptr; // ??? + (*ppFuncDesc)->elemdescFunc.tdesc.vt = VT_VOID; // ??? + (*ppFuncDesc)->wFuncFlags = 0; + + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetFuncDesc(" << index << "): S_OK: " << *ppFuncDesc); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetVarDesc(UINT, + VARDESC **) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetVarDesc: E_NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetNames(MEMBERID memid, + BSTR *rgBstrNames, + UINT cMaxNames, + UINT *pcNames) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetNames(" << memid << ")"); + assert(meKind != Kind::COCLASS); + + if (!rgBstrNames) + return E_POINTER; + + if (!pcNames) + return E_POINTER; + + if (memid < 1) + return E_INVALIDARG; + + if (cMaxNames < 1) + return E_INVALIDARG; + + if (meKind == Kind::MAIN) + { + SAL_WARN("extensions.olebridge", "GetNames() for MAIN not implemented"); + return E_NOTIMPL; + } + + Reference xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF)); + assert(xRefl.is()); + + Reference xClass = xRefl->forName(maType.getTypeName()); + assert(xClass.is()); + + auto aMethods = xClass->getMethods(); + assert(xClass->getTypeClass() == TypeClass_INTERFACE && + aMethods.getLength() > 0); + + // Subtract the three XInterface methods. Memid for the first following method is 1. + if (memid > aMethods.getLength() - 3) + return E_INVALIDARG; + + SAL_INFO("extensions.olebridge", "..." << this << "@CXTypeInfo::GetNames(" << memid << "): " << aMethods[memid + 2]->getName()); + rgBstrNames[0] = SysAllocString(reinterpret_cast(aMethods[memid + 2]->getName().pData->buffer)); + *pcNames = 1; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeOfImplType(UINT index, + HREFTYPE *pRefType) +{ + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeOfImplType(" << index << ")"); + + if (!pRefType) + return E_POINTER; + + assert(index == 0 || index == 1); + + *pRefType = 1000+index; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetImplTypeFlags(UINT index, + INT *pImplTypeFlags) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetImplTypeFlags(" << index << ")"); + + if (!pImplTypeFlags) + return E_POINTER; + + assert(meKind == Kind::COCLASS); + assert(index == 0 || index == 1); + + if (index == 0) + *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT; + else if (index == 1) + *pImplTypeFlags = IMPLTYPEFLAG_FDEFAULT|IMPLTYPEFLAG_FSOURCE; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetIDsOfNames(LPOLESTR *, + UINT, + MEMBERID *) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetIDsOfNames: E_NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::Invoke(PVOID, + MEMBERID, + WORD, + DISPPARAMS *, + VARIANT *, + EXCEPINFO *, + UINT *) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::Invoke: E_NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDocumentation(MEMBERID memid, + BSTR *pBstrName, + BSTR *pBstrDocString, + DWORD *pdwHelpContext, + BSTR *pBstrHelpFile) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetDocumentation(" << memid << ")"); + + if (pBstrName) + { + if (memid == MEMBERID_NIL) + { + *pBstrName = SysAllocString(o3tl::toW(msImplementationName.getStr())); + } + else if (memid == DISPID_VALUE) + { + // MEMBERIDs are the same as DISPIDs, apparently? + *pBstrName = SysAllocString(L"Value"); + } + else + { + // FIXME: Shouldn't we be able to know the names of the members of UNO interfaces? + *pBstrName = SysAllocString(o3tl::toW(OUString("UnknownNameOfMember#" + OUString::number(memid)).getStr())); + } + } + if (pBstrDocString) + *pBstrDocString = SysAllocString(L""); + if (pdwHelpContext) + *pdwHelpContext = 0; + if (pBstrHelpFile) + *pBstrHelpFile = nullptr; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetDllEntry(MEMBERID, + INVOKEKIND, + BSTR *, + BSTR *, + WORD *) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetDllEntry: E_NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetRefTypeInfo(HREFTYPE hRefType, + ITypeInfo **ppTInfo) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetRefTypeInfo(" << hRefType << ")"); + + if (!ppTInfo) + return E_POINTER; + + // FIXME: Is it correct to assume that the only interfaces on which GetRefTypeInfo() would be + // called are those that implement ooo::vba::XConnectable? + + Reference xConnectable(mxOrigin, UNO_QUERY); + if (!xConnectable.is()) + return E_NOTIMPL; + + ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint(); + + IID aIID; + if (!SUCCEEDED(IIDFromString(reinterpret_cast(aTypeAndIID.IID.pData->buffer), &aIID))) + return E_NOTIMPL; + + HRESULT ret; + + CComObject* pTypeInfo; + + ret = CComObject::CreateInstance(&pTypeInfo); + if (FAILED(ret)) + return ret; + + pTypeInfo->AddRef(); + + pTypeInfo->InitForOutgoing(mxOrigin, aTypeAndIID.Type.getTypeName(), aIID, mxMSF, aTypeAndIID.Type); + + *ppTInfo = pTypeInfo; + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::AddressOfMember(MEMBERID, + INVOKEKIND, + PVOID *) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::AddressOfMember: E_NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::CreateInstance(IUnknown *, + REFIID, + PVOID *) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::CreateInstance: E_NOTIMPL"); + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetMops(MEMBERID, + BSTR *) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::GetMops: E_NOTIMPL"); + return E_NOTIMPL; +} + +// This is not actually called any more by my vbscript test after I added the IProvideClassInfo +// thing... so all the CXTypeLib stuff is dead code at the moment. + +HRESULT STDMETHODCALLTYPE CXTypeInfo::GetContainingTypeLib(ITypeLib **ppTLib, + UINT *pIndex) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::GetContainingTypeLib"); + + if (!ppTLib || !pIndex) + return E_POINTER; + + HRESULT ret; + + CComObject* pTypeLib; + + ret = CComObject::CreateInstance(&pTypeLib); + if (FAILED(ret)) + return ret; + + pTypeLib->AddRef(); + + pTypeLib->Init(mxOrigin, msImplementationName, mxMSF); + + *ppTLib = pTypeLib; + + return S_OK; +} + +void STDMETHODCALLTYPE CXTypeInfo::ReleaseTypeAttr(TYPEATTR *pTypeAttr) +{ + SAL_INFO("extensions.olebridge", this << "@CXTypeInfo::ReleaseTypeAttr(" << pTypeAttr << ")"); + + delete pTypeAttr; +} + +void STDMETHODCALLTYPE CXTypeInfo::ReleaseFuncDesc(FUNCDESC *pFuncDesc) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseFuncDesc(" << pFuncDesc << ")"); + + delete pFuncDesc; +} + +void STDMETHODCALLTYPE CXTypeInfo::ReleaseVarDesc(VARDESC *) +{ + SAL_WARN("extensions.olebridge", this << "@CXTypeInfo::ReleaseVarDesc: E_NOTIMPL"); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetTypeInfo(UINT iTInfo, LCID, ITypeInfo ** ppTInfo) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetTypeInfo(" << iTInfo << ")"); + + if (!ppTInfo) + return E_POINTER; + + if (iTInfo != 0) + return E_NOTIMPL; + + // FIXME: This is surely incorrect. Why is being able to handle GetTypeInfo() here coupled to + // being a source for outgoing events, i.e. implementing XConnectable? What would break if we + // would use XInterfaceWithIID and its getIID instead? + + Reference xConnectable(m_xOrigin, UNO_QUERY); + if (!xConnectable.is()) + return E_NOTIMPL; + + OUString sIID = xConnectable->GetIIDForClassItselfNotCoclass(); + IID aIID; + if (!SUCCEEDED(IIDFromString(reinterpret_cast(sIID.pData->buffer), &aIID))) + return E_NOTIMPL; + + HRESULT ret; + + CComObject* pTypeInfo; + + ret = CComObject::CreateInstance(&pTypeInfo); + if (FAILED(ret)) + return ret; + + pTypeInfo->AddRef(); + + pTypeInfo->InitForClassItself(m_xOrigin, m_sImplementationName, aIID, m_smgr); + + *ppTInfo = pTypeInfo; + + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::GetIDsOfNames(REFIID /*riid*/, + LPOLESTR * rgszNames, + UINT cNames, + LCID /*lcid*/, + DISPID * rgdispid ) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + if( ! rgdispid) + return E_POINTER; + + SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetIDsOfNames:"); + for (unsigned int i = 0; i < cNames; ++i) + { + // Initialise returned rgdispid values. + rgdispid[i] = DISPID_UNKNOWN; + + SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i]))); + } + + HRESULT ret = DISP_E_UNKNOWNNAME; + try + { + MutexGuard guard( getBridgeMutex()); + + // FIXME: Handle the cNames > 1 case? Note that the rest of the names mean the names of *arguments*. + + if( ! _wcsicmp( *rgszNames, JSCRIPT_VALUE_FUNC) || + ! _wcsicmp( *rgszNames, BRIDGE_VALUE_FUNC)) + { + *rgdispid= DISPID_JSCRIPT_VALUE_FUNC; + return S_OK; + } + else if( ! _wcsicmp( *rgszNames, GET_STRUCT_FUNC) || + ! _wcsicmp( *rgszNames, BRIDGE_GET_STRUCT_FUNC)) + { + *rgdispid= DISPID_GET_STRUCT_FUNC; + return S_OK; + } + else if( ! _wcsicmp( *rgszNames, BRIDGE_CREATE_TYPE_FUNC)) + { + *rgdispid= DISPID_CREATE_TYPE_FUNC; + return S_OK; + } + + if (m_xInvocation.is() && (cNames > 0)) + { + OUString name(o3tl::toU(rgszNames[0])); + NameToIdMap::iterator iter = m_nameToDispIdMap.find(name); + + bool bIsMethod = false; + + OUString exactName = name; + + if (iter == m_nameToDispIdMap.end()) + { + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName(name); + if (exactName.isEmpty()) + exactName = name; + } + + MemberInfo d(0, exactName); + + if (m_xInvocation->hasProperty(exactName)) + { + d.flags |= DISPATCH_PROPERTYGET; + d.flags |= DISPATCH_PROPERTYPUT; + d.flags |= DISPATCH_PROPERTYPUTREF; + } + + if (m_xInvocation->hasMethod(exactName)) + { + d.flags |= DISPATCH_METHOD; + bIsMethod = true; + } + + if (d.flags != 0) + { + m_MemberInfos.push_back(d); + iter = m_nameToDispIdMap.emplace(exactName, static_cast(m_MemberInfos.size())).first; + + if (exactName != name) + { + iter = m_nameToDispIdMap.emplace(name, static_cast(m_MemberInfos.size())).first; + } + } + } + + if (iter == m_nameToDispIdMap.end()) + { + ret = DISP_E_UNKNOWNNAME; + SAL_INFO("extensions.olebridge", " " << name << ": UNKNOWN"); + } + else + { + rgdispid[0] = (*iter).second; + SAL_INFO("extensions.olebridge", " " << name << ": " << rgdispid[0]); + + if (bIsMethod && cNames > 1) + { + Reference xIdlMethod; + Reference xIntrospectionAccess = m_xInvocation->getIntrospection(); + try + { + if (xIntrospectionAccess.is()) + xIdlMethod = xIntrospectionAccess->getMethod(exactName, MethodConcept::ALL); + } + catch (const NoSuchMethodException&) + { + } + if (xIdlMethod.is()) + { + auto aParamInfos = xIdlMethod->getParameterInfos(); + for (unsigned int i = 1; i < cNames; ++i) + { + bool bFound = false; + for (int j = 0; j < aParamInfos.getLength(); ++j) + { + if (aParamInfos[j].aName.equalsIgnoreAsciiCase(o3tl::toU(rgszNames[i]))) + { + rgdispid[i] = j; + bFound = true; + SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": " << rgdispid[i]); + break; + } + } + if (!bFound) + SAL_INFO("extensions.olebridge", " " << OUString(o3tl::toU(rgszNames[i])) << ": NOT FOUND"); + } + } + } + + // Return value should be S_OK only if *all* the names were found. + unsigned int i; + for (i = 0; i < cNames; ++i) + if (rgdispid[i] == DISPID_UNKNOWN) + break; + if (i == cNames) + ret = S_OK; + } + } + } + catch(const BridgeRuntimeError&) + { + OSL_ASSERT(false); + } + catch(const Exception&) + { + OSL_ASSERT(false); + } + catch(...) + { + OSL_ASSERT(false); + } + + return ret; +} + +// Note: What the comments here say about JScript possibly holds for Automation clients in general, +// like VBScript ones, too. Or not. Hard to say. What is the relevance of JScript nowadays anyway, +// and can LO really be used from JScript code on web pages any longer? + +// "convertDispparamsArgs" converts VARIANTS to their respecting Any counterparts +// The parameters "id", "wFlags" and "pdispparams" equal those as used in +// IDispatch::Invoke. The function handles special JavaScript +// cases where a VARIANT of type VT_DISPATCH is ambiguous and could represent +// an object, array ( JavaScript Array object), out parameter and in/out ( JavaScript Array object) +// parameter (JavaScript Array object) +// Because all those VT_DISPATCH objects need a different conversion +// we have to find out what the object is supposed to be. The function does this +// by either using type information or by help of a specialized ValueObject object. + +// A. Type Information + +// With the help of type information the kind of parameter can be exactly determined +// and an appropriate conversion can be chosen. A problem arises if a method expects +// an Any. Then the type info does not tell what the type of the value, that is kept +// by the any, should be. In this situation the decision whether the param is a +// sequence or an object is made upon the fact if the object has a property "0" +// ( see function "isJScriptArray"). Since this is unsafe it is recommended to use +// the JScript value objects within a JScript script on such an occasion. + +// B. JavaScript Value Object ( class JScriptValue ) + +// A JScriptValue (ValueObject) object is a COM object in that it implements IDispatch and the +// IJScriptValue object interface. Such objects are provided by all UNO wrapper +// objects used within a JScript script. To obtain an instance one has to call +// "_GetValueObject() or Bridge_GetValueObject()" on a UNO wrapper object (class InterfaceOleWrapper). +// A value object is appropriately initialized within the script and passed as +// parameter to a UNO object method or property. The convertDispparamsArgs function +// can easily find out that a param is such an object by querying for the +// IJScriptValue interface. By this interface one the type and kind ( out, in/out) +// can be determined and the right conversion can be applied. +// Using ValueObjects we spare us the effort of acquiring and examining type information +// in order to figure out what the an IDispatch parameter is meant for. + +// Normal JScript object parameter can be mixed with JScriptValue object. If an +// VARIANT contains a VT_DISPATCH that is no JScriptValue than the type information +// is used to find out about the required type. +void InterfaceOleWrapper::convertDispparamsArgs(DISPID id, + unsigned short /*wFlags*/, DISPPARAMS* pdispparams, Sequence& rSeq) +{ + // Parameters come in in reverse order in pdispparams. There might be less parameters than + // expected. In that case, assume they are "optional" (but can't be marked as such in UNO IDL), + // and fill in the rest with empty Anys. There might also be more than expected. In that case, + // assume the oovbaapi UNO IDL hasn't kept up with added optional parameters in MSO, and just + // ignore the extra ones, as long as they are empty. + + // An example: incoming parameters: <12, 13, "foo/bar.tem"> + // + // Expected parameters: (string filename, int something, int somethingElse, Any whatever, Any + // whateverElse) + // + // Here the existing incoming parameters are placed in reverse order in the first three outgoing + // parameters, and the rest of the outgoing parameters are kept as empty Anys. + // + // Another example: incoming parameters: + // + // Expected parameters: (bool flag) + // + // Here the TRUE is passed as the sole outgoing parameter, and the incoming EMPTY is ignored. + // + // Still an example: incoming parameters: <"foo.doc", TRUE> + // + // Expected parameters: (bool flag) + // + // This throws an error as the incoming string parameter presumably should do something important, + // but there is no corresponding outgoing parameter. + + HRESULT hr = S_OK; + const int countIncomingArgs = pdispparams->cArgs; + + //Get type information for the current call + InvocationInfo info; + if( ! getInvocationInfoForCall( id, info)) + throw BridgeRuntimeError( + "[automation bridge]InterfaceOleWrapper::convertDispparamsArgs \n" + "Could not obtain type information for current call."); + + // Size rSeq according to the number of expected parameters. + const int expectedArgs = info.aParamTypes.getLength() + (info.eMemberType == MemberType_PROPERTY ? 1 : 0); + rSeq.realloc( expectedArgs ); + Any* pParams = rSeq.getArray(); + + Any anyParam; + + int outgoingArgIndex = 0; + + // Go through incoming parameters in reverse order, i.e. in the order as declared in IDL + for (int i = std::max(countIncomingArgs, expectedArgs) - 1; i >= 0; i--) + { + // Ignore too many parameters if they are VT_EMPTY anyway + if ( outgoingArgIndex >= expectedArgs && pdispparams->rgvarg[i].vt == VT_EMPTY ) + continue; + + // But otherwise too many parameters is an error + if ( outgoingArgIndex >= expectedArgs ) + throw BridgeRuntimeError( "[automation bridge] Too many parameters" ); + + if (info.eMemberType == MemberType_METHOD && + info.aParamModes[ outgoingArgIndex ] == ParamMode_OUT) + { + outgoingArgIndex++; + continue; + } + + if (i < countIncomingArgs) + { + // A missing (and hopefully optional) arg (in the middle of the argument list) is passed + // as an empty Any. + if (pdispparams->rgvarg[i].vt == VT_ERROR && pdispparams->rgvarg[i].scode == DISP_E_PARAMNOTFOUND) + { + Any aEmpty; + pParams[ outgoingArgIndex ] = aEmpty; + outgoingArgIndex++; + continue; + } + + if(convertValueObject( & pdispparams->rgvarg[i], anyParam)) + { //a param is a ValueObject and could be converted + pParams[ outgoingArgIndex ] = anyParam; + outgoingArgIndex++; + continue; + } + } + else + { + // A missing arg. Let's hope it is de facto optional (there is no way in UNO IDL to mark + // a parameter as optional). The corresponding slot in pParams is already a void Any. + // Here we don't increase outgoingArgIndex! + continue; + } + + // If the param is an out, in/out parameter in + // JScript (Array object, with value at index 0) then we + // extract Array[0] and put the value into varParam. At the end of the loop varParam + // is converted if it contains a value otherwise the VARIANT from + // DISPPARAMS is converted. + CComVariant varParam; + + // Check for JScript out and in/out paramsobjects (VT_DISPATCH). + // To find them out we use typeinformation of the function being called. + + // No idea how this stuff, originally written for JScript, works for other Automation + // clients. + + if( pdispparams->rgvarg[i].vt == VT_DISPATCH ) + { + if( info.eMemberType == MemberType_METHOD && info.aParamModes[ outgoingArgIndex ] == ParamMode_INOUT) + { + // INOUT-param + // Index ( property) "0" contains the actual IN-param. The object is a JScript + // Array object. + // Get the IN-param at index "0" + IDispatch* pdisp= pdispparams->rgvarg[i].pdispVal; + + OLECHAR const * sindex= L"0"; + DISPID id2; + DISPPARAMS noParams= {nullptr,nullptr,0,0}; + if(SUCCEEDED( hr= pdisp->GetIDsOfNames( IID_NULL, const_cast(&sindex), 1, LOCALE_USER_DEFAULT, &id2))) + hr= pdisp->Invoke( id2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, + & noParams, & varParam, nullptr, nullptr); + if( FAILED( hr)) + { + throw BridgeRuntimeError( + "[automation bridge] Could not determine " + "if the object has a member \"0\". Error: " + + OUString::number(hr)); + } + } + } + + if( varParam.vt == VT_EMPTY) // then it was no in/out parameter + varParam= pdispparams->rgvarg[i]; + + if(info.eMemberType == MemberType_METHOD) + variantToAny( & varParam, anyParam, + info.aParamTypes[ outgoingArgIndex ]); + else if(info.eMemberType == MemberType_PROPERTY) + variantToAny( & varParam, anyParam, info.aType); + else + OSL_ASSERT(false); + + if (outgoingArgIndex < expectedArgs) + pParams[ outgoingArgIndex ]= anyParam; + outgoingArgIndex++; + }// end for / iterating over all parameters +} + +bool InterfaceOleWrapper::getInvocationInfoForCall( DISPID id, InvocationInfo& info) +{ + bool bTypesAvailable= false; + + if( !m_xInvocation.is() )return false; + Reference inv2( m_xInvocation, UNO_QUERY); + if( inv2.is()) + { + // We need the name of the property or method to get its type information. + // The name can be identified through the param "id" + // that is kept as value in the map m_nameToDispIdMap. + // Problem: the Windows JScript engine sometimes changes small letters to capital + // letters as happens in xidlclass_obj.createObject( var) // in JScript. + // IDispatch::GetIdsOfNames is then called with "CreateObject" !!! + // m_nameToDispIdMap can contain several names for one DISPID but only one is + // the exact one. If there's no m_xExactName and therefore no exact name then + // there's only one entry in the map. + OUString sMemberName; + + auto ci1 = std::find_if(m_nameToDispIdMap.cbegin(), m_nameToDispIdMap.cend(), + [&id](const NameToIdMap::value_type& nameToDispId) { return nameToDispId.second == id; }); // item is a pair + if (ci1 != m_nameToDispIdMap.cend()) + sMemberName= (*ci1).first; + // Get information for the current call ( property or method). + // There could be similar names which only differ in the cases + // of letters. First we assume that the name which was passed into + // GetIDsOfNames is correct. If we won't get information with that + // name then we have the invocation service use the XExactName interface. + bool validInfo= true; + InvocationInfo invInfo; + try{ + invInfo= inv2->getInfoForName( sMemberName, false); + } + catch(const IllegalArgumentException&) + { + validInfo= false; + } + + if( ! validInfo) + { + invInfo= inv2->getInfoForName( sMemberName, true); + } + if( invInfo.aName.pData) + { + bTypesAvailable= true; + info= invInfo; + } + } + return bTypesAvailable; +} + +// XBridgeSupplier2 --------------------------------------------------- +// only bridges itself ( this instance of InterfaceOleWrapper)from UNO to IDispatch +// If sourceModelType is UNO than any UNO interface implemented by InterfaceOleWrapper +// can bridged to IDispatch ( if destModelType == OLE). The IDispatch is +// implemented by this class. +Any SAL_CALL InterfaceOleWrapper::createBridge(const Any& modelDepObject, + const Sequence& /*ProcessId*/, + sal_Int16 sourceModelType, + sal_Int16 destModelType) +{ + + Any retAny; + if( sourceModelType == UNO && destModelType == OLE && + modelDepObject.getValueTypeClass() == TypeClass_INTERFACE ) + { + Reference xInt; + if( modelDepObject >>= xInt ) + { + if( xInt == Reference( static_cast( this), UNO_QUERY)) + { + VARIANT *pVar= static_cast(CoTaskMemAlloc( sizeof( VARIANT))); + if( pVar) + { + pVar->vt= VT_DISPATCH; + pVar->pdispVal= this; + AddRef(); + + retAny<<= reinterpret_cast< sal_uIntPtr >( pVar); + } + } + } + } + + return retAny; +} + +// XInitialization -------------------------------------------------- +void SAL_CALL InterfaceOleWrapper::initialize( const Sequence< Any >& aArguments ) +{ + switch( aArguments.getLength() ) + { + case 2: // the object wraps a UNO struct + aArguments[0] >>= m_xInvocation; + aArguments[1] >>= m_defaultValueType; + break; + case 3: // the object wraps a UNO interface + aArguments[0] >>= m_xInvocation; + aArguments[1] >>= m_xOrigin; + aArguments[2] >>= m_defaultValueType; + + Reference xServiceInfo(m_xOrigin, UNO_QUERY); + if (xServiceInfo.is()) + m_sImplementationName = xServiceInfo->getImplementationName(); + + SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::initialize for " + << (m_sImplementationName.isEmpty()?"an unknown implementation":m_sImplementationName)); + break; + } + + m_xExactName.set( m_xInvocation, UNO_QUERY); +} + +Reference< XInterface > InterfaceOleWrapper::createUnoWrapperInstance() +{ + Reference xWeak= static_cast( new InterfaceOleWrapper( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); +} + +Reference InterfaceOleWrapper::createComWrapperInstance() +{ + Reference xWeak= static_cast( new IUnknownWrapper( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); +} + +// "getType" is used in convertValueObject to map the string denoting the type +// to an actual Type object. +bool getType( const BSTR name, Type & type) +{ + bool ret = false; + typelib_TypeDescription * pDesc= nullptr; + OUString str(o3tl::toU(name)); + typelib_typedescription_getByName( &pDesc, str.pData ); + if( pDesc) + { + type = Type( pDesc->pWeakRef ); + typelib_typedescription_release( pDesc); + ret = true; + } + return ret; +} + +static bool writeBackOutParameter2( VARIANTARG* pDest, VARIANT* pSource) +{ + bool ret = false; + HRESULT hr; + + // Handle JScriptValue objects and JScript out params ( Array object ) + CComVariant varDest( *pDest); + + if( SUCCEEDED( varDest.ChangeType(VT_DISPATCH))) + { + CComPtr spDispDest(varDest.pdispVal); + + // special Handling for a JScriptValue object + CComQIPtr spValueDest(spDispDest); + if (spValueDest) + { + VARIANT_BOOL varBool= VARIANT_FALSE; + if ((SUCCEEDED(hr = spValueDest->IsOutParam(&varBool)) + && varBool == VARIANT_TRUE) + || (SUCCEEDED(hr = spValueDest->IsInOutParam(&varBool)) + && varBool == VARIANT_TRUE)) + { + if( SUCCEEDED( spValueDest->Set( CComVariant(), *pSource))) + ret= true; + } + } + else if (pDest->vt == VT_DISPATCH)// VT_DISPATCH -> JScript out param + { + // We use IDispatchEx because its GetDispID function causes the creation + // of a property if it does not exist already. This is convenient for + // out parameters in JScript. Then the user must not specify property "0" + // explicitly + CComQIPtr spDispEx( spDispDest); + if( spDispEx) + { + CComBSTR nullProp(L"0"); + DISPID dwDispID; + if( SUCCEEDED( spDispEx->GetDispID( nullProp, fdexNameEnsure, &dwDispID))) + { + DISPPARAMS dispparams = {nullptr, nullptr, 1, 1}; + dispparams.rgvarg = pSource; + DISPID dispidPut = DISPID_PROPERTYPUT; + dispparams.rgdispidNamedArgs = &dispidPut; + + if (pSource->vt == VT_UNKNOWN || pSource->vt == VT_DISPATCH || + (pSource->vt & VT_ARRAY) || (pSource->vt & VT_BYREF)) + hr = spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUTREF, + &dispparams, nullptr, nullptr, nullptr); + else + hr= spDispEx->InvokeEx(dwDispID, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, + &dispparams, nullptr, nullptr, nullptr); + if( SUCCEEDED(hr)) + ret= true; + } + } + } + else + ret= writeBackOutParameter( pDest, pSource); + } + else // The param can't be a JScript out-parameter ( an Array object), it could be a VBScript + { // param. The function checks itself for correct VBScript params + ret= writeBackOutParameter( pDest, pSource); + } + return ret; +} + +// VisualBasic Script passes arguments as VT_VARIANT | VT_BYREF be it in or out parameter. +// Thus we are in charge of freeing an eventual value contained by the inner VARIANT +// Please note: VariantCopy doesn't free a VT_BYREF value +// The out parameters are expected to have always a valid type +static bool writeBackOutParameter(VARIANTARG* pDest, VARIANT* pSource) +{ + HRESULT hr; + bool ret = false; + // Out parameter must be VT_BYREF + if ((V_VT(pDest) & VT_BYREF) != 0 ) + { + VARTYPE oleTypeFlags = V_VT(pSource); + + // if caller accept VARIANT as out parameter, any value must be converted + if (V_VT(pDest) == (VT_VARIANT | VT_BYREF)) + { + // When the user provides a VARIANT rather than a concrete type + // we just copy the source to the out, in/out parameter + // VT_DISPATCH, VT_UNKNOWN, VT_ARRAY, VT_BSTR in the VARIANT that + // is contained in pDest are released by VariantCopy + VariantCopy(V_VARIANTREF(pDest), pSource); + ret = true; + } + else + { + // variantarg and variant must have same type + if ((V_VT(pDest) & oleTypeFlags) == oleTypeFlags) + { + if ((oleTypeFlags & VT_ARRAY) != 0) + { + // In / Out Param + if( *V_ARRAYREF(pDest) != nullptr) + hr= SafeArrayCopyData( V_ARRAY(pSource), *V_ARRAYREF(pDest)); + else + // Out Param + hr= SafeArrayCopy(V_ARRAY(pSource), V_ARRAYREF(pDest)); + if( SUCCEEDED( hr)) + ret = true; + } + else + { + // copy base type + switch (V_VT(pSource)) + { + case VT_I2: + { + *V_I2REF(pDest) = V_I2(pSource); + ret = true; + break; + } + case VT_I4: + *V_I4REF(pDest) = V_I4(pSource); + ret = true; + break; + case VT_R4: + *V_R4REF(pDest) = V_R4(pSource); + ret = true; + break; + case VT_R8: + *V_R8REF(pDest) = V_R8(pSource); + ret = true; + break; + case VT_CY: + *V_CYREF(pDest) = V_CY(pSource); + ret = true; + break; + case VT_DATE: + *V_DATEREF(pDest) = V_DATE(pSource); + ret = true; + break; + case VT_BSTR: + SysFreeString( *pDest->pbstrVal); + + *V_BSTRREF(pDest) = SysAllocString(V_BSTR(pSource)); + ret = true; + break; + case VT_DISPATCH: + if (*V_DISPATCHREF(pDest) != nullptr) + (*V_DISPATCHREF(pDest))->Release(); + + *V_DISPATCHREF(pDest) = V_DISPATCH(pSource); + + if (*V_DISPATCHREF(pDest) != nullptr) + (*V_DISPATCHREF(pDest))->AddRef(); + + ret = true; + break; + case VT_ERROR: + *V_ERRORREF(pDest) = V_ERROR(pSource); + ret = true; + break; + case VT_BOOL: + *V_BOOLREF(pDest) = V_BOOL(pSource); + ret = true; + break; + case VT_UNKNOWN: + if (*V_UNKNOWNREF(pDest) != nullptr) + (*V_UNKNOWNREF(pDest))->Release(); + + *V_UNKNOWNREF(pDest) = V_UNKNOWN(pSource); + + if (*V_UNKNOWNREF(pDest) != nullptr) + (*V_UNKNOWNREF(pDest))->AddRef(); + + ret = true; + break; + case VT_I1: + *V_I1REF(pDest) = V_I1(pSource); + ret = true; + break; + case VT_UI1: + *V_UI1REF(pDest) = V_UI1(pSource); + ret = true; + break; + case VT_UI2: + *V_UI2REF(pDest) = V_UI2(pSource); + ret = true; + break; + case VT_UI4: + *V_UI4REF(pDest) = V_UI4(pSource); + ret = true; + break; + case VT_INT: + *V_INTREF(pDest) = V_INT(pSource); + ret = true; + break; + case VT_UINT: + *V_UINTREF(pDest) = V_UINT(pSource); + ret = true; + break; + case VT_DECIMAL: + memcpy(pDest->pdecVal, pSource, sizeof(DECIMAL)); + ret = true; + break; + default: + break; + } + } + } + else + { + // Handling of special cases + // Destination and source types are different + if( pDest->vt == (VT_BSTR | VT_BYREF) + && pSource->vt == VT_I2) + { + // When the user provides a String as out our in/out parameter + // and the type is char (TypeClass_CHAR) then we convert to a BSTR + // instead of VT_I2 as is done otherwise + OLECHAR buff[]= {0,0}; + buff[0]= pSource->iVal; + + SysFreeString( *pDest->pbstrVal); + *pDest->pbstrVal= SysAllocString( buff); + ret = true; + } + } + } + } + return ret; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP InterfaceOleWrapper::Invoke(DISPID dispidMember, + REFIID /*riid*/, + LCID /*lcid*/, + WORD wFlags, + DISPPARAMS * pdispparams, + VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, + UINT * puArgErr ) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + OUString sParams; +#if defined SAL_LOG_INFO + sParams += "["; + for (unsigned int i = 0; i < pdispparams->cArgs; ++i) + { + if (i > 0) + sParams += ","; + std::stringstream aStringStream; + aStringStream << pdispparams->rgvarg[i]; + sParams += OUString::createFromAscii(aStringStream.str().c_str()); + } + sParams += "]"; +#endif + SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::Invoke(" << dispidMember << "," << sParams << ")"); + + comphelper::ProfileZone aZone("COM Bridge"); + HRESULT ret = S_OK; + + try + { + bool bHandled= false; + ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, + puArgErr, bHandled); + if( bHandled) + return ret; + + if ((dispidMember > 0) && (o3tl::make_unsigned(dispidMember) <= m_MemberInfos.size()) && m_xInvocation.is()) + { + MemberInfo d = m_MemberInfos[dispidMember - 1]; + DWORD flags = wFlags & d.flags; + + if (flags != 0) + { + if ((flags & DISPATCH_METHOD) != 0) + { + std::unique_ptr pNewDispParams; + std::vector vNewArgs; + + if (pdispparams->cNamedArgs > 0) + { + // Convert named arguments to positional ones. + + // An example: + // + // Function declaration (in pseudo-code): + // int foo(int A, int B, optional int C, optional int D, optional int E, optional int F, optional int G) + // + // Corresponding parameter numbers (DISPIDs): + // 0 1 2 3 4 5 6 + // + // Actual call: + // foo(10, 20, E:=50, D:=40, F:=60) + // + // That is, A and B are passed positionally, D, E, and F as named arguments, + // and the optional C and G parameters are left out. + // + // Incoming DISPPARAMS: + // cArgs=5, cNamedArgs=3 + // rgvarg: [60, 40, 50, 20, 10] + // rgdispidNamedArgs: [5, 3, 4] + // + // We calculate nLowestNamedArgDispid = 3 and nHighestNamedArgDispid = 5. + // + // Result of conversion, no named args: + // cArgs=6, cNamedArgs=0 + // rgvarg: [60, 50, 40, DISP_E_PARAMNOTFOUND, 20, 10] + + // First find the lowest and highest DISPID of the named arguments. + DISPID nLowestNamedArgDispid = 1000000; + DISPID nHighestNamedArgDispid = -1; + for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i) + { + if (pdispparams->rgdispidNamedArgs[i] < nLowestNamedArgDispid) + nLowestNamedArgDispid = pdispparams->rgdispidNamedArgs[i]; + if (pdispparams->rgdispidNamedArgs[i] > nHighestNamedArgDispid) + nHighestNamedArgDispid = pdispparams->rgdispidNamedArgs[i]; + } + + // Make sure named arguments don't overlap with positional ones. The lowest + // DISPID of the named arguments should be >= the number of positional + // arguments. + if (nLowestNamedArgDispid < static_cast(pdispparams->cArgs - pdispparams->cNamedArgs)) + return DISP_E_NONAMEDARGS; + + // Do the actual conversion. + pNewDispParams.reset(new DISPPARAMS); + vNewArgs.resize(nHighestNamedArgDispid + 1); + pNewDispParams->rgvarg = vNewArgs.data(); + pNewDispParams->rgdispidNamedArgs = nullptr; + pNewDispParams->cArgs = nHighestNamedArgDispid + 1; + pNewDispParams->cNamedArgs = 0; + + // Initialise all parameter slots as missing + for (int i = 0; i < nHighestNamedArgDispid; ++i) + { + pNewDispParams->rgvarg[i].vt = VT_ERROR; + pNewDispParams->rgvarg[i].scode = DISP_E_PARAMNOTFOUND; + } + + // Then set the value of those actually present. + for (unsigned int i = 0; i < pdispparams->cNamedArgs; ++i) + pNewDispParams->rgvarg[nHighestNamedArgDispid - pdispparams->rgdispidNamedArgs[i]] = pdispparams->rgvarg[i]; + + const int nFirstUnnamedArg = pdispparams->cNamedArgs + (nLowestNamedArgDispid-(pdispparams->cArgs - pdispparams->cNamedArgs)); + + for (unsigned int i = pdispparams->cNamedArgs; i < pdispparams->cArgs; ++i) + pNewDispParams->rgvarg[nFirstUnnamedArg + (i-pdispparams->cNamedArgs)] = pdispparams->rgvarg[i]; + + pdispparams = pNewDispParams.get(); + } + + Sequence params; + + convertDispparamsArgs(dispidMember, wFlags, pdispparams , params ); + + ret= doInvoke(pdispparams, pvarResult, + pexcepinfo, puArgErr, d.name, params); + } + else if ((flags & DISPATCH_PROPERTYGET) != 0) + { + ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, d.name); + } + else if ((flags & DISPATCH_PROPERTYPUT) != 0 || (flags & DISPATCH_PROPERTYPUTREF) != 0) + { + if (pdispparams->cArgs != 1) + ret = DISP_E_BADPARAMCOUNT; + else + { + Sequence params; + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + if(params.getLength() > 0) + ret= doSetProperty( pdispparams, pvarResult, pexcepinfo, puArgErr, d.name, params); + else + ret = DISP_E_BADVARTYPE; + } + } + } + else + ret= DISP_E_MEMBERNOTFOUND; + } + else + ret = DISP_E_MEMBERNOTFOUND; + } + catch(const BridgeRuntimeError& e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(const Exception& e) + { + OUString message= "InterfaceOleWrapper::Invoke : \n" + + e.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch(...) + { + writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::Invoke : \nUnexpected exception"); + ret = DISP_E_EXCEPTION; + } + + return ret; +} + +HRESULT InterfaceOleWrapper::doInvoke( DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence& params) +{ + + + HRESULT ret= S_OK; + try + { + Sequence outIndex; + Sequence outParams; + Any returnValue; + + if (pdispparams->cNamedArgs > 0) + return DISP_E_NONAMEDARGS; + + // invoke method and take care of exceptions + returnValue = m_xInvocation->invoke(name, + params, + outIndex, + outParams); + + // try to write back out parameter + if (outIndex.getLength() > 0) + { + const sal_Int16* pOutIndex = outIndex.getConstArray(); + const Any* pOutParams = outParams.getConstArray(); + + for (sal_Int32 i = 0; i < outIndex.getLength(); i++) + { + CComVariant variant; + // Currently a Sequence is converted to an SafeArray of VARIANTs. + anyToVariant( &variant, pOutParams[i]); + + // out parameter need special handling if they are VT_DISPATCH + // and used in JScript + int outindex= pOutIndex[i]; + writeBackOutParameter2(&(pdispparams->rgvarg[pdispparams->cArgs - 1 - outindex]), + &variant ); + } + } + + // write back return value + if (pvarResult != nullptr) + anyToVariant(pvarResult, returnValue); + } + catch(const IllegalArgumentException & e) //XInvocation::invoke + { + writeExcepinfo(pexcepinfo, e.Message); + ret = DISP_E_TYPEMISMATCH; + } + catch(const CannotConvertException & e) //XInvocation::invoke + { + writeExcepinfo(pexcepinfo, e.Message); + ret = mapCannotConvertException( e, puArgErr); + } + catch(const InvocationTargetException & e) //XInvocation::invoke + { + const Any& org = e.TargetException; + Exception excTarget; + org >>= excTarget; + OUString message= + org.getValueType().getTypeName() + ": " + excTarget.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch(const NoSuchMethodException & e) //XInvocation::invoke + { + writeExcepinfo(pexcepinfo, e.Message); + ret = DISP_E_MEMBERNOTFOUND; + } + catch(const BridgeRuntimeError & e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(const Exception & e) + { + OUString message= "InterfaceOleWrapper::doInvoke : \n" + + e.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch( ... ) + { + writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::doInvoke : \nUnexpected exception"); + ret = DISP_E_EXCEPTION; + } + return ret; +} + +HRESULT InterfaceOleWrapper::doGetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, OUString& name) +{ + HRESULT ret= S_OK; + + try + { + Any returnValue = m_xInvocation->getValue( name); + // write back return value + if (pvarResult) + anyToVariant(pvarResult, returnValue); + } + catch(const UnknownPropertyException& e) //XInvocation::getValue + { + writeExcepinfo(pexcepinfo, e.Message); + ret = DISP_E_MEMBERNOTFOUND; + } + catch(const BridgeRuntimeError& e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(const Exception& e) + { + OUString message= "InterfaceOleWrapper::doGetProperty : \n" + + e.Message; + writeExcepinfo(pexcepinfo, message); + } + catch( ... ) + { + writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::doInvoke : \nUnexpected exception"); + ret = DISP_E_EXCEPTION; + } + return ret; +} + +HRESULT InterfaceOleWrapper::doSetProperty( DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString& name, Sequence const & params) +{ + HRESULT ret= S_OK; + + try + { + m_xInvocation->setValue( name, params.getConstArray()[0]); + } + catch(const UnknownPropertyException &) + { + ret = DISP_E_MEMBERNOTFOUND; + } + catch(const CannotConvertException &e) + { + ret= mapCannotConvertException( e, puArgErr); + } + catch(const InvocationTargetException &e) + { + if (pexcepinfo != nullptr) + { + Any org = e.TargetException; + + pexcepinfo->wCode = UNO_2_OLE_EXCEPTIONCODE; + pexcepinfo->bstrSource = SysAllocString(L"any ONE component"); + pexcepinfo->bstrDescription = SysAllocString( + o3tl::toW(org.getValueType().getTypeName().getStr())); + } + ret = DISP_E_EXCEPTION; + } + catch( ... ) + { + ret= DISP_E_EXCEPTION; + } + return ret; +} + +namespace { + +class CXEnumVariant : public IEnumVARIANT, + public CComObjectRoot +{ +public: + CXEnumVariant() + : mnIndex(1) // ooo::vba::XCollection index starts at one + { + } + + virtual ~CXEnumVariant() + { + } + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + BEGIN_COM_MAP(CXEnumVariant) +#if defined __clang__ +#pragma clang diagnostic pop +#endif + COM_INTERFACE_ENTRY(IEnumVARIANT) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#pragma clang diagnostic ignored "-Wunused-function" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + DECLARE_NOT_AGGREGATABLE(CXEnumVariant) + + // Creates and initializes the enumerator + void Init(InterfaceOleWrapper* pInterfaceOleWrapper, + const Reference xCollection) + { + mpInterfaceOleWrapper = pInterfaceOleWrapper; + mxCollection = xCollection; + } + + // IEnumVARIANT + virtual HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT **) override + { + SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Clone: E_NOTIMPL"); + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Next(ULONG const celt, + VARIANT *rgVar, + ULONG *pCeltFetched) override + { + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + if (pCeltFetched) + *pCeltFetched = 0; + + if (celt == 0) + { + SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_INVALIDARG"); + return E_INVALIDARG; + } + + if (rgVar == nullptr || (celt != 1 && pCeltFetched == nullptr)) + { + SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): E_FAIL"); + return E_FAIL; + } + + for (ULONG i = 0; i < celt; i++) + VariantInit(&rgVar[i]); + + ULONG nLeft = celt; + ULONG nReturned = 0; + while (nLeft > 0) + { + if (mnIndex > mxCollection->getCount()) + { + SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): got " << nReturned << ": S_FALSE"); + return S_FALSE; + } + Any aIndex; + aIndex <<= mnIndex; + Any aElement = mxCollection->Item(aIndex, Any()); + mpInterfaceOleWrapper->anyToVariant(rgVar, aElement); + // rgVar->pdispVal->AddRef(); ?? + if (pCeltFetched) + (*pCeltFetched)++; + rgVar++; + nReturned++; + mnIndex++; + nLeft--; + } + SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Next(" << celt << "): S_OK"); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Reset() override + { + SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Reset: S_OK"); + mnIndex = 1; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE STDMETHODCALLTYPE Skip(ULONG const celt) override + { + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + ULONG nLeft = celt; + ULONG nSkipped = 0; + while (nLeft > 0) + { + if (mnIndex > mxCollection->getCount()) + { + SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): skipped " << nSkipped << ": S_FALSE"); + return S_FALSE; + } + mnIndex++; + nLeft--; + } + SAL_INFO("extensions.olebridge", this << "@CXEnumVariant::Skip(" << celt << "): S_OK"); + return S_OK; + } + +private: + InterfaceOleWrapper* mpInterfaceOleWrapper; + Reference mxCollection; + sal_Int32 mnIndex; +}; + +class Sink : public cppu::WeakImplHelper +{ +public: + Sink(IUnknown* pUnkSink, + Reference xMSF, + ooo::vba::TypeAndIID aTypeAndIID, + InterfaceOleWrapper* pInterfaceOleWrapper); + + // XSink + void SAL_CALL Call( const OUString& Method, Sequence< Any >& Arguments ) override; + +private: + IUnknown* mpUnkSink; + Reference mxMSF; + ooo::vba::TypeAndIID maTypeAndIID; + InterfaceOleWrapper* mpInterfaceOleWrapper; +}; + +} + +Sink::Sink(IUnknown* pUnkSink, + Reference xMSF, + ooo::vba::TypeAndIID aTypeAndIID, + InterfaceOleWrapper* pInterfaceOleWrapper) : + mpUnkSink(pUnkSink), + mxMSF(xMSF), + maTypeAndIID(aTypeAndIID), + mpInterfaceOleWrapper(pInterfaceOleWrapper) +{ + mpUnkSink->AddRef(); +} + +void SAL_CALL +Sink::Call( const OUString& Method, Sequence< Any >& Arguments ) +{ + SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << ", " << Arguments.getLength() << " arguments)"); + + IDispatch* pDispatch; + HRESULT nResult = mpUnkSink->QueryInterface(IID_IDispatch, reinterpret_cast(&pDispatch)); + if (!SUCCEEDED(nResult)) + { + SAL_WARN("extensions.olebridge", "Sink::Call: Not IDispatch: " << WindowsErrorStringFromHRESULT(nResult)); + return; + } + + Reference xRefl = theCoreReflection::get(comphelper::getComponentContext(mxMSF)); + assert(xRefl.is()); + + Reference xClass = xRefl->forName(maTypeAndIID.Type.getTypeName()); + assert(xClass.is()); + + auto aMethods = xClass->getMethods(); + assert(xClass->getTypeClass() == TypeClass_INTERFACE && + aMethods.getLength() > 0); + + int nMemId = 1; + auto ArgumentsRange = asNonConstRange(Arguments); + // Skip the three XInterface methods + for (int i = 3; i < aMethods.getLength(); i++) + { + if (aMethods[i]->getName() == Method) + { + // FIXME: Handle mismatch in type of actual argument and parameter of the method. + + // FIXME: Handle mismatch in number of arguments passed and actual number of parameters + // of the method. + + auto aParamInfos = aMethods[i]->getParameterInfos(); + + assert(Arguments.getLength() == aParamInfos.getLength()); + + DISPPARAMS aDispParams; + aDispParams.rgdispidNamedArgs = nullptr; + aDispParams.cArgs = Arguments.getLength(); + aDispParams.cNamedArgs = 0; + aDispParams.rgvarg = new VARIANT[aDispParams.cArgs]; + for (unsigned j = 0; j < aDispParams.cArgs; j++) + { + VariantInit(aDispParams.rgvarg+j); + // Note: Reverse order of arguments in Arguments and aDispParams.rgvarg! + const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1; + mpInterfaceOleWrapper->anyToVariant(aDispParams.rgvarg+j, Arguments[nIncomingArgIndex]); + + // Handle OUT and INOUT arguments. For instance, the second ('Cancel') parameter to + // DocumentBeforeClose() should be a VT_BYREF|VT_BOOL parameter. Need to handle that + // here. + + if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT || + aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT) + { + switch (aDispParams.rgvarg[j].vt) + { + case VT_I2: + aDispParams.rgvarg[j].byref = new SHORT(aDispParams.rgvarg[j].iVal); + aDispParams.rgvarg[j].vt |= VT_BYREF; + break; + case VT_I4: + aDispParams.rgvarg[j].byref = new LONG(aDispParams.rgvarg[j].lVal); + aDispParams.rgvarg[j].vt |= VT_BYREF; + break; + case VT_BSTR: + aDispParams.rgvarg[j].byref = new BSTR(aDispParams.rgvarg[j].bstrVal); + aDispParams.rgvarg[j].vt |= VT_BYREF; + break; + case VT_BOOL: + aDispParams.rgvarg[j].byref = new VARIANT_BOOL(aDispParams.rgvarg[j].boolVal); + aDispParams.rgvarg[j].vt |= VT_BYREF; + break; + default: + assert(false && "Not handled yet"); + break; + } + } + } + + VARIANT aVarResult; + VariantInit(&aVarResult); + UINT uArgErr; + + // In the case of a VBScript client, which uses "late binding", calling Invoke on the + // sink it provides will cause a callback to our CXTypeInfo::GetNames for the given + // member id, and in that we will tell it the name of the corresponding method, and the + // client will know what event handler to invoke based on that name. + // + // As the outgoing interfaces used (ooo::vba::word::XApplicationOutgoing and others) are + // totally not stable and not published in any way, there can be no client that would + // have done "compile-time binding" and where the sink would actually be an object with + // a vtbl corresponding to the outgoing interface. Late binding clients that work like + // VBScript is all we support. + SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Calling Invoke(" << nMemId << ")"); + + nResult = pDispatch->Invoke(nMemId, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &aDispParams, &aVarResult, nullptr, &uArgErr); + SAL_INFO("extensions.olebridge", "Sink::Call(" << Method << "): Invoke() returned"); + + SAL_WARN_IF(!SUCCEEDED(nResult), "extensions.olebridge", "Call to " << Method << " failed: " << WindowsErrorStringFromHRESULT(nResult)); + + // Undo VT_BYREF magic done above. Copy out parameters back to the Anys in Arguments + for (unsigned j = 0; j < aDispParams.cArgs; j++) + { + const unsigned nIncomingArgIndex = aDispParams.cArgs - j - 1; + if (aParamInfos[nIncomingArgIndex].aMode == ParamMode_OUT || + aParamInfos[nIncomingArgIndex].aMode == ParamMode_INOUT) + { + switch (aDispParams.rgvarg[j].vt) + { + case VT_BYREF|VT_I2: + { + SHORT *pI = static_cast(aDispParams.rgvarg[j].byref); + ArgumentsRange[nIncomingArgIndex] <<= static_cast(*pI); + delete pI; + } + break; + case VT_BYREF|VT_I4: + { + LONG *pL = static_cast(aDispParams.rgvarg[j].byref); + ArgumentsRange[nIncomingArgIndex] <<= static_cast(*pL); + delete pL; + } + break; + case VT_BYREF|VT_BSTR: + { + BSTR *pBstr = static_cast(aDispParams.rgvarg[j].byref); + ArgumentsRange[nIncomingArgIndex] <<= OUString(o3tl::toU(*pBstr)); + // Undo SysAllocString() done in anyToVariant() + SysFreeString(*pBstr); + delete pBstr; + } + break; + case VT_BYREF|VT_BOOL: + { + VARIANT_BOOL *pBool = static_cast(aDispParams.rgvarg[j].byref); + ArgumentsRange[nIncomingArgIndex] <<= (*pBool != VARIANT_FALSE); + delete pBool; + } + break; + default: + assert(false && "Not handled yet"); + break; + } + } + else + { + switch (aDispParams.rgvarg[j].vt) + { + case VT_BSTR: + // Undo SysAllocString() done in anyToVariant() + SysFreeString(aDispParams.rgvarg[j].bstrVal); + break; + } + } + } + + delete[] aDispParams.rgvarg; + return; + } + nMemId++; + } + SAL_WARN("extensions.olebridge", "Sink::Call: Unknown method '" << Method << "'"); +} + +namespace { + +class CXEnumConnections : public IEnumConnections, + public CComObjectRoot +{ +public: + CXEnumConnections() + { + } + + virtual ~CXEnumConnections() + { + } + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + BEGIN_COM_MAP(CXEnumConnections) +#if defined __clang__ +#pragma clang diagnostic pop +#endif + COM_INTERFACE_ENTRY(IEnumConnections) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#pragma clang diagnostic ignored "-Wunused-function" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + DECLARE_NOT_AGGREGATABLE(CXEnumConnections) + + void Init(std::vector& rUnknowns, std::vector& rCookies) + { + SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Init"); + SAL_WARN_IF(rUnknowns.size() != rCookies.size(), "extensions.olebridge", "Vectors of different size"); + mvUnknowns = rUnknowns; + mvCookies = rCookies; + mnIndex = 0; + } + + virtual HRESULT STDMETHODCALLTYPE Next(ULONG cConnections, + LPCONNECTDATA rgcd, + ULONG *pcFetched) override + { + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + if (!rgcd) + { + SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_POINTER"); + return E_POINTER; + } + + if (pcFetched && cConnections != 1) + { + SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): E_INVALIDARG"); + return E_INVALIDARG; + } + + ULONG nFetched = 0; + while (nFetched < cConnections && mnIndex < mvUnknowns.size()) + { + rgcd[nFetched].pUnk = mvUnknowns[mnIndex]; + rgcd[nFetched].pUnk->AddRef(); + rgcd[nFetched].dwCookie = mvCookies[mnIndex]; + ++nFetched; + ++mnIndex; + } + if (nFetched != cConnections) + { + SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_FALSE"); + if (pcFetched) + *pcFetched = nFetched; + return S_FALSE; + } + SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Next(" << cConnections << "): S_OK"); + if (pcFetched) + *pcFetched = nFetched; + + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Skip(ULONG cConnections) override + { + SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Skip(" << cConnections << "): E_NOTIMPL"); + + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Reset() override + { + SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Reset: E_NOTIMPL"); + + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Clone(IEnumConnections** /* ppEnum */) override + { + SAL_INFO("extensions.olebridge", this << "@CXEnumConnections::Clone: E_NOTIMPL"); + + return E_NOTIMPL; + } + +private: + std::vector mvUnknowns; + std::vector mvCookies; + ULONG mnIndex; +}; + +class CXConnectionPoint : public IConnectionPoint, + public CComObjectRoot +{ +public: +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + BEGIN_COM_MAP(CXConnectionPoint) +#if defined __clang__ +#pragma clang diagnostic pop +#endif + COM_INTERFACE_ENTRY(IConnectionPoint) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#pragma clang diagnostic ignored "-Wunused-function" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + DECLARE_NOT_AGGREGATABLE(CXConnectionPoint) + + virtual ~CXConnectionPoint() {} + + void Init(InterfaceOleWrapper* pInterfaceOleWrapper, + Reference& xCP, + Reference& xMSF, + ooo::vba::TypeAndIID aTypeAndIID) + { + SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Init for " << pInterfaceOleWrapper->getImplementationName()); + + IUnknown *pUnknown; + if (SUCCEEDED(QueryInterface(IID_IUnknown, reinterpret_cast(&pUnknown)))) + { + // In case QI for IUnknown returns a different pointer, but nah, it doesn't + SAL_INFO("extensions.olebridge", " (IUnknown@" << pUnknown << ")"); + } + + mpInterfaceOleWrapper = pInterfaceOleWrapper; + mxCP = xCP; + mxMSF = xMSF; + maTypeAndIID = aTypeAndIID; + } + + virtual HRESULT STDMETHODCALLTYPE GetConnectionInterface(IID *pIID) override + { + SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface(" << *pIID << "): E_NOTIMPL"); + + // FIXME: Needed? + + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE GetConnectionPointContainer(IConnectionPointContainer **) override + { + SAL_WARN("extensions.olebridge", this << "@CXConnectionPoint::GetConnectionInterface: E_NOTIMPL"); + + // FIXME: Needed? + + return E_NOTIMPL; + } + + virtual HRESULT STDMETHODCALLTYPE Advise(IUnknown *pUnkSink, + DWORD *pdwCookie) override + { + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Advise(" << pUnkSink << ")"); + + if (!pdwCookie) + return E_POINTER; + + Reference xSink(new Sink(pUnkSink, mxMSF, maTypeAndIID, mpInterfaceOleWrapper)); + + mvISinks.push_back(pUnkSink); + *pdwCookie = mvISinks.size(); + + mvCookies.push_back(mxCP->Advise(xSink)); + + mvXSinks.push_back(xSink); + + SAL_INFO("extensions.olebridge", " *pdwCookie: " << *pdwCookie); + + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Unadvise(DWORD dwCookie) override + { + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::Unadvise(" << dwCookie << ")"); + + if (dwCookie == 0 || dwCookie > mvISinks.size()) + return E_POINTER; + + mvISinks[dwCookie-1] = nullptr; + + mxCP->Unadvise(mvCookies[dwCookie-1]); + + mvXSinks[dwCookie-1] = Reference(); + + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE EnumConnections(IEnumConnections **ppEnum) override + { + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + HRESULT nResult; + + SAL_INFO("extensions.olebridge", this << "@CXConnectionPoint::EnumConnections..."); + + if (!ppEnum) + { + SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: E_POINTER"); + return E_POINTER; + } + + CComObject* pEnumConnections; + + nResult = CComObject::CreateInstance(&pEnumConnections); + if (FAILED(nResult)) + { + SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: " << WindowsErrorStringFromHRESULT(nResult)); + return nResult; + } + + pEnumConnections->AddRef(); + + pEnumConnections->Init(mvISinks, mvCookies); + *ppEnum = pEnumConnections; + + SAL_INFO("extensions.olebridge", "..." << this << "@CXConnectionPoint::EnumConnections: S_OK"); + + return S_OK; + } + + InterfaceOleWrapper* mpInterfaceOleWrapper; + std::vector mvISinks; + std::vector> mvXSinks; + std::vector mvCookies; + Reference mxMSF; + Reference mxCP; + ooo::vba::TypeAndIID maTypeAndIID; +}; + +} + +HRESULT InterfaceOleWrapper::InvokeGeneral( DISPID dispidMember, unsigned short wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + unsigned int * /*puArgErr*/, bool& bHandled) +{ + HRESULT ret= S_OK; + try + { +// DISPID_VALUE | The DEFAULT Value is required in JScript when the situation +// is that we put an object into an Array object ( out parameter). We have to return +// IDispatch otherwise the object cannot be accessed from the Script. + if( dispidMember == DISPID_VALUE && (wFlags & DISPATCH_PROPERTYGET) != 0 + && m_defaultValueType != VT_EMPTY && pvarResult != nullptr) + { + // Special case hack: If it is a ScVbaCheckBox, return the boolean value + Reference xCheckBox(m_xOrigin, UNO_QUERY); + if (xCheckBox.is()) + { + bHandled = true; + Any aValue = xCheckBox->getValue(); + anyToVariant(pvarResult, aValue); + return S_OK; + } + + bHandled= true; + if( m_defaultValueType == VT_DISPATCH) + { + pvarResult->vt= VT_DISPATCH; + pvarResult->pdispVal= this; + AddRef(); + ret= S_OK; + } + } + + // function: _GetValueObject + else if( dispidMember == DISPID_JSCRIPT_VALUE_FUNC) + { + bHandled= true; + if( !pvarResult) + return E_POINTER; + CComObject< JScriptValue>* pValue; + if( SUCCEEDED( CComObject::CreateInstance( &pValue))) + { + pValue->AddRef(); + pvarResult->vt= VT_DISPATCH; + pvarResult->pdispVal= CComQIPtr(pValue->GetUnknown()); + ret= S_OK; + } + else + ret= DISP_E_EXCEPTION; + } + else if( dispidMember == DISPID_GET_STRUCT_FUNC) + { + bHandled= true; + bool bStruct= false; + + + Reference xRefl = theCoreReflection::get(comphelper::getComponentContext(m_smgr)); + // the first parameter is in DISPPARAMS rgvargs contains the name of the struct. + CComVariant arg; + if( pdispparams->cArgs == 1 && SUCCEEDED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0])) ) + { + Reference classStruct= xRefl->forName(OUString(o3tl::toU(arg.bstrVal))); + if( classStruct.is()) + { + Any anyStruct; + classStruct->createObject( anyStruct); + CComVariant var; + anyToVariant( &var, anyStruct ); + + if( var.vt == VT_DISPATCH) + { + VariantCopy( pvarResult, & var); + bStruct= true; + } + } + } + ret= bStruct ? S_OK : DISP_E_EXCEPTION; + } + else if (dispidMember == DISPID_CREATE_TYPE_FUNC) + { + bHandled= true; + if( !pvarResult) + return E_POINTER; + // the first parameter is in DISPPARAMS rgvargs contains the name of the struct. + CComVariant arg; + if( pdispparams->cArgs != 1) + return DISP_E_BADPARAMCOUNT; + if (FAILED( arg.ChangeType( VT_BSTR, &pdispparams->rgvarg[0]))) + return DISP_E_BADVARTYPE; + + //check if the provided name represents a valid type + Type type; + if (!getType(arg.bstrVal, type)) + { + writeExcepinfo(pexcepinfo, OUString::Concat("[automation bridge] A UNO type with the name ") + + o3tl::toU(arg.bstrVal) + " does not exist!"); + return DISP_E_EXCEPTION; + } + + if (!createUnoTypeWrapper(arg.bstrVal, pvarResult)) + { + writeExcepinfo(pexcepinfo, "[automation bridge] InterfaceOleWrapper::InvokeGeneral\n" + "Could not initialize UnoTypeWrapper object!"); + return DISP_E_EXCEPTION; + } + } + else if (dispidMember == DISPID_NEWENUM) + { + bHandled = true; + if( !pvarResult) + return E_POINTER; + + Reference< ooo::vba::XCollection> xCollection(m_xOrigin, UNO_QUERY); + if (!xCollection.is()) + return DISP_E_MEMBERNOTFOUND; + + CComObject* pEnumVar; + + ret = CComObject::CreateInstance(&pEnumVar); + if (FAILED(ret)) + return ret; + + pEnumVar->AddRef(); + + pEnumVar->Init(this, xCollection); + + pvarResult->vt = VT_UNKNOWN; + pvarResult->punkVal = nullptr; + + ret = pEnumVar->QueryInterface(IID_IUnknown, reinterpret_cast(&pvarResult->punkVal)); + if (FAILED(ret)) + { + pEnumVar->Release(); + return ret; + } + } + } + catch(const BridgeRuntimeError & e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(const Exception & e) + { + OUString message= "InterfaceOleWrapper::InvokeGeneral : \n" + + e.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch( ... ) + { + writeExcepinfo(pexcepinfo, "InterfaceOleWrapper::InvokeGeneral : \nUnexpected exception"); + ret = DISP_E_EXCEPTION; + } + return ret; +} + +STDMETHODIMP InterfaceOleWrapper::GetDispID(BSTR /*bstrName*/, DWORD /*grfdex*/, DISPID __RPC_FAR* /*pid*/) +{ + return ResultFromScode(E_NOTIMPL); +} + +STDMETHODIMP InterfaceOleWrapper::InvokeEx( + /* [in] */ DISPID /*id*/, + /* [in] */ LCID /*lcid*/, + /* [in] */ WORD /*wFlags*/, + /* [in] */ DISPPARAMS __RPC_FAR* /*pdp*/, + /* [out] */ VARIANT __RPC_FAR* /*pvarRes*/, + /* [out] */ EXCEPINFO __RPC_FAR* /*pei*/, + /* [unique][in] */ IServiceProvider __RPC_FAR* /*pspCaller*/) +{ + return ResultFromScode(E_NOTIMPL); +} + +STDMETHODIMP InterfaceOleWrapper::DeleteMemberByName( + /* [in] */ BSTR /*bstr*/, + /* [in] */ DWORD /*grfdex*/) +{ + return ResultFromScode(E_NOTIMPL); +} + +STDMETHODIMP InterfaceOleWrapper::DeleteMemberByDispID(DISPID /*id*/) +{ + return ResultFromScode(E_NOTIMPL); +} + +STDMETHODIMP InterfaceOleWrapper::GetMemberProperties( + /* [in] */ DISPID /*id*/, + /* [in] */ DWORD /*grfdexFetch*/, + /* [out] */ DWORD __RPC_FAR* /*pgrfdex*/) +{ + return ResultFromScode(E_NOTIMPL); +} + +STDMETHODIMP InterfaceOleWrapper::GetMemberName( + /* [in] */ DISPID /*id*/, + /* [out] */ BSTR __RPC_FAR* /*pbstrName*/) +{ + return ResultFromScode(E_NOTIMPL); +} + +STDMETHODIMP InterfaceOleWrapper::GetNextDispID( + /* [in] */ DWORD /*grfdex*/, + /* [in] */ DISPID /*id*/, + /* [out] */ DISPID __RPC_FAR* /*pid*/) +{ + return ResultFromScode(E_NOTIMPL); +} + +STDMETHODIMP InterfaceOleWrapper::GetNameSpaceParent( + /* [out] */ IUnknown __RPC_FAR *__RPC_FAR* /*ppunk*/) +{ + return ResultFromScode(E_NOTIMPL); +} + +// IProvideClassInfo +HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::GetClassInfo ( + /* [out] */ ITypeInfo **ppTI) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::GetClassInfo"); + + if (!ppTI) + return E_POINTER; + + Reference xIID(m_xOrigin, UNO_QUERY); + if (!xIID.is()) + return E_NOTIMPL; + + OUString sIID = xIID->getIID(); + IID aIID; + if (!SUCCEEDED(IIDFromString(reinterpret_cast(sIID.pData->buffer), &aIID))) + return E_NOTIMPL; + + HRESULT ret; + + CComObject* pTypeInfo; + + ret = CComObject::CreateInstance(&pTypeInfo); + if (FAILED(ret)) + return ret; + + pTypeInfo->AddRef(); + + pTypeInfo->InitForCoclass(m_xOrigin, m_sImplementationName, aIID, m_smgr); + + *ppTI = pTypeInfo; + + return S_OK; +} + +// IConnectionPointContainer +HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::EnumConnectionPoints( + /* [out] */ IEnumConnectionPoints **) +{ + SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::EnumConnectionPoints"); + return ResultFromScode(E_NOTIMPL); +} + +HRESULT STDMETHODCALLTYPE InterfaceOleWrapper::FindConnectionPoint( + /* [in] */ REFIID riid, + /* [out] */ IConnectionPoint **ppCP) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + SAL_INFO("extensions.olebridge", this << "@InterfaceOleWrapper::FindConnectionPoint(" << riid << ")"); + + if (!ppCP) + return E_POINTER; + + Reference xConnectable(m_xOrigin, UNO_QUERY); + + // We checked already + assert(xConnectable.is()); + if (!xConnectable.is()) + return E_NOTIMPL; + + ooo::vba::TypeAndIID aTypeAndIID = xConnectable->GetConnectionPoint(); + + IID aIID; + if (!SUCCEEDED(IIDFromString(reinterpret_cast(aTypeAndIID.IID.pData->buffer), &aIID))) + return E_INVALIDARG; + + if (!IsEqualIID(riid, aIID)) + return E_INVALIDARG; + + Reference xCP = xConnectable->FindConnectionPoint(); + if (!xCP.is()) + return E_INVALIDARG; + + HRESULT ret; + + CComObject* pConnectionPoint; + + ret = CComObject::CreateInstance(&pConnectionPoint); + if (FAILED(ret)) + return ret; + + pConnectionPoint->AddRef(); + + pConnectionPoint->Init(this, xCP, m_smgr, aTypeAndIID); + + *ppCP = pConnectionPoint; + + return S_OK; +} + +// UnoObjectWrapperRemoteOpt --------------------------------------------------- + +UnoObjectWrapperRemoteOpt::UnoObjectWrapperRemoteOpt( Reference const & aFactory, + sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass): +InterfaceOleWrapper( aFactory, unoWrapperClass, comWrapperClass), +m_currentId(1) + +{ +} +UnoObjectWrapperRemoteOpt::~UnoObjectWrapperRemoteOpt() +{ +} + +// UnoConversionUtilities +Reference< XInterface > UnoObjectWrapperRemoteOpt::createUnoWrapperInstance() +{ + Reference xWeak= static_cast( new UnoObjectWrapperRemoteOpt( + m_smgr, m_nUnoWrapperClass, m_nComWrapperClass)); + return Reference( xWeak, UNO_QUERY); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::GetIDsOfNames ( REFIID /*riid*/, LPOLESTR * rgszNames, UINT cNames, + LCID /*lcid*/, DISPID * rgdispid ) +{ + MutexGuard guard( getBridgeMutex()); + + if( ! rgdispid) + return E_POINTER; + HRESULT ret = E_UNEXPECTED; + + // _GetValueObject + if( ! wcscmp( *rgszNames, JSCRIPT_VALUE_FUNC)) + { + *rgdispid= DISPID_JSCRIPT_VALUE_FUNC; + return S_OK; + } + else if( ! wcscmp( *rgszNames, GET_STRUCT_FUNC)) + { + *rgdispid= DISPID_GET_STRUCT_FUNC; + return S_OK; + } + + if (m_xInvocation.is() && (cNames > 0)) + { + OUString name(o3tl::toU(rgszNames[0])); + // has this name been determined as "bad" + BadNameMap::iterator badIter= m_badNameMap.find( name); + if( badIter == m_badNameMap.end() ) + { + // name has not been bad before( member exists + typedef NameToIdMap::iterator ITnames; + std::pair< ITnames, bool > pair_id= m_nameToDispIdMap.emplace(name, m_currentId++); + // new ID inserted ? + if( pair_id.second ) + {// yes, now create MemberInfo and ad to IdToMemberInfoMap + MemberInfo d(0, name); + m_idToMemberInfoMap.emplace(m_currentId - 1, d); + } + + *rgdispid = pair_id.first->second; + ret = S_OK; + } + else + ret= DISP_E_UNKNOWNNAME; + } + return ret; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP UnoObjectWrapperRemoteOpt::Invoke ( DISPID dispidMember, REFIID /*riid*/, LCID /*lcid*/, WORD wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + UINT * puArgErr ) +{ + comphelper::Automation::AutomationInvokedZone aAutomationActive; + + HRESULT ret = S_OK; + try + { + bool bHandled= false; + ret= InvokeGeneral( dispidMember, wFlags, pdispparams, pvarResult, pexcepinfo, + puArgErr, bHandled); + if( bHandled) + return ret; + + if ( dispidMember > 0 && m_xInvocation.is()) + { + + IdToMemberInfoMap::iterator it_MemberInfo= m_idToMemberInfoMap.find( dispidMember); + if( it_MemberInfo != m_idToMemberInfoMap.end() ) + { + MemberInfo& info= it_MemberInfo->second; + + Sequence params; // holds converted any s + if( ! info.flags ) + { // DISPID called for the first time + if( wFlags == DISPATCH_METHOD ) + { + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + + if( FAILED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + OUString exactName; + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( !exactName.isEmpty() ) + { + if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_METHOD; + } + else if( wFlags == DISPATCH_PROPERTYPUT || wFlags == DISPATCH_PROPERTYPUTREF) + { + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + if( FAILED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + OUString exactName; + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( !exactName.isEmpty() ) + { + if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET; + } + else if( wFlags == DISPATCH_PROPERTYGET) + { + if( FAILED( ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, info.name)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + OUString exactName; + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( !exactName.isEmpty() ) + { + if( SUCCEEDED( ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, exactName))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT; + } + else if( wFlags & DISPATCH_METHOD && + (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF)) + { + + OUString exactName; + // convert params for DISPATCH_METHOD or DISPATCH_PROPERTYPUT + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + // try first as method + if( FAILED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( !exactName.isEmpty() ) + { + if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_METHOD; + + // try as property + if( FAILED( ret) && pdispparams->cArgs == 1) + { + if( FAILED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + if( !exactName.isEmpty() ) + { + if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYGET; + } + } + else if( wFlags & DISPATCH_METHOD && wFlags & DISPATCH_PROPERTYGET) + { + OUString exactName; + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + + if( FAILED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params)) + && ret == DISP_E_MEMBERNOTFOUND) + { + // try to get the exact name + if (m_xExactName.is()) + { + exactName = m_xExactName->getExactName( info.name); + // invoke again + if( !exactName.isEmpty() ) + { + if( SUCCEEDED( ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_METHOD; + + // try as property + if( FAILED( ret) && pdispparams->cArgs == 1) + { + if( FAILED( ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, info.name)) + && ret == DISP_E_MEMBERNOTFOUND) + { + if( !exactName.isEmpty() ) + { + if( SUCCEEDED( ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, exactName, params))) + info.name= exactName; + } + } + if( SUCCEEDED( ret ) ) + info.flags= DISPATCH_PROPERTYGET; + } + } + + // update information about this member + if( ret == DISP_E_MEMBERNOTFOUND) + { + // Remember the name as not existing + // and remove the MemberInfo + m_badNameMap[info.name]= false; + m_idToMemberInfoMap.erase( it_MemberInfo); + } + } // if( ! info.flags ) + else // IdToMemberInfoMap contains a MemberInfo + { + if( wFlags & DISPATCH_METHOD && info.flags == DISPATCH_METHOD) + { + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + ret= doInvoke( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params); + } + else if( (wFlags & DISPATCH_PROPERTYPUT || wFlags & DISPATCH_PROPERTYPUTREF ) && + info.flags & DISPATCH_PROPERTYPUT) + { + convertDispparamsArgs(dispidMember, wFlags, pdispparams, params ); + ret= doSetProperty( pdispparams, pvarResult, + pexcepinfo, puArgErr, info.name, params); + } + else if( (wFlags & DISPATCH_PROPERTYGET) && ( info.flags & DISPATCH_PROPERTYGET)) + { + ret= doGetProperty( pdispparams, pvarResult, + pexcepinfo, info.name); + } + else + { + ret= DISP_E_MEMBERNOTFOUND; + } + } + }// if( it_MemberInfo != m_idToMemberInfoMap.end() ) + else + ret= DISP_E_MEMBERNOTFOUND; + } + } + catch(const BridgeRuntimeError& e) + { + writeExcepinfo(pexcepinfo, e.message); + ret = DISP_E_EXCEPTION; + } + catch(const Exception& e) + { + OUString message= "UnoObjectWrapperRemoteOpt::Invoke : \n" + + e.Message; + writeExcepinfo(pexcepinfo, message); + ret = DISP_E_EXCEPTION; + } + catch(...) + { + writeExcepinfo(pexcepinfo, "UnoObjectWrapperRemoteOpt::Invoke : \nUnexpected exception"); + ret = DISP_E_EXCEPTION; + } + + return ret; +} + +HRESULT UnoObjectWrapperRemoteOpt::methodInvoke( DISPID /*dispidMember*/, DISPPARAMS * /*pdispparams*/, VARIANT * /*pvarResult*/, + EXCEPINFO * /*pexcepinfo*/, unsigned int * /*puArgErr*/, Sequence const &) +{ + return S_OK; +} + +// The returned HRESULT is only appropriate for IDispatch::Invoke +static HRESULT mapCannotConvertException(const CannotConvertException &e, unsigned int * puArgErr) +{ + HRESULT ret; + bool bWriteIndex= true; + + switch ( e.Reason) + { + case FailReason::OUT_OF_RANGE: + ret = DISP_E_OVERFLOW; + break; + case FailReason::IS_NOT_NUMBER: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::IS_NOT_ENUM: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::IS_NOT_BOOL: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::NO_SUCH_INTERFACE: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::SOURCE_IS_NO_DERIVED_TYPE: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::TYPE_NOT_SUPPORTED: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::INVALID: + ret = DISP_E_TYPEMISMATCH; + break; + case FailReason::NO_DEFAULT_AVAILABLE: + ret = DISP_E_BADPARAMCOUNT; + break; + case FailReason::UNKNOWN: + ret = E_UNEXPECTED; + break; + default: + ret = E_UNEXPECTED; + bWriteIndex= false; + break; + } + + if( bWriteIndex && puArgErr != nullptr) + *puArgErr = e.ArgumentIndex; + return ret; +} + +// The function maps the TypeClass of the any to VARTYPE: If +// the Any contains STRUCT or INTERFACE then the return value +// is VT_DISPATCH. The function is used from o2u_createUnoObjectWrapper +// and the result is put into the constructor of the uno - wrapper +// object. If a client asks the object for DISPID_VALUE and this +// function returned VT_DISPATCH then the IDispatch of the same +// object is being returned. +// See InterfaceOleWrapper::Invoke, InterfaceOleWrapper::m_defaultValueType +VARTYPE getVarType( const Any& value) +{ + VARTYPE ret= VT_EMPTY; + + switch ( value.getValueTypeClass()) + { + case TypeClass_STRUCT: ret= VT_DISPATCH; break; + case TypeClass_INTERFACE: ret= VT_DISPATCH; break; + default: break; + } + return ret; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unoobjw.hxx b/extensions/source/ole/unoobjw.hxx new file mode 100644 index 000000000..845724d81 --- /dev/null +++ b/extensions/source/ole/unoobjw.hxx @@ -0,0 +1,268 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "comifaces.hxx" +#include "ole2uno.hxx" +#include "unoconversionutilities.hxx" + +#define JSCRIPT_VALUE_FUNC L"_GetValueObject" +#define GET_STRUCT_FUNC L"_GetStruct" +#define BRIDGE_VALUE_FUNC L"Bridge_GetValueObject" +#define BRIDGE_GET_STRUCT_FUNC L"Bridge_GetStruct" +#define BRIDGE_CREATE_TYPE_FUNC L"Bridge_CreateType" + +#define DISPID_JSCRIPT_VALUE_FUNC -10l +#define DISPID_GET_STRUCT_FUNC -102 +#define DISPID_CREATE_TYPE_FUNC -103 + +using namespace cppu; +using namespace com::sun::star::bridge; +using namespace com::sun::star::script; + +struct MemberInfo +{ + MemberInfo() : flags(0), name() {} + MemberInfo(WORD f, const OUString& n) : flags(f), name(n) {} + + WORD flags; + OUString name; +}; + +typedef std::unordered_map +< + OUString, + DISPID +> NameToIdMap; + +typedef std::unordered_map +< + OUString, + bool +> BadNameMap; + +typedef std::unordered_map +< + DISPID, + MemberInfo +> IdToMemberInfoMap; + +// An InterfaceOleWrapper object can wrap either a UNO struct or a UNO +// interface as a COM IDispatchEx and IUnoObjectWrapper. + +class InterfaceOleWrapper : public WeakImplHelper, + public IDispatchEx, + public IProvideClassInfo, + public IConnectionPointContainer, + public UnoConversionUtilities, + public IUnoObjectWrapper +{ +public: + InterfaceOleWrapper(Reference const & xFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass); + ~InterfaceOleWrapper() override; + + // IUnknown + STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj) override; + STDMETHOD_(ULONG, AddRef)() override; + STDMETHOD_(ULONG, Release)() override; + + // IDispatch + STDMETHOD( GetTypeInfoCount )( UINT * pctinfo ) override; + STDMETHOD( GetTypeInfo )( UINT itinfo, LCID lcid, ITypeInfo ** pptinfo ) override; + STDMETHOD( GetIDsOfNames )( REFIID riid, LPOLESTR * rgszNames, UINT cNames, + LCID lcid, DISPID * rgdispid ) override; + STDMETHOD( Invoke )( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + UINT * puArgErr ) override; + + // IDispatchEx + virtual HRESULT STDMETHODCALLTYPE GetDispID( + /* [in] */ BSTR bstrName, + /* [in] */ DWORD grfdex, + /* [out] */ DISPID __RPC_FAR *pid) override; + + virtual /* [local] */ HRESULT STDMETHODCALLTYPE InvokeEx( + /* [in] */ DISPID id, + /* [in] */ LCID lcid, + /* [in] */ WORD wFlags, + /* [in] */ DISPPARAMS __RPC_FAR *pdp, + /* [out] */ VARIANT __RPC_FAR *pvarRes, + /* [out] */ EXCEPINFO __RPC_FAR *pei, + /* [unique][in] */ IServiceProvider __RPC_FAR *pspCaller) override; + + virtual HRESULT STDMETHODCALLTYPE DeleteMemberByName( + /* [in] */ BSTR bstr, + /* [in] */ DWORD grfdex) override; + + virtual HRESULT STDMETHODCALLTYPE DeleteMemberByDispID( + /* [in] */ DISPID id) override; + + virtual HRESULT STDMETHODCALLTYPE GetMemberProperties( + /* [in] */ DISPID id, + /* [in] */ DWORD grfdexFetch, + /* [out] */ DWORD __RPC_FAR *pgrfdex) override; + + virtual HRESULT STDMETHODCALLTYPE GetMemberName( + /* [in] */ DISPID id, + /* [out] */ BSTR __RPC_FAR *pbstrName) override; + + virtual HRESULT STDMETHODCALLTYPE GetNextDispID( + /* [in] */ DWORD grfdex, + /* [in] */ DISPID id, + /* [out] */ DISPID __RPC_FAR *pid) override; + + virtual HRESULT STDMETHODCALLTYPE GetNameSpaceParent( + /* [out] */ IUnknown __RPC_FAR *__RPC_FAR *ppunk) override; + + // IProvideClassInfo + virtual HRESULT STDMETHODCALLTYPE GetClassInfo( + /* [out] */ ITypeInfo **ppTI) override; + + // IConnectionPointContainer + virtual HRESULT STDMETHODCALLTYPE EnumConnectionPoints( + /* [out] */ IEnumConnectionPoints **ppEnum) override; + virtual HRESULT STDMETHODCALLTYPE FindConnectionPoint( + /* [in] */ REFIID riid, + /* [out] */ IConnectionPoint **ppCP) override; + + // XBridgeSupplier2 + virtual Any SAL_CALL createBridge(const Any& modelDepObject, + const Sequence& ProcessId, + sal_Int16 sourceModelType, + sal_Int16 destModelType) override; + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // IUnoObjectWrapper + STDMETHOD( getWrapperXInterface)( Reference* pXInt) override; + STDMETHOD( getOriginalUnoObject)( Reference* pXInt) override; + STDMETHOD( getOriginalUnoStruct)( Any * pStruct) override; + + // UnoConversionUtility + virtual Reference< XInterface > createUnoWrapperInstance() override; + virtual Reference< XInterface > createComWrapperInstance() override; + + const OUString& getImplementationName() const + { + return m_sImplementationName; + } + +protected: + virtual HRESULT doInvoke( DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString & name, Sequence& params); + + virtual HRESULT doGetProperty( DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, OUString & name ); + + virtual HRESULT doSetProperty( DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, OUString & name, Sequence const & params); + + virtual HRESULT InvokeGeneral( DISPID dispidMember, unsigned short wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + unsigned int * puArgErr, bool& bHandled); + + void convertDispparamsArgs( DISPID id, unsigned short wFlags, DISPPARAMS* pdispparams, + Sequence& rSeq); + + bool getInvocationInfoForCall(DISPID id, InvocationInfo& info); + + Reference m_xInvocation; + Reference m_xExactName; + Reference m_xOrigin; + NameToIdMap m_nameToDispIdMap; + std::vector m_MemberInfos; + // This member is used to determine the default value + // denoted by DISPID_VALUE (0). For proper results in JavaScript + // we have to return the default value when we write an object + // as out parameter. That is, we get a JScript Array as parameter + // and put a wrapped object on index null. The array object tries + // to detect the default value. The wrapped object must then return + // its own IDispatch* otherwise we cannot access it within the script. + // see InterfaceOleWrapper::Invoke + VARTYPE m_defaultValueType; + + // The name of the implementation. Can be empty if unknown. + OUString m_sImplementationName; +}; + +/***************************************************************************** + + UnoObjectWrapperRemoteOpt = Uno Object Wrapper Remote Optimized + + This is the UNO wrapper used in the service com.sun.star.bridge.OleBridgeSupplierVar1. + Key features: + DISPIDs are passed out blindly. That is in GetIDsOfNames is no name checking carried out. + Only if Invoke fails the name is being checked. Moreover Invoke tries to figure out + if a call is made to a property or method if the flags are DISPATCH_METHOD | DISPATCH_PROPERTYPUT. + If something has been found out about a property or member than it is saved + in a MemberInfo structure hold by an IdToMemberInfoMap stl map. + +*****************************************************************************/ +class UnoObjectWrapperRemoteOpt: public InterfaceOleWrapper +{ +public: + UnoObjectWrapperRemoteOpt( Reference const & aFactory, sal_uInt8 unoWrapperClass, sal_uInt8 comWrapperClass); + ~UnoObjectWrapperRemoteOpt() override; + + STDMETHOD( GetIDsOfNames )( REFIID riid, LPOLESTR * rgszNames, UINT cNames, + LCID lcid, DISPID * rgdispid ) override; + STDMETHOD( Invoke )( DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, + DISPPARAMS * pdispparams, VARIANT * pvarResult, EXCEPINFO * pexcepinfo, + UINT * puArgErr ) override; + + // UnoConversionUtility + // If UNO interfaces are converted in methods of this class then + // they are always wrapped with instances of this class + virtual Reference< XInterface > createUnoWrapperInstance() override; + +protected: + + static HRESULT methodInvoke( DISPID dispidMember, DISPPARAMS * pdispparams, VARIANT * pvarResult, + EXCEPINFO * pexcepinfo, unsigned int * puArgErr, Sequence const & params); + // In GetIDsOfNames are blindly passed out, that is without verifying + // the name. If two names are passed in during different calls to + // GetIDsOfNames and the names differ only in their cases then different + // id's are passed out ( e.g. "doSomethingMethod" or "dosomethingmethod"). + // In Invoke the DISPID is remapped to the name passed to GetIDsOfNames + // and the name is used as parameter for XInvocation::invoke. If invoke + // fails because of a wrong name, then m_xExactName ( XExactName) is used + // to verify the name. The correct name is then inserted to m_MemberInfos + // ( vector ). During the next call to Invoke the right name + // is used. . + + + BadNameMap m_badNameMap; + + IdToMemberInfoMap m_idToMemberInfoMap; + + DISPID m_currentId; + + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unotypewrapper.cxx b/extensions/source/ole/unotypewrapper.cxx new file mode 100644 index 000000000..2824e8ef7 --- /dev/null +++ b/extensions/source/ole/unotypewrapper.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 "unotypewrapper.hxx" +#include +#include +#include + +bool createUnoTypeWrapper(BSTR sTypeName, VARIANT * pVar) +{ + bool ret = false; + OSL_ASSERT(sTypeName && pVar); + CComObject< UnoTypeWrapper>* pObj; + VariantClear(pVar); + if( SUCCEEDED( CComObject::CreateInstance( &pObj))) + { + pObj->AddRef(); + pVar->vt= VT_DISPATCH; + pVar->pdispVal= CComQIPtr(pObj->GetUnknown()); + //now set the value, e.i. the name of the type + CComQIPtr spType(pVar->pdispVal); + OSL_ASSERT(spType); + if (SUCCEEDED(spType->put_Name(sTypeName))) + { + ret = true; + } + } + return ret; +} + + +bool createUnoTypeWrapper(const OUString& sTypeName, VARIANT * pVar) +{ + CComBSTR bstr(o3tl::toW(sTypeName.getStr())); + return createUnoTypeWrapper(bstr, pVar); +} + +UnoTypeWrapper::UnoTypeWrapper() +{ +} + +UnoTypeWrapper::~UnoTypeWrapper() +{ +} + + +// UnoTypeWrapper, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::GetTypeInfoCount(UINT* /*pctinfo*/) +{ + return E_NOTIMPL; +} + +// UnoTypeWrapper, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::GetTypeInfo( UINT /*iTInfo*/, + LCID /*lcid*/, + ITypeInfo** /*ppTInfo*/) +{ + return E_NOTIMPL; +} + +// UnoTypeWrapper, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::GetIDsOfNames( REFIID /*riid*/, + LPOLESTR *rgszNames, + UINT /*cNames*/, + LCID /*lcid*/, + DISPID *rgDispId) +{ + if( !rgDispId) + return E_POINTER; + + HRESULT ret= S_OK; + CComBSTR name(*rgszNames); + name.ToLower(); + + if( name == CComBSTR( L"name") ) + *rgDispId= DISPID_VALUE; + else + ret= DISP_E_UNKNOWNNAME; + + return ret; +} + +// UnoTypeWrapper, IDispatch -------------------------------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::Invoke( DISPID dispIdMember, + REFIID /*riid*/, + LCID /*lcid*/, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO* /*pExcepInfo*/, + UINT* /*puArgErr*/) +{ + if (pDispParams == nullptr) + return DISP_E_EXCEPTION; + + if( pDispParams->cNamedArgs) + return DISP_E_NONAMEDARGS; + + + HRESULT ret= S_OK; + switch( dispIdMember) + { + case DISPID_VALUE: // DISPID_VALUE + if (wFlags & DISPATCH_PROPERTYGET) + { + if (pVarResult == nullptr) + { + ret = E_POINTER; + break; + } + get_Name( & pVarResult->bstrVal); + pVarResult->vt = VT_BSTR; + } + break; + default: + ret= DISP_E_MEMBERNOTFOUND; + break; + } + + return ret; +} + +// IUnoTypeWrapper----------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::put_Name(BSTR val) +{ + Lock(); + m_sName = val; + Unlock(); + return S_OK; +} + +// (UnoTypeWrapper----------------------- +COM_DECLSPEC_NOTHROW STDMETHODIMP UnoTypeWrapper::get_Name(BSTR *pVal) +{ + Lock(); + if( !pVal) + return E_POINTER; + *pVal = m_sName.Copy(); + Unlock(); + return S_OK; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/unotypewrapper.hxx b/extensions/source/ole/unotypewrapper.hxx new file mode 100644 index 000000000..a7515448c --- /dev/null +++ b/extensions/source/ole/unotypewrapper.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "wincrap.hxx" + +#include "comifaces.hxx" + +/* creates a UnoTypWrapper and sets the Name property to the value + specified by sTypeName. + Returns true if the object could be created and initialized. + */ +bool createUnoTypeWrapper(BSTR sTypeName, VARIANT * pVariant); +bool createUnoTypeWrapper(const OUString& sTypeName, VARIANT * pVar); + +class UnoTypeWrapper: + public CComObjectRootEx, + public IUnoTypeWrapper, + public IDispatch +{ +public: + UnoTypeWrapper(); + virtual ~UnoTypeWrapper(); + + BEGIN_COM_MAP(UnoTypeWrapper) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IUnoTypeWrapper) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + // IDispatch ------------------------------------------- + STDMETHOD( GetTypeInfoCount)(UINT *pctinfo) override; + + STDMETHOD( GetTypeInfo)( UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo) override; + + STDMETHOD( GetIDsOfNames)( REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId) override; + + STDMETHOD( Invoke)( DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr) override; + // IUnoTypeWrapper -------------------------------------- + STDMETHOD(put_Name)(BSTR val) override; + STDMETHOD(get_Name)(BSTR* pVal) override; + + CComBSTR m_sName; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/wincrap.hxx b/extensions/source/ole/wincrap.hxx new file mode 100644 index 000000000..4da57d53c --- /dev/null +++ b/extensions/source/ole/wincrap.hxx @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +/* wrap all includes that need to be wrapped by prewin.h/postwin.h here */ + +#define STRICT + +#define _WIN32_DCOM +#if OSL_DEBUG_LEVEL > 0 +//#define _ATL_DEBUG_INTERFACES +#endif + +#include + +#include +#include + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wall" +#pragma clang diagnostic ignored "-Wattributes" +#pragma clang diagnostic ignored "-Wdelete-incomplete" +#pragma clang diagnostic ignored "-Wextra" +#pragma clang diagnostic ignored "-Wint-to-pointer-cast" +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#pragma clang diagnostic ignored "-Wmicrosoft" +#pragma clang diagnostic ignored "-Wnon-pod-varargs" +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif + +// from oleobjw.hxx +#include +// from jscriptclasses.hxx +extern CComModule _Module; +#include + +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +// from unoobjw.cxx +#include + +#include + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/ole/windata.hxx b/extensions/source/ole/windata.hxx new file mode 100644 index 000000000..edf3c1d45 --- /dev/null +++ b/extensions/source/ole/windata.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 . + */ +#pragma once + +#include + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wall" +#pragma clang diagnostic ignored "-Wextra" +#pragma clang diagnostic ignored "-Wignored-attributes" +#pragma clang diagnostic ignored "-Wint-to-pointer-cast" +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#pragma clang diagnostic ignored "-Wmicrosoft" +#pragma clang diagnostic ignored "-Wnon-pod-varargs" +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif + +#include + +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#include + +//Wrapper for VARDESC +class VarDesc +{ + VARDESC* operator = (const VarDesc*); + VarDesc(const VarDesc&); +// Construction +public: + CComPtr< ITypeInfo > m_pTypeInfo; + VARDESC* m_pVarDesc; + + explicit VarDesc(ITypeInfo* pTypeInfo) : + m_pTypeInfo(pTypeInfo), + m_pVarDesc(nullptr) + { + OSL_ASSERT(pTypeInfo); + } + ~VarDesc() + { + if (m_pVarDesc != nullptr) + { + m_pTypeInfo->ReleaseVarDesc(m_pVarDesc); + } + } + + VARDESC* operator->() + { + return m_pVarDesc; + } + + VARDESC** operator&() + { + return &m_pVarDesc; + } + + operator VARDESC* () + { + return m_pVarDesc; + } +}; + +//Wrapper for FUNCDESC structure +class FuncDesc +{ + FUNCDESC* operator = (const FuncDesc &); + FuncDesc(const FuncDesc&); + CComPtr m_pTypeInfo; + FUNCDESC * m_pFuncDesc; + +public: + + explicit FuncDesc(ITypeInfo * pTypeInfo) : + m_pTypeInfo(pTypeInfo), + m_pFuncDesc(nullptr) + { + OSL_ASSERT(pTypeInfo); + } + ~FuncDesc() + { + ReleaseFUNCDESC(); + } + + FUNCDESC* operator -> () + { + return m_pFuncDesc; + } + + FUNCDESC** operator & () + { + return & m_pFuncDesc; + } + + operator FUNCDESC* () + { + return m_pFuncDesc; + } + + FUNCDESC* operator = (FUNCDESC* pDesc) + { + ReleaseFUNCDESC(); + m_pFuncDesc = pDesc; + return m_pFuncDesc; + } + FUNCDESC* Detach() + { + FUNCDESC* pDesc = m_pFuncDesc; + m_pFuncDesc = nullptr; + return pDesc; + } + + void ReleaseFUNCDESC() + { + if (m_pFuncDesc != nullptr) + { + m_pTypeInfo->ReleaseFuncDesc(m_pFuncDesc); + } + m_pFuncDesc = nullptr; + } +}; +//Wrapper for EXCEPINFO structure +class ExcepInfo : public EXCEPINFO +{ + EXCEPINFO* operator = (const ExcepInfo& ); + ExcepInfo(const ExcepInfo &); +public: + ExcepInfo() + : EXCEPINFO{} + { + } + ~ExcepInfo() + { + if (bstrSource != nullptr) + ::SysFreeString(bstrSource); + if (bstrDescription != nullptr) + ::SysFreeString(bstrDescription); + if (bstrHelpFile != nullptr) + ::SysFreeString(bstrHelpFile); + } +}; + +//Wrapper for TYPEATTR +class TypeAttr +{ + TYPEATTR* operator = (const TypeAttr &); + TypeAttr(const TypeAttr &); +public: + CComPtr< ITypeInfo > m_pTypeInfo; + TYPEATTR* m_pTypeAttr; + + explicit TypeAttr(ITypeInfo* pTypeInfo) : + m_pTypeInfo( pTypeInfo ), + m_pTypeAttr( nullptr ) + { + OSL_ASSERT(pTypeInfo); + } + ~TypeAttr() noexcept + { + if (m_pTypeAttr != nullptr) + { + m_pTypeInfo->ReleaseTypeAttr(m_pTypeAttr); + } + } + + TYPEATTR** operator&() noexcept + { + return &m_pTypeAttr; + } + + TYPEATTR* operator->() noexcept + { + return m_pTypeAttr; + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/MasterDetailLinkDialog.cxx b/extensions/source/propctrlr/MasterDetailLinkDialog.cxx new file mode 100644 index 000000000..5f38856fc --- /dev/null +++ b/extensions/source/propctrlr/MasterDetailLinkDialog.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 +#include +#include +#include "MasterDetailLinkDialog.hxx" +#include "formlinkdialog.hxx" + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + + MasterDetailLinkDialog::MasterDetailLinkDialog(const Reference< XComponentContext >& _rxContext ) + :OGenericUnoDialog( _rxContext ) + { + } + + Sequence SAL_CALL MasterDetailLinkDialog::getImplementationId( ) + { + return css::uno::Sequence(); + } + + + OUString SAL_CALL MasterDetailLinkDialog::getImplementationName() + { + return "org.openoffice.comp.form.ui.MasterDetailLinkDialog"; + } + + + css::uno::Sequence SAL_CALL MasterDetailLinkDialog::getSupportedServiceNames() + { + return { "com.sun.star.form.MasterDetailLinkDialog" }; + } + + + Reference SAL_CALL MasterDetailLinkDialog::getPropertySetInfo() + { + Reference xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + + ::cppu::IPropertyArrayHelper& MasterDetailLinkDialog::getInfoHelper() + { + return *getArrayHelper(); + } + + + ::cppu::IPropertyArrayHelper* MasterDetailLinkDialog::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + } + + std::unique_ptr MasterDetailLinkDialog::createDialog(const css::uno::Reference& rParent) + { + return std::make_unique(Application::GetFrameWeld(rParent), m_xDetail, + m_xMaster, m_aContext, m_sExplanation, + m_sDetailLabel, m_sMasterLabel); + } + + void MasterDetailLinkDialog::implInitialize(const Any& _rValue) + { + PropertyValue aProperty; + if (_rValue >>= aProperty) + { + if (aProperty.Name == "Detail") + { + if ( ! (aProperty.Value >>= m_xDetail) ) + SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property Detail"); + return; + } + else if (aProperty.Name == "Master") + { + if ( ! (aProperty.Value >>= m_xMaster) ) + SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property Master"); + return; + } + else if (aProperty.Name == "Explanation") + { + if ( ! (aProperty.Value >>= m_sExplanation) ) + SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property Explanation"); + return; + } + else if (aProperty.Name == "DetailLabel") + { + if ( ! (aProperty.Value >>= m_sDetailLabel) ) + SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property DetailLabel"); + return; + } + else if (aProperty.Name == "MasterLabel") + { + if ( ! (aProperty.Value >>= m_sMasterLabel) ) + SAL_WARN("extensions.propctrlr", "implInitialize: unable to get property MasterLabel"); + return; + } + } + MasterDetailLinkDialog_DBase::implInitialize(_rValue); + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_MasterDetailLinkDialog_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::MasterDetailLinkDialog(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/MasterDetailLinkDialog.hxx b/extensions/source/propctrlr/MasterDetailLinkDialog.hxx new file mode 100644 index 000000000..97911436a --- /dev/null +++ b/extensions/source/propctrlr/MasterDetailLinkDialog.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace pcr +{ + + + class MasterDetailLinkDialog; + typedef ::svt::OGenericUnoDialog MasterDetailLinkDialog_DBase; + typedef ::comphelper::OPropertyArrayUsageHelper< MasterDetailLinkDialog > MasterDetailLinkDialog_PBase; + + class MasterDetailLinkDialog : public MasterDetailLinkDialog_DBase + ,public MasterDetailLinkDialog_PBase + { + public: + explicit MasterDetailLinkDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + private: + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + // OGenericUnoDialog overridables + virtual std::unique_ptr createDialog(const css::uno::Reference& rParent) override; + virtual void implInitialize(const css::uno::Any& _rValue) override; + + css::uno::Reference< css::beans::XPropertySet> m_xDetail; + css::uno::Reference< css::beans::XPropertySet> m_xMaster; + OUString m_sExplanation; + OUString m_sDetailLabel; + OUString m_sMasterLabel; + }; + + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/browserline.cxx b/extensions/source/propctrlr/browserline.cxx new file mode 100644 index 000000000..814c24f4b --- /dev/null +++ b/extensions/source/propctrlr/browserline.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 "browserline.hxx" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pcr +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::inspection::XPropertyControl; + using ::com::sun::star::inspection::XPropertyControlContext; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::graphic::GraphicProvider; + using ::com::sun::star::graphic::XGraphicProvider; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::graphic::XGraphic; + + namespace PropertyLineElement = ::com::sun::star::inspection::PropertyLineElement; + + OBrowserLine::OBrowserLine(const OUString& rEntryName, weld::Container* pParent, weld::SizeGroup* pLabelGroup, + weld::Container* pInitialControlParent) + : m_sEntryName(rEntryName) + , m_xBuilder(Application::CreateBuilder(pParent, "modules/spropctrlr/ui/browserline.ui")) + , m_xContainer(m_xBuilder->weld_container("BrowserLine")) + , m_xFtTitle(m_xBuilder->weld_label("label")) + , m_xBrowseButton(m_xBuilder->weld_button("browse")) + , m_xAdditionalBrowseButton(m_xBuilder->weld_button("morebrowse")) + , m_pInitialControlParent(pInitialControlParent) // controls start with this as their parent and need to be moved into m_xContainer + , m_pParent(pParent) + , m_pControlWindow( nullptr ) + , m_pBrowseButton(nullptr) + , m_pAdditionalBrowseButton( nullptr ) + , m_pClickListener( nullptr ) + , m_nNameWidth(0) + , m_nEnableFlags( 0xFFFF ) + , m_bIndentTitle( false ) + , m_bReadOnly( false ) + { + pLabelGroup->add_widget(m_xFtTitle.get()); + } + + OBrowserLine::~OBrowserLine() + { + implHideBrowseButton(true); + implHideBrowseButton(false); + m_pParent->move(m_xContainer.get(), nullptr); + } + + void OBrowserLine::IndentTitle( bool _bIndent ) + { + if ( m_bIndentTitle != _bIndent ) + { + m_bIndentTitle = _bIndent; + } + } + + void OBrowserLine::SetComponentHelpIds(const OString& rHelpId) + { + if (m_pControlWindow) + m_pControlWindow->set_help_id(rHelpId); + + if ( m_pBrowseButton ) + { + m_pBrowseButton->set_help_id(rHelpId); + + if ( m_pAdditionalBrowseButton ) + { + m_pAdditionalBrowseButton->set_help_id(rHelpId); + } + } + } + + void OBrowserLine::setControl( const Reference< XPropertyControl >& rxControl ) + { + m_xControl = rxControl; + auto xWindow = m_xControl->getControlWindow(); + if (weld::TransportAsXWindow* pTunnel = dynamic_cast(xWindow.get())) + m_pControlWindow = pTunnel->getWidget(); + else + m_pControlWindow = nullptr; + DBG_ASSERT( m_pControlWindow, "OBrowserLine::setControl: setting NULL controls/windows is not allowed!" ); + + if ( m_pControlWindow ) + { + m_pInitialControlParent->move(m_pControlWindow, m_xContainer.get()); + m_pControlWindow->set_grid_left_attach(1); + m_xFtTitle->set_mnemonic_widget(m_pControlWindow); + m_pControlWindow->show(); + } + } + + bool OBrowserLine::GrabFocus() + { + bool bRes=false; + + if (m_pControlWindow && m_pControlWindow->get_sensitive()) + { + m_pControlWindow->grab_focus(); + bRes = true; + } + else if ( m_pAdditionalBrowseButton && m_pAdditionalBrowseButton->get_sensitive() ) + { + m_pAdditionalBrowseButton->grab_focus(); + bRes = true; + } + else if ( m_pBrowseButton && m_pBrowseButton->get_sensitive() ) + { + m_pBrowseButton->grab_focus(); + bRes = true; + } + return bRes; + } + + void OBrowserLine::Show(bool bFlag) + { + m_xFtTitle->set_visible(bFlag); + if (m_pControlWindow) + m_pControlWindow->set_visible( bFlag ); + if ( m_pBrowseButton ) + m_pBrowseButton->set_visible( bFlag ); + if ( m_pAdditionalBrowseButton ) + m_pAdditionalBrowseButton->set_visible( bFlag ); + } + + void OBrowserLine::Hide() + { + Show(false); + } + + void OBrowserLine::SetTitle(const OUString& rNewTitle ) + { + if ( GetTitle() == rNewTitle ) + return; + m_xFtTitle->set_label( rNewTitle ); + if (m_pControlWindow) + m_pControlWindow->set_accessible_name(rNewTitle); + if ( m_pBrowseButton ) + m_pBrowseButton->set_accessible_name( rNewTitle ); + FullFillTitleString(); + } + + void OBrowserLine::FullFillTitleString() + { + OUStringBuffer aText(m_xFtTitle->get_label()); + + int n10DotsWidth = m_xFtTitle->get_pixel_size("..........").Width(); + int nTextWidth = m_xFtTitle->get_pixel_size(OUString::unacquired(aText)).Width(); + int nDiff = m_nNameWidth - nTextWidth; + int nExtraChars = (nDiff * 10) / n10DotsWidth; + for (int i = 0; i < nExtraChars; ++i) + aText.append("."); + + // for Issue 69452 + if (AllSettings::GetLayoutRTL()) + { + sal_Unicode const cRTL_mark = 0x200F; + aText.append( cRTL_mark ); + } + + m_xFtTitle->set_label(aText.makeStringAndClear()); + } + + OUString OBrowserLine::GetTitle() const + { + OUString sDisplayName = m_xFtTitle->get_label(); + + // for Issue 69452 + if (AllSettings::GetLayoutRTL()) + { + sal_Unicode const cRTL_mark = 0x200F; + sDisplayName = comphelper::string::stripEnd(sDisplayName, cRTL_mark); + } + + sDisplayName = comphelper::string::stripEnd(sDisplayName, '.'); + + return sDisplayName; + } + + void OBrowserLine::SetReadOnly( bool _bReadOnly ) + { + if ( m_bReadOnly != _bReadOnly ) + { + m_bReadOnly = _bReadOnly; + implUpdateEnabledDisabled(); + } + } + + namespace + { + void implSetBitIfAffected(sal_uInt16& nEnabledBits, sal_Int16 _nAffectedMask, sal_Int16 _nTestBit, bool _bSet) + { + if ( _nAffectedMask & _nTestBit ) + { + if ( _bSet ) + nEnabledBits |= _nTestBit; + else + nEnabledBits &= ~_nTestBit; + } + } + + void implEnable(weld::Widget* pWindow, bool bEnable) + { + // tdf#138131 get_sensitive comparison as bodge for + // vcl's recursive Enable behavior + if (pWindow && pWindow->get_sensitive() != bEnable) + pWindow->set_sensitive(bEnable); + } + + void implEnable(weld::Widget* pWindow, sal_uInt16 nEnabledBits, sal_uInt16 nMatchBits) + { + bool bEnable = ((nEnabledBits & nMatchBits) == nMatchBits); + implEnable(pWindow, bEnable); + } + } + + void OBrowserLine::implUpdateEnabledDisabled() + { + implEnable( m_xFtTitle.get(), m_nEnableFlags, PropertyLineElement::CompleteLine ); + if ( m_pControlWindow ) + implEnable( m_pControlWindow, m_nEnableFlags, PropertyLineElement::CompleteLine | PropertyLineElement::InputControl ); + + if ( m_bReadOnly ) + { + implEnable( m_pBrowseButton, false ); + implEnable( m_pAdditionalBrowseButton, false ); + } + else + { + implEnable( m_pBrowseButton, m_nEnableFlags, PropertyLineElement::CompleteLine | PropertyLineElement::PrimaryButton ); + implEnable( m_pAdditionalBrowseButton, m_nEnableFlags, PropertyLineElement::CompleteLine | PropertyLineElement::SecondaryButton ); + } + } + + void OBrowserLine::EnablePropertyLine( bool _bEnable ) + { + implSetBitIfAffected( m_nEnableFlags, PropertyLineElement::CompleteLine, PropertyLineElement::CompleteLine, _bEnable ); + implUpdateEnabledDisabled(); + } + + + void OBrowserLine::EnablePropertyControls( sal_Int16 _nControls, bool _bEnable ) + { + implSetBitIfAffected( m_nEnableFlags, _nControls, PropertyLineElement::InputControl, _bEnable ); + implSetBitIfAffected( m_nEnableFlags, _nControls, PropertyLineElement::PrimaryButton, _bEnable ); + implSetBitIfAffected( m_nEnableFlags, _nControls, PropertyLineElement::SecondaryButton, _bEnable ); + implUpdateEnabledDisabled(); + } + + weld::Button& OBrowserLine::impl_ensureButton(bool bPrimary) + { + weld::Button* pButton; + if (bPrimary) + pButton = m_pBrowseButton; + else + pButton = m_pAdditionalBrowseButton; + + if (!pButton ) + { + if (bPrimary) + pButton = m_pBrowseButton = m_xBrowseButton.get(); + else + pButton = m_pAdditionalBrowseButton = m_xAdditionalBrowseButton.get(); + pButton->connect_focus_in(LINK(this, OBrowserLine, OnButtonFocus)); + pButton->connect_clicked(LINK(this, OBrowserLine, OnButtonClicked)); + } + + pButton->show(); + + return *pButton; + } + + void OBrowserLine::ShowBrowseButton( const OUString& rImageURL, bool bPrimary ) + { + weld::Button& rButton( impl_ensureButton( bPrimary ) ); + + OSL_PRECOND( !rImageURL.isEmpty(), "OBrowserLine::ShowBrowseButton: use the other version if you don't have an image!" ); + Reference xGraphic; + try + { + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference< XGraphicProvider > xGraphicProvider( GraphicProvider::create(xContext) ); + + Sequence aMediaProperties{ comphelper::makePropertyValue("URL", rImageURL) }; + + xGraphic = Reference(xGraphicProvider->queryGraphic(aMediaProperties), css::uno::UNO_SET_THROW); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + rButton.set_image(xGraphic); + } + + void OBrowserLine::ShowBrowseButton(const css::uno::Reference& rGraphic, bool bPrimary) + { + weld::Button& rButton( impl_ensureButton( bPrimary ) ); + rButton.set_image(rGraphic); + } + + void OBrowserLine::ShowBrowseButton( bool bPrimary ) + { + impl_ensureButton(bPrimary); + } + + void OBrowserLine::implHideBrowseButton(bool bPrimary) + { + if (bPrimary) + { + if (m_pBrowseButton) + { + m_pBrowseButton->hide(); + m_pBrowseButton->connect_focus_in(Link()); + m_pBrowseButton = nullptr; + } + } + else + { + if (m_pAdditionalBrowseButton) + { + m_pAdditionalBrowseButton->hide(); + m_pAdditionalBrowseButton->connect_focus_in(Link()); + m_pAdditionalBrowseButton = nullptr; + } + } + } + + void OBrowserLine::HideBrowseButton(bool bPrimary) + { + implHideBrowseButton(bPrimary); + } + + void OBrowserLine::SetTitleWidth(sal_uInt16 nWidth) + { + int nMinDotsWidth = m_xFtTitle->get_pixel_size("...").Width(); + if (m_nNameWidth != nWidth + nMinDotsWidth) + m_nNameWidth = nWidth + nMinDotsWidth; + FullFillTitleString(); + } + + void OBrowserLine::SetClickListener( IButtonClickListener* _pListener ) + { + m_pClickListener = _pListener; + } + + IMPL_LINK(OBrowserLine, OnButtonClicked, weld::Button&, rButton, void) + { + if ( m_pClickListener ) + m_pClickListener->buttonClicked(this, &rButton == m_pBrowseButton); + } + + IMPL_LINK_NOARG( OBrowserLine, OnButtonFocus, weld::Widget&, void ) + { + if ( m_xControl.is() ) + { + try + { + Reference< XPropertyControlContext > xContext( m_xControl->getControlContext(), css::uno::UNO_SET_THROW ); + xContext->focusGained( m_xControl ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + } + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/browserline.hxx b/extensions/source/propctrlr/browserline.hxx new file mode 100644 index 000000000..db33b7a55 --- /dev/null +++ b/extensions/source/propctrlr/browserline.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace com::sun::star::inspection::PropertyLineElement +{ + const sal_Int16 CompleteLine = 0x4000; +} + + +namespace pcr +{ + + + class OBrowserLine; + + + class IButtonClickListener + { + public: + virtual void buttonClicked( OBrowserLine* pLine, bool bPrimary ) = 0; + + protected: + ~IButtonClickListener() {} + }; + + + class OBrowserLine + { + private: + OUString m_sEntryName; + std::unique_ptr m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr m_xFtTitle; + std::unique_ptr m_xBrowseButton; + std::unique_ptr m_xAdditionalBrowseButton; + css::uno::Reference< css::inspection::XPropertyControl > + m_xControl; + weld::Container* m_pInitialControlParent; + weld::Container* m_pParent; + weld::Widget* m_pControlWindow; + weld::Button* m_pBrowseButton; + weld::Button* m_pAdditionalBrowseButton; + IButtonClickListener* m_pClickListener; + sal_uInt16 m_nNameWidth; + sal_uInt16 m_nEnableFlags; + bool m_bIndentTitle; + bool m_bReadOnly; + + public: + OBrowserLine(const OUString& rEntryName, weld::Container* pParent, weld::SizeGroup* pLabelGroup, + weld::Container* pInitialControlParent); + ~OBrowserLine(); + + void setControl( const css::uno::Reference< css::inspection::XPropertyControl >& rxControl ); + const css::uno::Reference< css::inspection::XPropertyControl >& getControl() const + { + return m_xControl; + } + weld::Widget* getControlWindow() const + { + return m_pControlWindow; + } + + const OUString& GetEntryName() const { return m_sEntryName; } + + void SetComponentHelpIds(const OString& rHelpId); + + void SetTitle(const OUString& rString ); + void FullFillTitleString(); + OUString GetTitle() const; + void SetTitleWidth(sal_uInt16); + + int GetRowHeight() const { return m_xContainer->get_preferred_size().Height(); } + void Show(bool bFlag=true); + void Hide(); + + bool GrabFocus(); + void ShowBrowseButton( const OUString& rImageURL, bool bPrimary ); + void ShowBrowseButton( const css::uno::Reference& rGraphic, bool bPrimary ); + void ShowBrowseButton( bool bPrimary ); + void HideBrowseButton( bool bPrimary ); + + void EnablePropertyControls( sal_Int16 nControls, bool bEnable ); + void EnablePropertyLine( bool bEnable ); + + void SetReadOnly( bool bReadOnly ); + + void SetClickListener( IButtonClickListener* pListener ); + + void IndentTitle( bool bIndent ); + + private: + DECL_LINK( OnButtonClicked, weld::Button&, void ); + DECL_LINK( OnButtonFocus, weld::Widget&, void ); + + void implHideBrowseButton(bool bPrimary); + void implUpdateEnabledDisabled(); + + weld::Button& impl_ensureButton(bool bPrimary); + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/browserlistbox.cxx b/extensions/source/propctrlr/browserlistbox.cxx new file mode 100644 index 000000000..04e9e44b3 --- /dev/null +++ b/extensions/source/propctrlr/browserlistbox.cxx @@ -0,0 +1,817 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "browserlistbox.hxx" +#include "pcrcommon.hxx" +#include "proplinelistener.hxx" +#include "propcontrolobserver.hxx" +#include "linedescriptor.hxx" +#include "inspectorhelpwindow.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace pcr +{ + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::inspection::XPropertyControlContext; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::inspection::XPropertyControl; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::lang::XComponent; + using ::com::sun::star::uno::UNO_QUERY; + + namespace PropertyControlType = ::com::sun::star::inspection::PropertyControlType; + + namespace { + + enum ControlEventType + { + FOCUS_GAINED, + VALUE_CHANGED, + ACTIVATE_NEXT + }; + + struct ControlEvent : public ::comphelper::AnyEvent + { + Reference< XPropertyControl > xControl; + ControlEventType eType; + + ControlEvent( const Reference< XPropertyControl >& _rxControl, ControlEventType _eType ) + :xControl( _rxControl ) + ,eType( _eType ) + { + } + }; + + class SharedNotifier + { + private: + static ::osl::Mutex& getMutex(); + static ::rtl::Reference< ::comphelper::AsyncEventNotifier > s_pNotifier; + + public: + SharedNotifier(const SharedNotifier&) = delete; + SharedNotifier& operator=(const SharedNotifier&) = delete; + static const ::rtl::Reference< ::comphelper::AsyncEventNotifier >& + getNotifier(); + }; + + } + + ::rtl::Reference< ::comphelper::AsyncEventNotifier > SharedNotifier::s_pNotifier; + + + ::osl::Mutex& SharedNotifier::getMutex() + { + static ::osl::Mutex s_aMutex; + return s_aMutex; + } + + + const ::rtl::Reference< ::comphelper::AsyncEventNotifier >& SharedNotifier::getNotifier() + { + ::osl::MutexGuard aGuard( getMutex() ); + if ( !s_pNotifier.is() ) + { + s_pNotifier.set( + new ::comphelper::AsyncEventNotifier("browserlistbox")); + s_pNotifier->launch(); + //TODO: a protocol is missing how to join with the launched + // 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 + } + return s_pNotifier; + } + + + /** implementation for of XPropertyControlContext + which forwards all events to a non-UNO version of this interface + */ + typedef ::cppu::WeakImplHelper< XPropertyControlContext > PropertyControlContext_Impl_Base; + class PropertyControlContext_Impl :public PropertyControlContext_Impl_Base + ,public ::comphelper::IEventProcessor + { + public: + enum NotificationMode + { + eSynchronously, + eAsynchronously + }; + + private: + OBrowserListBox* m_pContext; + NotificationMode m_eMode; + + public: + /** creates an instance + @param _rContextImpl + the instance to delegate events to + */ + explicit PropertyControlContext_Impl( OBrowserListBox& _rContextImpl ); + + /** disposes the context. + + When you call this method, all subsequent callbacks to the + XPropertyControlContext methods + will throw a DisposedException. + */ + void dispose(); + + /** sets the notification mode, so that notifications received from the controls are + forwarded to our OBrowserListBox either synchronously or asynchronously + @param _eMode + the new notification mode + */ + void setNotificationMode( NotificationMode _eMode ); + + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + protected: + virtual ~PropertyControlContext_Impl() override; + + // XPropertyControlObserver + virtual void SAL_CALL focusGained( const Reference< XPropertyControl >& Control ) override; + virtual void SAL_CALL valueChanged( const Reference< XPropertyControl >& Control ) override; + // XPropertyControlContext + virtual void SAL_CALL activateNextControl( const Reference< XPropertyControl >& CurrentControl ) override; + + // IEventProcessor + virtual void processEvent( const ::comphelper::AnyEvent& _rEvent ) override; + + private: + /** processes the given event, i.e. notifies it to our OBrowserListBox + @param _rEvent + the event no notify + @precond + our mutex (well, the SolarMutex) is locked + */ + void impl_processEvent_throw( const ::comphelper::AnyEvent& _rEvent ); + + /** checks whether the instance is already disposed + */ + bool impl_isDisposed_nothrow() const { return m_pContext == nullptr; } + + /** notifies the given event originating from the given control + @throws DisposedException + @param _rxControl + @param _eType + */ + void impl_notify_throw( const Reference< XPropertyControl >& _rxControl, ControlEventType _eType ); + }; + + PropertyControlContext_Impl::PropertyControlContext_Impl( OBrowserListBox& _rContextImpl ) + : m_pContext( &_rContextImpl ) + , m_eMode( eAsynchronously ) + { + } + + PropertyControlContext_Impl::~PropertyControlContext_Impl() + { + if ( !impl_isDisposed_nothrow() ) + dispose(); + } + + void PropertyControlContext_Impl::dispose() + { + SolarMutexGuard aGuard; + if ( impl_isDisposed_nothrow() ) + return; + + SharedNotifier::getNotifier()->removeEventsForProcessor( this ); + m_pContext = nullptr; + } + + void PropertyControlContext_Impl::setNotificationMode( NotificationMode _eMode ) + { + SolarMutexGuard aGuard; + m_eMode = _eMode; + } + + void PropertyControlContext_Impl::impl_notify_throw( const Reference< XPropertyControl >& _rxControl, ControlEventType _eType ) + { + ::comphelper::AnyEventRef pEvent; + + { + SolarMutexGuard aGuard; + if ( impl_isDisposed_nothrow() ) + throw DisposedException( OUString(), *this ); + pEvent = new ControlEvent( _rxControl, _eType ); + + if ( m_eMode == eSynchronously ) + { + impl_processEvent_throw( *pEvent ); + return; + } + } + + SharedNotifier::getNotifier()->addEvent( pEvent, this ); + } + + void SAL_CALL PropertyControlContext_Impl::focusGained( const Reference< XPropertyControl >& Control ) + { + impl_notify_throw( Control, FOCUS_GAINED ); + } + + void SAL_CALL PropertyControlContext_Impl::valueChanged( const Reference< XPropertyControl >& Control ) + { + impl_notify_throw( Control, VALUE_CHANGED ); + } + + void SAL_CALL PropertyControlContext_Impl::activateNextControl( const Reference< XPropertyControl >& CurrentControl ) + { + impl_notify_throw( CurrentControl, ACTIVATE_NEXT ); + } + + void SAL_CALL PropertyControlContext_Impl::acquire() noexcept + { + PropertyControlContext_Impl_Base::acquire(); + } + + void SAL_CALL PropertyControlContext_Impl::release() noexcept + { + PropertyControlContext_Impl_Base::release(); + } + + void PropertyControlContext_Impl::processEvent( const ::comphelper::AnyEvent& _rEvent ) + { + SolarMutexGuard aGuard; + if ( impl_isDisposed_nothrow() ) + return; + + try + { + impl_processEvent_throw( _rEvent ); + } + catch( const Exception& ) + { + // can't handle otherwise, since our caller (the notification thread) does not allow + // for exceptions (it could itself abort only) + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + void PropertyControlContext_Impl::impl_processEvent_throw( const ::comphelper::AnyEvent& _rEvent ) + { + const ControlEvent& rControlEvent = static_cast< const ControlEvent& >( _rEvent ); + switch ( rControlEvent.eType ) + { + case FOCUS_GAINED: + m_pContext->focusGained( rControlEvent.xControl ); + break; + case VALUE_CHANGED: + m_pContext->valueChanged( rControlEvent.xControl ); + break; + case ACTIVATE_NEXT: + m_pContext->activateNextControl( rControlEvent.xControl ); + break; + } + } + + OBrowserListBox::OBrowserListBox(weld::Builder& rBuilder, weld::Container* pContainer) + : m_xScrolledWindow(rBuilder.weld_scrolled_window("scrolledwindow")) + , m_xLinesPlayground(rBuilder.weld_container("playground")) + , m_xSizeGroup(rBuilder.create_size_group()) + , m_xHelpWindow(new InspectorHelpWindow(rBuilder)) + , m_pInitialControlParent(pContainer) + , m_pLineListener(nullptr) + , m_pControlObserver( nullptr ) + , m_nTheNameSize(0) + , m_nRowHeight(0) + , m_pControlContextImpl( new PropertyControlContext_Impl( *this ) ) + { + m_xScrolledWindow->set_size_request(-1, m_xScrolledWindow->get_text_height() * 20); + } + + OBrowserListBox::~OBrowserListBox() + { + OSL_ENSURE( !IsModified(), "OBrowserListBox::~OBrowserListBox: still modified - should have been committed before!" ); + + // doing the commit here, while we, as well as our owner, as well as some other components, + // are already "half dead" (means within their dtor) is potentially dangerous. + // By definition, CommitModified has to be called (if necessary) before destruction + m_pControlContextImpl->dispose(); + m_pControlContextImpl.clear(); + + Clear(); + } + + bool OBrowserListBox::IsModified() const + { + bool bModified = false; + + if (m_xScrolledWindow->get_visible() && m_xActiveControl.is()) + bModified = m_xActiveControl->isModified(); + + return bModified; + } + + void OBrowserListBox::CommitModified( ) + { + if ( !(IsModified() && m_xActiveControl.is()) ) + return; + + // for the time of this commit, notify all events synchronously + // #i63814# + m_pControlContextImpl->setNotificationMode( PropertyControlContext_Impl::eSynchronously ); + try + { + m_xActiveControl->notifyModifiedValue(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + m_pControlContextImpl->setNotificationMode( PropertyControlContext_Impl::eAsynchronously ); + } + + void OBrowserListBox::SetListener( IPropertyLineListener* _pListener ) + { + m_pLineListener = _pListener; + } + + void OBrowserListBox::SetObserver( IPropertyControlObserver* _pObserver ) + { + m_pControlObserver = _pObserver; + } + + void OBrowserListBox::EnableHelpSection( bool _bEnable ) + { + m_xHelpWindow->Show( _bEnable ); + } + + bool OBrowserListBox::HasHelpSection() const + { + return m_xHelpWindow->IsVisible(); + } + + void OBrowserListBox::SetHelpText( const OUString& _rHelpText ) + { + OSL_ENSURE( HasHelpSection(), "OBrowserListBox::SetHelpText: help section not visible!" ); + m_xHelpWindow->SetText( _rHelpText ); + } + + void OBrowserListBox::UpdatePlayGround() + { + for (auto& line : m_aLines) + line.pLine->SetTitleWidth(m_nTheNameSize); + } + + void OBrowserListBox::SetPropertyValue(const OUString& _rEntryName, const Any& _rValue, bool _bUnknownValue ) + { + ListBoxLines::iterator line = std::find_if(m_aLines.begin(), m_aLines.end(), + [&_rEntryName](const ListBoxLine& rLine) { return rLine.aName == _rEntryName; }); + + if ( line != m_aLines.end() ) + { + if ( _bUnknownValue ) + { + Reference< XPropertyControl > xControl( line->pLine->getControl() ); + OSL_ENSURE( xControl.is(), "OBrowserListBox::SetPropertyValue: illegal control!" ); + if ( xControl.is() ) + xControl->setValue( Any() ); + } + else + impl_setControlAsPropertyValue( *line, _rValue ); + } + } + + sal_uInt16 OBrowserListBox::GetPropertyPos( std::u16string_view _rEntryName ) const + { + sal_uInt16 nPos = 0; + for (auto const& line : m_aLines) + { + if ( line.aName == _rEntryName ) + { + return nPos; + } + ++nPos; + } + + return EDITOR_LIST_ENTRY_NOTFOUND; + } + + bool OBrowserListBox::impl_getBrowserLineForName( const OUString& _rEntryName, BrowserLinePointer& _out_rpLine ) const + { + ListBoxLines::const_iterator line = std::find_if(m_aLines.begin(), m_aLines.end(), + [&_rEntryName](const ListBoxLine& rLine) { return rLine.aName == _rEntryName; }); + + if ( line != m_aLines.end() ) + _out_rpLine = line->pLine; + else + _out_rpLine.reset(); + return bool(_out_rpLine); + } + + void OBrowserListBox::EnablePropertyControls( const OUString& _rEntryName, sal_Int16 _nControls, bool _bEnable ) + { + BrowserLinePointer pLine; + if ( impl_getBrowserLineForName( _rEntryName, pLine ) ) + pLine->EnablePropertyControls( _nControls, _bEnable ); + } + + void OBrowserListBox::EnablePropertyLine( const OUString& _rEntryName, bool _bEnable ) + { + BrowserLinePointer pLine; + if ( impl_getBrowserLineForName( _rEntryName, pLine ) ) + pLine->EnablePropertyLine( _bEnable ); + } + + Reference< XPropertyControl > OBrowserListBox::GetPropertyControl( const OUString& _rEntryName ) + { + BrowserLinePointer pLine; + if ( impl_getBrowserLineForName( _rEntryName, pLine ) ) + return pLine->getControl(); + return nullptr; + } + + void OBrowserListBox::InsertEntry(const OLineDescriptor& rPropertyData, sal_uInt16 _nPos) + { + // create a new line + BrowserLinePointer pBrowserLine = std::make_shared(rPropertyData.sName, m_xLinesPlayground.get(), + m_xSizeGroup.get(), m_pInitialControlParent); + + // check that the name is unique + for (auto const& line : m_aLines) + { + if (line.aName == rPropertyData.sName) + { + // already have another line for this name! + assert(false); + } + } + + ListBoxLine aNewLine( rPropertyData.sName, pBrowserLine, rPropertyData.xPropertyHandler ); + ListBoxLines::size_type nInsertPos = _nPos; + if ( _nPos >= m_aLines.size() ) + { + nInsertPos = m_aLines.size(); + m_aLines.push_back( aNewLine ); + } + else + m_aLines.insert( m_aLines.begin() + _nPos, aNewLine ); + + pBrowserLine->SetTitleWidth(m_nTheNameSize); + + // initialize the entry + ChangeEntry(rPropertyData, nInsertPos); + + m_nRowHeight = std::max(m_nRowHeight, pBrowserLine->GetRowHeight() + 6); // 6 is spacing of the "playground" in browserpage.ui + m_xScrolledWindow->vadjustment_set_step_increment(m_nRowHeight); + } + + void OBrowserListBox::ShowEntry(sal_uInt16 nPos) + { + if (nPos == 0) + { + // special case the simple entry 0 situation + m_xScrolledWindow->vadjustment_set_value(0); + return; + } + + if (nPos >= m_aLines.size()) + return; + + unsigned const nWinHeight = m_xScrolledWindow->vadjustment_get_page_size(); + + auto nThumbPos = m_xScrolledWindow->vadjustment_get_value(); + int const nWinTop = nThumbPos; + int const nWinBottom = nWinTop + nWinHeight; + + auto nCtrlPosY = nPos * m_nRowHeight; + + int const nSelectedItemTop = nCtrlPosY; + int const nSelectedItemBottom = nCtrlPosY + m_nRowHeight; + bool const shouldScrollDown = nSelectedItemBottom >= nWinBottom; + bool const shouldScrollUp = nSelectedItemTop <= nWinTop; + bool const isNeedToScroll = shouldScrollDown || shouldScrollUp; + + if (!isNeedToScroll) + return; + + if (shouldScrollDown) + { + int nOffset = nSelectedItemBottom - nWinBottom; + nThumbPos += nOffset; + } + else + { + int nOffset = nWinTop - nSelectedItemTop; + nThumbPos -= nOffset; + if(nThumbPos < 0) + nThumbPos = 0; + } + m_xScrolledWindow->vadjustment_set_value(nThumbPos); + } + + void OBrowserListBox::buttonClicked( OBrowserLine* _pLine, bool _bPrimary ) + { + DBG_ASSERT( _pLine, "OBrowserListBox::buttonClicked: invalid browser line!" ); + if ( _pLine && m_pLineListener ) + { + m_pLineListener->Clicked( _pLine->GetEntryName(), _bPrimary ); + } + } + + void OBrowserListBox::impl_setControlAsPropertyValue( const ListBoxLine& _rLine, const Any& _rPropertyValue ) + { + Reference< XPropertyControl > xControl( _rLine.pLine->getControl() ); + try + { + if ( _rPropertyValue.getValueType().equals( _rLine.pLine->getControl()->getValueType() ) ) + { + xControl->setValue( _rPropertyValue ); + } + else + { + SAL_WARN_IF( !_rLine.xHandler.is(), "extensions.propctrlr", + "OBrowserListBox::impl_setControlAsPropertyValue: no handler -> no conversion (property: '" + << _rLine.pLine->GetEntryName() << "')!" ); + if ( _rLine.xHandler.is() ) + { + Any aControlValue = _rLine.xHandler->convertToControlValue( + _rLine.pLine->GetEntryName(), _rPropertyValue, xControl->getValueType() ); + xControl->setValue( aControlValue ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + Any OBrowserListBox::impl_getControlAsPropertyValue( const ListBoxLine& _rLine ) + { + Reference< XPropertyControl > xControl( _rLine.pLine->getControl() ); + Any aPropertyValue; + try + { + SAL_WARN_IF( !_rLine.xHandler.is(), "extensions.propctrlr", + "OBrowserListBox::impl_getControlAsPropertyValue: no handler -> no conversion (property: '" + << _rLine.pLine->GetEntryName() << "')!" ); + if ( _rLine.xHandler.is() ) + aPropertyValue = _rLine.xHandler->convertToPropertyValue( _rLine.pLine->GetEntryName(), xControl->getValue() ); + else + aPropertyValue = xControl->getValue(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return aPropertyValue; + } + + sal_uInt16 OBrowserListBox::impl_getControlPos( const Reference< XPropertyControl >& _rxControl ) const + { + sal_uInt16 nPos = 0; + for (auto const& search : m_aLines) + { + if ( search.pLine->getControl().get() == _rxControl.get() ) + return nPos; + ++nPos; + } + OSL_FAIL( "OBrowserListBox::impl_getControlPos: invalid control - not part of any of our lines!" ); + return sal_uInt16(-1); + } + + + void OBrowserListBox::focusGained( const Reference< XPropertyControl >& _rxControl ) + { + DBG_TESTSOLARMUTEX(); + + DBG_ASSERT( _rxControl.is(), "OBrowserListBox::focusGained: invalid event source!" ); + if ( !_rxControl.is() ) + return; + + if ( m_pControlObserver ) + m_pControlObserver->focusGained( _rxControl ); + + m_xActiveControl = _rxControl; + ShowEntry( impl_getControlPos( m_xActiveControl ) ); + } + + + void OBrowserListBox::valueChanged( const Reference< XPropertyControl >& _rxControl ) + { + DBG_TESTSOLARMUTEX(); + + DBG_ASSERT( _rxControl.is(), "OBrowserListBox::valueChanged: invalid event source!" ); + if ( !_rxControl.is() ) + return; + + if ( m_pControlObserver ) + m_pControlObserver->valueChanged( _rxControl ); + + if ( m_pLineListener ) + { + const ListBoxLine& rLine = m_aLines[ impl_getControlPos( _rxControl ) ]; + m_pLineListener->Commit( + rLine.pLine->GetEntryName(), + impl_getControlAsPropertyValue( rLine ) + ); + } + } + + + void OBrowserListBox::activateNextControl( const Reference< XPropertyControl >& _rxCurrentControl ) + { + DBG_TESTSOLARMUTEX(); + + sal_uInt16 nLine = impl_getControlPos( _rxCurrentControl ); + + // cycle forwards, 'til we've the next control which can grab the focus + ++nLine; + while ( static_cast< size_t >( nLine ) < m_aLines.size() ) + { + if ( m_aLines[nLine].pLine->GrabFocus() ) + break; + ++nLine; + } + + // wrap around? + if ( ( static_cast< size_t >( nLine ) >= m_aLines.size() ) && ( !m_aLines.empty() ) ) + m_aLines[0].pLine->GrabFocus(); + } + + + namespace + { + + void lcl_implDisposeControl_nothrow( const Reference< XPropertyControl >& _rxControl ) + { + if ( !_rxControl.is() ) + return; + try + { + _rxControl->setControlContext( nullptr ); + Reference< XComponent > xControlComponent( _rxControl, UNO_QUERY ); + if ( xControlComponent.is() ) + xControlComponent->dispose(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + } + + void OBrowserListBox::Clear() + { + for (auto const& line : m_aLines) + { + // hide the line + line.pLine->Hide(); + // reset the listener + lcl_implDisposeControl_nothrow( line.pLine->getControl() ); + } + + clearContainer( m_aLines ); + } + + bool OBrowserListBox::RemoveEntry( const OUString& _rName ) + { + ListBoxLines::iterator it = std::find_if(m_aLines.begin(), m_aLines.end(), + [&_rName](const ListBoxLine& rLine) { return rLine.aName == _rName; }); + + if ( it == m_aLines.end() ) + return false; + + m_aLines.erase( it ); + + return true; + } + + void OBrowserListBox::ChangeEntry( const OLineDescriptor& rPropertyData, ListBoxLines::size_type nPos ) + { + OSL_PRECOND( rPropertyData.Control.is(), "OBrowserListBox::ChangeEntry: invalid control!" ); + if ( !rPropertyData.Control.is() ) + return; + + if ( nPos == EDITOR_LIST_REPLACE_EXISTING ) + nPos = GetPropertyPos( rPropertyData.sName ); + + if ( nPos >= m_aLines.size() ) + return; + + // the current line and control + ListBoxLine& rLine = m_aLines[nPos]; + + // the old control and some data about it + Reference< XPropertyControl > xControl = rLine.pLine->getControl(); + + // clean up the old control + lcl_implDisposeControl_nothrow( xControl ); + + // set the new control at the line + rLine.pLine->setControl( rPropertyData.Control ); + xControl = rLine.pLine->getControl(); + + if ( xControl.is() ) + xControl->setControlContext( m_pControlContextImpl ); + + // the initial property value + if ( rPropertyData.bUnknownValue ) + xControl->setValue( Any() ); + else + impl_setControlAsPropertyValue( rLine, rPropertyData.aValue ); + + rLine.pLine->SetTitle(rPropertyData.DisplayName); + rLine.xHandler = rPropertyData.xPropertyHandler; + + if ( rPropertyData.HasPrimaryButton ) + { + if ( !rPropertyData.PrimaryButtonImageURL.isEmpty() ) + rLine.pLine->ShowBrowseButton( rPropertyData.PrimaryButtonImageURL, true ); + else if ( rPropertyData.PrimaryButtonImage.is() ) + rLine.pLine->ShowBrowseButton( rPropertyData.PrimaryButtonImage, true ); + else + rLine.pLine->ShowBrowseButton( true ); + + if ( rPropertyData.HasSecondaryButton ) + { + if ( !rPropertyData.SecondaryButtonImageURL.isEmpty() ) + rLine.pLine->ShowBrowseButton( rPropertyData.SecondaryButtonImageURL, false ); + else if ( rPropertyData.SecondaryButtonImage.is() ) + rLine.pLine->ShowBrowseButton( rPropertyData.SecondaryButtonImage, false ); + else + rLine.pLine->ShowBrowseButton( false ); + } + else + rLine.pLine->HideBrowseButton( false ); + + rLine.pLine->SetClickListener( this ); + } + else + { + rLine.pLine->HideBrowseButton( true ); + rLine.pLine->HideBrowseButton( false ); + } + + DBG_ASSERT( ( rPropertyData.IndentLevel == 0 ) || ( rPropertyData.IndentLevel == 1 ), + "OBrowserListBox::ChangeEntry: unsupported indent level!" ); + rLine.pLine->IndentTitle( rPropertyData.IndentLevel > 0 ); + + rLine.pLine->SetComponentHelpIds( + HelpIdUrl::getHelpId( rPropertyData.HelpURL ) + ); + + if ( rPropertyData.bReadOnly ) + { + rLine.pLine->SetReadOnly( true ); + + // user controls (i.e. the ones not provided by the usual + // XPropertyControlFactory) have no chance to know that they should be read-only, + // since XPropertyHandler::describePropertyLine does not transport this + // information. + // So, we manually switch this to read-only. + if ( xControl.is() && ( xControl->getControlType() == PropertyControlType::Unknown ) ) + { + weld::Widget* pWindow = rLine.pLine->getControlWindow(); + weld::Entry* pControlWindowAsEdit = dynamic_cast(pWindow); + if (pControlWindowAsEdit) + pControlWindowAsEdit->set_editable(false); + else + pWindow->set_sensitive(false); + } + } + + sal_uInt16 nTextWidth = m_xLinesPlayground->get_pixel_size(rPropertyData.DisplayName).Width(); + if (m_nTheNameSize< nTextWidth) + { + m_nTheNameSize = nTextWidth; + UpdatePlayGround(); + } + } +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/browserlistbox.hxx b/extensions/source/propctrlr/browserlistbox.hxx new file mode 100644 index 000000000..1a7232612 --- /dev/null +++ b/extensions/source/propctrlr/browserlistbox.hxx @@ -0,0 +1,163 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "browserline.hxx" + +#include +#include +#include +#include + +#include +#include + +#define EDITOR_LIST_REPLACE_EXISTING \ + std::numeric_limits::max() + +namespace pcr +{ + + + class IPropertyLineListener; + class IPropertyControlObserver; + struct OLineDescriptor; + class InspectorHelpWindow; + class PropertyControlContext_Impl; + + + // administrative structures for OBrowserListBox + + typedef std::shared_ptr< OBrowserLine > BrowserLinePointer; + struct ListBoxLine + { + OUString aName; + BrowserLinePointer pLine; + css::uno::Reference< css::inspection::XPropertyHandler > + xHandler; + + ListBoxLine( const OUString& rName, const BrowserLinePointer& _pLine, const css::uno::Reference< css::inspection::XPropertyHandler >& _rxHandler ) + : aName( rName ), + pLine( _pLine ), + xHandler( _rxHandler ) + { + } + }; + typedef std::vector< ListBoxLine > ListBoxLines; + + + class OBrowserListBox final : public IButtonClickListener + { + std::unique_ptr m_xScrolledWindow; + std::unique_ptr m_xLinesPlayground; + std::unique_ptr m_xSizeGroup; + std::unique_ptr m_xHelpWindow; + weld::Container* m_pInitialControlParent; + ListBoxLines m_aLines; + IPropertyLineListener* m_pLineListener; + IPropertyControlObserver* m_pControlObserver; + css::uno::Reference< css::inspection::XPropertyControl > + m_xActiveControl; + sal_uInt16 m_nTheNameSize; + int m_nRowHeight; + ::rtl::Reference< PropertyControlContext_Impl > + m_pControlContextImpl; + + void UpdatePlayGround(); + void ShowEntry(sal_uInt16 nPos); + + public: + explicit OBrowserListBox(weld::Builder& rBuilder, weld::Container* pContainer); + ~OBrowserListBox(); + + void SetListener( IPropertyLineListener* _pListener ); + void SetObserver( IPropertyControlObserver* _pObserver ); + + void EnableHelpSection( bool _bEnable ); + bool HasHelpSection() const; + void SetHelpText( const OUString& _rHelpText ); + + void Clear(); + + void InsertEntry( const OLineDescriptor&, sal_uInt16 nPos ); + bool RemoveEntry( const OUString& _rName ); + void ChangeEntry( const OLineDescriptor&, ListBoxLines::size_type nPos ); + + void SetPropertyValue( const OUString& rEntryName, const css::uno::Any& rValue, bool _bUnknownValue ); + sal_uInt16 GetPropertyPos( std::u16string_view rEntryName ) const; + css::uno::Reference< css::inspection::XPropertyControl > + GetPropertyControl( const OUString& rEntryName ); + void EnablePropertyControls( const OUString& _rEntryName, sal_Int16 _nControls, bool _bEnable ); + void EnablePropertyLine( const OUString& _rEntryName, bool _bEnable ); + + bool IsModified( ) const; + void CommitModified( ); + + /// @throws css::uno::RuntimeException + void focusGained( const css::uno::Reference< css::inspection::XPropertyControl >& Control ); + /// @throws css::uno::RuntimeException + void valueChanged( const css::uno::Reference< css::inspection::XPropertyControl >& Control ); + /// @throws css::uno::RuntimeException + void activateNextControl( const css::uno::Reference< css::inspection::XPropertyControl >& CurrentControl ); + + private: + // IButtonClickListener + void buttonClicked( OBrowserLine* _pLine, bool _bPrimary ) override; + + /** retrieves the index of a given control in our line list + @param _rxControl + The control to lookup. Must denote a control of one of the lines in ->m_aLines + */ + sal_uInt16 impl_getControlPos( const css::uno::Reference< css::inspection::XPropertyControl >& _rxControl ) const; + + /** sets the given property value at the given control, after converting it as necessary + @param _rLine + The line whose at which the value is to be set. + @param _rPropertyValue + the property value to set. If it's not compatible with the control value, + it will be converted, using XPropertyHandler::convertToControlValue + */ + static void impl_setControlAsPropertyValue( const ListBoxLine& _rLine, const css::uno::Any& _rPropertyValue ); + + /** retrieves the value for the given control, as a property value, after converting it as necessary + @param _rLine + The line whose at which the value is to be set. + */ + static css::uno::Any + impl_getControlAsPropertyValue( const ListBoxLine& _rLine ); + + /** retrieves the ->BrowserLinePointer for a given entry name + @param _rEntryName + the name whose line is to be looked up + @param _out_rpLine + contains, upon return, the found browser line, if any + @return + if and only if a non- line for the given entry name could be + found. + */ + bool impl_getBrowserLineForName( const OUString& _rEntryName, BrowserLinePointer& _out_rpLine ) const; + }; + + +} // namespace pcr + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/browserpage.cxx b/extensions/source/propctrlr/browserpage.cxx new file mode 100644 index 000000000..5502418bd --- /dev/null +++ b/extensions/source/propctrlr/browserpage.cxx @@ -0,0 +1,41 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "browserpage.hxx" + +namespace pcr +{ + OBrowserPage::OBrowserPage(weld::Container* pParent, weld::Container* pInitialControlContainer) + : m_pParent(pParent) + , m_xBuilder(Application::CreateBuilder(pParent, "modules/spropctrlr/ui/browserpage.ui")) + , m_xContainer(m_xBuilder->weld_container("BrowserPage")) + , m_xListBox(new OBrowserListBox(*m_xBuilder, pInitialControlContainer)) + { + } + + OBrowserPage::~OBrowserPage() + { + if (m_pParent) + detach(); + assert(!m_pParent); + } +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/browserpage.hxx b/extensions/source/propctrlr/browserpage.hxx new file mode 100644 index 000000000..0db6cc3c7 --- /dev/null +++ b/extensions/source/propctrlr/browserpage.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include "browserlistbox.hxx" + +namespace pcr +{ + class OBrowserPage + { + private: + weld::Container* m_pParent; + std::unique_ptr m_xBuilder; + std::unique_ptr m_xContainer; + std::unique_ptr> m_xListBox; + + public: + // TODO inherit from BuilderPage + explicit OBrowserPage(weld::Container* pParent, weld::Container* pContainer); + ~OBrowserPage(); + + void SetHelpId(const OString& rHelpId) { m_xContainer->set_help_id(rHelpId); } + + OBrowserListBox& getListBox() { return *m_xListBox; } + const OBrowserListBox& getListBox() const { return *m_xListBox; } + + void detach() + { + assert(m_pParent && "already attached"); + m_pParent->move(m_xContainer.get(), nullptr); + m_pParent = nullptr; + } + + void reattach(weld::Container* pNewParent) + { + assert(!m_pParent && "already attached"); + m_pParent = pNewParent; + m_pParent->move(m_xContainer.get(), pNewParent); + } + }; +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/browserview.cxx b/extensions/source/propctrlr/browserview.cxx new file mode 100644 index 000000000..e7b7cb690 --- /dev/null +++ b/extensions/source/propctrlr/browserview.cxx @@ -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 . + */ + +#include "browserview.hxx" +#include "propertyeditor.hxx" +#include +#include + +namespace pcr +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + + OPropertyBrowserView::OPropertyBrowserView(const css::uno::Reference& rContext, weld::Builder& rBuilder) + : m_xPropBox(new OPropertyEditor(rContext, rBuilder)) + , m_nActivePage(0) + { + m_xPropBox->SetHelpId(HID_FM_PROPDLG_TABCTR); + m_xPropBox->setPageActivationHandler(LINK(this, OPropertyBrowserView, OnPageActivation)); + } + + IMPL_LINK(OPropertyBrowserView, OnPageActivation, const OString&, rNewPage, void) + { + m_nActivePage = rNewPage.toUInt32(); + m_aPageActivationHandler.Call(nullptr); + } + + OPropertyBrowserView::~OPropertyBrowserView() + { + sal_uInt16 nTmpPage = m_xPropBox->GetCurPage(); + if (nTmpPage) + m_nActivePage = nTmpPage; + } + + void OPropertyBrowserView::activatePage(sal_uInt16 _nPage) + { + m_nActivePage = _nPage; + getPropertyBox().SetPage(m_nActivePage); + } + + css::awt::Size OPropertyBrowserView::getMinimumSize() const + { + ::Size aSize = m_xPropBox->get_preferred_size(); + return css::awt::Size(aSize.Width(), aSize.Height()); + } +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/browserview.hxx b/extensions/source/propctrlr/browserview.hxx new file mode 100644 index 000000000..7a0711fb1 --- /dev/null +++ b/extensions/source/propctrlr/browserview.hxx @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include + +namespace pcr +{ + class OPropertyEditor; + class OPropertyBrowserView final + { + std::unique_ptr> m_xPropBox; + sal_uInt16 m_nActivePage; + Link m_aPageActivationHandler; + + public: + explicit OPropertyBrowserView(const css::uno::Reference& rContext, weld::Builder& rBuilder); + ~OPropertyBrowserView(); + + OPropertyEditor& getPropertyBox() { return *m_xPropBox; } + + // page handling + sal_uInt16 getActivePage() const { return m_nActivePage; } + void activatePage(sal_uInt16 _nPage); + + void setPageActivationHandler(const Link& _rHdl) { m_aPageActivationHandler = _rHdl; } + + css::awt::Size getMinimumSize() const; + + private: + DECL_LINK(OnPageActivation, const OString&, void); + }; + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/buttonnavigationhandler.cxx b/extensions/source/propctrlr/buttonnavigationhandler.cxx new file mode 100644 index 000000000..618d9db46 --- /dev/null +++ b/extensions/source/propctrlr/buttonnavigationhandler.cxx @@ -0,0 +1,268 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "buttonnavigationhandler.hxx" +#include "formstrings.hxx" +#include "formmetadata.hxx" +#include "pushbuttonnavigation.hxx" + +#include + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::inspection; + + ButtonNavigationHandler::ButtonNavigationHandler( const Reference< XComponentContext >& _rxContext ) + :PropertyHandlerComponent( _rxContext ) + { + + m_xSlaveHandler = css::form::inspection::FormComponentPropertyHandler::create( m_xContext ); + } + + + ButtonNavigationHandler::~ButtonNavigationHandler( ) + { + } + + + OUString ButtonNavigationHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.ButtonNavigationHandler"; + } + + + Sequence< OUString > ButtonNavigationHandler::getSupportedServiceNames( ) + { + return { "com.sun.star.form.inspection.ButtonNavigationHandler" }; + } + + + void SAL_CALL ButtonNavigationHandler::inspect( const Reference< XInterface >& _rxIntrospectee ) + { + PropertyHandlerComponent::inspect( _rxIntrospectee ); + m_xSlaveHandler->inspect( _rxIntrospectee ); + } + + + PropertyState SAL_CALL ButtonNavigationHandler::getPropertyState( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + PropertyState eState = PropertyState_DIRECT_VALUE; + switch ( nPropId ) + { + case PROPERTY_ID_BUTTONTYPE: + { + PushButtonNavigation aHelper( m_xComponent ); + eState = aHelper.getCurrentButtonTypeState(); + } + break; + case PROPERTY_ID_TARGET_URL: + { + PushButtonNavigation aHelper( m_xComponent ); + eState = aHelper.getCurrentTargetURLState(); + } + break; + + default: + OSL_FAIL( "ButtonNavigationHandler::getPropertyState: cannot handle this property!" ); + break; + } + + return eState; + } + + + Any SAL_CALL ButtonNavigationHandler::getPropertyValue( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + Any aReturn; + switch ( nPropId ) + { + case PROPERTY_ID_BUTTONTYPE: + { + PushButtonNavigation aHelper( m_xComponent ); + aReturn = aHelper.getCurrentButtonType(); + } + break; + + case PROPERTY_ID_TARGET_URL: + { + PushButtonNavigation aHelper( m_xComponent ); + aReturn = aHelper.getCurrentTargetURL(); + } + break; + + default: + OSL_FAIL( "ButtonNavigationHandler::getPropertyValue: cannot handle this property!" ); + break; + } + + return aReturn; + } + + + void SAL_CALL ButtonNavigationHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + switch ( nPropId ) + { + case PROPERTY_ID_BUTTONTYPE: + { + PushButtonNavigation aHelper( m_xComponent ); + aHelper.setCurrentButtonType( _rValue ); + } + break; + + case PROPERTY_ID_TARGET_URL: + { + PushButtonNavigation aHelper( m_xComponent ); + aHelper.setCurrentTargetURL( _rValue ); + } + break; + + default: + OSL_FAIL( "ButtonNavigationHandler::setPropertyValue: cannot handle this id!" ); + } + } + + + bool ButtonNavigationHandler::isNavigationCapableButton( const Reference< XPropertySet >& _rxComponent ) + { + Reference< XPropertySetInfo > xPSI; + if ( _rxComponent.is() ) + xPSI = _rxComponent->getPropertySetInfo(); + + return xPSI.is() + && xPSI->hasPropertyByName( PROPERTY_TARGET_URL ) + && xPSI->hasPropertyByName( PROPERTY_BUTTONTYPE ); + } + + + Sequence< Property > ButtonNavigationHandler::doDescribeSupportedProperties() const + { + std::vector< Property > aProperties; + + if ( isNavigationCapableButton( m_xComponent ) ) + { + addStringPropertyDescription( aProperties, PROPERTY_TARGET_URL ); + implAddPropertyDescription( aProperties, PROPERTY_BUTTONTYPE, ::cppu::UnoType::get() ); + } + + if ( aProperties.empty() ) + return Sequence< Property >(); + return comphelper::containerToSequence(aProperties); + } + + + Sequence< OUString > SAL_CALL ButtonNavigationHandler::getActuatingProperties( ) + { + Sequence< OUString > aActuating{ PROPERTY_BUTTONTYPE, PROPERTY_TARGET_URL }; + return aActuating; + } + + + InteractiveSelectionResult SAL_CALL ButtonNavigationHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, Any& _rData, const Reference< XObjectInspectorUI >& _rxInspectorUI ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + InteractiveSelectionResult eReturn( InteractiveSelectionResult_Cancelled ); + + switch ( nPropId ) + { + case PROPERTY_ID_TARGET_URL: + eReturn = m_xSlaveHandler->onInteractivePropertySelection( _rPropertyName, _bPrimary, _rData, _rxInspectorUI ); + break; + default: + eReturn = PropertyHandlerComponent::onInteractivePropertySelection( _rPropertyName, _bPrimary, _rData, _rxInspectorUI ); + break; + } + + return eReturn; + } + + + void SAL_CALL ButtonNavigationHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& /*_rNewValue*/, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool /*_bFirstTimeInit*/ ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) ); + switch ( nPropId ) + { + case PROPERTY_ID_BUTTONTYPE: + { + PushButtonNavigation aHelper( m_xComponent ); + _rxInspectorUI->enablePropertyUI( PROPERTY_TARGET_URL, aHelper.currentButtonTypeIsOpenURL() ); + } + break; + + case PROPERTY_ID_TARGET_URL: + { + PushButtonNavigation aHelper( m_xComponent ); + _rxInspectorUI->enablePropertyUI( PROPERTY_TARGET_FRAME, aHelper.hasNonEmptyCurrentTargetURL() ); + } + break; + + default: + OSL_FAIL( "ButtonNavigationHandler::actuatingPropertyChanged: cannot handle this id!" ); + } + } + + + LineDescriptor SAL_CALL ButtonNavigationHandler::describePropertyLine( const OUString& _rPropertyName, const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + LineDescriptor aReturn; + + switch ( nPropId ) + { + case PROPERTY_ID_TARGET_URL: + aReturn = m_xSlaveHandler->describePropertyLine( _rPropertyName, _rxControlFactory ); + break; + default: + aReturn = PropertyHandlerComponent::describePropertyLine( _rPropertyName, _rxControlFactory ); + break; + } + + return aReturn; + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_ButtonNavigationHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::ButtonNavigationHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/buttonnavigationhandler.hxx b/extensions/source/propctrlr/buttonnavigationhandler.hxx new file mode 100644 index 000000000..c5e01e1df --- /dev/null +++ b/extensions/source/propctrlr/buttonnavigationhandler.hxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "propertyhandler.hxx" + + +namespace pcr +{ + + /** a property handler for any virtual string properties + */ + class ButtonNavigationHandler : public PropertyHandlerComponent + { + private: + css::uno::Reference< css::inspection::XPropertyHandler > + m_xSlaveHandler; + + public: + explicit ButtonNavigationHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + protected: + virtual ~ButtonNavigationHandler() override; + + static bool isNavigationCapableButton( const css::uno::Reference< css::beans::XPropertySet >& _rxComponent ); + + protected: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override; + + // XPropertyHandler overriables + virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override; + virtual css::inspection::InteractiveSelectionResult + SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override; + virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + + // PropertyHandler overridables + virtual css::uno::Sequence< css::beans::Property > + doDescribeSupportedProperties() const override; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/cellbindinghandler.cxx b/extensions/source/propctrlr/cellbindinghandler.cxx new file mode 100644 index 000000000..633a3574b --- /dev/null +++ b/extensions/source/propctrlr/cellbindinghandler.cxx @@ -0,0 +1,487 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "cellbindinghandler.hxx" +#include "formstrings.hxx" +#include "formmetadata.hxx" +#include "cellbindinghelper.hxx" + +#include +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::table; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::inspection; + using namespace ::com::sun::star::form::binding; + using namespace ::comphelper; + + CellBindingPropertyHandler::CellBindingPropertyHandler( const Reference< XComponentContext >& _rxContext ) + :PropertyHandlerComponent( _rxContext ) + ,m_pCellExchangeConverter( new DefaultEnumRepresentation( *m_pInfoService, ::cppu::UnoType::get(), PROPERTY_ID_CELL_EXCHANGE_TYPE ) ) + { + } + + + OUString CellBindingPropertyHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.CellBindingPropertyHandler"; + } + + + Sequence< OUString > CellBindingPropertyHandler::getSupportedServiceNames( ) + { + return { "com.sun.star.form.inspection.CellBindingPropertyHandler" }; + } + + + void CellBindingPropertyHandler::onNewComponent() + { + PropertyHandlerComponent::onNewComponent(); + + Reference< XModel > xDocument( impl_getContextDocument_nothrow() ); + DBG_ASSERT( xDocument.is(), "CellBindingPropertyHandler::onNewComponent: no document!" ); + if ( CellBindingHelper::isSpreadsheetDocument( xDocument ) ) + m_pHelper.reset( new CellBindingHelper( m_xComponent, xDocument ) ); + } + + + CellBindingPropertyHandler::~CellBindingPropertyHandler( ) + { + } + + + Sequence< OUString > SAL_CALL CellBindingPropertyHandler::getActuatingProperties( ) + { + Sequence< OUString > aInterestingProperties{ PROPERTY_LIST_CELL_RANGE, + PROPERTY_BOUND_CELL, + PROPERTY_CONTROLSOURCE }; + return aInterestingProperties; + } + + + void SAL_CALL CellBindingPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) ); + OSL_PRECOND(m_pHelper, + "CellBindingPropertyHandler::actuatingPropertyChanged: inconsistency!"); + // if we survived impl_getPropertyId_throwRuntime, we should have a helper, since no helper implies no properties + + OSL_PRECOND( _rxInspectorUI.is(), "FormComponentPropertyHandler::actuatingPropertyChanged: no access to the UI!" ); + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + std::vector< PropertyId > aDependentProperties; + + switch ( nActuatingPropId ) + { + // ----- BoundCell ----- + case PROPERTY_ID_BOUND_CELL: + { + // the SQL-data-binding related properties need to be enabled if and only if + // there is *no* valid cell binding + Reference< XValueBinding > xBinding; + _rNewValue >>= xBinding; + + if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_CELL_EXCHANGE_TYPE ) ) + _rxInspectorUI->enablePropertyUI( PROPERTY_CELL_EXCHANGE_TYPE, xBinding.is() ); + if ( impl_componentHasProperty_throw( PROPERTY_CONTROLSOURCE ) ) + _rxInspectorUI->enablePropertyUI( PROPERTY_CONTROLSOURCE, !xBinding.is() ); + + if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_FILTERPROPOSAL ) ) + _rxInspectorUI->enablePropertyUI( PROPERTY_FILTERPROPOSAL, !xBinding.is() ); + if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_EMPTY_IS_NULL ) ) + _rxInspectorUI->enablePropertyUI( PROPERTY_EMPTY_IS_NULL, !xBinding.is() ); + + aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN ); + + if ( !xBinding.is() && m_pHelper->getCurrentBinding().is() ) + { + // ensure that the "transfer selection as" property is reset. Since we can't remember + // it at the object itself, but derive it from the binding only, we have to normalize + // it now that there *is* no binding anymore. + setPropertyValue( PROPERTY_CELL_EXCHANGE_TYPE, Any( sal_Int16(0) ) ); + } + } + break; + + // ----- CellRange ----- + case PROPERTY_ID_LIST_CELL_RANGE: + { + // the list source related properties need to be enabled if and only if + // there is *no* valid external list source for the control + Reference< XListEntrySource > xSource; + _rNewValue >>= xSource; + + _rxInspectorUI->enablePropertyUI( PROPERTY_STRINGITEMLIST, !xSource.is() ); + _rxInspectorUI->enablePropertyUI( PROPERTY_LISTSOURCE, !xSource.is() ); + _rxInspectorUI->enablePropertyUI( PROPERTY_LISTSOURCETYPE, !xSource.is() ); + + aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN ); + + // also reset the list entries if the cell range is reset + // #i28319# + if ( !_bFirstTimeInit ) + { + try + { + if ( !xSource.is() ) + { + setPropertyValue( PROPERTY_STRINGITEMLIST, Any( Sequence< OUString >() ) ); + setPropertyValue( PROPERTY_TYPEDITEMLIST, Any( Sequence< Any >() ) ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( + "extensions.propctrlr", + "ListCellRange: caught an exception while resetting the string items!"); + } + } + } + break; // case PROPERTY_ID_LIST_CELL_RANGE + + // ----- DataField ----- + case PROPERTY_ID_CONTROLSOURCE: + { + OUString sControlSource; + _rNewValue >>= sControlSource; + if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_BOUND_CELL ) ) + _rxInspectorUI->enablePropertyUI( PROPERTY_BOUND_CELL, sControlSource.isEmpty() ); + } + break; // case PROPERTY_ID_CONTROLSOURCE + + default: + OSL_FAIL( "CellBindingPropertyHandler::actuatingPropertyChanged: did not register for this property!" ); + } + + for (auto const& dependentProperty : aDependentProperties) + { + impl_updateDependentProperty_nothrow( dependentProperty, _rxInspectorUI ); + } + } + + + void CellBindingPropertyHandler::impl_updateDependentProperty_nothrow( PropertyId _nPropId, const Reference< XObjectInspectorUI >& _rxInspectorUI ) const + { + try + { + switch ( _nPropId ) + { + // ----- BoundColumn ----- + case PROPERTY_ID_BOUNDCOLUMN: + { + CellBindingPropertyHandler* pNonConstThis = const_cast< CellBindingPropertyHandler* >( this ); + Reference< XValueBinding > xBinding( pNonConstThis->getPropertyValue( PROPERTY_BOUND_CELL ), UNO_QUERY ); + Reference< XListEntrySource > xListSource( pNonConstThis->getPropertyValue( PROPERTY_LIST_CELL_RANGE ), UNO_QUERY ); + + if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_BOUNDCOLUMN ) ) + _rxInspectorUI->enablePropertyUI( PROPERTY_BOUNDCOLUMN, !xBinding.is() && !xListSource.is() ); + } + break; // case PROPERTY_ID_BOUNDCOLUMN + + } // switch + + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingPropertyHandler::impl_updateDependentProperty_nothrow" ); + } + } + + + Any SAL_CALL CellBindingPropertyHandler::getPropertyValue( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + OSL_ENSURE(m_pHelper, "CellBindingPropertyHandler::getPropertyValue: inconsistency!"); + // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties + + Any aReturn; + switch ( nPropId ) + { + case PROPERTY_ID_BOUND_CELL: + { + Reference< XValueBinding > xBinding( m_pHelper->getCurrentBinding() ); + if ( !CellBindingHelper::isCellBinding( xBinding ) ) + xBinding.clear(); + + aReturn <<= xBinding; + } + break; + + case PROPERTY_ID_LIST_CELL_RANGE: + { + Reference< XListEntrySource > xSource( m_pHelper->getCurrentListSource() ); + if ( !CellBindingHelper::isCellRangeListSource( xSource ) ) + xSource.clear(); + + aReturn <<= xSource; + } + break; + + case PROPERTY_ID_CELL_EXCHANGE_TYPE: + { + Reference< XValueBinding > xBinding( m_pHelper->getCurrentBinding() ); + aReturn <<= static_cast( CellBindingHelper::isCellIntegerBinding( xBinding ) ? 1 : 0 ); + } + break; + + default: + OSL_FAIL( "CellBindingPropertyHandler::getPropertyValue: cannot handle this!" ); + break; + } + return aReturn; + } + + + void SAL_CALL CellBindingPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + OSL_ENSURE(m_pHelper, "CellBindingPropertyHandler::setPropertyValue: inconsistency!"); + // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties + + try + { + Any aOldValue = getPropertyValue( _rPropertyName ); + + switch ( nPropId ) + { + case PROPERTY_ID_BOUND_CELL: + { + Reference< XValueBinding > xBinding; + _rValue >>= xBinding; + m_pHelper->setBinding( xBinding ); + } + break; + + case PROPERTY_ID_LIST_CELL_RANGE: + { + Reference< XListEntrySource > xSource; + _rValue >>= xSource; + m_pHelper->setListSource( xSource ); + } + break; + + case PROPERTY_ID_CELL_EXCHANGE_TYPE: + { + sal_Int16 nExchangeType = 0; + OSL_VERIFY( _rValue >>= nExchangeType ); + + Reference< XValueBinding > xBinding = m_pHelper->getCurrentBinding( ); + if ( xBinding.is() ) + { + bool bNeedIntegerBinding = ( nExchangeType == 1 ); + if ( bNeedIntegerBinding != CellBindingHelper::isCellIntegerBinding( xBinding ) ) + { + CellAddress aAddress; + if ( m_pHelper->getAddressFromCellBinding( xBinding, aAddress ) ) + { + xBinding = m_pHelper->createCellBindingFromAddress( aAddress, bNeedIntegerBinding ); + m_pHelper->setBinding( xBinding ); + } + } + } + } + break; + + default: + OSL_FAIL( "CellBindingPropertyHandler::setPropertyValue: cannot handle this!" ); + break; + } + + impl_setContextDocumentModified_nothrow(); + + Any aNewValue( getPropertyValue( _rPropertyName ) ); + firePropertyChange( _rPropertyName, nPropId, aOldValue, aNewValue ); + // TODO/UNOize: can't we make this a part of the base class, for all those "virtual" + // properties? Base class'es |setPropertyValue| could call some |doSetPropertyValue|, + // and handle the listener notification itself + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingPropertyHandler::setPropertyValue" ); + } + } + + + Any SAL_CALL CellBindingPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Any aPropertyValue; + + OSL_ENSURE( + m_pHelper, + "CellBindingPropertyHandler::convertToPropertyValue: we have no SupportedProperties!"); + if (!m_pHelper) + return aPropertyValue; + + PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) ); + + OUString sControlValue; + OSL_VERIFY( _rControlValue >>= sControlValue ); + switch( nPropId ) + { + case PROPERTY_ID_LIST_CELL_RANGE: + aPropertyValue <<= m_pHelper->createCellListSourceFromStringAddress( sControlValue ); + break; + + case PROPERTY_ID_BOUND_CELL: + { + // if we have the possibility of an integer binding, then we must preserve + // this property's value (e.g. if the current binding is an integer binding, then + // the newly created one must be, too) + bool bIntegerBinding = false; + if ( m_pHelper->isCellIntegerBindingAllowed() ) + { + sal_Int16 nCurrentBindingType = 0; + getPropertyValue( PROPERTY_CELL_EXCHANGE_TYPE ) >>= nCurrentBindingType; + bIntegerBinding = ( nCurrentBindingType != 0 ); + } + aPropertyValue <<= m_pHelper->createCellBindingFromStringAddress( sControlValue, bIntegerBinding ); + } + break; + + case PROPERTY_ID_CELL_EXCHANGE_TYPE: + m_pCellExchangeConverter->getValueFromDescription( sControlValue, aPropertyValue ); + break; + + default: + OSL_FAIL( "CellBindingPropertyHandler::convertToPropertyValue: cannot handle this!" ); + break; + } + + return aPropertyValue; + } + + + Any SAL_CALL CellBindingPropertyHandler::convertToControlValue( const OUString& _rPropertyName, + const Any& _rPropertyValue, const Type& /*_rControlValueType*/ ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Any aControlValue; + + OSL_ENSURE( + m_pHelper, + "CellBindingPropertyHandler::convertToControlValue: we have no SupportedProperties!"); + if (!m_pHelper) + return aControlValue; + + PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) ); + + switch ( nPropId ) + { + case PROPERTY_ID_BOUND_CELL: + { + Reference< XValueBinding > xBinding; + bool bSuccess = _rPropertyValue >>= xBinding; + OSL_ENSURE( bSuccess, "CellBindingPropertyHandler::convertToControlValue: invalid value (1)!" ); + + // the only value binding we support so far is linking to spreadsheet cells + aControlValue <<= m_pHelper->getStringAddressFromCellBinding( xBinding ); + } + break; + + case PROPERTY_ID_LIST_CELL_RANGE: + { + Reference< XListEntrySource > xSource; + bool bSuccess = _rPropertyValue >>= xSource; + OSL_ENSURE( bSuccess, "CellBindingPropertyHandler::convertToControlValue: invalid value (2)!" ); + + // the only value binding we support so far is linking to spreadsheet cells + aControlValue <<= m_pHelper->getStringAddressFromCellListSource( xSource ); + } + break; + + case PROPERTY_ID_CELL_EXCHANGE_TYPE: + aControlValue <<= m_pCellExchangeConverter->getDescriptionForValue( _rPropertyValue ); + break; + + default: + OSL_FAIL( "CellBindingPropertyHandler::convertToControlValue: cannot handle this!" ); + break; + } + + return aControlValue; + } + + + Sequence< Property > CellBindingPropertyHandler::doDescribeSupportedProperties() const + { + std::vector< Property > aProperties; + + bool bAllowCellLinking = m_pHelper && m_pHelper->isCellBindingAllowed(); + bool bAllowCellIntLinking = m_pHelper && m_pHelper->isCellIntegerBindingAllowed(); + bool bAllowListCellRange = m_pHelper && m_pHelper->isListCellRangeAllowed(); + if ( bAllowCellLinking || bAllowListCellRange || bAllowCellIntLinking ) + { + sal_Int32 nPos = ( bAllowCellLinking ? 1 : 0 ) + + ( bAllowListCellRange ? 1 : 0 ) + + ( bAllowCellIntLinking ? 1 : 0 ); + aProperties.resize( nPos ); + + if ( bAllowCellLinking ) + { + aProperties[ --nPos ] = Property( PROPERTY_BOUND_CELL, PROPERTY_ID_BOUND_CELL, + ::cppu::UnoType::get(), 0 ); + } + if ( bAllowCellIntLinking ) + { + aProperties[ --nPos ] = Property( PROPERTY_CELL_EXCHANGE_TYPE, PROPERTY_ID_CELL_EXCHANGE_TYPE, + ::cppu::UnoType::get(), 0 ); + } + if ( bAllowListCellRange ) + { + aProperties[ --nPos ] = Property( PROPERTY_LIST_CELL_RANGE, PROPERTY_ID_LIST_CELL_RANGE, + ::cppu::UnoType::get(), 0 ); + } + } + + if ( aProperties.empty() ) + return Sequence< Property >(); + return comphelper::containerToSequence(aProperties); + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_CellBindingPropertyHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::CellBindingPropertyHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/cellbindinghandler.hxx b/extensions/source/propctrlr/cellbindinghandler.hxx new file mode 100644 index 000000000..4e81b0624 --- /dev/null +++ b/extensions/source/propctrlr/cellbindinghandler.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 . + */ + +#pragma once + +#include "propertyhandler.hxx" + +#include + +#include + + +namespace pcr +{ + + + class CellBindingHelper; + class IPropertyEnumRepresentation; + + class CellBindingPropertyHandler : public PropertyHandlerComponent + { + private: + std::unique_ptr< CellBindingHelper > m_pHelper; + ::rtl::Reference< IPropertyEnumRepresentation > m_pCellExchangeConverter; + + public: + explicit CellBindingPropertyHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + protected: + virtual ~CellBindingPropertyHandler() override; + + protected: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override; + + // XPropertyHandler overriables + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override; + virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override; + + // PropertyHandler overridables + virtual css::uno::Sequence< css::beans::Property > + doDescribeSupportedProperties() const override; + virtual void onNewComponent() override; + + private: + /** updates a property (UI) whose state depends on more than one other property + + ->actuatingPropertyChanged is called for certain properties in whose changes + we expressed interes (->getActuatingProperty). Now such a property change can + result in simple UI updates, for instance another property being enabled or disabled. + + However, it can also result in a more complex change: The current (UI) state might + depend on the value of more than one other property. Those dependent properties (their + UI, more precisely) are updated in this method. + + @param _nPropid + the ->PropertyId of the dependent property whose UI state is to be updated + + @param _rxInspectorUI + provides access to the property browser UI. Must not be . + */ + void impl_updateDependentProperty_nothrow( PropertyId _nPropId, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) const; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/cellbindinghelper.cxx b/extensions/source/propctrlr/cellbindinghelper.cxx new file mode 100644 index 000000000..3c66fc8c9 --- /dev/null +++ b/extensions/source/propctrlr/cellbindinghelper.cxx @@ -0,0 +1,540 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "cellbindinghelper.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "formstrings.hxx" + +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::sheet; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::drawing; + using namespace ::com::sun::star::table; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::i18n; + using namespace ::com::sun::star::form::binding; + + namespace + { + + struct StringCompare + { + private: + OUString m_sReference; + + public: + explicit StringCompare( const OUString& _rReference ) : m_sReference( _rReference ) { } + + bool operator()( std::u16string_view _rCompare ) + { + return ( _rCompare == m_sReference ); + } + }; + } + + + CellBindingHelper::CellBindingHelper( const Reference< XPropertySet >& _rxControlModel, const Reference< XModel >& _rxContextDocument ) + :m_xControlModel( _rxControlModel ) + { + OSL_ENSURE( m_xControlModel.is(), "CellBindingHelper::CellBindingHelper: invalid control model!" ); + + m_xDocument.set(_rxContextDocument, css::uno::UNO_QUERY); + OSL_ENSURE( m_xDocument.is(), "CellBindingHelper::CellBindingHelper: This is no spreadsheet document!" ); + + OSL_ENSURE( isSpreadsheetDocumentWhichSupplies( SERVICE_ADDRESS_CONVERSION ), + "CellBindingHelper::CellBindingHelper: the document cannot convert address representations!" ); + } + + + bool CellBindingHelper::isSpreadsheetDocument( const Reference< XModel >& _rxContextDocument ) + { + return Reference< XSpreadsheetDocument >::query( _rxContextDocument ).is(); + } + + + sal_Int16 CellBindingHelper::getControlSheetIndex( Reference< XSpreadsheet >& _out_rxSheet ) const + { + sal_Int16 nSheetIndex = -1; + // every sheet has a draw page, and every draw page has a forms collection. + // Our control, OTOH, belongs to a forms collection. Match these... + try + { + // for determining the draw page, we need the forms collection which + // the object belongs to. This is the first object up the hierarchy which is + // *no* XForm (and, well, no XGridColumnFactory) + Reference< XChild > xCheck( m_xControlModel, UNO_QUERY ); + Reference< XForm > xParentAsForm; if ( xCheck.is() ) xParentAsForm.set(xCheck->getParent(), css::uno::UNO_QUERY); + Reference< XGridColumnFactory > xParentAsGrid; if ( xCheck.is() ) xParentAsGrid.set(xCheck->getParent(), css::uno::UNO_QUERY); + + while ( ( xParentAsForm.is() || xParentAsGrid.is() ) && xCheck.is() ) + { + xCheck.set(xCheck->getParent(), css::uno::UNO_QUERY); + xParentAsForm.set(xCheck.is() ? xCheck->getParent() : Reference< XForm >(), css::uno::UNO_QUERY); + xParentAsGrid.set(xCheck.is() ? xCheck->getParent() : Reference< XGridColumnFactory >(), css::uno::UNO_QUERY); + } + Reference< XInterface > xFormsCollection( xCheck.is() ? xCheck->getParent() : Reference< XInterface >() ); + + // now iterate through the sheets + Reference< XIndexAccess > xSheets( m_xDocument->getSheets(), UNO_QUERY ); + if ( xSheets.is() && xFormsCollection.is() ) + { + for ( sal_Int32 i = 0; i < xSheets->getCount(); ++i ) + { + Reference< XDrawPageSupplier > xSuppPage( xSheets->getByIndex( i ), UNO_QUERY_THROW ); + Reference< XFormsSupplier > xSuppForms( xSuppPage->getDrawPage(), UNO_QUERY_THROW ); + + if ( xSuppForms->getForms() == xFormsCollection ) + { // found it + nSheetIndex = static_cast(i); + _out_rxSheet.set( xSuppPage, UNO_QUERY_THROW ); + break; + } + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + return nSheetIndex; + } + + + bool CellBindingHelper::convertStringAddress( const OUString& _rAddressDescription, CellAddress& /* [out] */ _rAddress ) const + { + Any aAddress; + return doConvertAddressRepresentations( + PROPERTY_UI_REPRESENTATION, + Any( _rAddressDescription ), + PROPERTY_ADDRESS, + aAddress, + false + ) + && ( aAddress >>= _rAddress ); + } + + + bool CellBindingHelper::doConvertAddressRepresentations( const OUString& _rInputProperty, const Any& _rInputValue, + const OUString& _rOutputProperty, Any& _rOutputValue, bool _bIsRange ) const + { + bool bSuccess = false; + + Reference< XPropertySet > xConverter( + createDocumentDependentInstance( + _bIsRange ? OUString(SERVICE_RANGEADDRESS_CONVERSION) : OUString(SERVICE_ADDRESS_CONVERSION), + OUString(), + Any() + ), + UNO_QUERY + ); + OSL_ENSURE( xConverter.is(), "CellBindingHelper::doConvertAddressRepresentations: could not get a converter service!" ); + if ( xConverter.is() ) + { + try + { + Reference< XSpreadsheet > xSheet; + xConverter->setPropertyValue( PROPERTY_REFERENCE_SHEET, Any( static_cast(getControlSheetIndex( xSheet )) ) ); + xConverter->setPropertyValue( _rInputProperty, _rInputValue ); + _rOutputValue = xConverter->getPropertyValue( _rOutputProperty ); + bSuccess = true; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::doConvertAddressRepresentations" ); + } + } + + return bSuccess; + } + + + bool CellBindingHelper::convertStringAddress( const OUString& _rAddressDescription, + CellRangeAddress& /* [out] */ _rAddress ) const + { + Any aAddress; + return doConvertAddressRepresentations( + PROPERTY_UI_REPRESENTATION, + Any( _rAddressDescription ), + PROPERTY_ADDRESS, + aAddress, + true + ) + && ( aAddress >>= _rAddress ); + } + + + Reference< XValueBinding > CellBindingHelper::createCellBindingFromAddress( const CellAddress& _rAddress, bool _bSupportIntegerExchange ) const + { + Reference< XValueBinding > xBinding( createDocumentDependentInstance( + _bSupportIntegerExchange ? OUString(SERVICE_SHEET_CELL_INT_BINDING) : OUString(SERVICE_SHEET_CELL_BINDING), + PROPERTY_BOUND_CELL, + Any( _rAddress ) + ), UNO_QUERY ); + + return xBinding; + } + + + Reference< XValueBinding > CellBindingHelper::createCellBindingFromStringAddress( const OUString& _rAddress, bool _bSupportIntegerExchange ) const + { + Reference< XValueBinding > xBinding; + if ( !m_xDocument.is() ) + // very bad ... + return xBinding; + + // get the UNO representation of the address + CellAddress aAddress; + if ( _rAddress.isEmpty() || !convertStringAddress( _rAddress, aAddress ) ) + return xBinding; + + return createCellBindingFromAddress( aAddress, _bSupportIntegerExchange ); + } + + + Reference< XListEntrySource > CellBindingHelper::createCellListSourceFromStringAddress( const OUString& _rAddress ) const + { + Reference< XListEntrySource > xSource; + + CellRangeAddress aRangeAddress; + if ( _rAddress.isEmpty() || !convertStringAddress( _rAddress, aRangeAddress ) ) + return xSource; + + // create a range object for this address + xSource.set(createDocumentDependentInstance( + SERVICE_SHEET_CELLRANGE_LISTSOURCE, + PROPERTY_LIST_CELL_RANGE, + Any( aRangeAddress ) + ), css::uno::UNO_QUERY); + + return xSource; + } + + + Reference< XInterface > CellBindingHelper::createDocumentDependentInstance( const OUString& _rService, const OUString& _rArgumentName, + const Any& _rArgumentValue ) const + { + Reference< XInterface > xReturn; + + Reference< XMultiServiceFactory > xDocumentFactory( m_xDocument, UNO_QUERY ); + OSL_ENSURE( xDocumentFactory.is(), "CellBindingHelper::createDocumentDependentInstance: no document service factory!" ); + if ( xDocumentFactory.is() ) + { + try + { + if ( !_rArgumentName.isEmpty() ) + { + Sequence aArgs{ Any(NamedValue(_rArgumentName, _rArgumentValue)) }; + xReturn = xDocumentFactory->createInstanceWithArguments( _rService, aArgs ); + } + else + { + xReturn = xDocumentFactory->createInstance( _rService ); + } + } + catch ( const Exception& ) + { + OSL_FAIL( "CellBindingHelper::createDocumentDependentInstance: could not create the binding at the document!" ); + } + } + return xReturn; + } + + + bool CellBindingHelper::getAddressFromCellBinding( + const Reference< XValueBinding >& _rxBinding, CellAddress& _rAddress ) const + { + OSL_PRECOND( !_rxBinding.is() || isCellBinding( _rxBinding ), "CellBindingHelper::getAddressFromCellBinding: this is no cell binding!" ); + + bool bReturn = false; + if ( !m_xDocument.is() ) + // very bad ... + return bReturn; + + try + { + Reference< XPropertySet > xBindingProps( _rxBinding, UNO_QUERY ); + OSL_ENSURE( xBindingProps.is() || !_rxBinding.is(), "CellBindingHelper::getAddressFromCellBinding: no property set for the binding!" ); + if ( xBindingProps.is() ) + { + bReturn = ( xBindingProps->getPropertyValue( PROPERTY_BOUND_CELL ) >>= _rAddress ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::getAddressFromCellBinding" ); + } + + return bReturn; + } + + + OUString CellBindingHelper::getStringAddressFromCellBinding( const Reference< XValueBinding >& _rxBinding ) const + { + CellAddress aAddress; + OUString sAddress; + if ( getAddressFromCellBinding( _rxBinding, aAddress ) ) + { + Any aStringAddress; + doConvertAddressRepresentations( PROPERTY_ADDRESS, Any( aAddress ), + PROPERTY_UI_REPRESENTATION, aStringAddress, false ); + + aStringAddress >>= sAddress; + } + + return sAddress; + } + + + OUString CellBindingHelper::getStringAddressFromCellListSource( const Reference< XListEntrySource >& _rxSource ) const + { + OSL_PRECOND( !_rxSource.is() || isCellRangeListSource( _rxSource ), "CellBindingHelper::getStringAddressFromCellListSource: this is no cell list source!" ); + + OUString sAddress; + if ( !m_xDocument.is() ) + // very bad ... + return sAddress; + + try + { + Reference< XPropertySet > xSourceProps( _rxSource, UNO_QUERY ); + OSL_ENSURE( xSourceProps.is() || !_rxSource.is(), "CellBindingHelper::getStringAddressFromCellListSource: no property set for the list source!" ); + if ( xSourceProps.is() ) + { + CellRangeAddress aRangeAddress; + xSourceProps->getPropertyValue( PROPERTY_LIST_CELL_RANGE ) >>= aRangeAddress; + + Any aStringAddress; + doConvertAddressRepresentations( PROPERTY_ADDRESS, Any( aRangeAddress ), + PROPERTY_UI_REPRESENTATION, aStringAddress, true ); + aStringAddress >>= sAddress; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::getStringAddressFromCellListSource" ); + } + + return sAddress; + } + + + bool CellBindingHelper::isSpreadsheetDocumentWhichSupplies( const OUString& _rService ) const + { + bool bYesItIs = false; + + Reference< XServiceInfo > xSI( m_xDocument, UNO_QUERY ); + if ( xSI.is() && xSI->supportsService( SERVICE_SPREADSHEET_DOCUMENT ) ) + { + Reference< XMultiServiceFactory > xDocumentFactory( m_xDocument, UNO_QUERY ); + OSL_ENSURE( xDocumentFactory.is(), "CellBindingHelper::isSpreadsheetDocumentWhichSupplies: spreadsheet document, but no factory?" ); + + if ( xDocumentFactory.is() ) + { + const Sequence aAvailableServices = xDocumentFactory->getAvailableServiceNames( ); + + bYesItIs = std::any_of( + aAvailableServices.begin(), + aAvailableServices.end(), + StringCompare( _rService ) + ); + } + } + + return bYesItIs; + } + + + bool CellBindingHelper::isListCellRangeAllowed( ) const + { + bool bAllow( false ); + + Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); + if ( xSink.is() ) + { + bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_SHEET_CELLRANGE_LISTSOURCE ); + } + + return bAllow; + } + + + bool CellBindingHelper::isCellIntegerBindingAllowed( ) const + { + bool bAllow( true ); + + // first, we only offer this for controls which allow bindings in general + Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); + if ( !xBindable.is() ) + bAllow = false; + + // then, we must live in a spreadsheet document which can provide the special + // service needed for exchanging integer values + if ( bAllow ) + bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_SHEET_CELL_INT_BINDING ); + + // then, we only offer this for list boxes + if ( bAllow ) + { + try + { + sal_Int16 nClassId = FormComponentType::CONTROL; + m_xControlModel->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId; + if ( FormComponentType::LISTBOX != nClassId ) + bAllow = false; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::isCellIntegerBindingAllowed" ); + // are there really control models which survive isCellBindingAllowed, but don't have a ClassId + // property? + bAllow = false; + } + } + + return bAllow; + } + + + bool CellBindingHelper::isCellBindingAllowed( ) const + { + bool bAllow( false ); + + Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); + if ( xBindable.is() ) + { + // the control can potentially be bound to an external value + // Does it live within a Calc document, and is able to supply CellBindings? + bAllow = isSpreadsheetDocumentWhichSupplies( SERVICE_SHEET_CELL_BINDING ); + } + + // disallow for some types + // TODO: shouldn't the XBindableValue supply a list of supported types, and we can distinguish + // using this list? The current behavior below is somewhat hackish... + if ( bAllow ) + { + try + { + sal_Int16 nClassId = FormComponentType::CONTROL; + m_xControlModel->getPropertyValue( PROPERTY_CLASSID ) >>= nClassId; + if ( ( FormComponentType::DATEFIELD == nClassId ) || ( FormComponentType::TIMEFIELD == nClassId ) ) + bAllow = false; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "CellBindingHelper::isCellBindingAllowed" ); + bAllow = false; + } + } + return bAllow; + } + + + bool CellBindingHelper::isCellBinding( const Reference< XValueBinding >& _rxBinding ) + { + return doesComponentSupport( _rxBinding, SERVICE_SHEET_CELL_BINDING ); + } + + + bool CellBindingHelper::isCellIntegerBinding( const Reference< XValueBinding >& _rxBinding ) + { + return doesComponentSupport( _rxBinding, SERVICE_SHEET_CELL_INT_BINDING ); + } + + + bool CellBindingHelper::isCellRangeListSource( const Reference< XListEntrySource >& _rxSource ) + { + return doesComponentSupport( _rxSource, SERVICE_SHEET_CELLRANGE_LISTSOURCE ); + } + + + bool CellBindingHelper::doesComponentSupport( const Reference< XInterface >& _rxComponent, const OUString& _rService ) + { + Reference< XServiceInfo > xSI( _rxComponent, UNO_QUERY ); + bool bDoes = xSI.is() && xSI->supportsService( _rService ); + return bDoes; + } + + + Reference< XValueBinding > CellBindingHelper::getCurrentBinding( ) const + { + Reference< XValueBinding > xBinding; + Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); + if ( xBindable.is() ) + xBinding = xBindable->getValueBinding(); + return xBinding; + } + + + Reference< XListEntrySource > CellBindingHelper::getCurrentListSource( ) const + { + Reference< XListEntrySource > xSource; + Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); + if ( xSink.is() ) + xSource = xSink->getListEntrySource(); + return xSource; + } + + + void CellBindingHelper::setBinding( const Reference< XValueBinding >& _rxBinding ) + { + Reference< XBindableValue > xBindable( m_xControlModel, UNO_QUERY ); + OSL_PRECOND( xBindable.is(), "CellBindingHelper::setBinding: the object is not bindable!" ); + if ( xBindable.is() ) + xBindable->setValueBinding( _rxBinding ); + } + + + void CellBindingHelper::setListSource( const Reference< XListEntrySource >& _rxSource ) + { + Reference< XListEntrySink > xSink( m_xControlModel, UNO_QUERY ); + OSL_PRECOND( xSink.is(), "CellBindingHelper::setListSource: the object is no list entry sink!" ); + if ( xSink.is() ) + xSink->setListEntrySource( _rxSource ); + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/cellbindinghelper.hxx b/extensions/source/propctrlr/cellbindinghelper.hxx new file mode 100644 index 000000000..a2c85cd65 --- /dev/null +++ b/extensions/source/propctrlr/cellbindinghelper.hxx @@ -0,0 +1,272 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace pcr +{ + + /** encapsulates functionality related to binding a form control to a spreadsheet cell + */ + class CellBindingHelper final + { + css::uno::Reference< css::beans::XPropertySet > + m_xControlModel; // the model we work for + css::uno::Reference< css::sheet::XSpreadsheetDocument > + m_xDocument; // the document where the model lives + + public: + /** ctor + @param _rxControlModel + the control model which is or will be bound + */ + CellBindingHelper( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const css::uno::Reference< css::frame::XModel >& _rxContextDocument + ); + + /** determines whether the given model is a spreadsheet document model + +

If this method returns , you cannot instantiate a CellBindingHelper with + the document, since then no of its functionality will be available.

+ */ + static bool isSpreadsheetDocument( + const css::uno::Reference< css::frame::XModel >& _rxContextDocument + ); + + /** gets a cell binding for the given address + @precond + isCellBindingAllowed returns + */ + css::uno::Reference< css::form::binding::XValueBinding > + createCellBindingFromStringAddress( + const OUString& _rAddress, + bool _bSupportIntegerExchange + ) const; + + /** creates a cell binding (supporting integer exchange, if requested) for + the given address object + */ + css::uno::Reference< css::form::binding::XValueBinding > + createCellBindingFromAddress( + const css::table::CellAddress& _rAddress, + bool _bSupportIntegerExchange + ) const; + + /** gets a cell range list source binding for the given address + */ + css::uno::Reference< css::form::binding::XListEntrySource > + createCellListSourceFromStringAddress( const OUString& _rAddress ) const; + + /** creates a string representation for the given value binding's address + +

If the sheet of the bound cell is the same as the sheet which our control belongs + to, then the sheet name is omitted in the resulting string representation.

+ + @precond + The binding is a valid cell binding, or + @see isCellBinding + */ + OUString getStringAddressFromCellBinding( + const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding + ) const; + + /** creates an address object for the given value binding's address + + @precond + The binding is a valid cell binding, or + @return + if and only if an error occurred and no valid address could be obtained + @see isCellBinding + */ + bool getAddressFromCellBinding( + const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding, + css::table::CellAddress& _rAddress + ) const; + + /** creates a string representation for the given list source's range address + +

If the sheet of the cell range which acts as list source is the same as the + sheet which our control belongs to, then the sheet name is omitted in the + resulting string representation.

+ + @precond + The object is a valid cell range list source, or + @see isCellRangeListSource + */ + OUString getStringAddressFromCellListSource( + const css::uno::Reference< css::form::binding::XListEntrySource >& _rxSource + ) const; + + /** returns the current binding of our control model, if any. + */ + css::uno::Reference< css::form::binding::XValueBinding > + getCurrentBinding( ) const; + + /** returns the current external list source of the control model, if any + */ + css::uno::Reference< css::form::binding::XListEntrySource > + getCurrentListSource( ) const; + + /** sets a new binding for our control model + @precond + the control model is bindable (which is implied by isCellBindingAllowed + returning ) + */ + void setBinding( + const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding + ); + + /** sets a list source for our control model + @precond + the control model is a list sink (which is implied by isListCellRangeAllowed + returning ) + */ + void setListSource( + const css::uno::Reference< css::form::binding::XListEntrySource >& _rxSource + ); + + /** checks whether it's possible to bind the control model to a spreadsheet cell + */ + bool isCellBindingAllowed( ) const; + + /** checks whether it's possible to bind the control model to a spreadsheet cell, + with exchanging integer values + */ + bool isCellIntegerBindingAllowed( ) const; + + /** checks whether it's possible to bind the control model to range of spreadsheet cells + supplying the list entries + */ + bool isListCellRangeAllowed( ) const; + + /** checks whether a given binding is a spreadsheet cell binding + */ + static bool isCellBinding( + const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding + ); + + /** checks whether a given binding is a spreadsheet cell binding, exchanging + integer values + */ + static bool isCellIntegerBinding( + const css::uno::Reference< css::form::binding::XValueBinding >& _rxBinding + ); + + /** checks whether a given list source is a spreadsheet cell list source + */ + static bool isCellRangeListSource( + const css::uno::Reference< css::form::binding::XListEntrySource >& _rxSource + ); + + /** retrieves the index of the sheet which our control belongs to + @return the index of the sheet which our control belongs to or -1, if an error occurred + */ + sal_Int16 getControlSheetIndex( + css::uno::Reference< css::sheet::XSpreadsheet >& _out_rxSheet + ) const; + + private: + /** creates an address object from a string representation of a cell address + */ + bool convertStringAddress( + const OUString& _rAddressDescription, + css::table::CellAddress& /* [out] */ _rAddress + ) const; + + /** creates an address range object from a string representation of a cell range address + */ + bool convertStringAddress( + const OUString& _rAddressDescription, + css::table::CellRangeAddress& /* [out] */ _rAddress + ) const; + + /** determines if our document is a spreadsheet document, *and* can supply + the given service + */ + bool isSpreadsheetDocumentWhichSupplies( const OUString& _rService ) const; + + /** checks whether a given component supports a given service + */ + static bool doesComponentSupport( + const css::uno::Reference< css::uno::XInterface >& _rxComponent, + const OUString& _rService + ); + + /** uses the document (it's factory interface, respectively) to create a component instance + @param _rService + the service name + @param _rArgumentName + the name of the single argument to pass during creation. May be empty, in this case + no arguments are passed + @param _rArgumentValue + the value of the instantiation argument. Not evaluated if _rArgumentName + is empty. + */ + css::uno::Reference< css::uno::XInterface > + createDocumentDependentInstance( + const OUString& _rService, + const OUString& _rArgumentName, + const css::uno::Any& _rArgumentValue + ) const; + + /** converts an address representation into another one + + @param _rInputProperty + the input property name for the conversion service + @param _rInputValue + the input property value for the conversion service + @param _rOutputProperty + the output property name for the conversion service + @param _rOutputValue + the output property value for the conversion service + @param _bIsRange + if , the RangeAddressConversion service will be used, else + the AddressConversion service + + @return + if any only if the conversion was successful + + @see css::table::CellAddressConversion + @see css::table::CellRangeAddressConversion + */ + bool doConvertAddressRepresentations( + const OUString& _rInputProperty, + const css::uno::Any& _rInputValue, + const OUString& _rOutputProperty, + css::uno::Any& _rOutputValue, + bool _bIsRange + ) const; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/commoncontrol.cxx b/extensions/source/propctrlr/commoncontrol.cxx new file mode 100644 index 000000000..243bbd813 --- /dev/null +++ b/extensions/source/propctrlr/commoncontrol.cxx @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "commoncontrol.hxx" +#include + + +namespace pcr +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::inspection::XPropertyControlContext; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::inspection::XPropertyControl; + + CommonBehaviourControlHelper::CommonBehaviourControlHelper( sal_Int16 _nControlType, XPropertyControl& _rAntiImpl ) + :m_nControlType( _nControlType ) + ,m_rAntiImpl( _rAntiImpl ) + ,m_bModified( false ) + { + } + + + CommonBehaviourControlHelper::~CommonBehaviourControlHelper() + { + } + + void CommonBehaviourControlHelper::setControlContext( const Reference< XPropertyControlContext >& _controlcontext ) + { + m_xContext = _controlcontext; + } + + void CommonBehaviourControlHelper::notifyModifiedValue( ) + { + if ( isModified() && m_xContext.is() ) + { + try + { + m_xContext->valueChanged( &m_rAntiImpl ); + m_bModified = false; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + } + + void CommonBehaviourControlHelper::editChanged() + { + setModified(); + } + + IMPL_LINK_NOARG( CommonBehaviourControlHelper, EditModifiedHdl, weld::Entry&, void ) + { + editChanged(); + } + + IMPL_LINK_NOARG( CommonBehaviourControlHelper, ModifiedHdl, weld::ComboBox&, void ) + { + setModified(); + // notify as soon as the Data source is changed, don't wait until we lose focus + // because the Content dropdown cannot be populated after it is popped up + // and going from Data source direct to Content may give focus-lost to + // Content after the popup attempt is made + notifyModifiedValue(); + } + + IMPL_LINK_NOARG( CommonBehaviourControlHelper, MetricModifiedHdl, weld::MetricSpinButton&, void ) + { + setModified(); + } + + IMPL_LINK_NOARG( CommonBehaviourControlHelper, FormattedModifiedHdl, weld::FormattedSpinButton&, void ) + { + setModified(); + } + + IMPL_LINK_NOARG( CommonBehaviourControlHelper, TimeModifiedHdl, weld::FormattedSpinButton&, void ) + { + setModified(); + } + + IMPL_LINK_NOARG( CommonBehaviourControlHelper, DateModifiedHdl, SvtCalendarBox&, void ) + { + setModified(); + } + + IMPL_LINK_NOARG( CommonBehaviourControlHelper, ColorModifiedHdl, ColorListBox&, void ) + { + setModified(); + } + + IMPL_LINK_NOARG( CommonBehaviourControlHelper, GetFocusHdl, weld::Widget&, void ) + { + try + { + if ( m_xContext.is() ) + m_xContext->focusGained( &m_rAntiImpl ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + IMPL_LINK_NOARG( CommonBehaviourControlHelper, LoseFocusHdl, weld::Widget&, void ) + { + // TODO/UNOize: should this be outside the default control's implementations? If somebody + // has an own control implementation, which does *not* do this - would this be allowed? + // If not, then we must move this logic out of here. + notifyModifiedValue(); + } + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/commoncontrol.hxx b/extensions/source/propctrlr/commoncontrol.hxx new file mode 100644 index 000000000..746f2f56f --- /dev/null +++ b/extensions/source/propctrlr/commoncontrol.hxx @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class NotifyEvent; +class ColorListBox; +class SvtCalendarBox; + +namespace pcr +{ + + //= CommonBehaviourControlHelper + + /** A helper class for implementing the XPropertyControl + or one of its derived interfaces. + + This class is used as a base class the CommonBehaviourControl template. + */ + class CommonBehaviourControlHelper + { + private: + sal_Int16 m_nControlType; + css::uno::Reference< css::inspection::XPropertyControlContext > + m_xContext; + css::inspection::XPropertyControl& + m_rAntiImpl; + bool m_bModified; + + public: + /** creates the instance + @param nControlType + the type of the control - one of the PropertyControlType + constants + @param pAntiImpl + Reference to the instance as whose "impl-class" we act i.e. the CommonBehaviourControl<> template, + which is why we hold it without acquiring it/ + */ + CommonBehaviourControlHelper( + sal_Int16 nControlType, + css::inspection::XPropertyControl& rAntiImpl); + + virtual ~CommonBehaviourControlHelper(); + + virtual void setModified() { m_bModified = true; } + + virtual void editChanged(); + + // XPropertyControl + /// @throws css::uno::RuntimeException + ::sal_Int16 getControlType() const { return m_nControlType; } + /// @throws css::uno::RuntimeException + const css::uno::Reference< css::inspection::XPropertyControlContext >& getControlContext() const { return m_xContext; } + /// @throws css::uno::RuntimeException + void setControlContext( const css::uno::Reference< css::inspection::XPropertyControlContext >& controlcontext ); + /// @throws css::uno::RuntimeException + bool isModified( ) const { return m_bModified; } + /// @throws css::uno::RuntimeException + void notifyModifiedValue( ); + + virtual weld::Widget* getWidget() = 0; + + /// may be used by derived classes, they forward the event to the PropCtrListener + DECL_LINK( ModifiedHdl, weld::ComboBox&, void ); + DECL_LINK( ColorModifiedHdl, ColorListBox&, void ); + DECL_LINK( EditModifiedHdl, weld::Entry&, void ); + DECL_LINK( MetricModifiedHdl, weld::MetricSpinButton&, void ); + DECL_LINK( FormattedModifiedHdl, weld::FormattedSpinButton&, void ); + DECL_LINK( TimeModifiedHdl, weld::FormattedSpinButton&, void ); + DECL_LINK( DateModifiedHdl, SvtCalendarBox&, void ); + DECL_LINK( GetFocusHdl, weld::Widget&, void ); + DECL_LINK( LoseFocusHdl, weld::Widget&, void ); + }; + + + //= CommonBehaviourControl + + /** implements a base class for XPropertyControl + implementations + + @param TControlInterface + an interface class which is derived from (or identical to) XPropertyControl + @param TControlWindow + a class which is derived from weld::Widget + */ + template < class TControlInterface, class TControlWindow > + class CommonBehaviourControl :public ::cppu::BaseMutex + ,public ::cppu::WeakComponentImplHelper< TControlInterface > + ,public CommonBehaviourControlHelper + { + protected: + typedef ::cppu::WeakComponentImplHelper< TControlInterface > ComponentBaseClass; + + inline CommonBehaviourControl(sal_Int16 nControlType, + std::unique_ptr xBuilder, + std::unique_ptr xWidget, + bool bReadOnly); + + virtual ~CommonBehaviourControl() override + { + clear_widgetry(); + } + + // XPropertyControl - delegated to ->m_aImplControl + virtual ::sal_Int16 SAL_CALL getControlType() override + { return CommonBehaviourControlHelper::getControlType(); } + virtual css::uno::Reference< css::inspection::XPropertyControlContext > SAL_CALL getControlContext() override + { return CommonBehaviourControlHelper::getControlContext(); } + virtual void SAL_CALL setControlContext( const css::uno::Reference< css::inspection::XPropertyControlContext >& controlcontext ) override + { CommonBehaviourControlHelper::setControlContext( controlcontext ); } + virtual css::uno::Reference< css::awt::XWindow > SAL_CALL getControlWindow() override + { return new weld::TransportAsXWindow(getWidget()); } + virtual sal_Bool SAL_CALL isModified( ) override + { return CommonBehaviourControlHelper::isModified(); } + virtual void SAL_CALL notifyModifiedValue( ) override + { CommonBehaviourControlHelper::notifyModifiedValue(); } + + void clear_widgetry() + { + if (!m_xControlWindow) + return; + weld::Widget* pWidget = getWidget(); + std::unique_ptr xParent(pWidget->weld_parent()); + xParent->move(pWidget, nullptr); + m_xControlWindow.reset(); + m_xBuilder.reset(); + } + + // XComponent + virtual void SAL_CALL disposing() override + { + clear_widgetry(); + } + + TControlWindow* getTypedControlWindow() + { return m_xControlWindow.get(); } + const TControlWindow* getTypedControlWindow() const + { return m_xControlWindow.get(); } + + virtual void SetModifyHandler() + { + m_xControlWindow->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xControlWindow->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + } + + /** checks whether the instance is already disposed + @throws DisposedException + if the instance is already disposed + */ + inline void impl_checkDisposed_throw(); + protected: + std::unique_ptr m_xBuilder; + private: + std::unique_ptr m_xControlWindow; + }; + + //= CommonBehaviourControl - implementation + template< class TControlInterface, class TControlWindow > + inline CommonBehaviourControl< TControlInterface, TControlWindow >::CommonBehaviourControl(sal_Int16 nControlType, + std::unique_ptr xBuilder, + std::unique_ptr xWidget, + bool bReadOnly) + : ComponentBaseClass( m_aMutex ) + , CommonBehaviourControlHelper( nControlType, *this ) + , m_xBuilder(std::move(xBuilder)) + , m_xControlWindow(std::move(xWidget)) + { + if (bReadOnly) + { + // disable widget by default, entries will override to enable the widget but set it non-editable + m_xControlWindow->set_sensitive(false); + } + } + + template< class TControlInterface, class TControlWindow > + inline void CommonBehaviourControl< TControlInterface, TControlWindow >::impl_checkDisposed_throw() + { + if ( ComponentBaseClass::rBHelper.bDisposed ) + throw css::lang::DisposedException( OUString(), *this ); + } + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/composeduiupdate.cxx b/extensions/source/propctrlr/composeduiupdate.cxx new file mode 100644 index 000000000..0e32ef19a --- /dev/null +++ b/extensions/source/propctrlr/composeduiupdate.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 "composeduiupdate.hxx" +#include "pcrcommon.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace pcr +{ + + + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::lang::NullPointerException; + using ::com::sun::star::inspection::XPropertyHandler; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::inspection::XObjectInspectorUI; + using ::com::sun::star::inspection::XPropertyControl; + using ::com::sun::star::inspection::XPropertyControlObserver; + + namespace PropertyLineElement = ::com::sun::star::inspection::PropertyLineElement; + + namespace + { + struct HandlerLess + { + bool operator()( const Reference< XPropertyHandler >& lhs, const Reference< XPropertyHandler >& rhs) const + { + return lhs.get() < rhs.get(); + } + }; + + + typedef std::set< OUString > StringBag; + typedef std::map< sal_Int16, StringBag > MapIntToStringBag; + } + + + // callbacks for CachedInspectorUI + + typedef void (ComposedPropertyUIUpdate::*FNotifySingleUIChange)(); + + typedef ::cppu::WeakImplHelper < css::inspection::XObjectInspectorUI + > CachedInspectorUI_Base; + + namespace { + + struct CachedInspectorUI : public CachedInspectorUI_Base + { + private: + ::osl::Mutex m_aMutex; + bool m_bDisposed; + ComposedPropertyUIUpdate& + m_rMaster; + FNotifySingleUIChange m_pUIChangeNotification; + + // enablePropertyUI cache + StringBag aEnabledProperties; + StringBag aDisabledProperties; + + // show/hidePropertyUI cache + StringBag aShownProperties; + StringBag aHiddenProperties; + + // rebuildPropertyUI cache + StringBag aRebuiltProperties; + + // showCategory cache + StringBag aShownCategories; + StringBag aHiddenCategories; + + // enablePropertyUIElements cache + MapIntToStringBag aEnabledElements; + MapIntToStringBag aDisabledElements; + + public: + typedef StringBag& (CachedInspectorUI::*FGetStringBag)(); + + // enablePropertyUI cache + StringBag& getEnabledProperties() { return aEnabledProperties; } + StringBag& getDisabledProperties() { return aDisabledProperties; } + + // show/hidePropertyUI cache + StringBag& getShownProperties() { return aShownProperties; } + StringBag& getHiddenProperties() { return aHiddenProperties; } + + // rebuildPropertyUI cache + StringBag& getRebuiltProperties() { return aRebuiltProperties; } + + // showCategory cache + StringBag& getShownCategories() { return aShownCategories; } + StringBag& getHiddenCategories() { return aHiddenCategories; } + + // enablePropertyUIElements + StringBag& getEnabledInputControls() { return aEnabledElements[ PropertyLineElement::InputControl ]; } + StringBag& getDisabledInputControls() { return aDisabledElements[ PropertyLineElement::InputControl ]; } + StringBag& getEnabledPrimaryButtons() { return aEnabledElements[ PropertyLineElement::PrimaryButton ]; } + StringBag& getDisabledPrimaryButtons() { return aDisabledElements[ PropertyLineElement::PrimaryButton ]; } + StringBag& getEnabledSecondaryButtons() { return aEnabledElements[ PropertyLineElement::SecondaryButton ]; } + StringBag& getDisabledSecondaryButtons() { return aDisabledElements[ PropertyLineElement::SecondaryButton ]; } + + public: + CachedInspectorUI( ComposedPropertyUIUpdate& _rMaster, FNotifySingleUIChange _pUIChangeNotification ); + CachedInspectorUI(const CachedInspectorUI&) = delete; + CachedInspectorUI& operator=(const CachedInspectorUI&) = delete; + + /// disposes the instance + void dispose(); + + // XObjectInspectorUI overridables + virtual void SAL_CALL enablePropertyUI( const OUString& _rPropertyName, sal_Bool _bEnable ) override; + virtual void SAL_CALL enablePropertyUIElements( const OUString& _rPropertyName, ::sal_Int16 _nElements, sal_Bool _bEnable ) override; + virtual void SAL_CALL rebuildPropertyUI( const OUString& _rPropertyName ) override; + virtual void SAL_CALL showPropertyUI( const OUString& _rPropertyName ) override; + virtual void SAL_CALL hidePropertyUI( const OUString& _rPropertyName ) override; + virtual void SAL_CALL showCategory( const OUString& _rCategory, sal_Bool _bShow ) override; + virtual Reference< XPropertyControl > SAL_CALL getPropertyControl( const OUString& _rPropertyName ) override; + virtual void SAL_CALL registerControlObserver( const Reference< XPropertyControlObserver >& Observer ) override; + virtual void SAL_CALL revokeControlObserver( const Reference< XPropertyControlObserver >& Observer ) override; + virtual void SAL_CALL setHelpSectionText( const OUString& HelpText ) override; + + protected: + virtual ~CachedInspectorUI() override; + + /// throws an exception if the component is already disposed + void checkDisposed() const; + + private: + void impl_markElementEnabledOrDisabled( const OUString& _rPropertyName, sal_Int16 _nElementIdOrZero, bool _bEnable ); + + /** calls m_pUIChangeNotification at m_rMaster + */ + void impl_notifySingleUIChange() const; + + private: + class MethodGuard; + friend class MethodGuard; + class MethodGuard : public ::osl::MutexGuard + { + public: + explicit MethodGuard( CachedInspectorUI& rInstance ) + : ::osl::MutexGuard( rInstance.m_aMutex ) + { + rInstance.checkDisposed(); + } + }; + }; + + } + + CachedInspectorUI::CachedInspectorUI( ComposedPropertyUIUpdate& _rMaster, FNotifySingleUIChange _pUIChangeNotification ) + :m_bDisposed( false ) + ,m_rMaster( _rMaster ) + ,m_pUIChangeNotification( _pUIChangeNotification ) + { + } + + + CachedInspectorUI::~CachedInspectorUI() + { + } + + + void CachedInspectorUI::dispose() + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_bDisposed = true; + + clearContainer( aEnabledProperties ); + clearContainer( aDisabledProperties ); + clearContainer( aRebuiltProperties ); + clearContainer( aShownProperties ); + clearContainer( aHiddenProperties ); + clearContainer( aShownCategories ); + clearContainer( aHiddenCategories ); + clearContainer( aEnabledElements ); + clearContainer( aDisabledElements ); + } + + + void CachedInspectorUI::checkDisposed() const + { + if (m_bDisposed) + throw DisposedException(); + } + + + namespace + { + void lcl_markStringKeyPositiveOrNegative( const OUString& _rKeyName, StringBag& _rPositives, StringBag& _rNegatives, bool _bMarkPositive ) + { + if ( _bMarkPositive ) + { + _rPositives.insert( _rKeyName ); + // if the same key has been remember as in the "negative" list before, clear this information, since it's overruled + _rNegatives.erase( _rKeyName ); + } + else + _rNegatives.insert( _rKeyName ); + } + } + + + void CachedInspectorUI::enablePropertyUI( const OUString& _rPropertyName, sal_Bool _bEnable ) + { + MethodGuard aGuard( *this ); + if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) ) + return; + + lcl_markStringKeyPositiveOrNegative( _rPropertyName, aEnabledProperties, aDisabledProperties, _bEnable ); + impl_notifySingleUIChange(); + } + + + void CachedInspectorUI::impl_markElementEnabledOrDisabled( const OUString& _rPropertyName, sal_Int16 _nElementIdOrZero, bool _bEnable ) + { + if ( _nElementIdOrZero == 0 ) + return; + + lcl_markStringKeyPositiveOrNegative( + _rPropertyName, + aEnabledElements[ _nElementIdOrZero ], + aDisabledElements[ _nElementIdOrZero ], + _bEnable + ); + } + + + void CachedInspectorUI::impl_notifySingleUIChange() const + { + (m_rMaster.*m_pUIChangeNotification)(); + } + + + void CachedInspectorUI::enablePropertyUIElements( const OUString& _rPropertyName, sal_Int16 _nElements, sal_Bool _bEnable ) + { + MethodGuard aGuard( *this ); + if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) ) + return; + + impl_markElementEnabledOrDisabled( _rPropertyName, _nElements & PropertyLineElement::InputControl, _bEnable ); + impl_markElementEnabledOrDisabled( _rPropertyName, _nElements & PropertyLineElement::PrimaryButton, _bEnable ); + impl_markElementEnabledOrDisabled( _rPropertyName, _nElements & PropertyLineElement::SecondaryButton, _bEnable ); + + impl_notifySingleUIChange(); + } + + + void CachedInspectorUI::rebuildPropertyUI( const OUString& _rPropertyName ) + { + MethodGuard aGuard( *this ); + if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) ) + return; + + aRebuiltProperties.insert( _rPropertyName ); + + impl_notifySingleUIChange(); + } + + + void CachedInspectorUI::showPropertyUI( const OUString& _rPropertyName ) + { + MethodGuard aGuard( *this ); + if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) ) + return; + + aShownProperties.insert( _rPropertyName ); + // if the same category has been hidden before, clear this information, since it's overruled + aHiddenProperties.erase( _rPropertyName ); + + impl_notifySingleUIChange(); + } + + + void CachedInspectorUI::hidePropertyUI( const OUString& _rPropertyName ) + { + MethodGuard aGuard( *this ); + if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) ) + return; + + aHiddenProperties.insert( _rPropertyName ); + impl_notifySingleUIChange(); + } + + + void CachedInspectorUI::showCategory( const OUString& _rCategory, sal_Bool _bShow ) + { + MethodGuard aGuard( *this ); + + lcl_markStringKeyPositiveOrNegative( _rCategory, aShownCategories, aHiddenCategories, _bShow ); + impl_notifySingleUIChange(); + } + + + Reference< XPropertyControl > SAL_CALL CachedInspectorUI::getPropertyControl( const OUString& _rPropertyName ) + { + MethodGuard aGuard( *this ); + if ( !m_rMaster.shouldContinuePropertyHandling( _rPropertyName ) ) + return Reference< XPropertyControl >(); + + return m_rMaster.getDelegatorUI()->getPropertyControl( _rPropertyName ); + } + + + void SAL_CALL CachedInspectorUI::registerControlObserver( const Reference< XPropertyControlObserver >& Observer ) + { + OSL_FAIL( "CachedInspectorUI::registerControlObserver: not expected to be called!" ); + // CachedInspectorUI is used as context for the controls, and we don't expect them to + // register listeners themself + m_rMaster.getDelegatorUI()->registerControlObserver( Observer ); + } + + + void SAL_CALL CachedInspectorUI::revokeControlObserver( const Reference< XPropertyControlObserver >& Observer ) + { + OSL_FAIL( "CachedInspectorUI::revokeControlObserver: not expected to be called!" ); + // CachedInspectorUI is used as context for the controls, and we don't expect them to + // register listeners themself + m_rMaster.getDelegatorUI()->revokeControlObserver( Observer ); + } + + + void SAL_CALL CachedInspectorUI::setHelpSectionText( const OUString& HelpText ) + { + m_rMaster.getDelegatorUI()->setHelpSectionText( HelpText ); + } + + + // HandlerMap + + typedef std::map < Reference< XPropertyHandler > + , ::rtl::Reference< CachedInspectorUI > + , HandlerLess + > ImplMapHandlerToUI; + struct MapHandlerToUI + { + ImplMapHandlerToUI aHandlers; + }; + + ComposedPropertyUIUpdate::ComposedPropertyUIUpdate( const Reference< XObjectInspectorUI >& _rxDelegatorUI, + IPropertyExistenceCheck* _pPropertyCheck ) + :m_pCollectedUIs( new MapHandlerToUI ) + ,m_xDelegatorUI( _rxDelegatorUI ) + ,m_nSuspendCounter( 0 ) + ,m_pPropertyCheck( _pPropertyCheck ) + { + if ( !m_xDelegatorUI.is() ) + throw NullPointerException(); + } + + + ComposedPropertyUIUpdate::~ComposedPropertyUIUpdate( ) + { + } + + + Reference< XObjectInspectorUI > ComposedPropertyUIUpdate::getUIForPropertyHandler( const Reference< XPropertyHandler >& _rxHandler ) + { + impl_checkDisposed(); + + ::rtl::Reference< CachedInspectorUI >& rUI = m_pCollectedUIs->aHandlers[ _rxHandler ]; + if ( !rUI.is() ) + rUI = new CachedInspectorUI( *this, &ComposedPropertyUIUpdate::callback_inspectorUIChanged_throw ); + return rUI; + } + + + namespace + { + + // an STL-compatible structure which collects strings from a CachedInspectorUI instances + struct StringBagCollector + { + private: + StringBag& m_rBag; + CachedInspectorUI::FGetStringBag m_pGetter; + + public: + StringBagCollector( StringBag& _rBag, CachedInspectorUI::FGetStringBag _pGetter ) :m_rBag( _rBag ), m_pGetter( _pGetter ) { } + + void operator()( const ImplMapHandlerToUI::value_type& _rUI ) + { + StringBag& rBag( ((_rUI.second.get())->*m_pGetter)() ); + m_rBag.insert( rBag.begin(), rBag.end() ); + } + + static void collectAll( StringBag& _rAll, const ImplMapHandlerToUI& _rMap, CachedInspectorUI::FGetStringBag _pGetter ) + { + std::for_each( _rMap.begin(), _rMap.end(), StringBagCollector( _rAll, _pGetter ) ); + } + }; + + + // an STL-compatible structure which cleans a certain string bag in a CachedInspectorUI instances + struct StringBagClearer + { + private: + CachedInspectorUI::FGetStringBag m_pGetter; + + public: + explicit StringBagClearer( CachedInspectorUI::FGetStringBag _pGetter ) :m_pGetter( _pGetter ) { } + + void operator()( const ImplMapHandlerToUI::value_type& _rUI ) + { + clearContainer( ((_rUI.second.get())->*m_pGetter)() ); + } + + static void clearAll( const ImplMapHandlerToUI& _rMap, CachedInspectorUI::FGetStringBag _pGetter ) + { + std::for_each( _rMap.begin(), _rMap.end(), StringBagClearer( _pGetter ) ); + } + }; + + // a typedef for a ->XObjectInspectorUI member function taking a string + typedef void ( SAL_CALL XObjectInspectorUI::*FPropertyUISetter )( const OUString& ); + + + // an STL-compatible struct which calls a certain member method (taking a string) at a + // given ->XObjectInspectorUI instance + struct PropertyUIOperator + { + private: + Reference< XObjectInspectorUI > m_xUpdater; + FPropertyUISetter m_pSetter; + + public: + PropertyUIOperator( const Reference< XObjectInspectorUI >& _rxInspectorUI, FPropertyUISetter _pSetter ) + :m_xUpdater( _rxInspectorUI ) + ,m_pSetter( _pSetter ) + { + } + + void operator()( const OUString& _rPropertyName ) + { + ((m_xUpdater.get())->*m_pSetter)( _rPropertyName ); + } + + static void forEach( const StringBag& _rProperties, const Reference< XObjectInspectorUI >& _rxDelegatorUI, FPropertyUISetter _pSetter ) + { + std::for_each( _rProperties.begin(), _rProperties.end(), PropertyUIOperator( _rxDelegatorUI, _pSetter ) ); + } + }; + + + // an interface which encapsulates access to a single aspect of the ->XObjectInspectorUI, + // where this aspect is given by a string key, and has a boolean value. + class IStringKeyBooleanUIUpdate + { + public: + virtual void updateUIForKey( const OUString& _rKey, bool _bFlag ) const = 0; + + virtual ~IStringKeyBooleanUIUpdate() { } + }; + + + // FPropertyUIFlagSetter + + /** an implementation of the ->IStringKeyBooleanUIUpdate interface which, + for a fixed ->XObjectInspectorUI instance and a fixed UI element (->PropertyLineElement), + updates this element for a given property with a given boolean flag + (->XObjectInspectorUI::enablePropertyUIElements) + */ + class EnablePropertyUIElement : public IStringKeyBooleanUIUpdate + { + private: + Reference< XObjectInspectorUI > m_xUIUpdate; + sal_Int16 m_nElement; + + public: + EnablePropertyUIElement( const Reference< XObjectInspectorUI >& _rxUIUpdate, sal_Int16 _nElement ) + :m_xUIUpdate( _rxUIUpdate ) + ,m_nElement( _nElement ) + { + } + // IStringKeyBooleanUIUpdate + virtual void updateUIForKey( const OUString& _rKey, bool _bFlag ) const override; + }; + + + void EnablePropertyUIElement::updateUIForKey( const OUString& _rKey, bool _bFlag ) const + { + m_xUIUpdate->enablePropertyUIElements( _rKey, m_nElement, _bFlag ); + } + + + // a ->XObjectInspectorUI method taking a string and a boolean + typedef void ( SAL_CALL XObjectInspectorUI::*FPropertyUIFlagSetter )( const OUString&, sal_Bool ); + + + // an implementation of the ->IStringKeyBooleanUIUpdate interface which calls + // an arbitrary ->XObjectInspectorUI method taking a string and a boolean flag + class DefaultStringKeyBooleanUIUpdate : public IStringKeyBooleanUIUpdate + { + private: + Reference< XObjectInspectorUI > m_xUIUpdate; + FPropertyUIFlagSetter m_pSetter; + + public: + DefaultStringKeyBooleanUIUpdate( const Reference< XObjectInspectorUI >& _rxUIUpdate, FPropertyUIFlagSetter _pSetter ); + // IStringKeyBooleanUIUpdate + virtual void updateUIForKey( const OUString& _rKey, bool _bFlag ) const override; + }; + + + DefaultStringKeyBooleanUIUpdate::DefaultStringKeyBooleanUIUpdate( const Reference< XObjectInspectorUI >& _rxUIUpdate, FPropertyUIFlagSetter _pSetter ) + :m_xUIUpdate( _rxUIUpdate ) + ,m_pSetter( _pSetter ) + { + } + + + void DefaultStringKeyBooleanUIUpdate::updateUIForKey( const OUString& _rKey, bool _bFlag ) const + { + ((m_xUIUpdate.get())->*m_pSetter)( _rKey, _bFlag ); + } + + + // an STL-compatible structure which applies a ->IStringKeyBooleanUIUpdate::updateUIForKey + // operation with a fixed boolean value, for a given string value + struct BooleanUIAspectUpdate + { + private: + const IStringKeyBooleanUIUpdate& m_rUpdater; + bool m_bFlag; + + public: + BooleanUIAspectUpdate( const IStringKeyBooleanUIUpdate& _rUpdater, bool _bFlag ) + :m_rUpdater( _rUpdater ) + ,m_bFlag( _bFlag ) + { + } + + void operator()( const OUString& _rPropertyName ) + { + m_rUpdater.updateUIForKey( _rPropertyName, m_bFlag ); + } + + static void forEach( const StringBag& _rProperties, const IStringKeyBooleanUIUpdate& _rUpdater, bool _bFlag ) + { + std::for_each( _rProperties.begin(), _rProperties.end(), BooleanUIAspectUpdate( _rUpdater, _bFlag ) ); + } + }; + + + // BooleanUIAspectUpdate + + // an STL-compatible structure subtracting a given string from a fixed ->StringBag + struct StringBagComplement + { + private: + StringBag& m_rMinuend; + + public: + explicit StringBagComplement( StringBag& _rMinuend ) :m_rMinuend( _rMinuend ) { } + + void operator()( const OUString& _rPropertyToSubtract ) + { + m_rMinuend.erase( _rPropertyToSubtract ); + } + + static void subtract( StringBag& _rMinuend, const StringBag& _rSubtrahend ) + { + std::for_each( _rSubtrahend.begin(), _rSubtrahend.end(), StringBagComplement( _rMinuend ) ); + } + }; + + + // BooleanUIAspectUpdate + + void lcl_fireUIStateFlag( + const IStringKeyBooleanUIUpdate& _rUIUpdate, + const ImplMapHandlerToUI& _rHandlerUIs, + CachedInspectorUI::FGetStringBag _pGetPositives, + CachedInspectorUI::FGetStringBag _pGetNegatives + ) + { + // all strings which are in the "positive" list of one handler + StringBag aAllPositives; + StringBagCollector::collectAll( aAllPositives, _rHandlerUIs, _pGetPositives ); + + // all strings which are in the "negative" list of one handler + StringBag aAllNegatives; + StringBagCollector::collectAll( aAllNegatives, _rHandlerUIs, _pGetNegatives ); + + // propagate the "negative" flags to the delegator UI + BooleanUIAspectUpdate::forEach( aAllNegatives, _rUIUpdate, false ); + + // propagate the "positive" flags to the delegator UI, for all elements where _no_ + // "negative" flag exists + StringBagComplement::subtract( aAllPositives, aAllNegatives ); + BooleanUIAspectUpdate::forEach( aAllPositives, _rUIUpdate, true ); + + // the "positive" request can be cleared no, only negative requests + // (such as "disable a property" or "hide a category") need to be preserved for the next round + StringBagClearer::clearAll( _rHandlerUIs, _pGetPositives ); + } + } + + + void ComposedPropertyUIUpdate::impl_fireEnablePropertyUI_throw() + { + lcl_fireUIStateFlag( + DefaultStringKeyBooleanUIUpdate( m_xDelegatorUI, &XObjectInspectorUI::enablePropertyUI ), + m_pCollectedUIs->aHandlers, + &CachedInspectorUI::getEnabledProperties, + &CachedInspectorUI::getDisabledProperties + ); + } + + + void ComposedPropertyUIUpdate::impl_fireRebuildPropertyUI_throw() + { + // collect all properties for which a rebuild request has been made + StringBag aAllRebuilt; + StringBagCollector::collectAll( aAllRebuilt, m_pCollectedUIs->aHandlers, &CachedInspectorUI::getRebuiltProperties ); + + // rebuild all those properties + PropertyUIOperator::forEach( aAllRebuilt, m_xDelegatorUI, &XObjectInspectorUI::rebuildPropertyUI ); + + // clear the "properties to rebuild" at all handlers, since the request has been fulfilled now. + StringBagClearer::clearAll( m_pCollectedUIs->aHandlers, &CachedInspectorUI::getRebuiltProperties ); + } + + + void ComposedPropertyUIUpdate::impl_fireShowHidePropertyUI_throw() + { + // all properties which have been shown by at least one handler + StringBag aAllShown; + StringBagCollector::collectAll( aAllShown, m_pCollectedUIs->aHandlers, &CachedInspectorUI::getShownProperties ); + // all properties which have been hidden by at least one handler + StringBag aAllHidden; + StringBagCollector::collectAll( aAllHidden, m_pCollectedUIs->aHandlers, &CachedInspectorUI::getHiddenProperties ); + + // hide properties as necessary + PropertyUIOperator::forEach( aAllHidden, m_xDelegatorUI, &XObjectInspectorUI::hidePropertyUI ); + + // for those properties which are hidden, ignore all "show" requests which other handlers might have had + StringBagComplement::subtract( aAllShown, aAllHidden ); + + // show properties + PropertyUIOperator::forEach( aAllShown, m_xDelegatorUI, &XObjectInspectorUI::showPropertyUI ); + } + + + void ComposedPropertyUIUpdate::impl_fireShowCategory_throw() + { + lcl_fireUIStateFlag( + DefaultStringKeyBooleanUIUpdate( m_xDelegatorUI, &XObjectInspectorUI::showCategory ), + m_pCollectedUIs->aHandlers, + &CachedInspectorUI::getShownCategories, + &CachedInspectorUI::getHiddenCategories + ); + } + + + void ComposedPropertyUIUpdate::impl_fireEnablePropertyUIElements_throw() + { + lcl_fireUIStateFlag( + EnablePropertyUIElement( m_xDelegatorUI, PropertyLineElement::InputControl ), + m_pCollectedUIs->aHandlers, + &CachedInspectorUI::getEnabledInputControls, + &CachedInspectorUI::getDisabledInputControls + ); + + lcl_fireUIStateFlag( + EnablePropertyUIElement( m_xDelegatorUI, PropertyLineElement::PrimaryButton ), + m_pCollectedUIs->aHandlers, + &CachedInspectorUI::getEnabledPrimaryButtons, + &CachedInspectorUI::getDisabledPrimaryButtons + ); + + lcl_fireUIStateFlag( + EnablePropertyUIElement( m_xDelegatorUI, PropertyLineElement::SecondaryButton ), + m_pCollectedUIs->aHandlers, + &CachedInspectorUI::getEnabledSecondaryButtons, + &CachedInspectorUI::getDisabledSecondaryButtons + ); + } + + + void ComposedPropertyUIUpdate::impl_fireAll_throw() + { + OSL_PRECOND( !impl_isDisposed(), "ComposedPropertyUIUpdate::impl_fireAll_throw: already disposed, this will crash!" ); + + impl_fireEnablePropertyUI_throw(); + impl_fireShowHidePropertyUI_throw(); + impl_fireRebuildPropertyUI_throw(); + impl_fireShowCategory_throw(); + impl_fireEnablePropertyUIElements_throw(); + } + + + void ComposedPropertyUIUpdate::suspendAutoFire() + { + impl_checkDisposed(); + osl_atomic_increment( &m_nSuspendCounter ); + } + + + void ComposedPropertyUIUpdate::resumeAutoFire() + { + impl_checkDisposed(); + if ( 0 == osl_atomic_decrement( &m_nSuspendCounter ) ) + impl_fireAll_throw(); + } + + + void ComposedPropertyUIUpdate::impl_checkDisposed() const + { + if ( impl_isDisposed() ) + throw DisposedException(); + } + + + void ComposedPropertyUIUpdate::callback_inspectorUIChanged_throw() + { + if ( 0 == m_nSuspendCounter ) + impl_fireAll_throw(); + } + + + Reference< XObjectInspectorUI > const & ComposedPropertyUIUpdate::getDelegatorUI() const + { + impl_checkDisposed(); + return m_xDelegatorUI; + } + + + void ComposedPropertyUIUpdate::dispose() + { + if ( impl_isDisposed() ) + return; + + OSL_ENSURE( m_nSuspendCounter == 0, "ComposedPropertyUIUpdate::dispose: still suspended, the changes will be lost!" ); + + for (auto const& singleUI : m_pCollectedUIs->aHandlers) + { + singleUI.second->dispose(); + } + m_pCollectedUIs.reset(); + m_xDelegatorUI.set( nullptr ); + } + + + bool ComposedPropertyUIUpdate::shouldContinuePropertyHandling( const OUString& _rName ) const + { + if ( !m_pPropertyCheck ) + return true; + if ( m_pPropertyCheck->hasPropertyByName( _rName ) ) + return true; + return false; + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/composeduiupdate.hxx b/extensions/source/propctrlr/composeduiupdate.hxx new file mode 100644 index 000000000..5e356af1f --- /dev/null +++ b/extensions/source/propctrlr/composeduiupdate.hxx @@ -0,0 +1,208 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include + + +namespace pcr +{ + + struct MapHandlerToUI; + + /** callback for a ComposedPropertyUIUpdate checking a given property for existence + */ + class SAL_NO_VTABLE IPropertyExistenceCheck + { + public: + /// @throws css::uno::RuntimeException + virtual bool hasPropertyByName( const OUString& _rName ) = 0; + + protected: + ~IPropertyExistenceCheck() {} + }; + + /** helper class composing requests to a ->XObjectInspectorUI interface, coming + from multiple sources + + Usually, a handler tells the browser UI to enable to disable, or show or hide, certain + elements. Now when multiple handlers do this, their instructions must be combined: + If one handler disables a certain element, but others enable it, it must in the + result still be disabled. Similar for showing/hiding elements. + + ->ComposedPropertyUIUpdate implements this combination. It does so by providing a dedicated + ->XObjectInspectorUI instance for every participating handler, and remembering the UI + state on a per-handler basis. Upon request (->fire), the combined UI state is + forwarded to another ->XObjectInspectorUI instance, the so-called delegator UI. + */ + class ComposedPropertyUIUpdate + { + private: + std::unique_ptr< MapHandlerToUI > m_pCollectedUIs; + css::uno::Reference< css::inspection::XObjectInspectorUI > + m_xDelegatorUI; + oslInterlockedCount m_nSuspendCounter; + IPropertyExistenceCheck* m_pPropertyCheck; + + public: + /** constructs a ->ComposedPropertyUIUpdate instance + @param _rxDelegatorUI + a ->XObjectInspectorUI instance to which composed UI requests should be forwarded. Must + not be . + @param _pPropertyCheck + an instance checking properties for existence. If this is not , it will be invoked + whenever one of the ->XObjectInspectorUI methods is called, to check the passed property + name.
+ Beware of lifetime issues. The instance pointed to by _pPropertyCheck must + live at least as long as the ->ComposedPropertyUIUpdate instance you're going to create. + @throws css::lang::NullPointerException + if ->_rxDelegatorUI is + */ + ComposedPropertyUIUpdate( + const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxDelegatorUI, + IPropertyExistenceCheck* _pPropertyCheck ); + ~ComposedPropertyUIUpdate(); + + /** returns the delegator UI + @throw css::lang::DisposedException + */ + css::uno::Reference< css::inspection::XObjectInspectorUI > const & getDelegatorUI() const; + + /** returns a ->XObjectInspectorUI instance belonging to a given property handler + + In every call to an ->XPropertyHandler method which requires a ->XObjectInspectorUI, + the same UI instance should be used. The instance here will cache all requests passed + to it, and ->ComposedPropertyUIUpdate::fire will use the combination of all + cached UI states of all handlers to update the delegator UI. + */ + css::uno::Reference< css::inspection::XObjectInspectorUI > + getUIForPropertyHandler( const css::uno::Reference< css::inspection::XPropertyHandler >& _rxHandler ); + + /** Suspends automatic firing of UI changes + + normally, as soon as any of the property handlers does a request for an + arbitrary UI change, the set of collected UI changes is evaluated, and the combined + UI state is fired to the delegator UI. + + You can disable this automatic firing by calling ->suspendAutoFire. As longs as auto + firing is suspended, only explicit ->fire calls trigger the notification to the + delegator UI. + + Note that calls to ->suspendAutoFire are cumulative, that is, if you make multiple calls + they must be accompanied by an equal number of calls to ->resumeAutoFire, to enable + auto-firing again. + + @seealso resumeAutoFire + */ + void suspendAutoFire(); + + /** Suspends automatic firing of UI changes + + @seealso suspendAutoFire + */ + void resumeAutoFire(); + + /** disposes the instance, so it becomes non-functional. + + All cached handlers and cached ->XObjectInspectorUI instances will be released, + the latter will also be disposed, so that if anybody still holds a reference to them + and tries to operate them will get a DisposedException. + */ + void dispose(); + + /** invokes m_pPropertyCheck to check whether a given property should be handled + */ + bool shouldContinuePropertyHandling( const OUString& _rName ) const; + + private: + /// determines whether the instance is already disposed + bool impl_isDisposed() const { return !m_pCollectedUIs; } + + /// throws an exception if the component is already disposed + void impl_checkDisposed() const; + + /** fires the collected UI changes to our delegator UI + + All operations for any elements are forwarded: +
  • If an element has been hidden at least once, it's also hidden at the delegator UI.
  • +
  • If an element has been shown at least once, and never been hidden, it's also + shown at the delegator UI.
  • +
  • If an element has never been shown or hidden, it's also not touched at the delegator UI.
  • +
  • The same holds if you replace "hidden" in the last three items with "disabled", + and "shown" with "enabled".
  • +
  • If an element should have been rebuilt (->XObjectInspectorUI::rebuiltPropertyUI) + at least once, it's rebuilt at the delegator UI, too.
    + After that, the request to rebuild the UI for this property is cleared, so subsequent + calls to ->fire will not trigger a new rebuilt request. +
+ + @precond + instance is not disposed + */ + void impl_fireAll_throw(); + + /// fires the combination of ->XObjectInspectorUI::enablePropertyUI calls + void impl_fireEnablePropertyUI_throw(); + + /// fires the combination of ->XObjectInspectorUI::enablePropertyUIElements calls + void impl_fireEnablePropertyUIElements_throw(); + + /// fires the combination of ->XObjectInspectorUI::rebuildPropertyUI calls + void impl_fireRebuildPropertyUI_throw(); + + /// fires the combination of ->XObjectInspectorUI::showPropertyUI and ->XObjectInspectorUI::hidePropertyUI calls + void impl_fireShowHidePropertyUI_throw(); + + /// fires the combination of ->XObjectInspectorUI::showCategory calls + void impl_fireShowCategory_throw(); + + /** callback for when a single property handler requested any change in the inspector UI + */ + void callback_inspectorUIChanged_throw(); + + private: + ComposedPropertyUIUpdate( const ComposedPropertyUIUpdate& ) = delete; + ComposedPropertyUIUpdate& operator=( const ComposedPropertyUIUpdate& ) = delete; + }; + + class ComposedUIAutoFireGuard + { + private: + ComposedPropertyUIUpdate& m_rUIUpdate; + public: + explicit ComposedUIAutoFireGuard( ComposedPropertyUIUpdate& _rUIUpdate ) + :m_rUIUpdate( _rUIUpdate ) + { + m_rUIUpdate.suspendAutoFire(); + } + ~ComposedUIAutoFireGuard() COVERITY_NOEXCEPT_FALSE + { + m_rUIUpdate.resumeAutoFire(); + } + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/controlfontdialog.cxx b/extensions/source/propctrlr/controlfontdialog.cxx new file mode 100644 index 000000000..08088e074 --- /dev/null +++ b/extensions/source/propctrlr/controlfontdialog.cxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include "controlfontdialog.hxx" + +#include +#include +#include "fontdialog.hxx" +#include "formstrings.hxx" +#include "pcrcommon.hxx" + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + + OControlFontDialog::OControlFontDialog(const Reference< XComponentContext >& _rxContext ) + :OGenericUnoDialog( _rxContext ) + ,m_pItemPoolDefaults(nullptr) + { + registerProperty(PROPERTY_INTROSPECTEDOBJECT, OWN_PROPERTY_ID_INTROSPECTEDOBJECT, + PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT, + &m_xControlModel, cppu::UnoType::get()); + } + + + OControlFontDialog::~OControlFontDialog() + { + if (m_xDialog) + { + ::osl::MutexGuard aGuard(m_aMutex); + if (m_xDialog) + { + destroyDialog(); + ControlCharacterDialog::destroyItemSet(m_pFontItems, m_pItemPool, m_pItemPoolDefaults); + } + } + } + + + Sequence SAL_CALL OControlFontDialog::getImplementationId( ) + { + return css::uno::Sequence(); + } + + + OUString SAL_CALL OControlFontDialog::getImplementationName() + { + return "org.openoffice.comp.form.ui.OControlFontDialog"; + } + + + css::uno::Sequence SAL_CALL OControlFontDialog::getSupportedServiceNames() + { + return { "com.sun.star.form.ControlFontDialog" }; + } + + void OControlFontDialog::initialize( const Sequence< Any >& aArguments ) + { + Reference xGridModel; + if (aArguments.getLength() == 1 && (aArguments[0] >>= xGridModel)) + { + Sequence aNewArguments{ Any(comphelper::makePropertyValue("IntrospectedObject", + xGridModel)) }; + OControlFontDialog_DBase::initialize(aNewArguments); + } + else + OControlFontDialog_DBase::initialize(aArguments); + } + + + Reference SAL_CALL OControlFontDialog::getPropertySetInfo() + { + Reference xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + + ::cppu::IPropertyArrayHelper& OControlFontDialog::getInfoHelper() + { + return *getArrayHelper(); + } + + + ::cppu::IPropertyArrayHelper* OControlFontDialog::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + } + + std::unique_ptr OControlFontDialog::createDialog(const css::uno::Reference& rParent) + { + ControlCharacterDialog::createItemSet(m_pFontItems, m_pItemPool, m_pItemPoolDefaults); + + OSL_ENSURE(m_xControlModel.is(), "OControlFontDialog::createDialog: no introspectee set!"); + if (m_xControlModel.is()) + ControlCharacterDialog::translatePropertiesToItems(m_xControlModel, m_pFontItems.get()); + // TODO: we need a mechanism to prevent that somebody creates us, sets an introspectee, executes us, + // sets a new introspectee and re-executes us. In this case, the dialog returned here (upon the first + // execute) will be re-used upon the second execute, and thus it won't be initialized correctly. + + return std::make_unique(Application::GetFrameWeld(rParent), *m_pFontItems); + } + + void OControlFontDialog::executedDialog(sal_Int16 _nExecutionResult) + { + OSL_ENSURE(m_xDialog, "OControlFontDialog::executedDialog: no dialog anymore?!!"); + if (m_xDialog && (RET_OK == _nExecutionResult) && m_xControlModel.is()) + { + const SfxItemSet* pOutput = static_cast(m_xDialog.get())->GetOutputItemSet(); + if (pOutput) + ControlCharacterDialog::translateItemsToProperties( *pOutput, m_xControlModel ); + } + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_OControlFontDialog_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::OControlFontDialog(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/controlfontdialog.hxx b/extensions/source/propctrlr/controlfontdialog.hxx new file mode 100644 index 000000000..8dc520102 --- /dev/null +++ b/extensions/source/propctrlr/controlfontdialog.hxx @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +class SfxItemSet; +class SfxItemPool; +class SfxPoolItem; + +namespace pcr +{ + + class OControlFontDialog; + typedef ::svt::OGenericUnoDialog OControlFontDialog_DBase; + typedef ::comphelper::OPropertyArrayUsageHelper< OControlFontDialog > OControlFontDialog_PBase; + + class OControlFontDialog + :public OControlFontDialog_DBase + ,public OControlFontDialog_PBase + { + protected: + // + css::uno::Reference< css::beans::XPropertySet > + m_xControlModel; + // + + std::unique_ptr m_pFontItems; // item set for the dialog + rtl::Reference m_pItemPool; // item pool for the item set for the dialog + std::vector* + m_pItemPoolDefaults; // pool defaults + + public: + explicit OControlFontDialog(const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + virtual ~OControlFontDialog() override; + + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + protected: + // OGenericUnoDialog overridables + virtual std::unique_ptr createDialog(const css::uno::Reference& rParent) override; + virtual void executedDialog(sal_Int16 _nExecutionResult) override; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/controltype.hxx b/extensions/source/propctrlr/controltype.hxx new file mode 100644 index 000000000..89a400a76 --- /dev/null +++ b/extensions/source/propctrlr/controltype.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 . + */ +#pragma once + +#include + + +namespace pcr::ControlType +{ + const sal_Int16 FIXEDLINE = sal_Int16(100); + const sal_Int16 FORMATTEDFIELD = sal_Int16(101); + const sal_Int16 PROGRESSBAR = sal_Int16(102); + + // need only those which are not already covered as FormComponentType + +} // namespace pcr::ControlType + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/defaultforminspection.cxx b/extensions/source/propctrlr/defaultforminspection.cxx new file mode 100644 index 000000000..1fe8ee60e --- /dev/null +++ b/extensions/source/propctrlr/defaultforminspection.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 "defaultforminspection.hxx" +#include "pcrcommon.hxx" +#include +#include +#include "modulepcr.hxx" +#include "formmetadata.hxx" + +#include +#include +#include +#include + + +namespace pcr +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::inspection::PropertyCategoryDescriptor; + using ::com::sun::star::ucb::AlreadyInitializedException; + using ::com::sun::star::lang::IllegalArgumentException; + + DefaultFormComponentInspectorModel::DefaultFormComponentInspectorModel( bool _bUseFormFormComponentHandlers ) + :m_bUseFormComponentHandlers( _bUseFormFormComponentHandlers ) + ,m_bConstructed( false ) + ,m_pInfoService( new OPropertyInfoService ) + { + } + + + DefaultFormComponentInspectorModel::~DefaultFormComponentInspectorModel() + { + } + + + OUString SAL_CALL DefaultFormComponentInspectorModel::getImplementationName( ) + { + return "org.openoffice.comp.extensions.DefaultFormComponentInspectorModel"; + } + + + Sequence< OUString > SAL_CALL DefaultFormComponentInspectorModel::getSupportedServiceNames( ) + { + return { "com.sun.star.form.inspection.DefaultFormComponentInspectorModel" }; + } + + + Sequence< Any > SAL_CALL DefaultFormComponentInspectorModel::getHandlerFactories() + { + ::osl::MutexGuard aGuard( m_aMutex ); + + // service names for all our handlers + static struct + { + const char* serviceName; + bool isFormOnly; + } const aFactories[] = { + + // a generic handler for form component properties (must precede the ButtonNavigationHandler) + { "com.sun.star.form.inspection.FormComponentPropertyHandler", false }, + + // generic virtual edit properties + { "com.sun.star.form.inspection.EditPropertyHandler", false }, + + // a handler which virtualizes the ButtonType property, to provide additional types like + // "move to next record" + { "com.sun.star.form.inspection.ButtonNavigationHandler", false }, + + // a handler for script events bound to form components or dialog elements + { "com.sun.star.form.inspection.EventHandler", false }, + + // a handler which introduces virtual properties for binding controls to spreadsheet cells + { "com.sun.star.form.inspection.CellBindingPropertyHandler", false }, + + // properties related to binding to an XForms DOM node + { "com.sun.star.form.inspection.XMLFormsPropertyHandler", true }, + + // properties related to the XSD data against which a control content is validated + { "com.sun.star.form.inspection.XSDValidationPropertyHandler", true }, + + // a handler which cares for XForms submissions + { "com.sun.star.form.inspection.SubmissionPropertyHandler", true }, + + // a handler which cares for geometry properties of form controls + { "com.sun.star.form.inspection.FormGeometryHandler", true } + }; + + sal_Int32 nFactories = SAL_N_ELEMENTS( aFactories ); + Sequence< Any > aReturn( nFactories ); + Any* pReturn = aReturn.getArray(); + for ( sal_Int32 i = 0; i < nFactories; ++i ) + { + if ( aFactories[i].isFormOnly && !m_bUseFormComponentHandlers ) + continue; + *pReturn++ <<= OUString::createFromAscii( aFactories[i].serviceName ); + } + aReturn.realloc( pReturn - aReturn.getArray() ); + + return aReturn; + } + + + Sequence< PropertyCategoryDescriptor > SAL_CALL DefaultFormComponentInspectorModel::describeCategories( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + static struct + { + const char* programmaticName; + TranslateId uiNameResId; + rtl::OUStringConstExpr helpId; + } const aCategories[] = { + { "General", RID_STR_PROPPAGE_DEFAULT, HID_FM_PROPDLG_TAB_GENERAL }, + { "Data", RID_STR_PROPPAGE_DATA, HID_FM_PROPDLG_TAB_DATA }, + { "Events", RID_STR_EVENTS, HID_FM_PROPDLG_TAB_EVT } + }; + + sal_Int32 nCategories = SAL_N_ELEMENTS( aCategories ); + Sequence< PropertyCategoryDescriptor > aReturn( nCategories ); + PropertyCategoryDescriptor* pReturn = aReturn.getArray(); + for ( sal_Int32 i=0; iProgrammaticName = OUString::createFromAscii( aCategories[i].programmaticName ); + pReturn->UIName = PcrRes( aCategories[i].uiNameResId ); + pReturn->HelpURL = HelpIdUrl::getHelpURL( aCategories[i].helpId.asView() ); + } + + return aReturn; + } + + + ::sal_Int32 SAL_CALL DefaultFormComponentInspectorModel::getPropertyOrderIndex( const OUString& _rPropertyName ) + { + sal_Int32 nPropertyId( m_pInfoService->getPropertyId( _rPropertyName ) ); + if ( nPropertyId == -1 ) + { + if ( _rPropertyName.indexOf( ';' ) != -1 ) + // it's an event. Just give it an arbitrary number - events will be on a separate + // page, and by definition, if two properties have the same OrderIndex, then + // they will be ordered as they appear in the handler's getSupportedProperties. + return 1000; + return 0; + } + return m_pInfoService->getPropertyPos( nPropertyId ); + } + + + void SAL_CALL DefaultFormComponentInspectorModel::initialize( const Sequence< Any >& _arguments ) + { + if ( m_bConstructed ) + throw AlreadyInitializedException(); + + StlSyntaxSequence< Any > arguments( _arguments ); + if ( arguments.empty() ) + { // constructor: "createDefault()" + m_bConstructed = true; + return; + } + + if ( arguments.size() == 2 ) + { // constructor: "createWithHelpSection( long, long )" + sal_Int32 nMinHelpTextLines( 0 ), nMaxHelpTextLines( 0 ); + if ( !( arguments[0] >>= nMinHelpTextLines ) || !( arguments[1] >>= nMaxHelpTextLines ) ) + throw IllegalArgumentException( OUString(), *this, 0 ); + createWithHelpSection( nMinHelpTextLines, nMaxHelpTextLines ); + return; + } + + throw IllegalArgumentException( OUString(), *this, 0 ); + } + + + void DefaultFormComponentInspectorModel::createWithHelpSection( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines ) + { + if ( ( _nMinHelpTextLines <= 0 ) || ( _nMaxHelpTextLines <= 0 ) || ( _nMinHelpTextLines > _nMaxHelpTextLines ) ) + throw IllegalArgumentException( OUString(), *this, 0 ); + + enableHelpSectionProperties( _nMinHelpTextLines, _nMaxHelpTextLines ); + m_bConstructed = true; + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_DefaultFormComponentInspectorModel_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::DefaultFormComponentInspectorModel(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/defaultforminspection.hxx b/extensions/source/propctrlr/defaultforminspection.hxx new file mode 100644 index 000000000..e118e9da6 --- /dev/null +++ b/extensions/source/propctrlr/defaultforminspection.hxx @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "inspectormodelbase.hxx" + +#include + + +namespace pcr +{ + + + class OPropertyInfoService; + + class DefaultFormComponentInspectorModel final : public ImplInspectorModel + { + bool m_bUseFormComponentHandlers; + bool m_bConstructed; + + /// access to property meta data + std::unique_ptr< OPropertyInfoService > m_pInfoService; + + virtual ~DefaultFormComponentInspectorModel() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XObjectInspectorModel + virtual css::uno::Sequence< css::uno::Any > SAL_CALL getHandlerFactories() override; + virtual css::uno::Sequence< css::inspection::PropertyCategoryDescriptor > SAL_CALL describeCategories( ) override; + virtual ::sal_Int32 SAL_CALL getPropertyOrderIndex( const OUString& PropertyName ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + public: + explicit DefaultFormComponentInspectorModel( bool _bUseFormFormComponentHandlers = true ); + + private: + // Service constructors + void createWithHelpSection( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines ); + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/defaulthelpprovider.cxx b/extensions/source/propctrlr/defaulthelpprovider.cxx new file mode 100644 index 000000000..8f1e22b82 --- /dev/null +++ b/extensions/source/propctrlr/defaulthelpprovider.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 "defaulthelpprovider.hxx" +#include "pcrcommon.hxx" + +#include +#include +#include + +#include +#include +#include +#include + + +namespace pcr +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::inspection::XPropertyControl; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::inspection::XObjectInspectorUI; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::ucb::AlreadyInitializedException; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::awt::XWindow; + + DefaultHelpProvider::DefaultHelpProvider() + :m_bConstructed( false ) + { + } + + + DefaultHelpProvider::~DefaultHelpProvider() + { + } + + + Sequence< OUString > SAL_CALL DefaultHelpProvider::getSupportedServiceNames() + { + return { "com.sun.star.inspection.DefaultHelpProvider" }; + } + + OUString SAL_CALL DefaultHelpProvider::getImplementationName() + { + return "org.openoffice.comp.extensions.DefaultHelpProvider"; + } + + sal_Bool SAL_CALL DefaultHelpProvider::supportsService(const OUString& aServiceName) + { + return cppu::supportsService(this, aServiceName); + } + + + void SAL_CALL DefaultHelpProvider::focusGained( const Reference< XPropertyControl >& Control ) + { + if ( !m_xInspectorUI.is() ) + throw RuntimeException( OUString(), *this ); + + try + { + m_xInspectorUI->setHelpSectionText( impl_getHelpText_nothrow( Control ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + void SAL_CALL DefaultHelpProvider::valueChanged( const Reference< XPropertyControl >& ) + { + // not interested in + } + + + void SAL_CALL DefaultHelpProvider::initialize( const Sequence< Any >& _arguments ) + { + if ( m_bConstructed ) + throw AlreadyInitializedException(); + + StlSyntaxSequence< Any > arguments( _arguments ); + if ( arguments.size() == 1 ) + { // constructor: "create( XObjectInspectorUI )" + Reference< XObjectInspectorUI > xUI( arguments[0], UNO_QUERY ); + create( xUI ); + return; + } + + throw IllegalArgumentException( OUString(), *this, 0 ); + } + + + void DefaultHelpProvider::create( const Reference< XObjectInspectorUI >& _rxUI ) + { + if ( !_rxUI.is() ) + throw IllegalArgumentException( OUString(), *this, 1 ); + + try + { + m_xInspectorUI = _rxUI; + m_xInspectorUI->registerControlObserver( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + m_bConstructed = true; + } + + + vcl::Window* DefaultHelpProvider::impl_getVclControlWindow_nothrow( const Reference< XPropertyControl >& _rxControl ) + { + vcl::Window* pControlWindow = nullptr; + OSL_PRECOND( _rxControl.is(), "DefaultHelpProvider::impl_getVclControlWindow_nothrow: illegal control!" ); + if ( !_rxControl.is() ) + return pControlWindow; + + try + { + Reference< XWindow > xControlWindow( _rxControl->getControlWindow(), css::uno::UNO_SET_THROW ); + pControlWindow = VCLUnoHelper::GetWindow( xControlWindow ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + return pControlWindow; + } + + + OUString DefaultHelpProvider::impl_getHelpText_nothrow( const Reference< XPropertyControl >& _rxControl ) + { + OUString sHelpText; + OSL_PRECOND( _rxControl.is(), "DefaultHelpProvider::impl_getHelpText_nothrow: illegal control!" ); + if ( !_rxControl.is() ) + return sHelpText; + + vcl::Window* pControlWindow( impl_getVclControlWindow_nothrow( _rxControl ) ); + OSL_ENSURE( pControlWindow, "DefaultHelpProvider::impl_getHelpText_nothrow: could not determine the VCL window!" ); + if ( !pControlWindow ) + return sHelpText; + + sHelpText = pControlWindow->GetHelpText(); + return sHelpText; + } + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_DefaultHelpProvider_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::DefaultHelpProvider()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/defaulthelpprovider.hxx b/extensions/source/propctrlr/defaulthelpprovider.hxx new file mode 100644 index 000000000..f647937dd --- /dev/null +++ b/extensions/source/propctrlr/defaulthelpprovider.hxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include +#include + +#include + +namespace vcl { class Window; } + + +namespace pcr +{ + + + //= DefaultHelpProvider + + typedef ::cppu::WeakImplHelper < css::inspection::XPropertyControlObserver + , css::lang::XInitialization + , css::lang::XServiceInfo + > DefaultHelpProvider_Base; + class DefaultHelpProvider final : public DefaultHelpProvider_Base + { + private: + bool m_bConstructed; + css::uno::Reference< css::inspection::XObjectInspectorUI > + m_xInspectorUI; + + public: + DefaultHelpProvider(); + + private: + virtual ~DefaultHelpProvider() 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; + + // XPropertyControlObserver + virtual void SAL_CALL focusGained( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) override; + virtual void SAL_CALL valueChanged( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // Service constructors + void create( const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxUI ); + + static vcl::Window* impl_getVclControlWindow_nothrow( const css::uno::Reference< css::inspection::XPropertyControl >& _rxControl ); + static OUString impl_getHelpText_nothrow( const css::uno::Reference< css::inspection::XPropertyControl >& _rxControl ); + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/editpropertyhandler.cxx b/extensions/source/propctrlr/editpropertyhandler.cxx new file mode 100644 index 000000000..22ad04988 --- /dev/null +++ b/extensions/source/propctrlr/editpropertyhandler.cxx @@ -0,0 +1,308 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "editpropertyhandler.hxx" +#include "formstrings.hxx" +#include "formmetadata.hxx" + +#include +#include +#include + +#define TEXTTYPE_SINGLELINE 0 +#define TEXTTYPE_MULTILINE 1 +#define TEXTTYPE_RICHTEXT 2 + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::inspection; + + + //= EditPropertyHandler + + + EditPropertyHandler::EditPropertyHandler( const Reference< XComponentContext >& _rxContext ) + :PropertyHandlerComponent( _rxContext ) + { + } + + + EditPropertyHandler::~EditPropertyHandler( ) + { + } + + + OUString EditPropertyHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.EditPropertyHandler"; + } + + + Sequence< OUString > EditPropertyHandler::getSupportedServiceNames( ) + { + return { "com.sun.star.form.inspection.EditPropertyHandler" }; + } + + + Any SAL_CALL EditPropertyHandler::getPropertyValue( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + Any aReturn; + try + { + switch ( nPropId ) + { + case PROPERTY_ID_SHOW_SCROLLBARS: + { + bool bHasVScroll = false; + m_xComponent->getPropertyValue( PROPERTY_VSCROLL ) >>= bHasVScroll; + bool bHasHScroll = false; + m_xComponent->getPropertyValue( PROPERTY_HSCROLL ) >>= bHasHScroll; + + aReturn <<= static_cast( ( bHasVScroll ? 2 : 0 ) + ( bHasHScroll ? 1 : 0 ) ); + } + break; + + case PROPERTY_ID_TEXTTYPE: + { + sal_Int32 nTextType = TEXTTYPE_SINGLELINE; + bool bRichText = false; + OSL_VERIFY( m_xComponent->getPropertyValue( PROPERTY_RICHTEXT ) >>= bRichText ); + if ( bRichText ) + nTextType = TEXTTYPE_RICHTEXT; + else + { + bool bMultiLine = false; + OSL_VERIFY( m_xComponent->getPropertyValue( PROPERTY_MULTILINE ) >>= bMultiLine ); + if ( bMultiLine ) + nTextType = TEXTTYPE_MULTILINE; + else + nTextType = TEXTTYPE_SINGLELINE; + } + aReturn <<= nTextType; + } + break; + + + default: + OSL_FAIL( "EditPropertyHandler::getPropertyValue: cannot handle this property!" ); + break; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EditPropertyHandler::getPropertyValue" ); + } + + return aReturn; + } + + + void SAL_CALL EditPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + try + { + switch ( nPropId ) + { + case PROPERTY_ID_SHOW_SCROLLBARS: + { + sal_Int32 nScrollbars = 0; + _rValue >>= nScrollbars; + + bool bHasVScroll = 0 != ( nScrollbars & 2 ); + bool bHasHScroll = 0 != ( nScrollbars & 1 ); + + m_xComponent->setPropertyValue( PROPERTY_VSCROLL, Any( bHasVScroll ) ); + m_xComponent->setPropertyValue( PROPERTY_HSCROLL, Any( bHasHScroll ) ); + } + break; + + case PROPERTY_ID_TEXTTYPE: + { + bool bMultiLine = false; + bool bRichText = false; + sal_Int32 nTextType = TEXTTYPE_SINGLELINE; + OSL_VERIFY( _rValue >>= nTextType ); + switch ( nTextType ) + { + case TEXTTYPE_SINGLELINE: bMultiLine = bRichText = false; break; + case TEXTTYPE_MULTILINE: bMultiLine = true; bRichText = false; break; + case TEXTTYPE_RICHTEXT: bMultiLine = true; bRichText = true; break; + default: + OSL_FAIL( "EditPropertyHandler::setPropertyValue: invalid text type!" ); + } + + m_xComponent->setPropertyValue( PROPERTY_MULTILINE, Any( bMultiLine ) ); + m_xComponent->setPropertyValue( PROPERTY_RICHTEXT, Any( bRichText ) ); + } + break; + + default: + OSL_FAIL( "EditPropertyHandler::setPropertyValue: cannot handle this id!" ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EditPropertyHandler::setPropertyValue" ); + } + } + + + bool EditPropertyHandler::implHaveBothScrollBarProperties() const + { + // have a "Scrollbars" property if the object supports both "HScroll" and "VScroll" + Reference< XPropertySetInfo > xPSI; + if ( m_xComponent.is() ) + xPSI = m_xComponent->getPropertySetInfo(); + + return xPSI.is() + && xPSI->hasPropertyByName( PROPERTY_HSCROLL ) + && xPSI->hasPropertyByName( PROPERTY_VSCROLL ); + } + + + bool EditPropertyHandler::implHaveTextTypeProperty() const + { + // have a "Scrollbars" property if the object supports both "HScroll" and "VScroll" + Reference< XPropertySetInfo > xPSI; + if ( m_xComponent.is() ) + xPSI = m_xComponent->getPropertySetInfo(); + + return xPSI.is() + && xPSI->hasPropertyByName( PROPERTY_RICHTEXT ) + && xPSI->hasPropertyByName( PROPERTY_MULTILINE ); + } + + + Sequence< Property > EditPropertyHandler::doDescribeSupportedProperties() const + { + std::vector< Property > aProperties; + + if ( implHaveBothScrollBarProperties() ) + addInt32PropertyDescription( aProperties, PROPERTY_SHOW_SCROLLBARS ); + + if ( implHaveTextTypeProperty() ) + addInt32PropertyDescription( aProperties, PROPERTY_TEXTTYPE ); + + if ( aProperties.empty() ) + return Sequence< Property >(); + return comphelper::containerToSequence(aProperties); + } + + + Sequence< OUString > SAL_CALL EditPropertyHandler::getSupersededProperties( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + std::vector< OUString > aSuperseded; + if ( implHaveBothScrollBarProperties() ) + { + aSuperseded.push_back( PROPERTY_HSCROLL ); + aSuperseded.push_back( PROPERTY_VSCROLL ); + } + if ( implHaveTextTypeProperty() ) + { + aSuperseded.push_back( PROPERTY_RICHTEXT ); + aSuperseded.push_back( PROPERTY_MULTILINE ); + } + if ( aSuperseded.empty() ) + return Sequence< OUString >(); + return comphelper::containerToSequence(aSuperseded); + } + + + Sequence< OUString > SAL_CALL EditPropertyHandler::getActuatingProperties( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + std::vector< OUString > aInterestingActuatingProps; + if ( implHaveTextTypeProperty() ) + aInterestingActuatingProps.push_back( PROPERTY_TEXTTYPE ); + aInterestingActuatingProps.push_back( PROPERTY_MULTILINE ); + return comphelper::containerToSequence(aInterestingActuatingProps); + } + + + void SAL_CALL EditPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) ); + switch ( nActuatingPropId ) + { + case PROPERTY_ID_TEXTTYPE: + { + sal_Int32 nTextType = TEXTTYPE_SINGLELINE; + getPropertyValue( PROPERTY_TEXTTYPE ) >>= nTextType; + + if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_WORDBREAK ) ) + _rxInspectorUI->enablePropertyUI( PROPERTY_WORDBREAK, nTextType == TEXTTYPE_RICHTEXT ); + _rxInspectorUI->enablePropertyUI( PROPERTY_MAXTEXTLEN, nTextType != TEXTTYPE_RICHTEXT ); + _rxInspectorUI->enablePropertyUI( PROPERTY_ECHO_CHAR, nTextType == TEXTTYPE_SINGLELINE ); + _rxInspectorUI->enablePropertyUI( PROPERTY_FONT, nTextType != TEXTTYPE_RICHTEXT ); + _rxInspectorUI->enablePropertyUI( PROPERTY_ALIGN, nTextType != TEXTTYPE_RICHTEXT ); + _rxInspectorUI->enablePropertyUI( PROPERTY_DEFAULT_TEXT, nTextType != TEXTTYPE_RICHTEXT ); + _rxInspectorUI->enablePropertyUI( PROPERTY_SHOW_SCROLLBARS, nTextType != TEXTTYPE_SINGLELINE ); + _rxInspectorUI->enablePropertyUI( PROPERTY_LINEEND_FORMAT, nTextType != TEXTTYPE_SINGLELINE ); + _rxInspectorUI->enablePropertyUI( PROPERTY_VERTICAL_ALIGN, nTextType == TEXTTYPE_SINGLELINE ); + + _rxInspectorUI->showCategory( "Data", nTextType != TEXTTYPE_RICHTEXT ); + } + break; + + case PROPERTY_ID_MULTILINE: + { + bool bIsMultiline = false; + _rNewValue >>= bIsMultiline; + + _rxInspectorUI->enablePropertyUI( PROPERTY_SHOW_SCROLLBARS, bIsMultiline ); + _rxInspectorUI->enablePropertyUI( PROPERTY_ECHO_CHAR, !bIsMultiline ); + _rxInspectorUI->enablePropertyUI( PROPERTY_LINEEND_FORMAT, bIsMultiline ); + } + break; + + default: + OSL_FAIL( "EditPropertyHandler::actuatingPropertyChanged: cannot handle this id!" ); + } + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_EditPropertyHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::EditPropertyHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/editpropertyhandler.hxx b/extensions/source/propctrlr/editpropertyhandler.hxx new file mode 100644 index 000000000..33ad8df98 --- /dev/null +++ b/extensions/source/propctrlr/editpropertyhandler.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "propertyhandler.hxx" + + +namespace pcr +{ + + + //= EditPropertyHandler + + class EditPropertyHandler; + /** a property handler for any virtual string properties + */ + class EditPropertyHandler : public PropertyHandlerComponent + { + public: + explicit EditPropertyHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + protected: + virtual ~EditPropertyHandler() override; + + protected: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override; + + // XPropertyHandler overriables + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupersededProperties( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) override; + + // PropertyHandler overridables + virtual css::uno::Sequence< css::beans::Property > + doDescribeSupportedProperties() const override; + private: + bool implHaveBothScrollBarProperties() const; + bool implHaveTextTypeProperty() const; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/eformshelper.cxx b/extensions/source/propctrlr/eformshelper.cxx new file mode 100644 index 000000000..620368e9d --- /dev/null +++ b/extensions/source/propctrlr/eformshelper.cxx @@ -0,0 +1,762 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "eformshelper.hxx" +#include "formstrings.hxx" +#include +#include "modulepcr.hxx" +#include "propeventtranslation.hxx" +#include "formbrowsertools.hxx" + +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace pcr +{ + + + 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::form::binding; + using namespace ::com::sun::star::xsd; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::form; + + + //= file-local helpers + + namespace + { + + OUString composeModelElementUIName( std::u16string_view _rModelName, std::u16string_view _rElementName ) + { + OUString a = OUString::Concat("[") + + _rModelName + "] " + + _rElementName; + return a; + } + } + + + //= EFormsHelper + + + EFormsHelper::EFormsHelper( ::osl::Mutex& _rMutex, const Reference< XPropertySet >& _rxControlModel, const Reference< frame::XModel >& _rxContextDocument ) + :m_xControlModel( _rxControlModel ) + ,m_aPropertyListeners( _rMutex ) + { + OSL_ENSURE( _rxControlModel.is(), "EFormsHelper::EFormsHelper: invalid control model!" ); + m_xBindableControl.set(_rxControlModel, css::uno::UNO_QUERY); + + m_xDocument.set(_rxContextDocument, css::uno::UNO_QUERY); + OSL_ENSURE( m_xDocument.is(), "EFormsHelper::EFormsHelper: invalid document!" ); + + } + + + bool EFormsHelper::isEForm( const Reference< frame::XModel >& _rxContextDocument ) + { + try + { + Reference< xforms::XFormsSupplier > xDocument( _rxContextDocument, UNO_QUERY ); + if ( !xDocument.is() ) + return false; + + return xDocument->getXForms().is(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::isEForm" ); + } + return false; + } + + + bool EFormsHelper::canBindToDataType( sal_Int32 _nDataType ) const + { + if ( !m_xBindableControl.is() ) + // cannot bind at all + return false; + + // some types cannot be bound, independent from the control type + if ( ( DataTypeClass::hexBinary == _nDataType ) + || ( DataTypeClass::base64Binary == _nDataType ) + || ( DataTypeClass::QName == _nDataType ) + || ( DataTypeClass::NOTATION == _nDataType ) + ) + return false; + + bool bCan = false; + try + { + // classify the control model + sal_Int16 nControlType = FormComponentType::CONTROL; + OSL_VERIFY( m_xControlModel->getPropertyValue( PROPERTY_CLASSID ) >>= nControlType ); + + // some lists + sal_Int16 const nNumericCompatibleTypes[] = { DataTypeClass::DECIMAL, DataTypeClass::FLOAT, DataTypeClass::DOUBLE, 0 }; + sal_Int16 const nDateCompatibleTypes[] = { DataTypeClass::DATE, 0 }; + sal_Int16 const nTimeCompatibleTypes[] = { DataTypeClass::TIME, 0 }; + sal_Int16 const nCheckboxCompatibleTypes[] = { DataTypeClass::BOOLEAN, DataTypeClass::STRING, DataTypeClass::anyURI, 0 }; + sal_Int16 const nRadiobuttonCompatibleTypes[] = { DataTypeClass::STRING, DataTypeClass::anyURI, 0 }; + sal_Int16 const nFormattedCompatibleTypes[] = { DataTypeClass::DECIMAL, DataTypeClass::FLOAT, DataTypeClass::DOUBLE, DataTypeClass::DATETIME, DataTypeClass::DATE, DataTypeClass::TIME, 0 }; + + sal_Int16 const * pCompatibleTypes = nullptr; + switch ( nControlType ) + { + case FormComponentType::SPINBUTTON: + case FormComponentType::NUMERICFIELD: + pCompatibleTypes = nNumericCompatibleTypes; + break; + case FormComponentType::DATEFIELD: + pCompatibleTypes = nDateCompatibleTypes; + break; + case FormComponentType::TIMEFIELD: + pCompatibleTypes = nTimeCompatibleTypes; + break; + case FormComponentType::CHECKBOX: + pCompatibleTypes = nCheckboxCompatibleTypes; + break; + case FormComponentType::RADIOBUTTON: + pCompatibleTypes = nRadiobuttonCompatibleTypes; + break; + + case FormComponentType::TEXTFIELD: + { + // both the normal text field, and the formatted field, claim to be a TEXTFIELD + // need to distinguish by service name + Reference< XServiceInfo > xSI( m_xControlModel, UNO_QUERY ); + OSL_ENSURE( xSI.is(), "EFormsHelper::canBindToDataType: a control model which has no service info?" ); + if ( xSI.is() ) + { + if ( xSI->supportsService( SERVICE_COMPONENT_FORMATTEDFIELD ) ) + { + pCompatibleTypes = nFormattedCompatibleTypes; + break; + } + } + [[fallthrough]]; + } + case FormComponentType::LISTBOX: + case FormComponentType::COMBOBOX: + // edit fields and list/combo boxes can be bound to anything + bCan = true; + } + + if ( !bCan && pCompatibleTypes ) + { + if ( _nDataType == -1 ) + { + // the control can be bound to at least one type, and exactly this is being asked for + bCan = true; + } + else + { + while ( *pCompatibleTypes && !bCan ) + bCan = ( *pCompatibleTypes++ == _nDataType ); + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::canBindToDataType" ); + } + + return bCan; + } + + + bool EFormsHelper::isListEntrySink() const + { + bool bIs = false; + try + { + Reference< XListEntrySink > xAsSink( m_xControlModel, UNO_QUERY ); + bIs = xAsSink.is(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::isListEntrySink" ); + } + return bIs; + } + + + void EFormsHelper::impl_switchBindingListening_throw( bool _bDoListening, const Reference< XPropertyChangeListener >& _rxListener ) + { + Reference< XPropertySet > xBindingProps; + if ( m_xBindableControl.is() ) + xBindingProps.set(m_xBindableControl->getValueBinding(), css::uno::UNO_QUERY); + if ( !xBindingProps.is() ) + return; + + if ( _bDoListening ) + { + xBindingProps->addPropertyChangeListener( OUString(), _rxListener ); + } + else + { + xBindingProps->removePropertyChangeListener( OUString(), _rxListener ); + } + } + + + void EFormsHelper::registerBindingListener( const Reference< XPropertyChangeListener >& _rxBindingListener ) + { + if ( !_rxBindingListener.is() ) + return; + impl_toggleBindingPropertyListening_throw( true, _rxBindingListener ); + } + + + void EFormsHelper::impl_toggleBindingPropertyListening_throw( bool _bDoListen, const Reference< XPropertyChangeListener >& _rxConcreteListenerOrNull ) + { + if ( !_bDoListen ) + { + ::comphelper::OInterfaceIteratorHelper3 aListenerIterator(m_aPropertyListeners); + while ( aListenerIterator.hasMoreElements() ) + { + PropertyEventTranslation* pTranslator = dynamic_cast< PropertyEventTranslation* >( aListenerIterator.next().get() ); + OSL_ENSURE( pTranslator, "EFormsHelper::impl_toggleBindingPropertyListening_throw: invalid listener element in my container!" ); + if ( !pTranslator ) + continue; + + Reference< XPropertyChangeListener > xEventSourceTranslator( pTranslator ); + if ( _rxConcreteListenerOrNull.is() ) + { + if ( pTranslator->getDelegator() == _rxConcreteListenerOrNull ) + { + impl_switchBindingListening_throw( false, xEventSourceTranslator ); + m_aPropertyListeners.removeInterface( xEventSourceTranslator ); + break; + } + } + else + { + impl_switchBindingListening_throw( false, xEventSourceTranslator ); + } + } + } + else + { + if ( _rxConcreteListenerOrNull.is() ) + { + Reference< XPropertyChangeListener > xEventSourceTranslator( new PropertyEventTranslation( _rxConcreteListenerOrNull, m_xBindableControl ) ); + m_aPropertyListeners.addInterface( xEventSourceTranslator ); + impl_switchBindingListening_throw( true, xEventSourceTranslator ); + } + else + { + ::comphelper::OInterfaceIteratorHelper3 aListenerIterator(m_aPropertyListeners); + while ( aListenerIterator.hasMoreElements() ) + impl_switchBindingListening_throw( true, aListenerIterator.next() ); + } + } + } + + + void EFormsHelper::revokeBindingListener( const Reference< XPropertyChangeListener >& _rxBindingListener ) + { + impl_toggleBindingPropertyListening_throw( false, _rxBindingListener ); + } + + + void EFormsHelper::getFormModelNames( std::vector< OUString >& /* [out] */ _rModelNames ) const + { + if ( !m_xDocument.is() ) + return; + + try + { + _rModelNames.resize( 0 ); + + Reference< XNameContainer > xForms( m_xDocument->getXForms() ); + OSL_ENSURE( xForms.is(), "EFormsHelper::getFormModelNames: invalid forms container!" ); + if ( xForms.is() ) + { + const Sequence< OUString > aModelNames = xForms->getElementNames(); + _rModelNames.resize( aModelNames.getLength() ); + std::copy( aModelNames.begin(), aModelNames.end(), _rModelNames.begin() ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getFormModelNames" ); + } + } + + + void EFormsHelper::getBindingNames( const OUString& _rModelName, std::vector< OUString >& /* [out] */ _rBindingNames ) const + { + _rBindingNames.resize( 0 ); + try + { + Reference< xforms::XModel > xModel( getFormModelByName( _rModelName ) ); + if ( xModel.is() ) + { + Reference< XNameAccess > xBindings( xModel->getBindings(), UNO_QUERY ); + OSL_ENSURE( xBindings.is(), "EFormsHelper::getBindingNames: invalid bindings container obtained from the model!" ); + if ( xBindings.is() ) + { + const Sequence< OUString > aNames = xBindings->getElementNames(); + _rBindingNames.resize( aNames.getLength() ); + std::copy( aNames.begin(), aNames.end(), _rBindingNames.begin() ); + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getBindingNames" ); + } + } + + + Reference< xforms::XModel > EFormsHelper::getFormModelByName( const OUString& _rModelName ) const + { + Reference< xforms::XModel > xReturn; + try + { + Reference< XNameContainer > xForms( m_xDocument->getXForms() ); + OSL_ENSURE( xForms.is(), "EFormsHelper::getFormModelByName: invalid forms container!" ); + if ( xForms.is() ) + OSL_VERIFY( xForms->getByName( _rModelName ) >>= xReturn ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getFormModelByName" ); + } + return xReturn; + } + + + Reference< xforms::XModel > EFormsHelper::getCurrentFormModel() const + { + Reference< xforms::XModel > xModel; + try + { + Reference< XPropertySet > xBinding( getCurrentBinding() ); + if ( xBinding.is() ) + { + OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_MODEL ) >>= xModel ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentFormModel" ); + } + return xModel; + } + + + OUString EFormsHelper::getCurrentFormModelName() const + { + OUString sModelName; + try + { + Reference< xforms::XModel > xFormsModel( getCurrentFormModel() ); + if ( xFormsModel.is() ) + sModelName = xFormsModel->getID(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentFormModel" ); + } + return sModelName; + } + + + Reference< XPropertySet > EFormsHelper::getCurrentBinding() const + { + Reference< XPropertySet > xBinding; + + try + { + if ( m_xBindableControl.is() ) + xBinding.set(m_xBindableControl->getValueBinding(), css::uno::UNO_QUERY); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentBinding" ); + } + + return xBinding; + } + + + OUString EFormsHelper::getCurrentBindingName() const + { + OUString sBindingName; + try + { + Reference< XPropertySet > xBinding( getCurrentBinding() ); + if ( xBinding.is() ) + xBinding->getPropertyValue( PROPERTY_BINDING_ID ) >>= sBindingName; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentBindingName" ); + } + return sBindingName; + } + + + Reference< XListEntrySource > EFormsHelper::getCurrentListSourceBinding() const + { + Reference< XListEntrySource > xReturn; + try + { + Reference< XListEntrySink > xAsSink( m_xControlModel, UNO_QUERY ); + OSL_ENSURE( xAsSink.is(), "EFormsHelper::getCurrentListSourceBinding: you should have used isListEntrySink before!" ); + if ( xAsSink.is() ) + xReturn = xAsSink->getListEntrySource(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getCurrentListSourceBinding" ); + } + return xReturn; + } + + + void EFormsHelper::setListSourceBinding( const Reference< XListEntrySource >& _rxListSource ) + { + try + { + Reference< XListEntrySink > xAsSink( m_xControlModel, UNO_QUERY ); + OSL_ENSURE( xAsSink.is(), "EFormsHelper::setListSourceBinding: you should have used isListEntrySink before!" ); + if ( xAsSink.is() ) + xAsSink->setListEntrySource( _rxListSource ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::setListSourceBinding" ); + } + } + + + void EFormsHelper::setBinding( const Reference< css::beans::XPropertySet >& _rxBinding ) + { + if ( !m_xBindableControl.is() ) + return; + + try + { + Reference< XPropertySet > xOldBinding( m_xBindableControl->getValueBinding(), UNO_QUERY ); + + Reference< XValueBinding > xBinding( _rxBinding, UNO_QUERY ); + OSL_ENSURE( xBinding.is() || !_rxBinding.is(), "EFormsHelper::setBinding: invalid binding!" ); + + impl_toggleBindingPropertyListening_throw( false, nullptr ); + m_xBindableControl->setValueBinding( xBinding ); + impl_toggleBindingPropertyListening_throw( true, nullptr ); + + std::set< OUString > aSet; + firePropertyChanges( xOldBinding, _rxBinding, aSet ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::setBinding" ); + } + } + + + Reference< XPropertySet > EFormsHelper::getOrCreateBindingForModel( const OUString& _rTargetModel, const OUString& _rBindingName ) const + { + OSL_ENSURE( !_rBindingName.isEmpty(), "EFormsHelper::getOrCreateBindingForModel: invalid binding name!" ); + return implGetOrCreateBinding( _rTargetModel, _rBindingName ); + } + + + Reference< XPropertySet > EFormsHelper::implGetOrCreateBinding( const OUString& _rTargetModel, const OUString& _rBindingName ) const + { + OSL_ENSURE( !( _rTargetModel.isEmpty() && !_rBindingName.isEmpty() ), "EFormsHelper::implGetOrCreateBinding: no model, but a binding name?" ); + + Reference< XPropertySet > xBinding; + try + { + OUString sTargetModel( _rTargetModel ); + // determine the model which the binding should belong to + if ( sTargetModel.isEmpty() ) + { + std::vector< OUString > aModelNames; + getFormModelNames( aModelNames ); + if ( !aModelNames.empty() ) + sTargetModel = *aModelNames.begin(); + OSL_ENSURE( !sTargetModel.isEmpty(), "EFormsHelper::implGetOrCreateBinding: unable to obtain a default model!" ); + } + Reference< xforms::XModel > xModel( getFormModelByName( sTargetModel ) ); + Reference< XNameAccess > xBindingNames( xModel.is() ? xModel->getBindings() : Reference< XSet >(), UNO_QUERY ); + if ( xBindingNames.is() ) + { + // get or create the binding instance + if ( !_rBindingName.isEmpty() ) + { + if ( xBindingNames->hasByName( _rBindingName ) ) + OSL_VERIFY( xBindingNames->getByName( _rBindingName ) >>= xBinding ); + else + { + xBinding = xModel->createBinding( ); + if ( xBinding.is() ) + { + xBinding->setPropertyValue( PROPERTY_BINDING_ID, Any( _rBindingName ) ); + xModel->getBindings()->insert( Any( xBinding ) ); + } + } + } + else + { + xBinding = xModel->createBinding( ); + if ( xBinding.is() ) + { + // find a nice name for it + OUString sBaseName(PcrRes(RID_STR_BINDING_NAME) + " "); + OUString sNewName; + sal_Int32 nNumber = 1; + do + { + sNewName = sBaseName + OUString::number( nNumber++ ); + } + while ( xBindingNames->hasByName( sNewName ) ); + Reference< XNamed > xName( xBinding, UNO_QUERY_THROW ); + xName->setName( sNewName ); + // and insert into the model + xModel->getBindings()->insert( Any( xBinding ) ); + } + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + return xBinding; + } + + + namespace + { + + struct PropertyBagInserter + { + private: + PropertyBag& m_rProperties; + + public: + explicit PropertyBagInserter( PropertyBag& rProperties ) : m_rProperties( rProperties ) { } + + void operator()( const Property& _rProp ) + { + m_rProperties.insert( _rProp ); + } + }; + + + Reference< XPropertySetInfo > collectPropertiesGetInfo( const Reference< XPropertySet >& _rxProps, PropertyBag& _rBag ) + { + Reference< XPropertySetInfo > xInfo; + if ( _rxProps.is() ) + xInfo = _rxProps->getPropertySetInfo(); + if ( xInfo.is() ) + { + const Sequence< Property > aProperties = xInfo->getProperties(); + std::for_each( aProperties.begin(), aProperties.end(), + PropertyBagInserter( _rBag ) + ); + } + return xInfo; + } + } + + + OUString EFormsHelper::getModelElementUIName( const EFormsHelper::ModelElementType _eType, const Reference< XPropertySet >& _rxElement ) + { + OUString sUIName; + try + { + // determine the model which the element belongs to + Reference< xforms::XFormsUIHelper1 > xHelper; + if ( _rxElement.is() ) + _rxElement->getPropertyValue( PROPERTY_MODEL ) >>= xHelper; + OSL_ENSURE( xHelper.is(), "EFormsHelper::getModelElementUIName: invalid element or model!" ); + if ( xHelper.is() ) + { + OUString sElementName = ( _eType == Submission ) ? xHelper->getSubmissionName( _rxElement, true ) : xHelper->getBindingName( _rxElement, true ); + Reference< xforms::XModel > xModel( xHelper, UNO_QUERY_THROW ); + sUIName = composeModelElementUIName( xModel->getID(), sElementName ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getModelElementUIName" ); + } + + return sUIName; + } + + + Reference< XPropertySet > EFormsHelper::getModelElementFromUIName( const EFormsHelper::ModelElementType _eType, const OUString& _rUIName ) const + { + const MapStringToPropertySet& rMapUINameToElement( ( _eType == Submission ) ? m_aSubmissionUINames : m_aBindingUINames ); + MapStringToPropertySet::const_iterator pos = rMapUINameToElement.find( _rUIName ); + OSL_ENSURE( pos != rMapUINameToElement.end(), "EFormsHelper::getModelElementFromUIName: didn't find it!" ); + + return ( pos != rMapUINameToElement.end() ) ? pos->second : Reference< XPropertySet >(); + } + + + void EFormsHelper::getAllElementUINames( const ModelElementType _eType, std::vector< OUString >& /* [out] */ _rElementNames, bool _bPrepentEmptyEntry ) + { + MapStringToPropertySet& rMapUINameToElement( ( _eType == Submission ) ? m_aSubmissionUINames : m_aBindingUINames ); + rMapUINameToElement.clear(); + _rElementNames.resize( 0 ); + + if ( _bPrepentEmptyEntry ) + rMapUINameToElement[ OUString() ].clear(); + + try + { + // obtain the model names + std::vector< OUString > aModels; + getFormModelNames( aModels ); + _rElementNames.reserve( aModels.size() * 2 ); // heuristics + + // for every model, obtain the element + for (auto const& modelName : aModels) + { + Reference< xforms::XModel > xModel = getFormModelByName(modelName); + OSL_ENSURE( xModel.is(), "EFormsHelper::getAllElementUINames: inconsistency in the models!" ); + Reference< xforms::XFormsUIHelper1 > xHelper( xModel, UNO_QUERY ); + + Reference< XIndexAccess > xElements; + if ( xModel.is() ) + xElements.set(( _eType == Submission ) ? xModel->getSubmissions() : xModel->getBindings(), css::uno::UNO_QUERY); + if ( !xElements.is() ) + break; + + sal_Int32 nElementCount = xElements->getCount(); + for ( sal_Int32 i = 0; i < nElementCount; ++i ) + { + Reference< XPropertySet > xElement( xElements->getByIndex( i ), UNO_QUERY ); + OSL_ENSURE( xElement.is(), "EFormsHelper::getAllElementUINames: empty element!" ); + if ( !xElement.is() ) + continue; +#if OSL_DEBUG_LEVEL > 0 + { + Reference< xforms::XModel > xElementsModel; + xElement->getPropertyValue( PROPERTY_MODEL ) >>= xElementsModel; + OSL_ENSURE( xElementsModel == xModel, "EFormsHelper::getAllElementUINames: inconsistency in the model-element relationship!" ); + if ( xElementsModel != xModel ) + xElement->setPropertyValue( PROPERTY_MODEL, Any( xModel ) ); + } +#endif + OUString sElementName = ( _eType == Submission ) ? xHelper->getSubmissionName( xElement, true ) : xHelper->getBindingName( xElement, true ); + OUString sUIName = composeModelElementUIName( modelName, sElementName ); + + OSL_ENSURE( rMapUINameToElement.find( sUIName ) == rMapUINameToElement.end(), "EFormsHelper::getAllElementUINames: duplicate name!" ); + rMapUINameToElement.emplace( sUIName, xElement ); + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::getAllElementUINames" ); + } + + _rElementNames.resize( rMapUINameToElement.size() ); + std::transform( rMapUINameToElement.begin(), rMapUINameToElement.end(), _rElementNames.begin(), + ::o3tl::select1st< MapStringToPropertySet::value_type >() ); + } + + + void EFormsHelper::firePropertyChange( const OUString& _rName, const Any& _rOldValue, const Any& _rNewValue ) const + { + if ( m_aPropertyListeners.getLength() == 0 ) + return; + + if ( _rOldValue == _rNewValue ) + return; + + try + { + PropertyChangeEvent aEvent; + + aEvent.Source = m_xBindableControl.get(); + aEvent.PropertyName = _rName; + aEvent.OldValue = _rOldValue; + aEvent.NewValue = _rNewValue; + + const_cast< EFormsHelper* >( this )->m_aPropertyListeners.notifyEach( &XPropertyChangeListener::propertyChange, aEvent ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::firePropertyChange" ); + } + } + + + void EFormsHelper::firePropertyChanges( const Reference< XPropertySet >& _rxOldProps, const Reference< XPropertySet >& _rxNewProps, std::set< OUString >& _rFilter ) const + { + if ( m_aPropertyListeners.getLength() == 0 ) + return; + + try + { + PropertyBag aProperties; + Reference< XPropertySetInfo > xOldInfo = collectPropertiesGetInfo( _rxOldProps, aProperties ); + Reference< XPropertySetInfo > xNewInfo = collectPropertiesGetInfo( _rxNewProps, aProperties ); + + for (auto const& property : aProperties) + { + if ( _rFilter.find( property.Name ) != _rFilter.end() ) + continue; + + Any aOldValue( nullptr, property.Type ); + if ( xOldInfo.is() && xOldInfo->hasPropertyByName( property.Name ) ) + aOldValue = _rxOldProps->getPropertyValue( property.Name ); + + Any aNewValue( nullptr, property.Type ); + if ( xNewInfo.is() && xNewInfo->hasPropertyByName( property.Name ) ) + aNewValue = _rxNewProps->getPropertyValue( property.Name ); + + firePropertyChange( property.Name, aOldValue, aNewValue ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsHelper::firePropertyChanges" ); + } + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/eformshelper.hxx b/extensions/source/propctrlr/eformshelper.hxx new file mode 100644 index 000000000..e88cb7491 --- /dev/null +++ b/extensions/source/propctrlr/eformshelper.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 . + */ + +#pragma once + +#include "pcrcommon.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace pcr +{ + + + typedef std::map< OUString, css::uno::Reference< css::beans::XPropertySet >, std::less< OUString > > + MapStringToPropertySet; + + + //= EFormsHelper + + class EFormsHelper + { + protected: + css::uno::Reference< css::beans::XPropertySet > + m_xControlModel; + css::uno::Reference< css::form::binding::XBindableValue > + m_xBindableControl; + css::uno::Reference< css::xforms::XFormsSupplier > + m_xDocument; + PropertyChangeListeners + m_aPropertyListeners; + MapStringToPropertySet + m_aSubmissionUINames; // only filled upon request + MapStringToPropertySet + m_aBindingUINames; // only filled upon request + + public: + EFormsHelper( + ::osl::Mutex& _rMutex, + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const css::uno::Reference< css::frame::XModel >& _rxContextDocument + ); + + /** determines whether the given document is an eForm + + If this method returns , you cannot instantiate an EFormsHelper with + this document, since none of its functionality will be available then. + */ + static bool + isEForm( + const css::uno::Reference< css::frame::XModel >& _rxContextDocument + ); + + /** registers a listener to be notified when any aspect of the binding changes. + + The listener will be registered at the current binding of the control model. If the binding + changes (see setBinding), the listener will be revoked from the old binding, + registered at the new binding, and for all properties which differ between both bindings, + the listener will be notified. + @see revokeBindingListener + */ + void registerBindingListener( + const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxBindingListener + ); + + /** revokes the binding listener which has previously been registered + @see registerBindingListener + */ + void revokeBindingListener( + const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxBindingListener + ); + + /** checks whether it's possible to bind the control model to a given XSD data type + + @param _nDataType + the data type which should be bound. If this is -1, is returned if the control model + can be bound to any data type. + */ + bool canBindToDataType( sal_Int32 _nDataType = -1 ) const; + + /** checks whether the control model can be bound to any XSD data type + */ + bool canBindToAnyDataType() const { return canBindToDataType(); } + + /** checks whether the control model is a source for list entries, as supplied by XML data bindings + */ + bool isListEntrySink() const; + + /** retrieves the names of all XForms models in the document the control lives in + */ + void getFormModelNames( std::vector< OUString >& /* [out] */ _rModelNames ) const; + + /** retrieves the names of all bindings for a given model + @see getFormModelNames + */ + void getBindingNames( const OUString& _rModelName, std::vector< OUString >& /* [out] */ _rBindingNames ) const; + + /// retrieves the XForms model (within the control model's document) with the given name + css::uno::Reference< css::xforms::XModel > + getFormModelByName( const OUString& _rModelName ) const; + + /** retrieves the model which the active binding of the control model belongs to + */ + css::uno::Reference< css::xforms::XModel > + getCurrentFormModel() const; + + /** retrieves the name of the model which the active binding of the control model belongs to + */ + OUString + getCurrentFormModelName() const; + + /** retrieves the binding instance which is currently attached to the control model + */ + css::uno::Reference< css::beans::XPropertySet > + getCurrentBinding() const; + + /** retrieves the name of the binding instance which is currently attached to the control model + */ + OUString + getCurrentBindingName() const; + + /** sets a new binding at the control model + */ + void setBinding( const css::uno::Reference< css::beans::XPropertySet >& _rxBinding ); + + /** retrieves the binding instance which is currently used as list source for the control model + @see isListEntrySink + */ + css::uno::Reference< css::form::binding::XListEntrySource > + getCurrentListSourceBinding() const; + + /** sets a new list source at the control model + @see isListEntrySink + */ + void setListSourceBinding( const css::uno::Reference< css::form::binding::XListEntrySource >& _rxListSource ); + + /** retrieves a given binding for a given model, or creates a new one + + @param _rTargetModel + the name of the model to create a binding for. Must not be empty + @param _rBindingName + the name of the binding to retrieve. If the model denoted by _rTargetModel does not + have a binding with this name, a new binding is created and returned. + */ + css::uno::Reference< css::beans::XPropertySet > + getOrCreateBindingForModel( const OUString& _rTargetModel, const OUString& _rBindingName ) const; + + /** types of sub-elements of a model + */ + enum ModelElementType + { + Submission, + Binding + }; + + /** retrieves the name of a model's sub-element, as to be shown in the UI + @see getModelElementFromUIName + @see getAllElementUINames + */ + static OUString + getModelElementUIName( + const ModelElementType _eType, + const css::uno::Reference< css::beans::XPropertySet >& _rxElement + ); + + /** retrieves the submission object for an UI name + + Note that getAllElementUINames must have been called before, for the given element type + + @see getModelElementUIName + @see getAllElementUINames + */ + css::uno::Reference< css::beans::XPropertySet > + getModelElementFromUIName( + const ModelElementType _eType, + const OUString& _rUIName + ) const; + + /** retrieves the UI names of all elements of all models in our document + @param _eType + the type of elements for which the names should be retrieved + @param _rElementNames + the array of element names + @see getModelElementUIName + @see getModelElementFromUIName + */ + void getAllElementUINames( + const ModelElementType _eType, + std::vector< OUString >& /* [out] */ _rElementNames, + bool _bPrepentEmptyEntry + ); + + protected: + void firePropertyChanges( + const css::uno::Reference< css::beans::XPropertySet >& _rxOldProps, + const css::uno::Reference< css::beans::XPropertySet >& _rxNewProps, + std::set< OUString >& _rFilter + ) const; + + /** fires a change in a single property, if the property value changed, and if we have a listener + interested in property changes + */ + void firePropertyChange( + const OUString& _rName, + const css::uno::Any& _rOldValue, + const css::uno::Any& _rNewValue + ) const; + + private: + void impl_switchBindingListening_throw( bool _bDoListening, const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ); + + /// implementation for both getOrCreateBindingForModel + css::uno::Reference< css::beans::XPropertySet > + implGetOrCreateBinding( const OUString& _rTargetModel, const OUString& _rBindingName ) const; + + void + impl_toggleBindingPropertyListening_throw( bool _bDoListen, const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxConcreteListenerOrNull ); + + private: + EFormsHelper( const EFormsHelper& ) = delete; + EFormsHelper& operator=( const EFormsHelper& ) = delete; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/eformspropertyhandler.cxx b/extensions/source/propctrlr/eformspropertyhandler.cxx new file mode 100644 index 000000000..42ca7ed1a --- /dev/null +++ b/extensions/source/propctrlr/eformspropertyhandler.cxx @@ -0,0 +1,598 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "eformspropertyhandler.hxx" +#include "formstrings.hxx" +#include "formmetadata.hxx" +#include +#include "eformshelper.hxx" +#include "handlerhelper.hxx" + +#include +#include +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::xforms; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::ui::dialogs; + using namespace ::com::sun::star::form::binding; + using namespace ::com::sun::star::inspection; + + + //= EFormsPropertyHandler + + + EFormsPropertyHandler::EFormsPropertyHandler( const Reference< XComponentContext >& _rxContext ) + :PropertyHandlerComponent( _rxContext ) + ,m_bSimulatingModelChange( false ) + { + } + + + EFormsPropertyHandler::~EFormsPropertyHandler( ) + { + } + + + OUString EFormsPropertyHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.EFormsPropertyHandler"; + } + + + Sequence< OUString > EFormsPropertyHandler::getSupportedServiceNames( ) + { + return { "com.sun.star.form.inspection.XMLFormsPropertyHandler" }; + } + + + OUString EFormsPropertyHandler::getModelNamePropertyValue() const + { + OUString sModelName = m_pHelper->getCurrentFormModelName(); + if ( sModelName.isEmpty() ) + sModelName = m_sBindingLessModelName; + return sModelName; + } + + + Any SAL_CALL EFormsPropertyHandler::getPropertyValue( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + OSL_ENSURE( + m_pHelper, + "EFormsPropertyHandler::getPropertyValue: we don't have any SupportedProperties!"); + // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties + + Any aReturn; + try + { + switch ( nPropId ) + { + case PROPERTY_ID_LIST_BINDING: + aReturn <<= m_pHelper->getCurrentListSourceBinding(); + break; + + case PROPERTY_ID_XML_DATA_MODEL: + aReturn <<= getModelNamePropertyValue(); + break; + + case PROPERTY_ID_BINDING_NAME: + aReturn <<= m_pHelper->getCurrentBindingName(); + break; + + case PROPERTY_ID_BIND_EXPRESSION: + case PROPERTY_ID_XSD_CONSTRAINT: + case PROPERTY_ID_XSD_CALCULATION: + case PROPERTY_ID_XSD_REQUIRED: + case PROPERTY_ID_XSD_RELEVANT: + case PROPERTY_ID_XSD_READONLY: + { + Reference< XPropertySet > xBindingProps( m_pHelper->getCurrentBinding() ); + if ( xBindingProps.is() ) + { + aReturn = xBindingProps->getPropertyValue( _rPropertyName ); + DBG_ASSERT( aReturn.getValueType().equals( ::cppu::UnoType::get() ), + "EFormsPropertyHandler::getPropertyValue: invalid BindingExpression value type!" ); + } + else + aReturn <<= OUString(); + } + break; + + default: + OSL_FAIL( "EFormsPropertyHandler::getPropertyValue: cannot handle this property!" ); + break; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsPropertyHandler::getPropertyValue: caught exception!" + "(have been asked for the \"" <<_rPropertyName << "\" property.)"); + } + return aReturn; + } + + + void SAL_CALL EFormsPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + OSL_ENSURE( + m_pHelper, + "EFormsPropertyHandler::setPropertyValue: we don't have any SupportedProperties!"); + // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties + + try + { + Any aOldValue = getPropertyValue( _rPropertyName ); + + switch ( nPropId ) + { + case PROPERTY_ID_LIST_BINDING: + { + Reference< XListEntrySource > xSource; + OSL_VERIFY( _rValue >>= xSource ); + m_pHelper->setListSourceBinding( xSource ); + } + break; + + case PROPERTY_ID_XML_DATA_MODEL: + { + OSL_VERIFY( _rValue >>= m_sBindingLessModelName ); + + // if the model changed, reset the binding to NULL + if ( m_pHelper->getCurrentFormModelName() != m_sBindingLessModelName ) + { + OUString sOldBindingName = m_pHelper->getCurrentBindingName(); + m_pHelper->setBinding( nullptr ); + firePropertyChange( PROPERTY_BINDING_NAME, PROPERTY_ID_BINDING_NAME, + Any( sOldBindingName ), Any( OUString() ) ); + } + } + break; + + case PROPERTY_ID_BINDING_NAME: + { + OUString sNewBindingName; + OSL_VERIFY( _rValue >>= sNewBindingName ); + + bool bPreviouslyEmptyModel = !m_pHelper->getCurrentFormModel().is(); + + Reference< XPropertySet > xNewBinding; + if ( !sNewBindingName.isEmpty() ) + // obtain the binding with this name, for the current model + xNewBinding = m_pHelper->getOrCreateBindingForModel( getModelNamePropertyValue(), sNewBindingName ); + + m_pHelper->setBinding( xNewBinding ); + + if ( bPreviouslyEmptyModel ) + { // simulate a property change for the model property + // This is because we "simulate" the Model property by remembering the + // value ourself. Other instances might, however, not know this value, + // but prefer to retrieve it somewhere else - e.g. from the EFormsHelper + + // The really correct solution would be if *all* property handlers + // obtain a "current property value" for *all* properties from a central + // instance. Then, handler A could ask it for the value of property + // X, and this request would be re-routed to handler B, which ultimately + // knows the current value. + // However, there's no such mechanism in place currently. + m_bSimulatingModelChange = true; + firePropertyChange( PROPERTY_XML_DATA_MODEL, PROPERTY_ID_XML_DATA_MODEL, + Any( OUString() ), Any( getModelNamePropertyValue() ) ); + m_bSimulatingModelChange = false; + } + } + break; + + case PROPERTY_ID_BIND_EXPRESSION: + { + Reference< XPropertySet > xBinding( m_pHelper->getCurrentBinding() ); + OSL_ENSURE( xBinding.is(), "You should not reach this without an active binding!" ); + if ( xBinding.is() ) + xBinding->setPropertyValue( PROPERTY_BIND_EXPRESSION, _rValue ); + } + break; + + case PROPERTY_ID_XSD_REQUIRED: + case PROPERTY_ID_XSD_RELEVANT: + case PROPERTY_ID_XSD_READONLY: + case PROPERTY_ID_XSD_CONSTRAINT: + case PROPERTY_ID_XSD_CALCULATION: + { + Reference< XPropertySet > xBindingProps( m_pHelper->getCurrentBinding() ); + DBG_ASSERT( xBindingProps.is(), "EFormsPropertyHandler::setPropertyValue: how can I set a property if there's no binding?" ); + if ( xBindingProps.is() ) + { + DBG_ASSERT( _rValue.getValueType().equals( ::cppu::UnoType::get() ), + "EFormsPropertyHandler::setPropertyValue: invalid value type!" ); + xBindingProps->setPropertyValue( _rPropertyName, _rValue ); + } + } + break; + + default: + OSL_FAIL( "EFormsPropertyHandler::setPropertyValue: cannot handle this property!" ); + break; + } + + impl_setContextDocumentModified_nothrow(); + + Any aNewValue( getPropertyValue( _rPropertyName ) ); + firePropertyChange( _rPropertyName, nPropId, aOldValue, aNewValue ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsPropertyHandler::setPropertyValue" ); + } + } + + + void EFormsPropertyHandler::onNewComponent() + { + PropertyHandlerComponent::onNewComponent(); + + Reference< frame::XModel > xDocument( impl_getContextDocument_nothrow() ); + DBG_ASSERT( xDocument.is(), "EFormsPropertyHandler::onNewComponent: no document!" ); + if ( EFormsHelper::isEForm( xDocument ) ) + m_pHelper.reset( new EFormsHelper( m_aMutex, m_xComponent, xDocument ) ); + else + m_pHelper.reset(); + } + + + Sequence< Property > EFormsPropertyHandler::doDescribeSupportedProperties() const + { + std::vector< Property > aProperties; + + if (m_pHelper) + { + if ( m_pHelper->canBindToAnyDataType() ) + { + aProperties.reserve( 7 ); + addStringPropertyDescription( aProperties, PROPERTY_XML_DATA_MODEL ); + addStringPropertyDescription( aProperties, PROPERTY_BINDING_NAME ); + addStringPropertyDescription( aProperties, PROPERTY_BIND_EXPRESSION ); + addStringPropertyDescription( aProperties, PROPERTY_XSD_REQUIRED ); + addStringPropertyDescription( aProperties, PROPERTY_XSD_RELEVANT ); + addStringPropertyDescription( aProperties, PROPERTY_XSD_READONLY ); + addStringPropertyDescription( aProperties, PROPERTY_XSD_CONSTRAINT ); + addStringPropertyDescription( aProperties, PROPERTY_XSD_CALCULATION ); + } + if ( m_pHelper->isListEntrySink() ) + { + implAddPropertyDescription( aProperties, PROPERTY_LIST_BINDING, + cppu::UnoType::get() ); + } + } + + if ( aProperties.empty() ) + return Sequence< Property >(); + return comphelper::containerToSequence(aProperties); + } + + + Any SAL_CALL EFormsPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Any aReturn; + + OSL_ENSURE( + m_pHelper, + "EFormsPropertyHandler::convertToPropertyValue: we have no SupportedProperties!"); + if (!m_pHelper) + return aReturn; + + PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) ); + + OUString sControlValue; + switch ( nPropId ) + { + case PROPERTY_ID_LIST_BINDING: + { + OSL_VERIFY( _rControlValue >>= sControlValue ); + Reference< XListEntrySource > xListSource( m_pHelper->getModelElementFromUIName( EFormsHelper::Binding, sControlValue ), UNO_QUERY ); + OSL_ENSURE( xListSource.is() || !m_pHelper->getModelElementFromUIName( EFormsHelper::Binding, sControlValue ).is(), + "EFormsPropertyHandler::convertToPropertyValue: there's a binding which is no ListEntrySource!" ); + aReturn <<= xListSource; + } + break; + + default: + aReturn = PropertyHandlerComponent::convertToPropertyValue( _rPropertyName, _rControlValue ); + break; + } + + return aReturn; + } + + + Any SAL_CALL EFormsPropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Any aReturn; + + OSL_ENSURE(m_pHelper, + "EFormsPropertyHandler::convertToControlValue: we have no SupportedProperties!"); + if (!m_pHelper) + return aReturn; + + PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) ); + + OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING, + "EFormsPropertyHandler::convertToControlValue: all our controls should use strings for value exchange!" ); + + switch ( nPropId ) + { + case PROPERTY_ID_LIST_BINDING: + { + Reference< XPropertySet > xListSourceBinding( _rPropertyValue, UNO_QUERY ); + if ( xListSourceBinding.is() ) + aReturn <<= EFormsHelper::getModelElementUIName( EFormsHelper::Binding, xListSourceBinding ); + } + break; + + default: + aReturn = PropertyHandlerComponent::convertToControlValue( _rPropertyName, _rPropertyValue, _rControlValueType ); + break; + } + + return aReturn; + } + + + Sequence< OUString > SAL_CALL EFormsPropertyHandler::getActuatingProperties( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_pHelper) + return Sequence< OUString >(); + + std::vector< OUString > aInterestedInActuations( 2 ); + aInterestedInActuations[ 0 ] = PROPERTY_XML_DATA_MODEL; + aInterestedInActuations[ 1 ] = PROPERTY_BINDING_NAME; + return comphelper::containerToSequence(aInterestedInActuations); + } + + + Sequence< OUString > SAL_CALL EFormsPropertyHandler::getSupersededProperties( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_pHelper) + return Sequence< OUString >(); + + Sequence aReturn { PROPERTY_INPUT_REQUIRED }; + return aReturn; + } + + LineDescriptor SAL_CALL EFormsPropertyHandler::describePropertyLine( const OUString& _rPropertyName, + const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !_rxControlFactory.is() ) + throw NullPointerException(); + if (!m_pHelper) + throw RuntimeException(); + + LineDescriptor aDescriptor; + sal_Int16 nControlType = PropertyControlType::TextField; + std::vector< OUString > aListEntries; + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + switch ( nPropId ) + { + case PROPERTY_ID_LIST_BINDING: + nControlType = PropertyControlType::ListBox; + m_pHelper->getAllElementUINames(EFormsHelper::Binding, aListEntries, true); + break; + + case PROPERTY_ID_XML_DATA_MODEL: + nControlType = PropertyControlType::ListBox; + m_pHelper->getFormModelNames( aListEntries ); + break; + + case PROPERTY_ID_BINDING_NAME: + { + nControlType = PropertyControlType::ComboBox; + OUString sCurrentModel( getModelNamePropertyValue() ); + if ( !sCurrentModel.isEmpty() ) + m_pHelper->getBindingNames( sCurrentModel, aListEntries ); + } + break; + + case PROPERTY_ID_BIND_EXPRESSION: aDescriptor.PrimaryButtonId = UID_PROP_DLG_BIND_EXPRESSION; break; + case PROPERTY_ID_XSD_REQUIRED: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_REQUIRED; break; + case PROPERTY_ID_XSD_RELEVANT: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_RELEVANT; break; + case PROPERTY_ID_XSD_READONLY: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_READONLY; break; + case PROPERTY_ID_XSD_CONSTRAINT: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_CONSTRAINT; break; + case PROPERTY_ID_XSD_CALCULATION: aDescriptor.PrimaryButtonId = UID_PROP_DLG_XSD_CALCULATION; break; + + default: + OSL_FAIL( "EFormsPropertyHandler::describePropertyLine: cannot handle this property!" ); + break; + } + + switch ( nControlType ) + { + case PropertyControlType::ListBox: + aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory, std::move(aListEntries), false, true ); + break; + case PropertyControlType::ComboBox: + aDescriptor.Control = PropertyHandlerHelper::createComboBoxControl( _rxControlFactory, std::move(aListEntries), true ); + break; + default: + aDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, false ); + break; + } + + aDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( nPropId ); + aDescriptor.Category = "Data"; + aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) ); + return aDescriptor; + } + + InteractiveSelectionResult SAL_CALL EFormsPropertyHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool /*_bPrimary*/, Any& _rData, const Reference< XObjectInspectorUI >& _rxInspectorUI ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_ENSURE(m_pHelper, "EFormsPropertyHandler::onInteractivePropertySelection: we do not " + "have any SupportedProperties!"); + if (!m_pHelper) + return InteractiveSelectionResult_Cancelled; + + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + OSL_ENSURE( ( PROPERTY_ID_BINDING_NAME == nPropId ) + || ( PROPERTY_ID_BIND_EXPRESSION == nPropId ) + || ( PROPERTY_ID_XSD_REQUIRED == nPropId ) + || ( PROPERTY_ID_XSD_RELEVANT == nPropId ) + || ( PROPERTY_ID_XSD_READONLY == nPropId ) + || ( PROPERTY_ID_XSD_CONSTRAINT == nPropId ) + || ( PROPERTY_ID_XSD_CALCULATION == nPropId ), "EFormsPropertyHandler::onInteractivePropertySelection: unexpected!" ); + + try + { + Reference< XExecutableDialog > xDialog; + xDialog.set( m_xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.xforms.ui.dialogs.AddCondition", m_xContext ), UNO_QUERY ); + Reference< XPropertySet > xDialogProps( xDialog, UNO_QUERY_THROW ); + + // the model for the dialog to work with + Reference< xforms::XModel > xModel( m_pHelper->getCurrentFormModel() ); + // the binding for the dialog to work with + Reference< XPropertySet > xBinding( m_pHelper->getCurrentBinding() ); + // the aspect of the binding which the dialog should modify + const OUString& sFacetName( _rPropertyName ); + + OSL_ENSURE( xModel.is() && xBinding.is() && !sFacetName.isEmpty(), + "EFormsPropertyHandler::onInteractivePropertySelection: something is missing for the dialog initialization!" ); + if ( !xModel.is() || !xBinding.is() || sFacetName.isEmpty() ) + return InteractiveSelectionResult_Cancelled; + + xDialogProps->setPropertyValue("FormModel", Any( xModel ) ); + xDialogProps->setPropertyValue("Binding", Any( xBinding ) ); + xDialogProps->setPropertyValue("FacetName", Any( sFacetName ) ); + + if ( !xDialog->execute() ) + // cancelled + return InteractiveSelectionResult_Cancelled; + + _rData = xDialogProps->getPropertyValue("ConditionValue"); + return InteractiveSelectionResult_ObtainedValue; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EFormsPropertyHandler::onInteractivePropertySelection" ); + } + + // something went wrong here ...(but has been asserted already) + return InteractiveSelectionResult_Cancelled; + } + + + void SAL_CALL EFormsPropertyHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyHandlerComponent::addPropertyChangeListener( _rxListener ); + if (m_pHelper) + m_pHelper->registerBindingListener( _rxListener ); + } + + + void SAL_CALL EFormsPropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (m_pHelper) + m_pHelper->revokeBindingListener( _rxListener ); + PropertyHandlerComponent::removePropertyChangeListener( _rxListener ); + } + + + void SAL_CALL EFormsPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) ); + OSL_PRECOND(m_pHelper, "EFormsPropertyHandler::actuatingPropertyChanged: inconsistency!"); + // if we survived impl_getPropertyId_throwRuntime, we should have a helper, since no helper implies no properties + + DBG_ASSERT( _rxInspectorUI.is(), "EFormsPropertyHandler::actuatingPropertyChanged: invalid callback!" ); + if ( !_rxInspectorUI.is() ) + return; + + switch ( nActuatingPropId ) + { + case PROPERTY_ID_XML_DATA_MODEL: + { + if ( m_bSimulatingModelChange ) + break; + OUString sDataModelName; + OSL_VERIFY( _rNewValue >>= sDataModelName ); + bool bBoundToSomeModel = !sDataModelName.isEmpty(); + _rxInspectorUI->rebuildPropertyUI( PROPERTY_BINDING_NAME ); + _rxInspectorUI->enablePropertyUI( PROPERTY_BINDING_NAME, bBoundToSomeModel ); + [[fallthrough]]; + } + + case PROPERTY_ID_BINDING_NAME: + { + bool bHaveABinding = !m_pHelper->getCurrentBindingName().isEmpty(); + _rxInspectorUI->enablePropertyUI( PROPERTY_BIND_EXPRESSION, bHaveABinding ); + _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_REQUIRED, bHaveABinding ); + _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_RELEVANT, bHaveABinding ); + _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_READONLY, bHaveABinding ); + _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_CONSTRAINT, bHaveABinding ); + _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_CALCULATION, bHaveABinding ); + _rxInspectorUI->enablePropertyUI( PROPERTY_XSD_DATA_TYPE, bHaveABinding ); + } + break; + + default: + OSL_FAIL( "EFormsPropertyHandler::actuatingPropertyChanged: cannot handle this property!" ); + break; + } + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_EFormsPropertyHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::EFormsPropertyHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/eformspropertyhandler.hxx b/extensions/source/propctrlr/eformspropertyhandler.hxx new file mode 100644 index 000000000..8945c24f4 --- /dev/null +++ b/extensions/source/propctrlr/eformspropertyhandler.hxx @@ -0,0 +1,95 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "propertyhandler.hxx" + +#include + + +namespace pcr +{ + + + class EFormsHelper; + + //= EFormsPropertyHandler + + class EFormsPropertyHandler; + class EFormsPropertyHandler : public PropertyHandlerComponent + { + private: + std::unique_ptr< EFormsHelper > m_pHelper; + /** current value of the Model property, if there is no binding, yet + */ + OUString m_sBindingLessModelName; + /** are we currently simulating a propertyChange event of the Model property? + */ + bool m_bSimulatingModelChange; + + public: + explicit EFormsPropertyHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + protected: + virtual ~EFormsPropertyHandler() override; + + protected: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override; + + // XPropertyHandler overriables + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::uno::Sequence< OUString > + SAL_CALL getActuatingProperties( ) override; + virtual css::uno::Sequence< OUString > + SAL_CALL getSupersededProperties( ) override; + virtual css::inspection::LineDescriptor + SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + virtual css::inspection::InteractiveSelectionResult + SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) override; + virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override; + virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override; + virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + + // PropertyHandler overridables + virtual css::uno::Sequence< css::beans::Property > + doDescribeSupportedProperties() const override; + virtual void onNewComponent() override; + + protected: + /** returns the value of the PROPERTY_XML_DATA_MODEL property. + + An extra method is necessary here, which respects both the value set at our helper, + and m_sBindingLessModelName + */ + OUString getModelNamePropertyValue() const; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/enumrepresentation.hxx b/extensions/source/propctrlr/enumrepresentation.hxx new file mode 100644 index 000000000..b3ba04c9a --- /dev/null +++ b/extensions/source/propctrlr/enumrepresentation.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +#include + + +namespace pcr +{ + + + //= IPropertyEnumRepresentation + + class SAL_NO_VTABLE IPropertyEnumRepresentation : public salhelper::SimpleReferenceObject + { + public: + /** retrieves all descriptions of all possible values of the enumeration property + */ + virtual std::vector< OUString > getDescriptions( + ) const = 0; + + /** converts a given description into a property value + */ + virtual void getValueFromDescription( + const OUString& _rDescription, + css::uno::Any& _out_rValue + ) const = 0; + + /** converts a given property value into a description + */ + virtual OUString getDescriptionForValue( + const css::uno::Any& _rEnumValue + ) const = 0; + + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/eventhandler.cxx b/extensions/source/propctrlr/eventhandler.cxx new file mode 100644 index 000000000..d07f524bf --- /dev/null +++ b/extensions/source/propctrlr/eventhandler.cxx @@ -0,0 +1,1112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "eventhandler.hxx" +#include +#include +#include "formbrowsertools.hxx" +#include +#include "formstrings.hxx" +#include "handlerhelper.hxx" +#include "modulepcr.hxx" +#include "pcrcommon.hxx" +#include "propertycontrolextender.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace pcr +{ + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::TypeClass_STRING; + using ::com::sun::star::uno::Type; + using ::com::sun::star::beans::theIntrospection; + using ::com::sun::star::beans::XPropertyChangeListener; + using ::com::sun::star::beans::Property; + using ::com::sun::star::beans::PropertyState; + using ::com::sun::star::beans::PropertyState_DIRECT_VALUE; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::script::ScriptEventDescriptor; + using ::com::sun::star::script::XScriptEventsSupplier; + using ::com::sun::star::lang::NullPointerException; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::container::XChild; + using ::com::sun::star::container::XIndexAccess; + using ::com::sun::star::script::XEventAttacherManager; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::beans::XIntrospection; + using ::com::sun::star::beans::XIntrospectionAccess; + using ::com::sun::star::container::XNameContainer; + using ::com::sun::star::awt::XTabControllerModel; + using ::com::sun::star::form::XForm; + using ::com::sun::star::form::runtime::FormController; + using ::com::sun::star::form::runtime::XFormController; + using ::com::sun::star::beans::UnknownPropertyException; + using ::com::sun::star::container::NoSuchElementException; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::container::XNameReplace; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::inspection::LineDescriptor; + using ::com::sun::star::inspection::XPropertyControlFactory; + using ::com::sun::star::inspection::InteractiveSelectionResult; + using ::com::sun::star::inspection::InteractiveSelectionResult_Cancelled; + using ::com::sun::star::inspection::InteractiveSelectionResult_Success; + using ::com::sun::star::inspection::XObjectInspectorUI; + using ::com::sun::star::beans::PropertyChangeEvent; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::frame::XController; + using ::com::sun::star::uno::UNO_SET_THROW; + using com::sun::star::uri::UriReferenceFactory; + using com::sun::star::uri::XUriReferenceFactory; + using com::sun::star::uri::XVndSunStarScriptUrlReference; + using ::com::sun::star::lang::XEventListener; + + namespace PropertyControlType = css::inspection::PropertyControlType; + namespace PropertyAttribute = css::beans::PropertyAttribute; + namespace FormComponentType = css::form::FormComponentType; + + EventDescription::EventDescription( EventId _nId, const char* _pListenerNamespaceAscii, const char* _pListenerClassAsciiName, + const char* _pListenerMethodAsciiName, TranslateId pDisplayNameResId, const OUString& _sHelpId, const OString& _sUniqueBrowseId ) + :sDisplayName(PcrRes( pDisplayNameResId )) + ,sListenerMethodName( OUString::createFromAscii( _pListenerMethodAsciiName ) ) + ,sHelpId( _sHelpId ) + ,sUniqueBrowseId( _sUniqueBrowseId ) + ,nId( _nId ) + { + OUStringBuffer aQualifiedListenerClass; + aQualifiedListenerClass.append( "com.sun.star." ); + aQualifiedListenerClass.appendAscii( _pListenerNamespaceAscii ); + aQualifiedListenerClass.append( "." ); + aQualifiedListenerClass.appendAscii( _pListenerClassAsciiName ); + sListenerClassName = aQualifiedListenerClass.makeStringAndClear(); + } + + namespace + { + #define DESCRIBE_EVENT( map, asciinamespace, asciilistener, asciimethod, id_postfix ) \ + map.emplace( \ + asciimethod, \ + EventDescription( ++nEventId, asciinamespace, asciilistener, asciimethod, RID_STR_EVT_##id_postfix, HID_EVT_##id_postfix, UID_BRWEVT_##id_postfix ) ) + + bool lcl_getEventDescriptionForMethod( const OUString& _rMethodName, EventDescription& _out_rDescription ) + { + static EventMap s_aKnownEvents = []() { + EventMap aMap; + sal_Int32 nEventId = 0; + + DESCRIBE_EVENT(aMap, "form", "XApproveActionListener", "approveAction", APPROVEACTIONPERFORMED); + DESCRIBE_EVENT(aMap, "awt", "XActionListener", "actionPerformed", ACTIONPERFORMED); + DESCRIBE_EVENT(aMap, "form", "XChangeListener", "changed", CHANGED); + DESCRIBE_EVENT(aMap, "awt", "XTextListener", "textChanged", TEXTCHANGED); + DESCRIBE_EVENT(aMap, "awt", "XItemListener", "itemStateChanged", ITEMSTATECHANGED); + DESCRIBE_EVENT(aMap, "awt", "XFocusListener", "focusGained", FOCUSGAINED); + DESCRIBE_EVENT(aMap, "awt", "XFocusListener", "focusLost", FOCUSLOST); + DESCRIBE_EVENT(aMap, "awt", "XKeyListener", "keyPressed", KEYTYPED); + DESCRIBE_EVENT(aMap, "awt", "XKeyListener", "keyReleased", KEYUP); + DESCRIBE_EVENT(aMap, "awt", "XMouseListener", "mouseEntered", MOUSEENTERED); + DESCRIBE_EVENT(aMap, "awt", "XMouseMotionListener", "mouseDragged", MOUSEDRAGGED); + DESCRIBE_EVENT(aMap, "awt", "XMouseMotionListener", "mouseMoved", MOUSEMOVED); + DESCRIBE_EVENT(aMap, "awt", "XMouseListener", "mousePressed", MOUSEPRESSED); + DESCRIBE_EVENT(aMap, "awt", "XMouseListener", "mouseReleased", MOUSERELEASED); + DESCRIBE_EVENT(aMap, "awt", "XMouseListener", "mouseExited", MOUSEEXITED); + DESCRIBE_EVENT(aMap, "form", "XResetListener", "approveReset", APPROVERESETTED); + DESCRIBE_EVENT(aMap, "form", "XResetListener", "resetted", RESETTED); + DESCRIBE_EVENT(aMap, "form", "XSubmitListener", "approveSubmit", SUBMITTED); + DESCRIBE_EVENT(aMap, "form", "XUpdateListener", "approveUpdate", BEFOREUPDATE); + DESCRIBE_EVENT(aMap, "form", "XUpdateListener", "updated", AFTERUPDATE); + DESCRIBE_EVENT(aMap, "form", "XLoadListener", "loaded", LOADED); + DESCRIBE_EVENT(aMap, "form", "XLoadListener", "reloading", RELOADING); + DESCRIBE_EVENT(aMap, "form", "XLoadListener", "reloaded", RELOADED); + DESCRIBE_EVENT(aMap, "form", "XLoadListener", "unloading", UNLOADING); + DESCRIBE_EVENT(aMap, "form", "XLoadListener", "unloaded", UNLOADED); + DESCRIBE_EVENT(aMap, "form", "XConfirmDeleteListener", "confirmDelete", CONFIRMDELETE); + DESCRIBE_EVENT(aMap, "sdb", "XRowSetApproveListener", "approveRowChange", APPROVEROWCHANGE); + DESCRIBE_EVENT(aMap, "sdbc", "XRowSetListener", "rowChanged", ROWCHANGE); + DESCRIBE_EVENT(aMap, "sdb", "XRowSetApproveListener", "approveCursorMove", POSITIONING); + DESCRIBE_EVENT(aMap, "sdbc", "XRowSetListener", "cursorMoved", POSITIONED); + DESCRIBE_EVENT(aMap, "form", "XDatabaseParameterListener", "approveParameter", APPROVEPARAMETER); + DESCRIBE_EVENT(aMap, "sdb", "XSQLErrorListener", "errorOccured", ERROROCCURRED); + DESCRIBE_EVENT(aMap, "awt", "XAdjustmentListener", "adjustmentValueChanged", ADJUSTMENTVALUECHANGED); + + return aMap; + }(); + + EventMap::const_iterator pos = s_aKnownEvents.find( _rMethodName ); + if ( pos == s_aKnownEvents.end() ) + return false; + + _out_rDescription = pos->second; + return true; + } + + OUString lcl_getEventPropertyName( std::u16string_view _rListenerClassName, std::u16string_view _rMethodName ) + { + return _rListenerClassName + OUStringChar(';') + _rMethodName; + } + + ScriptEventDescriptor lcl_getAssignedScriptEvent( const EventDescription& _rEvent, const std::vector< ScriptEventDescriptor >& _rAllAssignedMacros ) + { + ScriptEventDescriptor aScriptEvent; + // for the case there is actually no event assigned, initialize at least ListenerType and MethodName, + // so this ScriptEventDescriptor properly describes the given event + aScriptEvent.ListenerType = _rEvent.sListenerClassName; + aScriptEvent.EventMethod = _rEvent.sListenerMethodName; + + for ( const ScriptEventDescriptor& rSED : _rAllAssignedMacros ) + { + if ( rSED.ListenerType != _rEvent.sListenerClassName + || rSED.EventMethod != _rEvent.sListenerMethodName + ) + continue; + + if ( rSED.ScriptCode.isEmpty() + || rSED.ScriptType.isEmpty() + ) + { + OSL_FAIL( "lcl_getAssignedScriptEvent: me thinks this should not happen!" ); + continue; + } + + aScriptEvent = rSED; + + if ( aScriptEvent.ScriptType != "StarBasic" ) + continue; + + // this is an old-style macro specification: + // [document|application]:Library.Module.Function + // we need to translate this to the new-style macro specification + // vnd.sun.star.script:Library.Module.Function?language=Basic&location=[document|application] + + sal_Int32 nPrefixLen = aScriptEvent.ScriptCode.indexOf( ':' ); + OSL_ENSURE( nPrefixLen > 0, "lcl_getAssignedScriptEvent: illegal location!" ); + std::u16string_view sLocation = aScriptEvent.ScriptCode.subView( 0, nPrefixLen ); + std::u16string_view sMacroPath = aScriptEvent.ScriptCode.subView( nPrefixLen + 1 ); + + aScriptEvent.ScriptCode = + OUString::Concat("vnd.sun.star.script:") + + sMacroPath + + "?language=Basic&location=" + + sLocation; + + // also, this new-style spec requires the script code to be "Script" instead of "StarBasic" + aScriptEvent.ScriptType = "Script"; + } + return aScriptEvent; + } + + OUString lcl_getQualifiedKnownListenerName( const ScriptEventDescriptor& _rFormComponentEventDescriptor ) + { + EventDescription aKnownEvent; + if ( lcl_getEventDescriptionForMethod( _rFormComponentEventDescriptor.EventMethod, aKnownEvent ) ) + return aKnownEvent.sListenerClassName; + OSL_FAIL( "lcl_getQualifiedKnownListenerName: unknown method name!" ); + // somebody assigned an script to a form component event which we don't know + // Speaking strictly, this is not really an error - it is possible to do + // this programmatically -, but it should rarely happen, since it's not possible + // via UI + return _rFormComponentEventDescriptor.ListenerType; + } + + typedef std::set< Type, TypeLessByName > TypeBag; + + void lcl_addListenerTypesFor_throw( const Reference< XInterface >& _rxComponent, + const Reference< XIntrospection >& _rxIntrospection, TypeBag& _out_rTypes ) + { + if ( !_rxComponent.is() ) + return; + OSL_PRECOND( _rxIntrospection.is(), "lcl_addListenerTypesFor_throw: this will crash!" ); + + Reference< XIntrospectionAccess > xIntrospectionAccess( + _rxIntrospection->inspect( Any( _rxComponent ) ), UNO_SET_THROW ); + + const Sequence< Type > aListeners( xIntrospectionAccess->getSupportedListeners() ); + + std::copy( aListeners.begin(), aListeners.end(), + std::insert_iterator< TypeBag >( _out_rTypes, _out_rTypes.begin() ) ); + } + } + + typedef ::cppu::WeakImplHelper < css::container::XNameReplace + > EventHolder_Base; + + namespace { + + /* A UNO component holding assigned event descriptions, for use with a SvxMacroAssignDlg */ + class EventHolder : public EventHolder_Base + { + private: + typedef std::unordered_map< OUString, ScriptEventDescriptor > EventMap; + typedef std::map< EventId, OUString > EventMapIndexAccess; + + EventMap m_aEventNameAccess; + EventMapIndexAccess m_aEventIndexAccess; + + public: + EventHolder( ); + + void addEvent( EventId _nId, const OUString& _rEventName, const ScriptEventDescriptor& _rScriptEvent ); + + /** effectively the same as getByName, but instead of converting the ScriptEventDescriptor to the weird + format used by the macro assignment dialog, it is returned directly + */ + ScriptEventDescriptor getNormalizedDescriptorByName( const OUString& _rEventName ) const; + + // XNameReplace + virtual void SAL_CALL replaceByName( const OUString& _rName, const Any& aElement ) override; + virtual Any SAL_CALL getByName( const OUString& _rName ) override; + virtual Sequence< OUString > SAL_CALL getElementNames( ) override; + virtual sal_Bool SAL_CALL hasByName( const OUString& _rName ) override; + virtual Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) override; + + protected: + virtual ~EventHolder( ) override; + + private: + ScriptEventDescriptor const & impl_getDescriptor_throw( const OUString& _rEventName ) const; + }; + + } + + EventHolder::EventHolder() + { + } + + EventHolder::~EventHolder() + { + m_aEventNameAccess.clear(); + m_aEventIndexAccess.clear(); + } + + void EventHolder::addEvent( EventId _nId, const OUString& _rEventName, const ScriptEventDescriptor& _rScriptEvent ) + { + std::pair< EventMap::iterator, bool > insertionResult = + m_aEventNameAccess.emplace( _rEventName, _rScriptEvent ); + OSL_ENSURE( insertionResult.second, "EventHolder::addEvent: there already was a MacroURL for this event!" ); + m_aEventIndexAccess[ _nId ] = _rEventName; + } + + ScriptEventDescriptor EventHolder::getNormalizedDescriptorByName( const OUString& _rEventName ) const + { + return impl_getDescriptor_throw( _rEventName ); + } + + ScriptEventDescriptor const & EventHolder::impl_getDescriptor_throw( const OUString& _rEventName ) const + { + EventMap::const_iterator pos = m_aEventNameAccess.find( _rEventName ); + if ( pos == m_aEventNameAccess.end() ) + throw NoSuchElementException( OUString(), *const_cast< EventHolder* >( this ) ); + return pos->second; + } + + void SAL_CALL EventHolder::replaceByName( const OUString& _rName, const Any& _rElement ) + { + EventMap::iterator pos = m_aEventNameAccess.find( _rName ); + if ( pos == m_aEventNameAccess.end() ) + throw NoSuchElementException( OUString(), *this ); + + Sequence< PropertyValue > aScriptDescriptor; + OSL_VERIFY( _rElement >>= aScriptDescriptor ); + + ::comphelper::NamedValueCollection aExtractor( aScriptDescriptor ); + + pos->second.ScriptType = aExtractor.getOrDefault( "EventType", OUString() ); + pos->second.ScriptCode = aExtractor.getOrDefault( "Script", OUString() ); + } + + Any SAL_CALL EventHolder::getByName( const OUString& _rName ) + { + ScriptEventDescriptor aDescriptor( impl_getDescriptor_throw( _rName ) ); + + Sequence< PropertyValue > aScriptDescriptor{ + comphelper::makePropertyValue("EventType", aDescriptor.ScriptType), + comphelper::makePropertyValue("Script", aDescriptor.ScriptCode) + }; + + return Any( aScriptDescriptor ); + } + + Sequence< OUString > SAL_CALL EventHolder::getElementNames( ) + { + Sequence< OUString > aReturn( m_aEventIndexAccess.size() ); + OUString* pReturn = aReturn.getArray(); + + // SvxMacroAssignDlg has a weird API: It expects a XNameReplace, means a container whose + // main access method is by name. In its UI, it shows the possible events in exactly the + // order in which XNameAccess::getElementNames returns them. + // However, SvxMacroAssignDlg *also* takes an index for the initial selection, which is + // relative to the sequence returned by XNameAccess::getElementNames. + // This is IMO weird, since it mixes index access with name access, which decreases efficiency + // of the implementation. + // Well, it means we're forced to return the events in getElementNames in exactly the same as they + // appear in the property browser UI. + for (auto const& elem : m_aEventIndexAccess) + { + *pReturn = elem.second; + ++pReturn; + } + return aReturn; + } + + sal_Bool SAL_CALL EventHolder::hasByName( const OUString& _rName ) + { + EventMap::const_iterator pos = m_aEventNameAccess.find( _rName ); + return pos != m_aEventNameAccess.end(); + } + + Type SAL_CALL EventHolder::getElementType( ) + { + return cppu::UnoType>::get(); + } + + sal_Bool SAL_CALL EventHolder::hasElements( ) + { + return !m_aEventNameAccess.empty(); + } + + + EventHandler::EventHandler( const Reference< XComponentContext >& _rxContext ) + :EventHandler_Base( m_aMutex ) + ,m_xContext( _rxContext ) + ,m_aPropertyListeners( m_aMutex ) + ,m_bEventsMapInitialized( false ) + ,m_bIsDialogElement( false ) + ,m_nGridColumnType( -1 ) + { + } + + EventHandler::~EventHandler() + { + } + + OUString SAL_CALL EventHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.EventHandler"; + } + + sal_Bool SAL_CALL EventHandler::supportsService( const OUString& ServiceName ) + { + return cppu::supportsService(this, ServiceName); + } + + Sequence< OUString > SAL_CALL EventHandler::getSupportedServiceNames( ) + { + return { "com.sun.star.form.inspection.EventHandler" }; + } + + void SAL_CALL EventHandler::inspect( const Reference< XInterface >& _rxIntrospectee ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !_rxIntrospectee.is() ) + throw NullPointerException(); + + m_xComponent.set( _rxIntrospectee, UNO_QUERY_THROW ); + + m_bEventsMapInitialized = false; + EventMap().swap(m_aEvents); + + m_bIsDialogElement = false; + m_nGridColumnType = -1; + try + { + Reference< XPropertySetInfo > xPSI( m_xComponent->getPropertySetInfo() ); + m_bIsDialogElement = xPSI.is() + && xPSI->hasPropertyByName( PROPERTY_WIDTH ) + && xPSI->hasPropertyByName( PROPERTY_HEIGHT ) + && xPSI->hasPropertyByName( PROPERTY_POSITIONX ) + && xPSI->hasPropertyByName( PROPERTY_POSITIONY ); + + Reference< XChild > xAsChild( _rxIntrospectee, UNO_QUERY ); + if ( xAsChild.is() && !Reference< XForm >( _rxIntrospectee, UNO_QUERY ).is() ) + { + if ( FormComponentType::GRIDCONTROL == classifyComponent( xAsChild->getParent() ) ) + { + m_nGridColumnType = classifyComponent( _rxIntrospectee ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + Any SAL_CALL EventHandler::getPropertyValue( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName ); + + std::vector< ScriptEventDescriptor > aEvents; + impl_getComponentScriptEvents_nothrow( aEvents ); + + ScriptEventDescriptor aPropertyValue; + for ( const ScriptEventDescriptor& rSCD : aEvents ) + { + if ( rEvent.sListenerClassName == rSCD.ListenerType + && rEvent.sListenerMethodName == rSCD.EventMethod + ) + { + aPropertyValue = rSCD; + break; + } + } + + return Any( aPropertyValue ); + } + + void SAL_CALL EventHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName ); + + ScriptEventDescriptor aNewScriptEvent; + OSL_VERIFY( _rValue >>= aNewScriptEvent ); + + ScriptEventDescriptor aOldScriptEvent; + OSL_VERIFY( getPropertyValue( _rPropertyName ) >>= aOldScriptEvent ); + if ( aOldScriptEvent == aNewScriptEvent ) + return; + + if ( m_bIsDialogElement ) + impl_setDialogElementScriptEvent_nothrow( aNewScriptEvent ); + else + impl_setFormComponentScriptEvent_nothrow( aNewScriptEvent ); + + PropertyHandlerHelper::setContextDocumentModified( m_xContext ); + + PropertyChangeEvent aEvent; + aEvent.Source = m_xComponent; + aEvent.PropertyHandle = rEvent.nId; + aEvent.PropertyName = _rPropertyName; + aEvent.OldValue <<= aOldScriptEvent; + aEvent.NewValue <<= aNewScriptEvent; + m_aPropertyListeners.notifyEach( &XPropertyChangeListener::propertyChange, aEvent ); + } + + Any SAL_CALL EventHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + OUString sNewScriptCode; + OSL_VERIFY( _rControlValue >>= sNewScriptCode ); + + std::vector< ScriptEventDescriptor > aAllAssignedEvents; + impl_getComponentScriptEvents_nothrow( aAllAssignedEvents ); + + const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName ); + ScriptEventDescriptor aAssignedScript = lcl_getAssignedScriptEvent( rEvent, aAllAssignedEvents ); + + OSL_ENSURE( sNewScriptCode.isEmpty(), "EventHandler::convertToPropertyValue: cannot convert a non-empty display name!" ); + // Usually, there is no possibility for the user to change the content of an event binding directly in the + // input field, this instead is done with the macro assignment dialog. + // The only exception is the user pressing "DEL" while the control has the focus, in this case, we reset the + // control content to an empty string. So this is the only scenario where this method is allowed to be called. + + // Strictly, we would be able to convert the display value to a property value, + // using the "name (location, language)" format we used in convertToControlValue. However, + // there is no need for this code... + + aAssignedScript.ScriptCode = sNewScriptCode; + return Any( aAssignedScript ); + } + + Any SAL_CALL EventHandler::convertToControlValue( const OUString& /*_rPropertyName*/, const Any& _rPropertyValue, const Type& _rControlValueType ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + ScriptEventDescriptor aScriptEvent; + OSL_VERIFY( _rPropertyValue >>= aScriptEvent ); + + OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING, + "EventHandler::convertToControlValue: unexpected ControlValue type class!" ); + + OUString sScript( aScriptEvent.ScriptCode ); + if ( !sScript.isEmpty() ) + { + // format is: "name (location, language)" + try + { + // parse + Reference< XUriReferenceFactory > xUriRefFac = UriReferenceFactory::create( m_xContext ); + Reference< XVndSunStarScriptUrlReference > xScriptUri( xUriRefFac->parse( sScript ), UNO_QUERY_THROW ); + + OUStringBuffer aComposeBuffer; + + // name + aComposeBuffer.append( xScriptUri->getName() ); + + // location + const OUString sLocation = xScriptUri->getParameter( "location" ); + const OUString sLanguage = xScriptUri->getParameter( "language" ); + + if ( !(sLocation.isEmpty() && sLanguage.isEmpty()) ) + { + aComposeBuffer.append( " (" ); + + // location + OSL_ENSURE( !sLocation.isEmpty(), "EventHandler::convertToControlValue: unexpected: no location!" ); + if ( !sLocation.isEmpty() ) + { + aComposeBuffer.append( sLocation ); + aComposeBuffer.append( ", " ); + } + + // language + if ( !sLanguage.isEmpty() ) + { + aComposeBuffer.append( sLanguage ); + } + + aComposeBuffer.append( ')' ); + } + + sScript = aComposeBuffer.makeStringAndClear(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + return Any( sScript ); + } + + PropertyState SAL_CALL EventHandler::getPropertyState( const OUString& /*_rPropertyName*/ ) + { + return PropertyState_DIRECT_VALUE; + } + + void SAL_CALL EventHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !_rxListener.is() ) + throw NullPointerException(); + m_aPropertyListeners.addInterface( _rxListener ); + } + + void SAL_CALL EventHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_aPropertyListeners.removeInterface( _rxListener ); + } + + Sequence< Property > SAL_CALL EventHandler::getSupportedProperties() + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_bEventsMapInitialized ) + { + m_bEventsMapInitialized = true; + try + { + std::vector< Type > aListeners; + impl_getComponentListenerTypes_nothrow( aListeners ); + + OUString sListenerClassName; + + // loop through all listeners and all methods, and see which we can present at the UI + for ( const Type& rListener : aListeners ) + { + // the programmatic name of the listener, to be used as "property" name + sListenerClassName = rListener.getTypeName(); + OSL_ENSURE( !sListenerClassName.isEmpty(), "EventHandler::getSupportedProperties: strange - no listener name ..." ); + if ( sListenerClassName.isEmpty() ) + continue; + + // loop through all methods + const Sequence aEventMethods = comphelper::getEventMethodsForType( rListener ); + for (const OUString& rMethod : aEventMethods) + { + EventDescription aEvent; + if ( !lcl_getEventDescriptionForMethod( rMethod, aEvent ) ) + continue; + + if ( !impl_filterMethod_nothrow( aEvent ) ) + continue; + + m_aEvents.emplace( + lcl_getEventPropertyName( sListenerClassName, rMethod ), aEvent ); + } + } + + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + // sort them by ID - this is the relative ordering in the UI + std::map< EventId, Property > aOrderedProperties; + for (auto const& event : m_aEvents) + { + aOrderedProperties[ event.second.nId ] = Property( + event.first, event.second.nId, + ::cppu::UnoType::get(), + PropertyAttribute::BOUND ); + } + + return comphelper::mapValuesToSequence( aOrderedProperties ); + } + + Sequence< OUString > SAL_CALL EventHandler::getSupersededProperties( ) + { + // none + return Sequence< OUString >( ); + } + + Sequence< OUString > SAL_CALL EventHandler::getActuatingProperties( ) + { + // none + return Sequence< OUString >( ); + } + + LineDescriptor SAL_CALL EventHandler::describePropertyLine( const OUString& _rPropertyName, + const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + if ( !_rxControlFactory.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + + LineDescriptor aDescriptor; + + aDescriptor.Control = _rxControlFactory->createPropertyControl( PropertyControlType::TextField, true ); + new PropertyControlExtender( aDescriptor.Control ); + + const EventDescription& rEvent = impl_getEventForName_throw( _rPropertyName ); + aDescriptor.DisplayName = rEvent.sDisplayName; + aDescriptor.HelpURL = HelpIdUrl::getHelpURL( rEvent.sHelpId ); + aDescriptor.PrimaryButtonId = OStringToOUString(rEvent.sUniqueBrowseId, RTL_TEXTENCODING_UTF8); + aDescriptor.HasPrimaryButton = true; + aDescriptor.Category = "Events"; + return aDescriptor; + } + + sal_Bool SAL_CALL EventHandler::isComposable( const OUString& /*_rPropertyName*/ ) + { + return false; + } + + InteractiveSelectionResult SAL_CALL EventHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool /*_bPrimary*/, Any& /*_rData*/, const Reference< XObjectInspectorUI >& _rxInspectorUI ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + const EventDescription& rForEvent = impl_getEventForName_throw( _rPropertyName ); + + std::vector< ScriptEventDescriptor > aAllAssignedEvents; + impl_getComponentScriptEvents_nothrow( aAllAssignedEvents ); + + // SvxMacroAssignDlg-compatible structure holding all event/assignments + ::rtl::Reference< EventHolder > pEventHolder( new EventHolder ); + + for (auto const& event : m_aEvents) + { + // the script which is assigned to the current event (if any) + ScriptEventDescriptor aAssignedScript = lcl_getAssignedScriptEvent( event.second, aAllAssignedEvents ); + pEventHolder->addEvent( event.second.nId, event.second.sListenerMethodName, aAssignedScript ); + } + + // the initial selection in the dialog + const Sequence< OUString > aNames( pEventHolder->getElementNames() ); + const OUString* pChosenEvent = std::find( aNames.begin(), aNames.end(), rForEvent.sListenerMethodName ); + sal_uInt16 nInitialSelection = static_cast( pChosenEvent - aNames.begin() ); + + // the dialog + SvxAbstractDialogFactory* pFactory = SvxAbstractDialogFactory::Create(); + + ScopedVclPtr pDialog( pFactory->CreateSvxMacroAssignDlg( + PropertyHandlerHelper::getDialogParentFrame( m_xContext ), + impl_getContextFrame_nothrow(), + m_bIsDialogElement, + pEventHolder, + nInitialSelection + ) ); + + if ( !pDialog ) + return InteractiveSelectionResult_Cancelled; + + // DF definite problem here + // OK & Cancel seem to be both returning 0 + if ( pDialog->Execute() == RET_CANCEL ) + return InteractiveSelectionResult_Cancelled; + + try + { + for (auto const& event : m_aEvents) + { + ScriptEventDescriptor aScriptDescriptor( pEventHolder->getNormalizedDescriptorByName( event.second.sListenerMethodName ) ); + + // set the new "property value" + setPropertyValue( + lcl_getEventPropertyName( event.second.sListenerClassName, event.second.sListenerMethodName ), + Any( aScriptDescriptor ) + ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + return InteractiveSelectionResult_Success; + } + + void SAL_CALL EventHandler::actuatingPropertyChanged( const OUString& /*_rActuatingPropertyName*/, const Any& /*_rNewValue*/, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/, sal_Bool /*_bFirstTimeInit*/ ) + { + OSL_FAIL( "EventHandler::actuatingPropertyChanged: no actuating properties -> no callback (well, this is how it *should* be!)" ); + } + + IMPLEMENT_FORWARD_XCOMPONENT( EventHandler, EventHandler_Base ) + + void SAL_CALL EventHandler::disposing() + { + EventMap().swap(m_aEvents); + m_xComponent.clear(); + } + + sal_Bool SAL_CALL EventHandler::suspend( sal_Bool /*_bSuspend*/ ) + { + return true; + } + + Reference< XFrame > EventHandler::impl_getContextFrame_nothrow() const + { + Reference< XFrame > xContextFrame; + + try + { + Reference< XModel > xContextDocument( PropertyHandlerHelper::getContextDocument(m_xContext), UNO_QUERY_THROW ); + Reference< XController > xController( xContextDocument->getCurrentController(), UNO_SET_THROW ); + xContextFrame.set( xController->getFrame(), UNO_SET_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + return xContextFrame; + } + + sal_Int32 EventHandler::impl_getComponentIndexInParent_throw() const + { + Reference< XChild > xChild( m_xComponent, UNO_QUERY_THROW ); + Reference< XIndexAccess > xParentAsIndexAccess( xChild->getParent(), UNO_QUERY_THROW ); + + // get the index of the inspected object within its parent container + sal_Int32 nElements = xParentAsIndexAccess->getCount(); + for ( sal_Int32 i=0; i xElement( xParentAsIndexAccess->getByIndex( i ), UNO_QUERY_THROW ); + if ( xElement == m_xComponent ) + return i; + } + throw NoSuchElementException(); + } + + void EventHandler::impl_getFormComponentScriptEvents_nothrow( std::vector < ScriptEventDescriptor >& _out_rEvents ) const + { + _out_rEvents.clear(); + try + { + Reference< XChild > xChild( m_xComponent, UNO_QUERY_THROW ); + Reference< XEventAttacherManager > xEventManager( xChild->getParent(), UNO_QUERY_THROW ); + comphelper::sequenceToContainer(_out_rEvents, xEventManager->getScriptEvents( impl_getComponentIndexInParent_throw() )); + + // the form component script API has unqualified listener names, but for normalization + // purpose, we want fully qualified ones + for ( ScriptEventDescriptor& rSED : _out_rEvents) + { + rSED.ListenerType = lcl_getQualifiedKnownListenerName( rSED ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + void EventHandler::impl_getComponentListenerTypes_nothrow( std::vector< Type >& _out_rTypes ) const + { + _out_rTypes.clear(); + try + { + // we use a set to avoid duplicates + TypeBag aListeners; + + Reference< XIntrospection > xIntrospection = theIntrospection::get( m_xContext ); + + // --- model listeners + lcl_addListenerTypesFor_throw( + m_xComponent, xIntrospection, aListeners ); + + // --- "secondary component" (usually: "control" listeners) + { + Reference< XInterface > xSecondaryComponent( impl_getSecondaryComponentForEventInspection_throw() ); + lcl_addListenerTypesFor_throw( xSecondaryComponent, xIntrospection, aListeners ); + ::comphelper::disposeComponent( xSecondaryComponent ); + } + + // now that they're disambiguated, copy these types into our member + _out_rTypes.insert( _out_rTypes.end(), aListeners.begin(), aListeners.end() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + void EventHandler::impl_getDialogElementScriptEvents_nothrow( std::vector < ScriptEventDescriptor >& _out_rEvents ) const + { + _out_rEvents.clear(); + try + { + Reference< XScriptEventsSupplier > xEventsSupplier( m_xComponent, UNO_QUERY_THROW ); + Reference< XNameContainer > xEvents( xEventsSupplier->getEvents(), UNO_SET_THROW ); + Sequence< OUString > aEventNames( xEvents->getElementNames() ); + + sal_Int32 nEventCount = aEventNames.getLength(); + _out_rEvents.resize( nEventCount ); + + for( sal_Int32 i = 0; i < nEventCount; ++i ) + OSL_VERIFY( xEvents->getByName( aEventNames[i] ) >>= _out_rEvents[i] ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + Reference< XInterface > EventHandler::impl_getSecondaryComponentForEventInspection_throw( ) const + { + Reference< XInterface > xReturn; + + // if it's a form, create a form controller for the additional events + Reference< XForm > xComponentAsForm( m_xComponent, UNO_QUERY ); + if ( xComponentAsForm.is() ) + { + Reference< XTabControllerModel > xComponentAsTCModel( m_xComponent, UNO_QUERY_THROW ); + Reference< XFormController > xController = FormController::create( m_xContext ); + xController->setModel( xComponentAsTCModel ); + + xReturn = xController; + } + else + { + OUString sControlService; + OSL_VERIFY( m_xComponent->getPropertyValue( PROPERTY_DEFAULTCONTROL ) >>= sControlService ); + + xReturn = m_xContext->getServiceManager()->createInstanceWithContext( sControlService, m_xContext ); + } + return xReturn; + } + + const EventDescription& EventHandler::impl_getEventForName_throw( const OUString& _rPropertyName ) const + { + EventMap::const_iterator pos = m_aEvents.find( _rPropertyName ); + if ( pos == m_aEvents.end() ) + throw UnknownPropertyException(_rPropertyName); + return pos->second; + } + + namespace + { + bool lcl_endsWith( const OUString& _rText, const OUString& _rCheck ) + { + sal_Int32 nTextLen = _rText.getLength(); + sal_Int32 nCheckLen = _rCheck.getLength(); + if ( nCheckLen > nTextLen ) + return false; + + return _rText.indexOf( _rCheck ) == ( nTextLen - nCheckLen ); + } + } + + void EventHandler::impl_setFormComponentScriptEvent_nothrow( const ScriptEventDescriptor& _rScriptEvent ) + { + try + { + OUString sScriptCode( _rScriptEvent.ScriptCode ); + OUString sScriptType( _rScriptEvent.ScriptType ); + bool bResetScript = sScriptCode.isEmpty(); + + sal_Int32 nObjectIndex = impl_getComponentIndexInParent_throw(); + Reference< XChild > xChild( m_xComponent, UNO_QUERY_THROW ); + Reference< XEventAttacherManager > xEventManager( xChild->getParent(), UNO_QUERY_THROW ); + std::vector< ScriptEventDescriptor > aEvents; + comphelper::sequenceToContainer( aEvents, xEventManager->getScriptEvents( nObjectIndex ) ); + + // is there already a registered script for this event? + sal_Int32 eventCount = aEvents.size(), event = 0; + for ( event = 0; event < eventCount; ++event ) + { + ScriptEventDescriptor* pEvent = &aEvents[event]; + if ( ( pEvent->EventMethod == _rScriptEvent.EventMethod ) + && ( lcl_endsWith( _rScriptEvent.ListenerType, pEvent->ListenerType ) ) + // (strange enough, the events we get from getScriptEvents are not fully qualified) + ) + { + // yes + if ( !bResetScript ) + { + // set to something non-empty -> overwrite + pEvent->ScriptCode = sScriptCode; + pEvent->ScriptType = sScriptType; + } + else + { + // set to empty -> remove from vector + aEvents.erase(aEvents.begin() + event ); + --eventCount; + } + break; + } + } + if ( ( event >= eventCount ) && !bResetScript ) + { + // no, did not find it -> append + aEvents.push_back( _rScriptEvent ); + } + + xEventManager->revokeScriptEvents( nObjectIndex ); + xEventManager->registerScriptEvents( nObjectIndex, comphelper::containerToSequence(aEvents) ); + + PropertyHandlerHelper::setContextDocumentModified( m_xContext ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + void EventHandler::impl_setDialogElementScriptEvent_nothrow( const ScriptEventDescriptor& _rScriptEvent ) + { + try + { + OUString sScriptCode( _rScriptEvent.ScriptCode ); + bool bResetScript = sScriptCode.isEmpty(); + + Reference< XScriptEventsSupplier > xEventsSupplier( m_xComponent, UNO_QUERY_THROW ); + Reference< XNameContainer > xEvents( xEventsSupplier->getEvents(), UNO_SET_THROW ); + + OUString sCompleteName = + _rScriptEvent.ListenerType + + "::" + + _rScriptEvent.EventMethod; + + bool bExists = xEvents->hasByName( sCompleteName ); + + if ( bResetScript ) + { + if ( bExists ) + xEvents->removeByName( sCompleteName ); + } + else + { + Any aNewValue; aNewValue <<= _rScriptEvent; + + if ( bExists ) + xEvents->replaceByName( sCompleteName, aNewValue ); + else + xEvents->insertByName( sCompleteName, aNewValue ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + bool EventHandler::impl_filterMethod_nothrow( const EventDescription& _rEvent ) const + { + // some (control-triggered) events do not make sense for certain grid control columns. However, + // our mechanism to retrieve control-triggered events does not know about this, so we do some + // late filtering here. + switch ( m_nGridColumnType ) + { + case FormComponentType::COMBOBOX: + if ( UID_BRWEVT_ACTIONPERFORMED == _rEvent.sUniqueBrowseId ) + return false; + break; + case FormComponentType::LISTBOX: + if ( ( UID_BRWEVT_CHANGED == _rEvent.sUniqueBrowseId ) + || ( UID_BRWEVT_ACTIONPERFORMED == _rEvent.sUniqueBrowseId ) + ) + return false; + break; + } + + return true; + } + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_EventHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::EventHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/eventhandler.hxx b/extensions/source/propctrlr/eventhandler.hxx new file mode 100644 index 000000000..4506f1b06 --- /dev/null +++ b/extensions/source/propctrlr/eventhandler.hxx @@ -0,0 +1,241 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "pcrcommon.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace pcr +{ + + + //= EventDescription + + typedef sal_Int32 EventId; + struct EventDescription + { + public: + OUString sDisplayName; + OUString sListenerClassName; + OUString sListenerMethodName; + OUString sHelpId; + OString sUniqueBrowseId; + EventId nId; + + EventDescription() + :nId( 0 ) + { + } + + EventDescription( + EventId _nId, + const char* _pListenerNamespaceAscii, + const char* _pListenerClassAsciiName, + const char* _pListenerMethodAsciiName, + TranslateId pDisplayNameResId, + const OUString& _sHelpId, + const OString& _sUniqueBrowseId ); + }; + + typedef std::unordered_map< OUString, EventDescription > EventMap; + + + //= EventHandler + + typedef ::cppu::WeakComponentImplHelper < css::inspection::XPropertyHandler + , css::lang::XServiceInfo + > EventHandler_Base; + class EventHandler final : public EventHandler_Base + { + private: + mutable ::osl::Mutex m_aMutex; + + /// the context in which the instance was created + css::uno::Reference< css::uno::XComponentContext > m_xContext; + /// the properties of the object we're handling + css::uno::Reference< css::beans::XPropertySet > m_xComponent; + /// our XPropertyChangeListener(s) + PropertyChangeListeners m_aPropertyListeners; + /// cache of the events we found at our introspectee + EventMap m_aEvents; + /// has m_aEvents been initialized? + bool m_bEventsMapInitialized; + /// is our introspectee a dialog element? + bool m_bIsDialogElement; + // TODO: move different handling into different derived classes? + /// (FormComponent) type of the grid column being inspected, or -1 if we're not inspecting a grid column + sal_Int16 m_nGridColumnType; + + public: + explicit EventHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + virtual ~EventHandler() override; + + private: + // XPropertyHandler overridables + virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override; + virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override; + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual css::uno::Sequence< css::beans::Property > SAL_CALL getSupportedProperties() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupersededProperties( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override; + virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + virtual sal_Bool SAL_CALL isComposable( const OUString& _rPropertyName ) override; + virtual css::inspection::InteractiveSelectionResult SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override; + virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override; + + // XComponent + DECLARE_XCOMPONENT() + virtual void SAL_CALL disposing() 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; + + /** returns the script events associated with our introspectee + @param _out_rEvents + Takes, upon successful return, the events currently associated with the introspectee + @precond + Our introspectee is a form component + */ + void impl_getFormComponentScriptEvents_nothrow( + std::vector< css::script::ScriptEventDescriptor >& _out_rEvents + ) const; + + /** returns the script events associated with our introspectee + @param _out_rEvents + Takes, upon successful return, the events currently associated with the introspectee + @precond + Our introspectee is a dialog element + */ + void impl_getDialogElementScriptEvents_nothrow( + std::vector< css::script::ScriptEventDescriptor >& _out_rEvents + ) const; + + /** returns the script events associated with our introspectee + @param _out_rEvents + Takes, the events currently associated with the introspectee + */ + void impl_getComponentScriptEvents_nothrow( + std::vector< css::script::ScriptEventDescriptor >& _out_rEvents + ) const + { + if ( m_bIsDialogElement ) + impl_getDialogElementScriptEvents_nothrow( _out_rEvents ); + else + impl_getFormComponentScriptEvents_nothrow( _out_rEvents ); + } + + /** returns the types of the listeners which can be registered at our introspectee + @param _out_rTypes + Takes, upon successful return, the types of possible listeners at the introspectee + */ + void impl_getComponentListenerTypes_nothrow( + std::vector< css::uno::Type >& _out_rTypes + ) const; + + /** returns a secondary component to be used for event inspection + + In the UI, we want to mix events for the control model with events for the control. + Since our introspectee is a model, this method creates a control for it (if possible). + + @return + the secondary component whose events should be mixed with the introspectee's events + The caller takes the ownership of the component (if not ). + + @throws + if an unexpected error occurs during creation of the secondary component. + A component to be returned is not unexpected, but allowed + + @precond + ->m_xComponent is not + */ + css::uno::Reference< css::uno::XInterface > + impl_getSecondaryComponentForEventInspection_throw( ) const; + + /** returns the event description for the given (programmatic) property name + @param _rPropertyName + the name whose event description should be looked up + @return + the event description for the property name + @throws css::beans::UnknownPropertyException + if our introspectee does not have an event with the given logical name (see ->getSupportedProperties) + */ + const EventDescription& + impl_getEventForName_throw( const OUString& _rPropertyName ) const; + + /** returns the index of our component within its parent, if this parent can be + obtained (XChild::getParent) and supports an ->XIndexAccess interface + */ + sal_Int32 impl_getComponentIndexInParent_throw() const; + + /** sets a given script event as event handler at a form component + + @param _rScriptEvent + the script event to set + */ + void impl_setFormComponentScriptEvent_nothrow( const css::script::ScriptEventDescriptor& _rScriptEvent ); + + /** sets a given script event as event handler at a dialog component + + @param _rScriptEvent + the script event to set + */ + void impl_setDialogElementScriptEvent_nothrow( const css::script::ScriptEventDescriptor& _rScriptEvent ); + + /** returns the frame associated with our context document + */ + css::uno::Reference< css::frame::XFrame > + impl_getContextFrame_nothrow() const; + + /** approves or denies a certain method to be included in the UI + @return + if and only if the given method is allowed. + */ + bool impl_filterMethod_nothrow( const EventDescription& _rEvent ) const; + + EventHandler( const EventHandler& ) = delete; + EventHandler& operator=( const EventHandler& ) = delete; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/fontdialog.cxx b/extensions/source/propctrlr/fontdialog.cxx new file mode 100644 index 000000000..133367953 --- /dev/null +++ b/extensions/source/propctrlr/fontdialog.cxx @@ -0,0 +1,572 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "fontdialog.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "formstrings.hxx" +#include "fontitemids.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + + + //= OFontPropertyExtractor + + namespace { + + class OFontPropertyExtractor + { + protected: + css::uno::Reference< css::beans::XPropertySet > + m_xPropValueAccess; + css::uno::Reference< css::beans::XPropertyState > + m_xPropStateAccess; + + public: + explicit OFontPropertyExtractor( const css::uno::Reference< css::beans::XPropertySet >& + _rxProps ); + + public: + bool getCheckFontProperty(const OUString& _rPropName, css::uno::Any& _rValue); + OUString getStringFontProperty(const OUString& _rPropName, const OUString& _rDefault); + sal_Int16 getInt16FontProperty(const OUString& _rPropName, const sal_Int16 _nDefault); + sal_Int32 getInt32FontProperty(const OUString& _rPropName, const sal_Int32 _nDefault); + float getFloatFontProperty(const OUString& _rPropName, const float _nDefault); + + void invalidateItem( + const OUString& _rPropName, + sal_uInt16 _nItemId, + SfxItemSet& _rSet, + bool _bForceInvalidation = false); + }; + + } + + OFontPropertyExtractor::OFontPropertyExtractor(const Reference< XPropertySet >& _rxProps) + :m_xPropValueAccess(_rxProps) + ,m_xPropStateAccess(_rxProps, UNO_QUERY) + { + OSL_ENSURE(m_xPropValueAccess.is(), "OFontPropertyExtractor::OFontPropertyExtractor: invalid property set!"); + } + + + bool OFontPropertyExtractor::getCheckFontProperty(const OUString& _rPropName, Any& _rValue) + { + _rValue = m_xPropValueAccess->getPropertyValue(_rPropName); + if (m_xPropStateAccess.is()) + return PropertyState_DEFAULT_VALUE == m_xPropStateAccess->getPropertyState(_rPropName); + + return false; + } + + + OUString OFontPropertyExtractor::getStringFontProperty(const OUString& _rPropName, const OUString& _rDefault) + { + Any aValue; + if (getCheckFontProperty(_rPropName, aValue)) + return _rDefault; + + return ::comphelper::getString(aValue); + } + + + sal_Int16 OFontPropertyExtractor::getInt16FontProperty(const OUString& _rPropName, const sal_Int16 _nDefault) + { + Any aValue; + if (getCheckFontProperty(_rPropName, aValue)) + return _nDefault; + + sal_Int32 nValue(_nDefault); + ::cppu::enum2int(nValue, aValue); + return static_cast(nValue); + } + + + sal_Int32 OFontPropertyExtractor::getInt32FontProperty(const OUString& _rPropName, const sal_Int32 _nDefault) + { + Any aValue; + if (getCheckFontProperty(_rPropName, aValue)) + return _nDefault; + + sal_Int32 nValue(_nDefault); + ::cppu::enum2int(nValue, aValue); + return nValue; + } + + + float OFontPropertyExtractor::getFloatFontProperty(const OUString& _rPropName, const float _nDefault) + { + Any aValue; + if (getCheckFontProperty(_rPropName, aValue)) + return _nDefault; + + return ::comphelper::getFloat(aValue); + } + + + void OFontPropertyExtractor::invalidateItem(const OUString& _rPropName, sal_uInt16 _nItemId, SfxItemSet& _rSet, bool _bForceInvalidation) + { + if ( _bForceInvalidation + || ( m_xPropStateAccess.is() + && (PropertyState_AMBIGUOUS_VALUE == m_xPropStateAccess->getPropertyState(_rPropName)) + ) + ) + _rSet.InvalidateItem(_nItemId); + } + + //= ControlCharacterDialog + ControlCharacterDialog::ControlCharacterDialog(weld::Window* pParent, const SfxItemSet& _rCoreSet) + : SfxTabDialogController(pParent, "modules/spropctrlr/ui/controlfontdialog.ui", "ControlFontDialog", &_rCoreSet) + { + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + AddTabPage("font", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_CHAR_NAME), nullptr ); + AddTabPage("fonteffects", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_CHAR_EFFECTS), nullptr ); + } + + ControlCharacterDialog::~ControlCharacterDialog() + { + } + + void ControlCharacterDialog::translatePropertiesToItems(const Reference< XPropertySet >& _rxModel, SfxItemSet* _pSet) + { + OSL_ENSURE(_pSet && _rxModel.is(), "ControlCharacterDialog::translatePropertiesToItems: invalid arguments!"); + if (!_pSet || !_rxModel.is()) + return; + + try + { + OFontPropertyExtractor aPropExtractor(_rxModel); + + // some items, which may be in default state, have to be filled with non-void information + vcl::Font aDefaultVCLFont = Application::GetDefaultDevice()->GetSettings().GetStyleSettings().GetAppFont(); + css::awt::FontDescriptor aDefaultFont = VCLUnoHelper::CreateFontDescriptor(aDefaultVCLFont); + + // get the current properties + OUString aFontName = aPropExtractor.getStringFontProperty(PROPERTY_FONT_NAME, aDefaultFont.Name); + OUString aFontStyleName = aPropExtractor.getStringFontProperty(PROPERTY_FONT_STYLENAME, aDefaultFont.StyleName); + sal_Int16 nFontFamily = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_FAMILY, aDefaultFont.Family); + sal_Int16 nFontCharset = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_CHARSET, aDefaultFont.CharSet); + float nFontHeight = aPropExtractor.getFloatFontProperty(PROPERTY_FONT_HEIGHT, static_cast(aDefaultFont.Height)); + float nFontWeight = aPropExtractor.getFloatFontProperty(PROPERTY_FONT_WEIGHT, aDefaultFont.Weight); + css::awt::FontSlant nFontSlant = static_cast(aPropExtractor.getInt16FontProperty(PROPERTY_FONT_SLANT, static_cast(aDefaultFont.Slant))); + sal_Int16 nFontLineStyle = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_UNDERLINE, aDefaultFont.Underline); + sal_Int16 nFontStrikeout = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_STRIKEOUT, aDefaultFont.Strikeout); + + sal_Int32 nTextLineColor = aPropExtractor.getInt32FontProperty(PROPERTY_TEXTLINECOLOR, sal_uInt32(COL_AUTO)); + sal_Int16 nFontRelief = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_RELIEF, static_cast(aDefaultVCLFont.GetRelief())); + sal_Int16 nFontEmphasisMark = aPropExtractor.getInt16FontProperty(PROPERTY_FONT_EMPHASIS_MARK, static_cast(aDefaultVCLFont.GetEmphasisMark())); + + Any aValue; + bool bWordLineMode = aPropExtractor.getCheckFontProperty(PROPERTY_WORDLINEMODE, aValue) ? aDefaultFont.WordLineMode : ::cppu::any2bool(aValue); + sal_Int32 nColor32 = aPropExtractor.getInt32FontProperty(PROPERTY_TEXTCOLOR, 0); + + // build SfxItems with the values + SvxFontItem aFontItem(static_cast(nFontFamily), aFontName, aFontStyleName, PITCH_DONTKNOW, nFontCharset, CFID_FONT); + + nFontHeight = static_cast(o3tl::convert(nFontHeight, o3tl::Length::pt, o3tl::Length::twip)); + + SvxFontHeightItem aSvxFontHeightItem(static_cast(nFontHeight),100,CFID_HEIGHT); + + FontWeight eWeight=vcl::unohelper::ConvertFontWeight(nFontWeight); + FontItalic eItalic=vcl::unohelper::ConvertFontSlant(nFontSlant); + FontLineStyle eUnderline=static_cast(nFontLineStyle); + FontStrikeout eStrikeout=static_cast(nFontStrikeout); + + SvxWeightItem aWeightItem(eWeight,CFID_WEIGHT); + SvxPostureItem aPostureItem(eItalic,CFID_POSTURE); + + SvxCrossedOutItem aCrossedOutItem(eStrikeout,CFID_STRIKEOUT); + SvxWordLineModeItem aWordLineModeItem(bWordLineMode, CFID_WORDLINEMODE); + + SvxUnderlineItem aUnderlineItem(eUnderline,CFID_UNDERLINE); + aUnderlineItem.SetColor(Color(ColorTransparency, nTextLineColor)); + + SvxColorItem aSvxColorItem(Color(ColorTransparency, nColor32),CFID_CHARCOLOR); + SvxLanguageItem aLanguageItem(Application::GetSettings().GetUILanguageTag().getLanguageType(), CFID_LANGUAGE); + + // the 2 CJK props + SvxCharReliefItem aFontReliefItem(static_cast(nFontRelief), CFID_RELIEF); + SvxEmphasisMarkItem aEmphasisMarkitem(static_cast(nFontEmphasisMark), CFID_EMPHASIS); + + _pSet->Put(aFontItem); + _pSet->Put(aSvxFontHeightItem); + _pSet->Put(aWeightItem); + _pSet->Put(aPostureItem); + _pSet->Put(aLanguageItem); + _pSet->Put(aUnderlineItem); + _pSet->Put(aCrossedOutItem); + _pSet->Put(aWordLineModeItem); + _pSet->Put(aSvxColorItem); + _pSet->Put(aFontReliefItem); + _pSet->Put(aEmphasisMarkitem); + + aPropExtractor.invalidateItem(PROPERTY_FONT_NAME, CFID_FONT, *_pSet); + aPropExtractor.invalidateItem(PROPERTY_FONT_HEIGHT, CFID_HEIGHT, *_pSet); + aPropExtractor.invalidateItem(PROPERTY_FONT_WEIGHT, CFID_WEIGHT, *_pSet, css::awt::FontWeight::DONTKNOW == nFontWeight); + aPropExtractor.invalidateItem(PROPERTY_FONT_SLANT, CFID_POSTURE, *_pSet, css::awt::FontSlant_DONTKNOW == nFontSlant); + aPropExtractor.invalidateItem(PROPERTY_FONT_UNDERLINE, CFID_UNDERLINE, *_pSet, css::awt::FontUnderline::DONTKNOW == nFontLineStyle); + aPropExtractor.invalidateItem(PROPERTY_FONT_STRIKEOUT, CFID_STRIKEOUT, *_pSet, css::awt::FontStrikeout::DONTKNOW == nFontStrikeout); + aPropExtractor.invalidateItem(PROPERTY_WORDLINEMODE, CFID_WORDLINEMODE, *_pSet); + aPropExtractor.invalidateItem(PROPERTY_TEXTCOLOR, CFID_CHARCOLOR, *_pSet); + aPropExtractor.invalidateItem(PROPERTY_FONT_RELIEF, CFID_RELIEF, *_pSet); + aPropExtractor.invalidateItem(PROPERTY_FONT_EMPHASIS_MARK, CFID_EMPHASIS, *_pSet); + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "ControlCharacterDialog::translatePropertiesToItems"); + } + + _pSet->DisableItem(SID_ATTR_CHAR_CJK_FONT); + _pSet->DisableItem(SID_ATTR_CHAR_CJK_FONTHEIGHT); + _pSet->DisableItem(SID_ATTR_CHAR_CJK_LANGUAGE); + _pSet->DisableItem(SID_ATTR_CHAR_CJK_POSTURE); + _pSet->DisableItem(SID_ATTR_CHAR_CJK_WEIGHT); + + _pSet->DisableItem(SID_ATTR_CHAR_CASEMAP); + _pSet->DisableItem(SID_ATTR_CHAR_CONTOUR); + _pSet->DisableItem(SID_ATTR_CHAR_SHADOWED); + } + + namespace + { + void lcl_pushBackPropertyValue( std::vector< NamedValue >& _out_properties, const OUString& _name, const Any& _value ) + { + _out_properties.push_back( NamedValue( _name, _value ) ); + } + } + + void ControlCharacterDialog::translateItemsToProperties( const SfxItemSet& _rSet, std::vector< NamedValue >& _out_properties ) + { + _out_properties.clear(); + + try + { + + // font name + SfxItemState eState = _rSet.GetItemState(CFID_FONT); + + if ( eState == SfxItemState::SET ) + { + const SvxFontItem& rFontItem = + static_cast(_rSet.Get(CFID_FONT)); + + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_NAME , Any(rFontItem.GetFamilyName())); + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_STYLENAME, Any(rFontItem.GetStyleName())); + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_FAMILY , Any(static_cast(rFontItem.GetFamily()))); + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_CHARSET , Any(static_cast(rFontItem.GetCharSet()))); + } + + + // font height + eState = _rSet.GetItemState(CFID_HEIGHT); + + if ( eState == SfxItemState::SET ) + { + const SvxFontHeightItem& rSvxFontHeightItem = + static_cast(_rSet.Get(CFID_HEIGHT)); + + float nHeight = static_cast(o3tl::convert(rSvxFontHeightItem.GetHeight(), o3tl::Length::twip, o3tl::Length::pt)); + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_HEIGHT,Any(nHeight)); + + } + + + // font weight + eState = _rSet.GetItemState(CFID_WEIGHT); + + if ( eState == SfxItemState::SET ) + { + const SvxWeightItem& rWeightItem = + static_cast(_rSet.Get(CFID_WEIGHT)); + + float nWeight = vcl::unohelper::ConvertFontWeight(rWeightItem.GetWeight()); + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_WEIGHT,Any(nWeight)); + } + + + // font slant + eState = _rSet.GetItemState(CFID_POSTURE); + + if ( eState == SfxItemState::SET ) + { + const SvxPostureItem& rPostureItem = + static_cast(_rSet.Get(CFID_POSTURE)); + + css::awt::FontSlant eSlant = vcl::unohelper::ConvertFontSlant(rPostureItem.GetPosture()); + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_SLANT, Any(static_cast(eSlant))); + } + + + // font underline + eState = _rSet.GetItemState(CFID_UNDERLINE); + + if ( eState == SfxItemState::SET ) + { + const SvxUnderlineItem& rUnderlineItem = + static_cast(_rSet.Get(CFID_UNDERLINE)); + + sal_Int16 nUnderline = static_cast(rUnderlineItem.GetLineStyle()); + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_UNDERLINE,Any(nUnderline)); + + // the text line color is transported in this item, too + Color nColor = rUnderlineItem.GetColor(); + + Any aUnoColor; + if (COL_AUTO != nColor) + aUnoColor <<= nColor; + + lcl_pushBackPropertyValue( _out_properties, PROPERTY_TEXTLINECOLOR, aUnoColor ); + } + + + // font strikeout + eState = _rSet.GetItemState(CFID_STRIKEOUT); + + if ( eState == SfxItemState::SET ) + { + const SvxCrossedOutItem& rCrossedOutItem = + static_cast(_rSet.Get(CFID_STRIKEOUT)); + + sal_Int16 nStrikeout = static_cast(rCrossedOutItem.GetStrikeout()); + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_STRIKEOUT,Any(nStrikeout)); + } + + + // font wordline mode + eState = _rSet.GetItemState(CFID_WORDLINEMODE); + + if ( eState == SfxItemState::SET ) + { + const SvxWordLineModeItem& rWordLineModeItem = + static_cast(_rSet.Get(CFID_WORDLINEMODE)); + + lcl_pushBackPropertyValue( _out_properties, PROPERTY_WORDLINEMODE, css::uno::Any(rWordLineModeItem.GetValue())); + } + + + // text color + eState = _rSet.GetItemState(CFID_CHARCOLOR); + + if ( eState == SfxItemState::SET ) + { + const SvxColorItem& rColorItem = + static_cast(_rSet.Get(CFID_CHARCOLOR)); + + Color nColor = rColorItem.GetValue(); + + Any aUnoColor; + if (COL_AUTO != nColor) + aUnoColor <<= nColor; + + lcl_pushBackPropertyValue( _out_properties, PROPERTY_TEXTCOLOR, aUnoColor ); + } + + + // font relief + eState = _rSet.GetItemState(CFID_RELIEF); + + if ( eState == SfxItemState::SET ) + { + const SvxCharReliefItem& rReliefItem = + static_cast(_rSet.Get(CFID_RELIEF)); + + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_RELIEF, Any(static_cast(rReliefItem.GetValue())) ); + } + + + // font emphasis mark + eState = _rSet.GetItemState(CFID_EMPHASIS); + + if ( eState == SfxItemState::SET ) + { + const SvxEmphasisMarkItem& rEmphMarkItem = + static_cast(_rSet.Get(CFID_EMPHASIS)); + + lcl_pushBackPropertyValue( _out_properties, PROPERTY_FONT_EMPHASIS_MARK, Any(static_cast(rEmphMarkItem.GetEmphasisMark())) ); + } + } + catch (const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + void ControlCharacterDialog::translateItemsToProperties( const SfxItemSet& _rSet, const Reference< XPropertySet >& _rxModel) + { + OSL_ENSURE( _rxModel.is(), "ControlCharacterDialog::translateItemsToProperties: invalid arguments!" ); + if ( !_rxModel.is()) + return; + + std::vector< NamedValue > aPropertyValues; + translateItemsToProperties( _rSet, aPropertyValues ); + try + { + for ( const NamedValue& rNV : aPropertyValues ) + _rxModel->setPropertyValue( rNV.Name, rNV.Value ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + void ControlCharacterDialog::createItemSet(std::unique_ptr& _rpSet, rtl::Reference& _rpPool, std::vector*& _rpDefaults) + { + // just to be sure... + _rpSet = nullptr; + _rpPool = nullptr; + _rpDefaults = nullptr; + + // create and initialize the defaults + _rpDefaults = new std::vector(CFID_LAST_ITEM_ID - CFID_FIRST_ITEM_ID + 1); + + vcl::Font aDefaultVCLFont = Application::GetDefaultDevice()->GetSettings().GetStyleSettings().GetAppFont(); + + SfxPoolItem** pCounter = _rpDefaults->data(); // want to modify this without affecting the out param _rppDefaults + *pCounter++ = new SvxFontItem(aDefaultVCLFont.GetFamilyType(), aDefaultVCLFont.GetFamilyName(), aDefaultVCLFont.GetStyleName(), aDefaultVCLFont.GetPitch(), aDefaultVCLFont.GetCharSet(), CFID_FONT); + *pCounter++ = new SvxFontHeightItem(aDefaultVCLFont.GetFontHeight(), 100, CFID_HEIGHT); + *pCounter++ = new SvxWeightItem(aDefaultVCLFont.GetWeight(), CFID_WEIGHT); + *pCounter++ = new SvxPostureItem(aDefaultVCLFont.GetItalic(), CFID_POSTURE); + *pCounter++ = new SvxLanguageItem(Application::GetSettings().GetUILanguageTag().getLanguageType(), CFID_LANGUAGE); + *pCounter++ = new SvxUnderlineItem(aDefaultVCLFont.GetUnderline(), CFID_UNDERLINE); + *pCounter++ = new SvxCrossedOutItem(aDefaultVCLFont.GetStrikeout(), CFID_STRIKEOUT); + *pCounter++ = new SvxWordLineModeItem(aDefaultVCLFont.IsWordLineMode(), CFID_WORDLINEMODE); + *pCounter++ = new SvxColorItem(aDefaultVCLFont.GetColor(), CFID_CHARCOLOR); + *pCounter++ = new SvxCharReliefItem(aDefaultVCLFont.GetRelief(), CFID_RELIEF); + *pCounter++ = new SvxEmphasisMarkItem(aDefaultVCLFont.GetEmphasisMark(), CFID_EMPHASIS); + + *pCounter++ = new SvxFontItem(aDefaultVCLFont.GetFamilyType(), aDefaultVCLFont.GetFamilyName(), aDefaultVCLFont.GetStyleName(), aDefaultVCLFont.GetPitch(), aDefaultVCLFont.GetCharSet(), CFID_CJK_FONT); + *pCounter++ = new SvxFontHeightItem(aDefaultVCLFont.GetFontHeight(), 100, CFID_CJK_HEIGHT); + *pCounter++ = new SvxWeightItem(aDefaultVCLFont.GetWeight(), CFID_CJK_WEIGHT); + *pCounter++ = new SvxPostureItem(aDefaultVCLFont.GetItalic(), CFID_CJK_POSTURE); + *pCounter++ = new SvxLanguageItem(Application::GetSettings().GetUILanguageTag().getLanguageType(), CFID_CJK_LANGUAGE); + + *pCounter++ = new SvxCaseMapItem(SvxCaseMap::NotMapped, CFID_CASEMAP); + *pCounter++ = new SvxContourItem(false, CFID_CONTOUR); + *pCounter++ = new SvxShadowedItem(false, CFID_SHADOWED); + + *pCounter++ = new SvxFontListItem (new FontList(Application::GetDefaultDevice()), CFID_FONTLIST); + + // create the pool + static SfxItemInfo const aItemInfos[CFID_LAST_ITEM_ID - CFID_FIRST_ITEM_ID + 1] = + { + { SID_ATTR_CHAR_FONT, false }, + { SID_ATTR_CHAR_FONTHEIGHT, false }, + { SID_ATTR_CHAR_WEIGHT, false }, + { SID_ATTR_CHAR_POSTURE, false }, + { SID_ATTR_CHAR_LANGUAGE, false }, + { SID_ATTR_CHAR_UNDERLINE, false }, + { SID_ATTR_CHAR_STRIKEOUT, false }, + { SID_ATTR_CHAR_WORDLINEMODE, false }, + { SID_ATTR_CHAR_COLOR, false }, + { SID_ATTR_CHAR_RELIEF, false }, + { SID_ATTR_CHAR_EMPHASISMARK, false }, + { 0, false }, + { 0, false }, + { 0, false }, + { 0, false }, + { 0, false }, + { 0, false }, + { 0, false }, + { 0, false }, + { SID_ATTR_CHAR_FONTLIST, false } + }; + + _rpPool = new SfxItemPool("PCRControlFontItemPool", CFID_FIRST_ITEM_ID, CFID_LAST_ITEM_ID, + aItemInfos, _rpDefaults); + _rpPool->FreezeIdRanges(); + + // and, finally, the set + _rpSet.reset(new SfxItemSet(*_rpPool)); + } + + void ControlCharacterDialog::destroyItemSet(std::unique_ptr& _rpSet, rtl::Reference& _rpPool, std::vector*& _rpDefaults) + { + // from the pool, get and remember the font list (needs to be deleted) + const SvxFontListItem& rFontListItem = static_cast(_rpPool->GetDefaultItem(CFID_FONTLIST)); + const FontList* pFontList = rFontListItem.GetFontList(); + + // _first_ delete the set (referring the pool) + _rpSet.reset(); + + // delete the pool + _rpPool->ReleaseDefaults(true); + // the "true" means delete the items, too + _rpPool = nullptr; + + // reset the defaults ptr + _rpDefaults = nullptr; + // no need to explicitly delete the defaults, this has been done by the ReleaseDefaults + + delete pFontList; + } + + void ControlCharacterDialog::PageCreated(const OString& rId, SfxTabPage& rPage) + { + SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool())); + if (rId == "font") + { + aSet.Put (static_cast(GetInputSetImpl()->Get(CFID_FONTLIST))); + aSet.Put (SfxUInt16Item(SID_DISABLE_CTL,DISABLE_HIDE_LANGUAGE)); + rPage.PageCreated(aSet); + } + } +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/fontdialog.hxx b/extensions/source/propctrlr/fontdialog.hxx new file mode 100644 index 000000000..eaba29db0 --- /dev/null +++ b/extensions/source/propctrlr/fontdialog.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + + +namespace pcr +{ + + + //= ControlCharacterDialog + class ControlCharacterDialog : public SfxTabDialogController + { + public: + ControlCharacterDialog(weld::Window* pParent, const SfxItemSet& rCoreSet); + virtual ~ControlCharacterDialog() override; + + /// creates an item set to be used with this dialog + static void createItemSet(std::unique_ptr& _rpSet, rtl::Reference& _rpPool, std::vector*& _rpDefaults); + + /// destroys an item previously created with createItemSet + static void destroyItemSet(std::unique_ptr& _rpSet, rtl::Reference& _rpPool, std::vector*& _rpDefaults); + + /// fills the given item set with values obtained from the given property set + static void translatePropertiesToItems( + const css::uno::Reference< css::beans::XPropertySet >& _rxModel, + SfxItemSet* _pSet); + + /** fills the given property set with values obtained from the given item set + */ + static void translateItemsToProperties( + const SfxItemSet& _rSet, + const css::uno::Reference< css::beans::XPropertySet >& _rxModel); + + /** fills the given property set with values obtained from the given item set + */ + static void translateItemsToProperties( + const SfxItemSet& _rSet, + std::vector< css::beans::NamedValue >& _out_properties ); + + protected: + virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; + }; + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/fontitemids.hxx b/extensions/source/propctrlr/fontitemids.hxx new file mode 100644 index 000000000..c9b3a455f --- /dev/null +++ b/extensions/source/propctrlr/fontitemids.hxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#define CFID_FONT 1 +#define CFID_HEIGHT 2 +#define CFID_WEIGHT 3 +#define CFID_POSTURE 4 +#define CFID_LANGUAGE 5 +#define CFID_UNDERLINE 6 +#define CFID_STRIKEOUT 7 +#define CFID_WORDLINEMODE 8 +#define CFID_CHARCOLOR 9 +#define CFID_RELIEF 10 +#define CFID_EMPHASIS 11 + +#define CFID_CJK_FONT 12 +#define CFID_CJK_HEIGHT 13 +#define CFID_CJK_WEIGHT 14 +#define CFID_CJK_POSTURE 15 +#define CFID_CJK_LANGUAGE 16 +#define CFID_CASEMAP 17 +#define CFID_CONTOUR 18 +#define CFID_SHADOWED 19 + +#define CFID_FONTLIST 20 + +#define CFID_FIRST_ITEM_ID CFID_FONT +#define CFID_LAST_ITEM_ID CFID_FONTLIST + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formbrowsertools.cxx b/extensions/source/propctrlr/formbrowsertools.cxx new file mode 100644 index 000000000..b31aa0ce4 --- /dev/null +++ b/extensions/source/propctrlr/formbrowsertools.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 "formbrowsertools.hxx" +#include +#include +#include +#include +#include +#include "modulepcr.hxx" +#include "formstrings.hxx" + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + + + OUString GetUIHeadlineName(sal_Int16 nClassId, const Any& aUnoObj) + { + OUString sClassName; + switch (nClassId) + { + case FormComponentType::TEXTFIELD: + { + Reference< XInterface > xIFace; + aUnoObj >>= xIFace; + sClassName = PcrRes(RID_STR_PROPTITLE_EDIT); + if (xIFace.is()) + { // we have a chance to check if it's a formatted field model + Reference< XServiceInfo > xInfo(xIFace, UNO_QUERY); + if (xInfo.is() && (xInfo->supportsService(SERVICE_COMPONENT_FORMATTEDFIELD))) + sClassName = PcrRes(RID_STR_PROPTITLE_FORMATTED); + else if (!xInfo.is()) + { + // couldn't distinguish between formatted and edit with the service name, so try with the properties + Reference< XPropertySet > xProps(xIFace, UNO_QUERY); + if (xProps.is()) + { + Reference< XPropertySetInfo > xPropsInfo = xProps->getPropertySetInfo(); + if (xPropsInfo.is() && xPropsInfo->hasPropertyByName(PROPERTY_FORMATSSUPPLIER)) + sClassName = PcrRes(RID_STR_PROPTITLE_FORMATTED); + } + } + } + } + break; + + case FormComponentType::COMMANDBUTTON: + sClassName = PcrRes(RID_STR_PROPTITLE_PUSHBUTTON); break; + case FormComponentType::RADIOBUTTON: + sClassName = PcrRes(RID_STR_PROPTITLE_RADIOBUTTON); break; + case FormComponentType::CHECKBOX: + sClassName = PcrRes(RID_STR_PROPTITLE_CHECKBOX); break; + case FormComponentType::LISTBOX: + sClassName = PcrRes(RID_STR_PROPTITLE_LISTBOX); break; + case FormComponentType::COMBOBOX: + sClassName = PcrRes(RID_STR_PROPTITLE_COMBOBOX); break; + case FormComponentType::GROUPBOX: + sClassName = PcrRes(RID_STR_PROPTITLE_GROUPBOX); break; + case FormComponentType::IMAGEBUTTON: + sClassName = PcrRes(RID_STR_PROPTITLE_IMAGEBUTTON); break; + case FormComponentType::FIXEDTEXT: + sClassName = PcrRes(RID_STR_PROPTITLE_FIXEDTEXT); break; + case FormComponentType::GRIDCONTROL: + sClassName = PcrRes(RID_STR_PROPTITLE_DBGRID); break; + case FormComponentType::FILECONTROL: + sClassName = PcrRes(RID_STR_PROPTITLE_FILECONTROL); break; + + case FormComponentType::DATEFIELD: + sClassName = PcrRes(RID_STR_PROPTITLE_DATEFIELD); break; + case FormComponentType::TIMEFIELD: + sClassName = PcrRes(RID_STR_PROPTITLE_TIMEFIELD); break; + case FormComponentType::NUMERICFIELD: + sClassName = PcrRes(RID_STR_PROPTITLE_NUMERICFIELD); break; + case FormComponentType::CURRENCYFIELD: + sClassName = PcrRes(RID_STR_PROPTITLE_CURRENCYFIELD); break; + case FormComponentType::PATTERNFIELD: + sClassName = PcrRes(RID_STR_PROPTITLE_PATTERNFIELD); break; + case FormComponentType::IMAGECONTROL: + sClassName = PcrRes(RID_STR_PROPTITLE_IMAGECONTROL); break; + case FormComponentType::HIDDENCONTROL: + sClassName = PcrRes(RID_STR_PROPTITLE_HIDDENCONTROL); break; + + case FormComponentType::CONTROL: + default: + sClassName = PcrRes(RID_STR_PROPTITLE_UNKNOWNCONTROL); break; + } + + return sClassName; + } + + + sal_Int16 classifyComponent( const Reference< XInterface >& _rxComponent ) + { + Reference< XPropertySet > xComponentProps( _rxComponent, UNO_QUERY_THROW ); + Reference< XPropertySetInfo > xPSI( xComponentProps->getPropertySetInfo(), UNO_SET_THROW ); + + sal_Int16 nControlType( FormComponentType::CONTROL ); + if ( xPSI->hasPropertyByName( PROPERTY_CLASSID ) ) + { + OSL_VERIFY( xComponentProps->getPropertyValue( PROPERTY_CLASSID ) >>= nControlType ); + } + return nControlType; + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formbrowsertools.hxx b/extensions/source/propctrlr/formbrowsertools.hxx new file mode 100644 index 000000000..08d48747c --- /dev/null +++ b/extensions/source/propctrlr/formbrowsertools.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +#include + + +namespace pcr +{ + + + OUString GetUIHeadlineName(sal_Int16 _nClassId, const css::uno::Any& _rUnoObject); + sal_Int16 classifyComponent( const css::uno::Reference< css::uno::XInterface >& _rxComponent ); + + + struct FindPropertyByHandle + { + private: + sal_Int32 m_nId; + + public: + explicit FindPropertyByHandle( sal_Int32 _nId ) : m_nId ( _nId ) { } + bool operator()( const css::beans::Property& _rProp ) const + { + return m_nId == _rProp.Handle; + } + }; + + + struct FindPropertyByName + { + private: + OUString m_sName; + + public: + explicit FindPropertyByName( const OUString& _rName ) : m_sName( _rName ) { } + bool operator()( const css::beans::Property& _rProp ) const + { + return m_sName == _rProp.Name; + } + }; + + + struct PropertyLessByName + { + bool operator() (const css::beans::Property& _rLhs, const css::beans::Property& _rRhs) const + { + return _rLhs.Name < _rRhs.Name; + } + }; + + + struct TypeLessByName + { + bool operator() (const css::uno::Type& _rLhs, const css::uno::Type& _rRhs) const + { + return _rLhs.getTypeName() < _rRhs.getTypeName(); + } + }; + + + typedef std::set< css::beans::Property, PropertyLessByName > PropertyBag; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formcomponenthandler.cxx b/extensions/source/propctrlr/formcomponenthandler.cxx new file mode 100644 index 000000000..d5f397662 --- /dev/null +++ b/extensions/source/propctrlr/formcomponenthandler.cxx @@ -0,0 +1,3305 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "controltype.hxx" +#include "modulepcr.hxx" +#include +#include +#include "fontdialog.hxx" +#include "formcomponenthandler.hxx" +#include "formlinkdialog.hxx" +#include "formmetadata.hxx" +#include +#include +#include +#include "formstrings.hxx" +#include "handlerhelper.hxx" +#include "listselectiondlg.hxx" +#include "pcrcommon.hxx" +#include "selectlabeldialog.hxx" +#include "standardcontrol.hxx" +#include "taborder.hxx" +#include "usercontrol.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 + +namespace pcr +{ + + + using namespace ::com::sun::star; + using namespace uno; + using namespace lang; + using namespace beans; + using namespace frame; + using namespace script; + using namespace form; + using namespace util; + using namespace awt; + using namespace sdb; + using namespace sdbc; + using namespace sdbcx; + using namespace report; + using namespace container; + using namespace ui::dialogs; + using namespace inspection; + using namespace ::dbtools; + + namespace WritingMode2 = ::com::sun::star::text::WritingMode2; + + + //= FormComponentPropertyHandler + +#define PROPERTY_ID_ROWSET 1 + + FormComponentPropertyHandler::FormComponentPropertyHandler( const Reference< XComponentContext >& _rxContext ) + :PropertyHandlerComponent( _rxContext ) + ,::comphelper::OPropertyContainer(PropertyHandlerComponent::rBHelper) + ,m_sDefaultValueString( PcrRes(RID_STR_STANDARD) ) + ,m_eComponentClass( eUnknown ) + ,m_bComponentIsSubForm( false ) + ,m_bHaveListSource( false ) + ,m_bHaveCommand( false ) + ,m_nClassId( 0 ) + { + registerProperty(PROPERTY_ROWSET,PROPERTY_ID_ROWSET,0,&m_xRowSet,cppu::UnoType::get()); + } + + + FormComponentPropertyHandler::~FormComponentPropertyHandler() + { + } + + IMPLEMENT_FORWARD_XINTERFACE2(FormComponentPropertyHandler,PropertyHandlerComponent,::comphelper::OPropertyContainer) + + OUString FormComponentPropertyHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.FormComponentPropertyHandler"; + } + + + Sequence< OUString > FormComponentPropertyHandler::getSupportedServiceNames( ) + { + return { "com.sun.star.form.inspection.FormComponentPropertyHandler" }; + } + + namespace { + + // TODO: -> export from toolkit + struct LanguageDependentProp + { + const char* pPropName; + sal_Int32 nPropNameLength; + }; + + } + + const LanguageDependentProp aLanguageDependentProp[] = + { + { "Text", 4 }, + { "Label", 5 }, + { "Title", 5 }, + { "HelpText", 8 }, + { "CurrencySymbol", 14 }, + { "StringItemList", 14 }, + { nullptr, 0 } + }; + + namespace + { + bool lcl_isLanguageDependentProperty( const OUString& aName ) + { + bool bRet = false; + + const LanguageDependentProp* pLangDepProp = aLanguageDependentProp; + while( pLangDepProp->pPropName != nullptr ) + { + if( aName.equalsAsciiL( pLangDepProp->pPropName, pLangDepProp->nPropNameLength )) + { + bRet = true; + break; + } + pLangDepProp++; + } + return bRet; + } + + Reference< resource::XStringResourceResolver > lcl_getStringResourceResolverForProperty + ( const Reference< XPropertySet >& _xComponent, const OUString& _rPropertyName, + const Any& _rPropertyValue ) + { + Reference< resource::XStringResourceResolver > xRet; + const TypeClass eType = _rPropertyValue.getValueType().getTypeClass(); + if ( (eType == TypeClass_STRING || eType == TypeClass_SEQUENCE) && + lcl_isLanguageDependentProperty( _rPropertyName ) ) + { + Reference< resource::XStringResourceResolver > xStringResourceResolver; + try + { + xStringResourceResolver.set( _xComponent->getPropertyValue( "ResourceResolver" ),UNO_QUERY); + if( xStringResourceResolver.is() && + xStringResourceResolver->getLocales().hasElements() ) + { + xRet = xStringResourceResolver; + } + } + catch(const UnknownPropertyException&) + { + // nii + } + } + + return xRet; + } + } + + + Any FormComponentPropertyHandler::impl_getPropertyValue_throw( const OUString& _rPropertyName ) const + { + const PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + // tdf#117159 crash with chart in database report + if (!m_xComponent) + return Any(); + + Any aPropertyValue( m_xComponent->getPropertyValue( _rPropertyName ) ); + + Reference< resource::XStringResourceResolver > xStringResourceResolver + = lcl_getStringResourceResolverForProperty( m_xComponent, _rPropertyName, aPropertyValue ); + if( xStringResourceResolver.is() ) + { + TypeClass eType = aPropertyValue.getValueType().getTypeClass(); + if( eType == TypeClass_STRING ) + { + OUString aPropStr; + aPropertyValue >>= aPropStr; + if( aPropStr.getLength() > 1 ) + { + OUString aPureIdStr = aPropStr.copy( 1 ); + if( xStringResourceResolver->hasEntryForId( aPureIdStr ) ) + { + OUString aResourceStr = xStringResourceResolver->resolveString( aPureIdStr ); + aPropertyValue <<= aResourceStr; + } + } + } + // StringItemList? + else if( eType == TypeClass_SEQUENCE ) + { + Sequence< OUString > aStrings; + aPropertyValue >>= aStrings; + + std::vector< OUString > aResolvedStrings; + aResolvedStrings.reserve( aStrings.getLength() ); + try + { + for ( const OUString& rIdStr : std::as_const(aStrings) ) + { + OUString aPureIdStr = rIdStr.copy( 1 ); + if( xStringResourceResolver->hasEntryForId( aPureIdStr ) ) + aResolvedStrings.push_back(xStringResourceResolver->resolveString( aPureIdStr )); + else + aResolvedStrings.push_back(rIdStr); + } + } + catch( const resource::MissingResourceException & ) + {} + aPropertyValue <<= comphelper::containerToSequence(aResolvedStrings); + } + } + else + impl_normalizePropertyValue_nothrow( aPropertyValue, nPropId ); + + return aPropertyValue; + } + + Any SAL_CALL FormComponentPropertyHandler::getPropertyValue( const OUString& _rPropertyName ) + { + if( _rPropertyName == PROPERTY_ROWSET ) + return ::comphelper::OPropertyContainer::getPropertyValue( _rPropertyName ); + + ::osl::MutexGuard aGuard( m_aMutex ); + return impl_getPropertyValue_throw( _rPropertyName ); + } + + void SAL_CALL FormComponentPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + if( _rPropertyName == PROPERTY_ROWSET ) + { + ::comphelper::OPropertyContainer::setPropertyValue( _rPropertyName, _rValue ); + return; + } + + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); // check if property is known by the handler + + Reference< graphic::XGraphicObject > xGrfObj; + if ( PROPERTY_ID_IMAGE_URL == nPropId && ( _rValue >>= xGrfObj ) ) + { + DBG_ASSERT( xGrfObj.is(), "FormComponentPropertyHandler::setPropertyValue() xGrfObj is invalid"); + m_xComponent->setPropertyValue(PROPERTY_GRAPHIC, uno::Any(xGrfObj->getGraphic())); + } + else if ( PROPERTY_ID_FONT == nPropId ) + { + // special handling, the value is a faked value we generated ourself in impl_executeFontDialog_nothrow + Sequence< NamedValue > aFontPropertyValues; + if( ! (_rValue >>= aFontPropertyValues) ) + SAL_WARN("extensions.propctrlr", "setPropertyValue: unable to get property " << PROPERTY_ID_FONT); + + for ( const NamedValue& fontPropertyValue : std::as_const(aFontPropertyValues) ) + m_xComponent->setPropertyValue( fontPropertyValue.Name, fontPropertyValue.Value ); + } + else + { + Any aValue = _rValue; + + Reference< resource::XStringResourceResolver > xStringResourceResolver + = lcl_getStringResourceResolverForProperty( m_xComponent, _rPropertyName, _rValue ); + if( xStringResourceResolver.is() ) + { + Reference< resource::XStringResourceManager > + xStringResourceManager( xStringResourceResolver, UNO_QUERY ); + if( xStringResourceManager.is() ) + { + Any aPropertyValue( m_xComponent->getPropertyValue( _rPropertyName ) ); + TypeClass eType = aPropertyValue.getValueType().getTypeClass(); + if( eType == TypeClass_STRING ) + { + OUString aPropStr; + aPropertyValue >>= aPropStr; + if( aPropStr.getLength() > 1 ) + { + OUString aPureIdStr = aPropStr.copy( 1 ); + OUString aValueStr; + _rValue >>= aValueStr; + xStringResourceManager->setString( aPureIdStr, aValueStr ); + aValue = aPropertyValue; // set value to force modified + } + } + // StringItemList? + else if( eType == TypeClass_SEQUENCE ) + { + static const char aDot[] = "."; + + // Put strings into resource using new ids + Sequence< OUString > aNewStrings; + _rValue >>= aNewStrings; + + const sal_Int32 nNewCount = aNewStrings.getLength(); + + // Create new Ids + std::unique_ptr pNewPureIds(new OUString[nNewCount]); + Any aNameAny = m_xComponent->getPropertyValue(PROPERTY_NAME); + OUString sControlName; + aNameAny >>= sControlName; + OUString aIdStrBase = aDot + + sControlName + + aDot + + _rPropertyName; + sal_Int32 i; + for ( i = 0; i < nNewCount; ++i ) + { + sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId(); + OUString aPureIdStr = OUString::number( nUniqueId ) + aIdStrBase; + pNewPureIds[i] = aPureIdStr; + // Force usage of next Unique Id + xStringResourceManager->setString( aPureIdStr, OUString() ); + } + + // Move strings to new Ids for all locales + const Sequence< Locale > aLocaleSeq = xStringResourceManager->getLocales(); + Sequence< OUString > aOldIdStrings; + aPropertyValue >>= aOldIdStrings; + try + { + const OUString* pOldIdStrings = aOldIdStrings.getConstArray(); + sal_Int32 nOldIdCount = aOldIdStrings.getLength(); + for ( i = 0; i < nNewCount; ++i ) + { + OUString aOldPureIdStr; + if( i < nOldIdCount ) + { + OUString aOldIdStr = pOldIdStrings[i]; + aOldPureIdStr = aOldIdStr.copy( 1 ); + } + OUString aNewPureIdStr = pNewPureIds[i]; + + for ( const Locale& rLocale : aLocaleSeq ) + { + OUString aResourceStr; + if( !aOldPureIdStr.isEmpty() ) + { + if( xStringResourceManager->hasEntryForIdAndLocale( aOldPureIdStr, rLocale ) ) + { + aResourceStr = xStringResourceManager-> + resolveStringForLocale( aOldPureIdStr, rLocale ); + } + } + xStringResourceManager->setStringForLocale( aNewPureIdStr, aResourceStr, rLocale ); + } + } + } + catch( const resource::MissingResourceException & ) + {} + + + // Set new strings for current locale and create + // new Id sequence as new property value + Sequence< OUString > aNewIdStrings; + aNewIdStrings.realloc( nNewCount ); + OUString* pNewIdStrings = aNewIdStrings.getArray(); + for ( i = 0; i < nNewCount; ++i ) + { + const OUString& aPureIdStr = pNewPureIds[i]; + const OUString& aStr = aNewStrings[i]; + xStringResourceManager->setString( aPureIdStr, aStr ); + + pNewIdStrings[i] = "&" + aPureIdStr; + } + aValue <<= aNewIdStrings; + + // Remove old ids from resource for all locales + for( const OUString& rIdStr : std::as_const(aOldIdStrings) ) + { + OUString aPureIdStr = rIdStr.copy( 1 ); + for ( const Locale& rLocale : aLocaleSeq ) + { + try + { + xStringResourceManager->removeIdForLocale( aPureIdStr, rLocale ); + } + catch( const resource::MissingResourceException & ) + {} + } + } + } + } + } + + m_xComponent->setPropertyValue( _rPropertyName, aValue ); + } + } + + Any SAL_CALL FormComponentPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + Property aProperty( impl_getPropertyFromId_throw( nPropId ) ); + + Any aPropertyValue( _rControlValue ); + if ( !aPropertyValue.hasValue() ) + { + if ( ( aProperty.Attributes & PropertyAttribute::MAYBEVOID ) == 0 ) + // default construct an instance of the proper type + aPropertyValue = Any( nullptr, aProperty.Type ); + // nothing to do + return aPropertyValue; + } + + /// care for the special "default" string, translate it to VOID + if ( m_aPropertiesWithDefListEntry.find( _rPropertyName ) != m_aPropertiesWithDefListEntry.end() ) + { + // it's a control with a string list + OUString sStringValue; + if ( _rControlValue >>= sStringValue ) + { // note that ColorListBoxes might transfer values either as string or as css.util.Color, + // so this check here is important + if ( sStringValue == m_sDefaultValueString ) + return Any(); + } + } + + switch ( nPropId ) + { + case PROPERTY_ID_DATASOURCE: + { + OUString sControlValue; + if( ! (_rControlValue >>= sControlValue) ) + SAL_WARN("extensions.propctrlr", "convertToPropertyValue: unable to get property " << PROPERTY_ID_DATASOURCE); + + if ( !sControlValue.isEmpty() ) + { + Reference< XDatabaseContext > xDatabaseContext = sdb::DatabaseContext::create( m_xContext ); + if ( !xDatabaseContext->hasByName( sControlValue ) ) + { + ::svt::OFileNotation aTransformer(sControlValue); + aPropertyValue <<= aTransformer.get( ::svt::OFileNotation::N_URL ); + } + } + } + break; // case PROPERTY_ID_DATASOURCE + + case PROPERTY_ID_SHOW_POSITION: + case PROPERTY_ID_SHOW_NAVIGATION: + case PROPERTY_ID_SHOW_RECORDACTIONS: + case PROPERTY_ID_SHOW_FILTERSORT: + { + OUString sControlValue; + if( ! (_rControlValue >>= sControlValue) ) + SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for Show/Hide"); + + static_assert(SAL_N_ELEMENTS(RID_RSC_ENUM_SHOWHIDE) == 2, "FormComponentPropertyHandler::convertToPropertyValue: broken resource for Show/Hide!"); + bool bShow = sControlValue == PcrRes(RID_RSC_ENUM_SHOWHIDE[1]); + + aPropertyValue <<= bShow; + } + break; + + case PROPERTY_ID_TARGET_URL: + case PROPERTY_ID_IMAGE_URL: + { + OUString sControlValue; + if( ! (_rControlValue >>= sControlValue) ) + SAL_WARN("extensions.propctrlr", "convertToPropertyValue: unable to get property for URLs"); + // Don't convert a placeholder + if ( nPropId == PROPERTY_ID_IMAGE_URL && sControlValue == PcrRes(RID_EMBED_IMAGE_PLACEHOLDER) ) + aPropertyValue <<= sControlValue; + else + { + INetURLObject aDocURL( impl_getDocumentURL_nothrow() ); + aPropertyValue <<= URIHelper::SmartRel2Abs( aDocURL, sControlValue, Link(), false, true ); + } + } + break; + + case PROPERTY_ID_DATEMIN: + case PROPERTY_ID_DATEMAX: + case PROPERTY_ID_DEFAULT_DATE: + case PROPERTY_ID_DATE: + { + util::Date aDate; + if( ! (_rControlValue >>= aDate) ) + SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for date"); + aPropertyValue <<= aDate; + } + break; + + case PROPERTY_ID_TIMEMIN: + case PROPERTY_ID_TIMEMAX: + case PROPERTY_ID_DEFAULT_TIME: + case PROPERTY_ID_TIME: + { + util::Time aTime; + if( ! (_rControlValue >>= aTime) ) + SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for time"); + aPropertyValue <<= aTime; + } + break; + + case PROPERTY_ID_WRITING_MODE: + { + aPropertyValue = PropertyHandlerComponent::convertToPropertyValue( _rPropertyName, _rControlValue ); + + sal_Int16 nNormalizedValue( 2 ); + if( ! (aPropertyValue >>= nNormalizedValue) ) + SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for " << PROPERTY_ID_WRITING_MODE); + + sal_Int16 nWritingMode = WritingMode2::CONTEXT; + switch ( nNormalizedValue ) + { + case 0: nWritingMode = WritingMode2::LR_TB; break; + case 1: nWritingMode = WritingMode2::RL_TB; break; + case 2: nWritingMode = WritingMode2::CONTEXT; break; + default: + OSL_FAIL( "FormComponentPropertyHandler::convertToPropertyValue: unexpected 'normalized value' for WritingMode!" ); + nWritingMode = WritingMode2::CONTEXT; + break; + } + + aPropertyValue <<= nWritingMode; + } + break; + + default: + aPropertyValue = PropertyHandlerComponent::convertToPropertyValue( _rPropertyName, _rControlValue ); + break; // default + + } // switch ( nPropId ) + + return aPropertyValue; + } + + Any SAL_CALL FormComponentPropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + sal_Int32 nPropId = m_pInfoService->getPropertyId( _rPropertyName ); + DBG_ASSERT( nPropId != -1, "FormComponentPropertyHandler::convertToPropertyValue: not one of my properties!!" ); + + impl_getPropertyFromId_throw( nPropId ); + + Any aControlValue( _rPropertyValue ); + if ( !aControlValue.hasValue() ) + { + // if the property is represented with a list box or color list box, we need to + // translate this into the string "Default" + if ( m_aPropertiesWithDefListEntry.find( _rPropertyName ) != m_aPropertiesWithDefListEntry.end() ) + aControlValue <<= m_sDefaultValueString; + + return aControlValue; + } + + switch ( nPropId ) + { + + case PROPERTY_ID_SHOW_POSITION: + case PROPERTY_ID_SHOW_NAVIGATION: + case PROPERTY_ID_SHOW_RECORDACTIONS: + case PROPERTY_ID_SHOW_FILTERSORT: + { + static_assert(SAL_N_ELEMENTS(RID_RSC_ENUM_SHOWHIDE) == 2, "FormComponentPropertyHandler::convertToPropertyValue: broken resource for Show/Hide!"); + OUString sControlValue = ::comphelper::getBOOL(_rPropertyValue) + ? PcrRes(RID_RSC_ENUM_SHOWHIDE[1]) + : PcrRes(RID_RSC_ENUM_SHOWHIDE[0]); + aControlValue <<= sControlValue; + } + break; + + + case PROPERTY_ID_DATASOURCE: + { + OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING, + "FormComponentPropertyHandler::convertToControlValue: wrong ControlValueType!" ); + + OUString sDataSource; + _rPropertyValue >>= sDataSource; + if ( !sDataSource.isEmpty() ) + { + ::svt::OFileNotation aTransformer( sDataSource ); + sDataSource = aTransformer.get( ::svt::OFileNotation::N_SYSTEM ); + } + aControlValue <<= sDataSource; + } + break; + + + case PROPERTY_ID_CONTROLLABEL: + { + OUString sControlValue; + + Reference< XPropertySet > xSet; + _rPropertyValue >>= xSet; + Reference< XPropertySetInfo > xPSI; + if ( xSet.is() ) + xPSI = xSet->getPropertySetInfo(); + if ( xPSI.is() && xPSI->hasPropertyByName( PROPERTY_LABEL ) ) + { + OUString sLabel; + if( ! (xSet->getPropertyValue( PROPERTY_LABEL) >>= sLabel) ) + SAL_WARN("extensions.propctrlr", "convertToPropertyValue: unable to get property " << PROPERTY_LABEL); + sControlValue = "<" + sLabel + ">"; + } + + aControlValue <<= sControlValue; + } + break; + + + case PROPERTY_ID_DATEMIN: + case PROPERTY_ID_DATEMAX: + case PROPERTY_ID_DEFAULT_DATE: + case PROPERTY_ID_DATE: + { + sal_Int32 nDate = 0; + if( ! (_rPropertyValue >>= nDate) ) + SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for dates"); + aControlValue <<= DBTypeConversion::toDate( nDate ); + } + break; + + case PROPERTY_ID_TIMEMIN: + case PROPERTY_ID_TIMEMAX: + case PROPERTY_ID_DEFAULT_TIME: + case PROPERTY_ID_TIME: + { + sal_Int64 nTime = 0; + if( ! (_rPropertyValue >>= nTime) ) + SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property for times"); + aControlValue <<= DBTypeConversion::toTime( nTime ); + } + break; + + case PROPERTY_ID_WRITING_MODE: + { + sal_Int16 nWritingMode( WritingMode2::CONTEXT ); + if( ! (_rPropertyValue >>= nWritingMode) ) + SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property " << PROPERTY_ID_WRITING_MODE); + + sal_Int16 nNormalized = 2; + switch ( nWritingMode ) + { + case WritingMode2::LR_TB: nNormalized = 0; break; + case WritingMode2::RL_TB: nNormalized = 1; break; + case WritingMode2::CONTEXT: nNormalized = 2; break; + default: + OSL_FAIL( "FormComponentPropertyHandler::convertToControlValue: unsupported API value for WritingMode!" ); + nNormalized = 2; + break; + } + + aControlValue = PropertyHandlerComponent::convertToControlValue( _rPropertyName, Any( nNormalized ), _rControlValueType ); + } + break; + + case PROPERTY_ID_FONT: + { + FontDescriptor aFont; + if( ! (_rPropertyValue >>= aFont) ) + SAL_WARN("extensions.propctrlr", "convertToControlValue: unable to get property " << PROPERTY_ID_FONT); + + OUStringBuffer displayName; + if ( aFont.Name.isEmpty() ) + { + displayName.append( PcrRes(RID_STR_FONT_DEFAULT) ); + } + else + { + // font name + displayName.append( aFont.Name ); + displayName.append( ", " ); + + // font style + ::FontWeight eWeight = vcl::unohelper::ConvertFontWeight( aFont.Weight ); + TranslateId pStyleResID = RID_STR_FONTSTYLE_REGULAR; + if ( aFont.Slant == FontSlant_ITALIC ) + { + if ( eWeight > WEIGHT_NORMAL ) + pStyleResID = RID_STR_FONTSTYLE_BOLD_ITALIC; + else + pStyleResID = RID_STR_FONTSTYLE_ITALIC; + } + else + { + if ( eWeight > WEIGHT_NORMAL ) + pStyleResID = RID_STR_FONTSTYLE_BOLD; + } + displayName.append(PcrRes(pStyleResID)); + + // font size + if ( aFont.Height ) + { + displayName.append( ", " ); + displayName.append( sal_Int32( aFont.Height ) ); + } + } + + aControlValue <<= displayName.makeStringAndClear(); + } + break; + + default: + aControlValue = PropertyHandlerComponent::convertToControlValue( _rPropertyName, _rPropertyValue, _rControlValueType ); + break; + + } // switch ( nPropId ) + + return aControlValue; + } + + PropertyState SAL_CALL FormComponentPropertyHandler::getPropertyState( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_xPropertyState.is() ) + return m_xPropertyState->getPropertyState( _rPropertyName ); + return PropertyState_DIRECT_VALUE; + } + + void SAL_CALL FormComponentPropertyHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyHandlerComponent::addPropertyChangeListener( _rxListener ); + if ( m_xComponent.is() ) + m_xComponent->addPropertyChangeListener( OUString(), _rxListener ); + } + + void SAL_CALL FormComponentPropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_xComponent.is() ) + m_xComponent->removePropertyChangeListener( OUString(), _rxListener ); + PropertyHandlerComponent::removePropertyChangeListener( _rxListener ); + } + + Sequence< Property > FormComponentPropertyHandler::doDescribeSupportedProperties() const + { + if ( !m_xComponentPropertyInfo.is() ) + return Sequence< Property >(); + + std::vector< Property > aProperties; + + Sequence< Property > aAllProperties( m_xComponentPropertyInfo->getProperties() ); + aProperties.reserve( aAllProperties.getLength() ); + + // filter the properties + PropertyId nPropId( 0 ); + OUString sDisplayName; + + for ( Property & rProperty : asNonConstRange(aAllProperties) ) + { + nPropId = m_pInfoService->getPropertyId( rProperty.Name ); + if ( nPropId == -1 ) + continue; + rProperty.Handle = nPropId; + + sDisplayName = m_pInfoService->getPropertyTranslation( nPropId ); + if ( sDisplayName.isEmpty() ) + continue; + + sal_uInt32 nPropertyUIFlags = m_pInfoService->getPropertyUIFlags( nPropId ); + bool bIsVisibleForForms = ( nPropertyUIFlags & PROP_FLAG_FORM_VISIBLE ) != 0; + bool bIsVisibleForDialogs = ( nPropertyUIFlags & PROP_FLAG_DIALOG_VISIBLE ) != 0; + + // depending on whether we're working for a form or a UNO dialog, some + // properties are not displayed + if ( ( m_eComponentClass == eFormControl && !bIsVisibleForForms ) + || ( m_eComponentClass == eDialogControl && !bIsVisibleForDialogs ) + ) + continue; + + // some generic sanity checks + if ( impl_shouldExcludeProperty_nothrow( rProperty ) ) + continue; + + switch ( nPropId ) + { + case PROPERTY_ID_BORDER: + case PROPERTY_ID_TABSTOP: + // BORDER and TABSTOP are normalized (see impl_normalizePropertyValue_nothrow) + // to not allow VOID values + rProperty.Attributes &= ~PropertyAttribute::MAYBEVOID; + break; + + case PROPERTY_ID_LISTSOURCE: + // no cursor source if no Base is installed. + if ( SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) ) + const_cast< FormComponentPropertyHandler* >( this )->m_bHaveListSource = true; + break; + + case PROPERTY_ID_COMMAND: + // no cursor source if no Base is installed. + if ( SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) ) + const_cast< FormComponentPropertyHandler* >( this )->m_bHaveCommand = true; + break; + } // switch ( nPropId ) + + aProperties.push_back( rProperty ); + } + + if ( aProperties.empty() ) + return Sequence< Property >(); + return comphelper::containerToSequence(aProperties); + } + + Sequence< OUString > SAL_CALL FormComponentPropertyHandler::getSupersededProperties( ) + { + return Sequence< OUString >( ); + } + + Sequence< OUString > SAL_CALL FormComponentPropertyHandler::getActuatingProperties( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return + { + PROPERTY_DATASOURCE, + PROPERTY_COMMAND, + PROPERTY_COMMANDTYPE, + PROPERTY_LISTSOURCE, + PROPERTY_LISTSOURCETYPE, + PROPERTY_SUBMIT_ENCODING, + PROPERTY_REPEAT, + PROPERTY_TABSTOP, + PROPERTY_BORDER, + PROPERTY_CONTROLSOURCE, + PROPERTY_DROPDOWN, + PROPERTY_IMAGE_URL, + PROPERTY_TARGET_URL, + PROPERTY_STRINGITEMLIST, + PROPERTY_BUTTONTYPE, + PROPERTY_ESCAPE_PROCESSING, + PROPERTY_TRISTATE, + PROPERTY_DECIMAL_ACCURACY, + PROPERTY_SHOWTHOUSANDSEP, + PROPERTY_FORMATKEY, + PROPERTY_EMPTY_IS_NULL, + PROPERTY_TOGGLE + }; + } + + LineDescriptor SAL_CALL FormComponentPropertyHandler::describePropertyLine( const OUString& _rPropertyName, + const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + if ( !_rxControlFactory.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + Property aProperty( impl_getPropertyFromId_throw( nPropId ) ); + + + // for the MultiLine property, we have different UI translations depending on the control + // type + if ( nPropId == PROPERTY_ID_MULTILINE ) + { + if ( ( m_nClassId == FormComponentType::FIXEDTEXT ) + || ( m_nClassId == FormComponentType::COMMANDBUTTON ) + || ( m_nClassId == FormComponentType::RADIOBUTTON ) + || ( m_nClassId == FormComponentType::CHECKBOX ) + ) + nPropId = PROPERTY_ID_WORDBREAK; + } + + OUString sDisplayName = m_pInfoService->getPropertyTranslation( nPropId ); + if ( sDisplayName.isEmpty() ) + { + OSL_FAIL( "FormComponentPropertyHandler::describePropertyLine: did getSupportedProperties not work properly?" ); + throw UnknownPropertyException(); + } + + + LineDescriptor aDescriptor; + aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) ); + aDescriptor.DisplayName = sDisplayName; + + // for the moment, assume a text field + sal_Int16 nControlType = PropertyControlType::TextField; + bool bReadOnly = false; + aDescriptor.Control.clear(); + + + bool bNeedDefaultStringIfVoidAllowed = false; + + TypeClass eType = aProperty.Type.getTypeClass(); + + switch ( nPropId ) + { + case PROPERTY_ID_DEFAULT_SELECT_SEQ: + case PROPERTY_ID_SELECTEDITEMS: + aDescriptor.PrimaryButtonId = UID_PROP_DLG_SELECTION; + break; + + case PROPERTY_ID_FILTER: + aDescriptor.PrimaryButtonId = UID_PROP_DLG_FILTER; + break; + + case PROPERTY_ID_SORT: + aDescriptor.PrimaryButtonId = UID_PROP_DLG_ORDER; + break; + + case PROPERTY_ID_MASTERFIELDS: + case PROPERTY_ID_DETAILFIELDS: + nControlType = PropertyControlType::StringListField; + aDescriptor.PrimaryButtonId = UID_PROP_DLG_FORMLINKFIELDS; + break; + + case PROPERTY_ID_COMMAND: + aDescriptor.PrimaryButtonId = UID_PROP_DLG_SQLCOMMAND; + break; + + case PROPERTY_ID_TABINDEX: + { + Reference< XControlContainer > xControlContext( impl_getContextControlContainer_nothrow() ); + if ( xControlContext.is() ) + aDescriptor.PrimaryButtonId = UID_PROP_DLG_TABINDEX; + nControlType = PropertyControlType::NumericField; + }; + break; + + case PROPERTY_ID_FONT: + bReadOnly = true; + aDescriptor.PrimaryButtonId = UID_PROP_DLG_FONT_TYPE; + break; + + case PROPERTY_ID_TARGET_URL: + case PROPERTY_ID_IMAGE_URL: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/urlcontrol.ui", m_xContext)); + auto pURLBox = std::make_unique(xBuilder->weld_combo_box("urlcontrol")); + rtl::Reference pControl = new OFileUrlControl(std::move(pURLBox), std::move(xBuilder), false); + pControl->SetModifyHandler(); + aDescriptor.Control = pControl; + + aDescriptor.PrimaryButtonId = PROPERTY_ID_TARGET_URL == nPropId + ? OUString(UID_PROP_DLG_ATTR_TARGET_URL) + : OUString(UID_PROP_DLG_IMAGE_URL); + break; + } + + case PROPERTY_ID_ECHO_CHAR: + nControlType = PropertyControlType::CharacterField; + break; + + case PROPERTY_ID_BACKGROUNDCOLOR: + case PROPERTY_ID_FILLCOLOR: + case PROPERTY_ID_SYMBOLCOLOR: + case PROPERTY_ID_BORDERCOLOR: + case PROPERTY_ID_GRIDLINECOLOR: + case PROPERTY_ID_HEADERBACKGROUNDCOLOR: + case PROPERTY_ID_HEADERTEXTCOLOR: + case PROPERTY_ID_ACTIVESELECTIONBACKGROUNDCOLOR: + case PROPERTY_ID_ACTIVESELECTIONTEXTCOLOR: + case PROPERTY_ID_INACTIVESELECTIONBACKGROUNDCOLOR: + case PROPERTY_ID_INACTIVESELECTIONTEXTCOLOR: + nControlType = PropertyControlType::ColorListBox; + + switch( nPropId ) + { + case PROPERTY_ID_BACKGROUNDCOLOR: + aDescriptor.PrimaryButtonId = UID_PROP_DLG_BACKGROUNDCOLOR; break; + case PROPERTY_ID_FILLCOLOR: + aDescriptor.PrimaryButtonId = UID_PROP_DLG_FILLCOLOR; break; + case PROPERTY_ID_SYMBOLCOLOR: + aDescriptor.PrimaryButtonId = UID_PROP_DLG_SYMBOLCOLOR; break; + case PROPERTY_ID_BORDERCOLOR: + aDescriptor.PrimaryButtonId = UID_PROP_DLG_BORDERCOLOR; break; + case PROPERTY_ID_GRIDLINECOLOR: + aDescriptor.PrimaryButtonId = HID_PROP_GRIDLINECOLOR; break; + case PROPERTY_ID_HEADERBACKGROUNDCOLOR: + aDescriptor.PrimaryButtonId = HID_PROP_HEADERBACKGROUNDCOLOR; break; + case PROPERTY_ID_HEADERTEXTCOLOR: + aDescriptor.PrimaryButtonId = HID_PROP_HEADERTEXTCOLOR; break; + case PROPERTY_ID_ACTIVESELECTIONBACKGROUNDCOLOR: + aDescriptor.PrimaryButtonId = HID_PROP_ACTIVESELECTIONBACKGROUNDCOLOR; break; + case PROPERTY_ID_ACTIVESELECTIONTEXTCOLOR: + aDescriptor.PrimaryButtonId = HID_PROP_ACTIVESELECTIONTEXTCOLOR; break; + case PROPERTY_ID_INACTIVESELECTIONBACKGROUNDCOLOR: + aDescriptor.PrimaryButtonId = HID_PROP_INACTIVESELECTIONBACKGROUNDCOLOR; break; + case PROPERTY_ID_INACTIVESELECTIONTEXTCOLOR: + aDescriptor.PrimaryButtonId = HID_PROP_INACTIVESELECTIONTEXTCOLOR; break; + } + break; + + case PROPERTY_ID_LABEL: + case PROPERTY_ID_URL: + nControlType = PropertyControlType::MultiLineTextField; + break; + + case PROPERTY_ID_DEFAULT_TEXT: + { + if (FormComponentType::FILECONTROL == m_nClassId) + nControlType = PropertyControlType::TextField; + else + nControlType = PropertyControlType::MultiLineTextField; + } + break; + + case PROPERTY_ID_TEXT: + if ( impl_componentHasProperty_throw( PROPERTY_MULTILINE ) ) + nControlType = PropertyControlType::MultiLineTextField; + break; + + case PROPERTY_ID_CONTROLLABEL: + bReadOnly = true; + aDescriptor.PrimaryButtonId = UID_PROP_DLG_CONTROLLABEL; + break; + + case PROPERTY_ID_FORMATKEY: + case PROPERTY_ID_EFFECTIVE_MIN: + case PROPERTY_ID_EFFECTIVE_MAX: + case PROPERTY_ID_EFFECTIVE_DEFAULT: + case PROPERTY_ID_EFFECTIVE_VALUE: + { + // and the supplier is really available + Reference< XNumberFormatsSupplier > xSupplier; + m_xComponent->getPropertyValue( PROPERTY_FORMATSSUPPLIER ) >>= xSupplier; + if (xSupplier.is()) + { + Reference< XUnoTunnel > xTunnel(xSupplier,UNO_QUERY); + DBG_ASSERT(xTunnel.is(), "FormComponentPropertyHandler::describePropertyLine : xTunnel is invalid!"); + if (auto pSupplier = comphelper::getFromUnoTunnel(xTunnel)) + { + bool bIsFormatKey = (PROPERTY_ID_FORMATKEY == nPropId); + + bReadOnly = bIsFormatKey; + + if ( bIsFormatKey ) + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/formattedsample.ui", m_xContext)); + auto pContainer = xBuilder->weld_container("formattedsample"); + rtl::Reference pControl = new OFormatSampleControl(std::move(pContainer), std::move(xBuilder), false); + pControl->SetModifyHandler(); + + pControl->SetFormatSupplier(pSupplier); + + aDescriptor.Control = pControl; + + aDescriptor.PrimaryButtonId = UID_PROP_DLG_NUMBER_FORMAT; + } + else + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/formattedcontrol.ui", m_xContext)); + auto pSpinButton = xBuilder->weld_formatted_spin_button("formattedcontrol"); + rtl::Reference pControl = new OFormattedNumericControl(std::move(pSpinButton), std::move(xBuilder), false); + pControl->SetModifyHandler(); + + FormatDescription aDesc; + aDesc.pSupplier = pSupplier; + Any aFormatKeyValue = m_xComponent->getPropertyValue(PROPERTY_FORMATKEY); + if ( !( aFormatKeyValue >>= aDesc.nKey ) ) + aDesc.nKey = 0; + + pControl->SetFormatDescription( aDesc ); + + aDescriptor.Control = pControl; + } + } + } + } + break; + + case PROPERTY_ID_DATEMIN: + case PROPERTY_ID_DATEMAX: + case PROPERTY_ID_DEFAULT_DATE: + case PROPERTY_ID_DATE: + nControlType = PropertyControlType::DateField; + break; + + case PROPERTY_ID_TIMEMIN: + case PROPERTY_ID_TIMEMAX: + case PROPERTY_ID_DEFAULT_TIME: + case PROPERTY_ID_TIME: + nControlType = PropertyControlType::TimeField; + break; + + case PROPERTY_ID_VALUEMIN: + case PROPERTY_ID_VALUEMAX: + case PROPERTY_ID_DEFAULT_VALUE: + case PROPERTY_ID_VALUE: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/formattedcontrol.ui", m_xContext)); + auto pSpinButton = xBuilder->weld_formatted_spin_button("formattedcontrol"); + rtl::Reference pControl = new OFormattedNumericControl(std::move(pSpinButton), std::move(xBuilder), false); + pControl->SetModifyHandler(); + aDescriptor.Control = pControl; + + // we don't set a formatter so the control uses a default (which uses the application + // language and a default numeric format) + // but we set the decimal digits + pControl->SetDecimalDigits( + ::comphelper::getINT16( m_xComponent->getPropertyValue( PROPERTY_DECIMAL_ACCURACY ) ) + ); + + // and the default value for the property + try + { + if (m_xPropertyState.is() && ((PROPERTY_ID_VALUEMIN == nPropId) || (PROPERTY_ID_VALUEMAX == nPropId))) + { + double nDefault = 0; + if ( m_xPropertyState->getPropertyDefault( aProperty.Name ) >>= nDefault ) + pControl->SetDefaultValue(nDefault); + } + } + catch (const Exception&) + { + // just ignore it + } + + break; + } + + default: + if ( TypeClass_BYTE <= eType && eType <= TypeClass_DOUBLE ) + { + sal_Int16 nDigits = 0; + sal_Int16 nValueUnit = -1; + sal_Int16 nDisplayUnit = -1; + if ( m_eComponentClass == eFormControl ) + { + if ( ( nPropId == PROPERTY_ID_WIDTH ) + || ( nPropId == PROPERTY_ID_ROWHEIGHT ) + || ( nPropId == PROPERTY_ID_HEIGHT ) + ) + { + nValueUnit = MeasureUnit::MM_10TH; + nDisplayUnit = impl_getDocumentMeasurementUnit_throw(); + nDigits = 2; + } + } + + Optional< double > aValueNotPresent( false, 0 ); + aDescriptor.Control = PropertyHandlerHelper::createNumericControl( + _rxControlFactory, nDigits, aValueNotPresent, aValueNotPresent ); + + Reference< XNumericControl > xNumericControl( aDescriptor.Control, UNO_QUERY_THROW ); + if ( nValueUnit != -1 ) + xNumericControl->setValueUnit( nValueUnit ); + if ( nDisplayUnit != -1 ) + xNumericControl->setDisplayUnit( nDisplayUnit ); + } + break; + } + + if ( eType == TypeClass_SEQUENCE ) + nControlType = PropertyControlType::StringListField; + + // boolean values + if ( eType == TypeClass_BOOLEAN ) + { + if ( ( nPropId == PROPERTY_ID_SHOW_POSITION ) + || ( nPropId == PROPERTY_ID_SHOW_NAVIGATION ) + || ( nPropId == PROPERTY_ID_SHOW_RECORDACTIONS ) + || ( nPropId == PROPERTY_ID_SHOW_FILTERSORT ) + ) + { + aDescriptor.Control = PropertyHandlerHelper::createListBoxControl(_rxControlFactory, RID_RSC_ENUM_SHOWHIDE, SAL_N_ELEMENTS(RID_RSC_ENUM_SHOWHIDE), false); + } + else + aDescriptor.Control = PropertyHandlerHelper::createListBoxControl(_rxControlFactory, RID_RSC_ENUM_YESNO, SAL_N_ELEMENTS(RID_RSC_ENUM_YESNO), false); + bNeedDefaultStringIfVoidAllowed = true; + } + + + // enum properties + sal_uInt32 nPropertyUIFlags = m_pInfoService->getPropertyUIFlags( nPropId ); + bool bIsEnumProperty = ( nPropertyUIFlags & PROP_FLAG_ENUM ) != 0; + if ( bIsEnumProperty || ( PROPERTY_ID_TARGET_FRAME == nPropId ) ) + { + std::vector< OUString > aEnumValues = m_pInfoService->getPropertyEnumRepresentations( nPropId ); + std::vector< OUString >::const_iterator pStart = aEnumValues.begin(); + std::vector< OUString >::const_iterator pEnd = aEnumValues.end(); + + // for a checkbox: if "ambiguous" is not allowed, remove this from the sequence + if ( ( PROPERTY_ID_DEFAULT_STATE == nPropId ) + || ( PROPERTY_ID_STATE == nPropId ) + ) + { + if ( impl_componentHasProperty_throw( PROPERTY_TRISTATE ) ) + { + if ( !::comphelper::getBOOL( m_xComponent->getPropertyValue( PROPERTY_TRISTATE ) ) ) + { // remove the last sequence element + if ( pEnd > pStart ) + --pEnd; + } + } + else + --pEnd; + } + + if ( PROPERTY_ID_LISTSOURCETYPE == nPropId ) + if ( FormComponentType::COMBOBOX == m_nClassId ) + // remove the first sequence element -> value list not possible for combo boxes + ++pStart; + + // copy the sequence + std::vector< OUString > aListEntries( pEnd - pStart ); + std::copy( pStart, pEnd, aListEntries.begin() ); + + // create the control + if ( PROPERTY_ID_TARGET_FRAME == nPropId ) + aDescriptor.Control = PropertyHandlerHelper::createComboBoxControl( _rxControlFactory, std::move(aListEntries), false ); + else + { + aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory, std::move(aListEntries), false, false ); + bNeedDefaultStringIfVoidAllowed = true; + } + } + + + switch( nPropId ) + { + case PROPERTY_ID_REPEAT_DELAY: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/numericfield.ui", m_xContext)); + auto pSpinButton = xBuilder->weld_metric_spin_button("numericfield", FieldUnit::MILLISECOND); + rtl::Reference pControl = new ONumericControl(std::move(pSpinButton), std::move(xBuilder), bReadOnly); + pControl->SetModifyHandler(); + pControl->setMinValue( Optional< double >( true, 0 ) ); + pControl->setMaxValue( Optional< double >( true, std::numeric_limits< double >::max() ) ); + aDescriptor.Control = pControl; + } + break; + + case PROPERTY_ID_TABINDEX: + case PROPERTY_ID_BOUNDCOLUMN: + case PROPERTY_ID_VISIBLESIZE: + case PROPERTY_ID_MAXTEXTLEN: + case PROPERTY_ID_LINEINCREMENT: + case PROPERTY_ID_BLOCKINCREMENT: + case PROPERTY_ID_SPININCREMENT: + { + Optional< double > aMinValue( true, 0 ); + Optional< double > aMaxValue( true, 0x7FFFFFFF ); + + if ( nPropId == PROPERTY_ID_MAXTEXTLEN || nPropId == PROPERTY_ID_BOUNDCOLUMN ) + aMinValue.Value = -1; + else if ( nPropId == PROPERTY_ID_VISIBLESIZE ) + aMinValue.Value = 1; + else + aMinValue.Value = 0; + + aDescriptor.Control = PropertyHandlerHelper::createNumericControl( + _rxControlFactory, 0, aMinValue, aMaxValue ); + } + break; + + case PROPERTY_ID_DECIMAL_ACCURACY: + { + Optional< double > aMinValue( true, 0 ); + Optional< double > aMaxValue( true, 20 ); + + aDescriptor.Control = PropertyHandlerHelper::createNumericControl( + _rxControlFactory, 0, aMinValue, aMaxValue ); + } + break; + + + // DataSource + case PROPERTY_ID_DATASOURCE: + { + aDescriptor.PrimaryButtonId = UID_PROP_DLG_ATTR_DATASOURCE; + + std::vector< OUString > aListEntries; + + Reference< XDatabaseContext > xDatabaseContext = sdb::DatabaseContext::create( m_xContext ); + const Sequence< OUString > aDatasources = xDatabaseContext->getElementNames(); + aListEntries.resize( aDatasources.getLength() ); + std::copy( aDatasources.begin(), aDatasources.end(), aListEntries.begin() ); + aDescriptor.Control = PropertyHandlerHelper::createComboBoxControl( + _rxControlFactory, std::move(aListEntries), true ); + } + break; + + case PROPERTY_ID_CONTROLSOURCE: + { + std::vector< OUString > aFieldNames; + impl_initFieldList_nothrow( aFieldNames ); + aDescriptor.Control = PropertyHandlerHelper::createComboBoxControl( + _rxControlFactory, std::move(aFieldNames), false ); + } + break; + + case PROPERTY_ID_COMMAND: + impl_describeCursorSource_nothrow( aDescriptor, _rxControlFactory ); + break; + + case PROPERTY_ID_LISTSOURCE: + impl_describeListSourceUI_throw( aDescriptor, _rxControlFactory ); + break; + } + + if ( !aDescriptor.Control.is() ) + aDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, bReadOnly ); + + if ( ( aProperty.Attributes & PropertyAttribute::MAYBEVOID ) != 0 ) + { + // insert the string "Default" string, if necessary + if (bNeedDefaultStringIfVoidAllowed) + { + Reference< XStringListControl > xStringList( aDescriptor.Control, UNO_QUERY_THROW ); + xStringList->prependListEntry( m_sDefaultValueString ); + m_aPropertiesWithDefListEntry.insert( _rPropertyName ); + } + } + + if ( !aDescriptor.PrimaryButtonId.isEmpty() ) + aDescriptor.HasPrimaryButton = true; + if ( !aDescriptor.SecondaryButtonId.isEmpty() ) + aDescriptor.HasSecondaryButton = true; + + bool bIsDataProperty = ( nPropertyUIFlags & PROP_FLAG_DATA_PROPERTY ) != 0; + aDescriptor.Category = bIsDataProperty ? std::u16string_view(u"Data") : std::u16string_view(u"General"); + return aDescriptor; + } + + InteractiveSelectionResult SAL_CALL FormComponentPropertyHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool /*_bPrimary*/, Any& _rData, const Reference< XObjectInspectorUI >& _rxInspectorUI ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::ClearableMutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + InteractiveSelectionResult eResult = InteractiveSelectionResult_Cancelled; + switch ( nPropId ) + { + case PROPERTY_ID_DEFAULT_SELECT_SEQ: + case PROPERTY_ID_SELECTEDITEMS: + if ( impl_dialogListSelection_nothrow( _rPropertyName, aGuard ) ) + eResult = InteractiveSelectionResult_Success; + break; + + case PROPERTY_ID_FILTER: + case PROPERTY_ID_SORT: + { + OUString sClause; + if ( impl_dialogFilterOrSort_nothrow( PROPERTY_ID_FILTER == nPropId, sClause, aGuard ) ) + { + _rData <<= sClause; + eResult = InteractiveSelectionResult_ObtainedValue; + } + } + break; + + case PROPERTY_ID_MASTERFIELDS: + case PROPERTY_ID_DETAILFIELDS: + if ( impl_dialogLinkedFormFields_nothrow( aGuard ) ) + eResult = InteractiveSelectionResult_Success; + break; + + case PROPERTY_ID_FORMATKEY: + if ( impl_dialogFormatting_nothrow( _rData, aGuard ) ) + eResult = InteractiveSelectionResult_ObtainedValue; + break; + + case PROPERTY_ID_IMAGE_URL: + if ( impl_browseForImage_nothrow( _rData, aGuard ) ) + eResult = InteractiveSelectionResult_ObtainedValue; + break; + + case PROPERTY_ID_TARGET_URL: + if ( impl_browseForTargetURL_nothrow( _rData, aGuard ) ) + eResult = InteractiveSelectionResult_ObtainedValue; + break; + + case PROPERTY_ID_FONT: + if ( impl_executeFontDialog_nothrow( _rData, aGuard ) ) + eResult = InteractiveSelectionResult_ObtainedValue; + break; + + case PROPERTY_ID_DATASOURCE: + if ( impl_browseForDatabaseDocument_throw( _rData, aGuard ) ) + eResult = InteractiveSelectionResult_ObtainedValue; + break; + + case PROPERTY_ID_BACKGROUNDCOLOR: + case PROPERTY_ID_FILLCOLOR: + case PROPERTY_ID_SYMBOLCOLOR: + case PROPERTY_ID_BORDERCOLOR: + case PROPERTY_ID_GRIDLINECOLOR: + case PROPERTY_ID_HEADERBACKGROUNDCOLOR: + case PROPERTY_ID_HEADERTEXTCOLOR: + case PROPERTY_ID_ACTIVESELECTIONBACKGROUNDCOLOR: + case PROPERTY_ID_ACTIVESELECTIONTEXTCOLOR: + case PROPERTY_ID_INACTIVESELECTIONBACKGROUNDCOLOR: + case PROPERTY_ID_INACTIVESELECTIONTEXTCOLOR: + if ( impl_dialogColorChooser_throw( nPropId, _rData, aGuard ) ) + eResult = InteractiveSelectionResult_ObtainedValue; + break; + + case PROPERTY_ID_CONTROLLABEL: + if ( impl_dialogChooseLabelControl_nothrow( _rData, aGuard ) ) + eResult = InteractiveSelectionResult_ObtainedValue; + break; + + case PROPERTY_ID_TABINDEX: + if ( impl_dialogChangeTabOrder_nothrow( aGuard ) ) + eResult = InteractiveSelectionResult_Success; + break; + + case PROPERTY_ID_COMMAND: + case PROPERTY_ID_LISTSOURCE: + if ( impl_doDesignSQLCommand_nothrow( _rxInspectorUI, nPropId ) ) + eResult = InteractiveSelectionResult_Pending; + break; + default: + OSL_FAIL( "FormComponentPropertyHandler::onInteractivePropertySelection: request for a property which does not have dedicated UI!" ); + break; + } + return eResult; + } + + namespace + { + void lcl_rebuildAndResetCommand( const Reference< XObjectInspectorUI >& _rxInspectorUI, const Reference< XPropertyHandler >& _rxHandler ) + { + OSL_PRECOND( _rxInspectorUI.is(), "lcl_rebuildAndResetCommand: invalid BrowserUI!" ); + OSL_PRECOND( _rxHandler.is(), "lcl_rebuildAndResetCommand: invalid handler!" ); + _rxInspectorUI->rebuildPropertyUI( PROPERTY_COMMAND ); + _rxHandler->setPropertyValue( PROPERTY_COMMAND, Any( OUString() ) ); + } + } + + void SAL_CALL FormComponentPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nActuatingPropId( impl_getPropertyId_nothrow( _rActuatingPropertyName ) ); + + std::vector< PropertyId > aDependentProperties; + + switch ( nActuatingPropId ) + { + // ----- EscapeProcessing ----- + case PROPERTY_ID_ESCAPE_PROCESSING: + aDependentProperties.push_back( PROPERTY_ID_FILTER ); + aDependentProperties.push_back( PROPERTY_ID_SORT ); + break; // case PROPERTY_ID_ESCAPE_PROCESSING + + // ----- CommandType ----- + case PROPERTY_ID_COMMANDTYPE: + // available commands (tables or queries) might have changed + if ( !_bFirstTimeInit && m_bHaveCommand ) + lcl_rebuildAndResetCommand( _rxInspectorUI, this ); + aDependentProperties.push_back( PROPERTY_ID_COMMAND ); + break; // case PROPERTY_ID_COMMANDTYPE + + // ----- DataSourceName ----- + case PROPERTY_ID_DATASOURCE: + // reset the connection, now that we have a new data source + m_xRowSetConnection.clear(); + + // available list source values (tables or queries) might have changed + if ( !_bFirstTimeInit && m_bHaveListSource ) + _rxInspectorUI->rebuildPropertyUI( PROPERTY_LISTSOURCE ); + + // available commands (tables or queries) might have changed + if ( !_bFirstTimeInit && m_bHaveCommand ) + lcl_rebuildAndResetCommand( _rxInspectorUI, this ); + + // Command also depends on DataSource + aDependentProperties.push_back( PROPERTY_ID_COMMAND ); + [[fallthrough]]; + + // ----- Command ----- + case PROPERTY_ID_COMMAND: + aDependentProperties.push_back( PROPERTY_ID_FILTER ); + aDependentProperties.push_back( PROPERTY_ID_SORT ); + if ( m_bComponentIsSubForm ) + aDependentProperties.push_back( PROPERTY_ID_DETAILFIELDS ); + break; + + // ----- ListSourceType ----- + case PROPERTY_ID_LISTSOURCETYPE: + if ( !_bFirstTimeInit && m_bHaveListSource ) + // available list source values (tables or queries) might have changed + _rxInspectorUI->rebuildPropertyUI( PROPERTY_LISTSOURCE ); + aDependentProperties.push_back( PROPERTY_ID_STRINGITEMLIST ); + aDependentProperties.push_back( PROPERTY_ID_TYPEDITEMLIST ); + aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN ); + [[fallthrough]]; + + // ----- StringItemList ----- + case PROPERTY_ID_STRINGITEMLIST: + aDependentProperties.push_back( PROPERTY_ID_TYPEDITEMLIST ); + aDependentProperties.push_back( PROPERTY_ID_SELECTEDITEMS ); + aDependentProperties.push_back( PROPERTY_ID_DEFAULT_SELECT_SEQ ); + break; + + // ----- ListSource ----- + case PROPERTY_ID_LISTSOURCE: + aDependentProperties.push_back( PROPERTY_ID_STRINGITEMLIST ); + aDependentProperties.push_back( PROPERTY_ID_TYPEDITEMLIST ); + break; + + // ----- DataField ----- + case PROPERTY_ID_CONTROLSOURCE: + { + OUString sControlSource; + _rNewValue >>= sControlSource; + if ( impl_componentHasProperty_throw( PROPERTY_FILTERPROPOSAL ) ) + _rxInspectorUI->enablePropertyUI( PROPERTY_FILTERPROPOSAL, !sControlSource.isEmpty() ); + if ( impl_componentHasProperty_throw( PROPERTY_EMPTY_IS_NULL ) ) + _rxInspectorUI->enablePropertyUI( PROPERTY_EMPTY_IS_NULL, !sControlSource.isEmpty() ); + + aDependentProperties.push_back( PROPERTY_ID_BOUNDCOLUMN ); + aDependentProperties.push_back( PROPERTY_ID_SCALEIMAGE ); + aDependentProperties.push_back( PROPERTY_ID_SCALE_MODE ); + aDependentProperties.push_back( PROPERTY_ID_INPUT_REQUIRED ); + } + break; + + case PROPERTY_ID_EMPTY_IS_NULL: + aDependentProperties.push_back( PROPERTY_ID_INPUT_REQUIRED ); + break; + + // ----- SubmitEncoding ----- + case PROPERTY_ID_SUBMIT_ENCODING: + { + FormSubmitEncoding eEncoding = FormSubmitEncoding_URL; + if( ! (_rNewValue >>= eEncoding) ) + SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_SUBMIT_ENCODING); + _rxInspectorUI->enablePropertyUI( PROPERTY_SUBMIT_METHOD, eEncoding == FormSubmitEncoding_URL ); + } + break; + + // ----- Repeat ----- + case PROPERTY_ID_REPEAT: + { + bool bIsRepeating = false; + if( ! (_rNewValue >>= bIsRepeating) ) + SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_REPEAT); + _rxInspectorUI->enablePropertyUI( PROPERTY_REPEAT_DELAY, bIsRepeating ); + } + break; + + // ----- TabStop ----- + case PROPERTY_ID_TABSTOP: + { + if ( !impl_componentHasProperty_throw( PROPERTY_TABINDEX ) ) + break; + bool bHasTabStop = false; + _rNewValue >>= bHasTabStop; + _rxInspectorUI->enablePropertyUI( PROPERTY_TABINDEX, bHasTabStop ); + } + break; + + // ----- Border ----- + case PROPERTY_ID_BORDER: + { + sal_Int16 nBordeType = VisualEffect::NONE; + if( ! (_rNewValue >>= nBordeType) ) + SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_BORDER); + _rxInspectorUI->enablePropertyUI( PROPERTY_BORDERCOLOR, nBordeType == VisualEffect::FLAT ); + } + break; + + // ----- DropDown ----- + case PROPERTY_ID_DROPDOWN: + { + if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_LINECOUNT ) ) + { + bool bDropDown = true; + _rNewValue >>= bDropDown; + _rxInspectorUI->enablePropertyUI( PROPERTY_LINECOUNT, bDropDown ); + } + } + break; + + // ----- ImageURL ----- + case PROPERTY_ID_IMAGE_URL: + { + if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_IMAGEPOSITION ) ) + { + OUString sImageURL; + if( ! (_rNewValue >>= sImageURL) ) + SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_IMAGE_URL); + _rxInspectorUI->enablePropertyUI( PROPERTY_IMAGEPOSITION, !sImageURL.isEmpty() ); + } + + aDependentProperties.push_back( PROPERTY_ID_SCALEIMAGE ); + aDependentProperties.push_back( PROPERTY_ID_SCALE_MODE ); + } + break; + + // ----- ButtonType ----- + case PROPERTY_ID_BUTTONTYPE: + { + FormButtonType eButtonType( FormButtonType_PUSH ); + if( ! (_rNewValue >>= eButtonType) ) + SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_BUTTONTYPE); + _rxInspectorUI->enablePropertyUI( PROPERTY_TARGET_URL, FormButtonType_URL == eButtonType ); + [[fallthrough]]; + } + + // ----- TargetURL ----- + case PROPERTY_ID_TARGET_URL: + aDependentProperties.push_back( PROPERTY_ID_TARGET_FRAME ); + break; // case PROPERTY_ID_TARGET_URL + + // ----- TriState ----- + case PROPERTY_ID_TRISTATE: + if ( !_bFirstTimeInit ) + _rxInspectorUI->rebuildPropertyUI( m_eComponentClass == eFormControl ? OUString(PROPERTY_DEFAULT_STATE) : OUString(PROPERTY_STATE) ); + break; // case PROPERTY_ID_TRISTATE + + // ----- DecimalAccuracy ----- + case PROPERTY_ID_DECIMAL_ACCURACY: + // ----- ShowThousandsSeparator ----- + case PROPERTY_ID_SHOWTHOUSANDSEP: + { + bool bAccuracy = (PROPERTY_ID_DECIMAL_ACCURACY == nActuatingPropId); + sal_uInt16 nNewDigits = 0; + if ( bAccuracy ) + { + if( ! (_rNewValue >>= nNewDigits) ) + SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_DECIMAL_ACCURACY); + } + else + { + bool bUseSep = false; + if( ! (_rNewValue >>= bUseSep) ) + SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_SHOWTHOUSANDSEP); + } + + // propagate the changes to the min/max/default fields + OUString aAffectedProps[] = { OUString(PROPERTY_VALUE), OUString(PROPERTY_DEFAULT_VALUE), OUString(PROPERTY_VALUEMIN), OUString(PROPERTY_VALUEMAX) }; + for (const OUString & aAffectedProp : aAffectedProps) + { + Reference< XPropertyControl > xControl; + try + { + xControl = _rxInspectorUI->getPropertyControl( aAffectedProp ); + } + catch( const UnknownPropertyException& ) {} + if ( xControl.is() ) + { + OFormattedNumericControl* pControl = dynamic_cast< OFormattedNumericControl* >( xControl.get() ); + DBG_ASSERT( pControl, "FormComponentPropertyHandler::actuatingPropertyChanged: invalid control!" ); + if (pControl) + { + if ( bAccuracy ) + pControl->SetDecimalDigits( nNewDigits ); + } + } + } + } + break; + + // ----- FormatKey ----- + case PROPERTY_ID_FORMATKEY: + { + FormatDescription aNewDesc; + + Reference< XNumberFormatsSupplier > xSupplier; + if( ! (m_xComponent->getPropertyValue( PROPERTY_FORMATSSUPPLIER ) >>= xSupplier) ) + SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_FORMATKEY); + + Reference< XUnoTunnel > xTunnel( xSupplier, UNO_QUERY ); + DBG_ASSERT(xTunnel.is(), "FormComponentPropertyHandler::actuatingPropertyChanged: xTunnel is invalid!"); + if ( xTunnel.is() ) + { + SvNumberFormatsSupplierObj* pSupplier = reinterpret_cast(xTunnel->getSomething(SvNumberFormatsSupplierObj::getUnoTunnelId())); + // the same again + + aNewDesc.pSupplier = pSupplier; + if ( !( _rNewValue >>= aNewDesc.nKey ) ) + aNewDesc.nKey = 0; + + // give each control which has to know this an own copy of the description + OUString aFormattedPropertyControls[] = { + OUString(PROPERTY_EFFECTIVE_MIN), OUString(PROPERTY_EFFECTIVE_MAX), OUString(PROPERTY_EFFECTIVE_DEFAULT), OUString(PROPERTY_EFFECTIVE_VALUE) + }; + for (const OUString & aFormattedPropertyControl : aFormattedPropertyControls) + { + Reference< XPropertyControl > xControl; + try + { + xControl = _rxInspectorUI->getPropertyControl( aFormattedPropertyControl ); + } + catch( const UnknownPropertyException& ) {} + if ( xControl.is() ) + { + OFormattedNumericControl* pControl = dynamic_cast< OFormattedNumericControl* >( xControl.get() ); + DBG_ASSERT( pControl, "FormComponentPropertyHandler::actuatingPropertyChanged: invalid control!" ); + if ( pControl ) + pControl->SetFormatDescription( aNewDesc ); + } + } + } + } + break; + + case PROPERTY_ID_TOGGLE: + { + bool bIsToggleButton = false; + if( ! (_rNewValue >>= bIsToggleButton) ) + SAL_WARN("extensions.propctrlr", "actuatingPropertyChanged: unable to get property " << PROPERTY_ID_TOGGLE); + _rxInspectorUI->enablePropertyUI( PROPERTY_DEFAULT_STATE, bIsToggleButton ); + } + break; + case -1: + throw RuntimeException(); + break; + default: + OSL_FAIL( "FormComponentPropertyHandler::actuatingPropertyChanged: did not register for this property!" ); + break; + + } // switch ( nActuatingPropId ) + + for (auto const& dependentProperty : aDependentProperties) + { + if ( impl_isSupportedProperty_nothrow(dependentProperty) ) + impl_updateDependentProperty_nothrow(dependentProperty, _rxInspectorUI); + } + } + + void FormComponentPropertyHandler::impl_updateDependentProperty_nothrow( PropertyId _nPropId, const Reference< XObjectInspectorUI >& _rxInspectorUI ) const + { + try + { + switch ( _nPropId ) + { + // ----- StringItemList ----- + case PROPERTY_ID_STRINGITEMLIST: + { + ListSourceType eLSType = ListSourceType_VALUELIST; + if( ! (impl_getPropertyValue_throw( PROPERTY_LISTSOURCETYPE ) >>= eLSType) ) + SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_LISTSOURCETYPE); + + OUString sListSource; + { + Sequence< OUString > aListSource; + Any aListSourceValue( impl_getPropertyValue_throw( PROPERTY_LISTSOURCE ) ); + if ( aListSourceValue >>= aListSource ) + { + if ( aListSource.hasElements() ) + sListSource = aListSource[0]; + } + else + if( ! (aListSourceValue >>= sListSource) ) + SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_LISTSOURCE); + } + + bool bIsEnabled = ( ( eLSType == ListSourceType_VALUELIST ) + || ( sListSource.isEmpty() ) + ); + _rxInspectorUI->enablePropertyUI( PROPERTY_STRINGITEMLIST, bIsEnabled ); + } + break; // case PROPERTY_ID_STRINGITEMLIST + + // ----- TypedItemList ----- + case PROPERTY_ID_TYPEDITEMLIST: + { + /* TODO: anything? */ + } + break; // case PROPERTY_ID_TYPEDITEMLIST + + // ----- BoundColumn ----- + case PROPERTY_ID_BOUNDCOLUMN: + { + ListSourceType eLSType = ListSourceType_VALUELIST; + if( ! (impl_getPropertyValue_throw( PROPERTY_LISTSOURCETYPE ) >>= eLSType) ) + SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_LISTSOURCETYPE); + + _rxInspectorUI->enablePropertyUI( PROPERTY_BOUNDCOLUMN, + ( eLSType != ListSourceType_VALUELIST ) + ); + } + break; // case PROPERTY_ID_BOUNDCOLUMN + + // ----- ScaleImage, ScaleMode ----- + case PROPERTY_ID_SCALEIMAGE: + case PROPERTY_ID_SCALE_MODE: + { + OUString sControlSource; + if ( impl_isSupportedProperty_nothrow( PROPERTY_ID_CONTROLSOURCE ) ) + impl_getPropertyValue_throw( PROPERTY_CONTROLSOURCE ) >>= sControlSource; + + OUString sImageURL; + impl_getPropertyValue_throw( PROPERTY_IMAGE_URL ) >>= sImageURL; + + _rxInspectorUI->enablePropertyUI( impl_getPropertyNameFromId_nothrow( _nPropId ), + ( !sControlSource.isEmpty() ) || ( !sImageURL.isEmpty() ) + ); + } + break; // case PROPERTY_ID_SCALEIMAGE, PROPERTY_ID_SCALE_MODE + + // ----- InputRequired ----- + case PROPERTY_ID_INPUT_REQUIRED: + { + OUString sControlSource; + if( ! (impl_getPropertyValue_throw( PROPERTY_CONTROLSOURCE ) >>= sControlSource) ) + SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_CONTROLSOURCE); + + bool bEmptyIsNULL = false; + bool bHasEmptyIsNULL = impl_componentHasProperty_throw( PROPERTY_EMPTY_IS_NULL ); + if ( bHasEmptyIsNULL ) + if( ! (impl_getPropertyValue_throw( PROPERTY_EMPTY_IS_NULL ) >>= bEmptyIsNULL) ) + SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_EMPTY_IS_NULL); + + // if the control is not bound to a DB field, there is no sense in having the "Input required" + // property + // Also, if an empty input of this control are *not* written as NULL, but as empty strings, + // then "Input required" does not make sense, too (since there's always an input, even if the control + // is empty). + _rxInspectorUI->enablePropertyUI( PROPERTY_INPUT_REQUIRED, + ( !sControlSource.isEmpty() ) && ( !bHasEmptyIsNULL || bEmptyIsNULL ) + ); + } + break; + + // ----- SelectedItems, DefaultSelection ----- + case PROPERTY_ID_SELECTEDITEMS: + case PROPERTY_ID_DEFAULT_SELECT_SEQ: + { + Sequence< OUString > aEntries; + impl_getPropertyValue_throw( PROPERTY_STRINGITEMLIST ) >>= aEntries; + bool isEnabled = aEntries.hasElements(); + + if ( ( m_nClassId == FormComponentType::LISTBOX ) && ( m_eComponentClass == eFormControl ) ) + { + ListSourceType eLSType = ListSourceType_VALUELIST; + impl_getPropertyValue_throw( PROPERTY_LISTSOURCETYPE ) >>= eLSType; + isEnabled &= ( eLSType == ListSourceType_VALUELIST ); + } + _rxInspectorUI->enablePropertyUIElements( impl_getPropertyNameFromId_nothrow( _nPropId ), + PropertyLineElement::PrimaryButton, isEnabled ); + } + break; // case PROPERTY_ID_DEFAULT_SELECT_SEQ + + // ----- TargetFrame ------ + case PROPERTY_ID_TARGET_FRAME: + { + OUString sTargetURL; + impl_getPropertyValue_throw( PROPERTY_TARGET_URL ) >>= sTargetURL; + FormButtonType eButtonType( FormButtonType_URL ); + if ( 0 != m_nClassId ) + { + if( ! (impl_getPropertyValue_throw( PROPERTY_BUTTONTYPE ) >>= eButtonType) ) + SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_BUTTONTYPE); + } + // if m_nClassId is 0, then we're inspecting a form. In this case, eButtonType is always + // FormButtonType_URL here + _rxInspectorUI->enablePropertyUI( PROPERTY_TARGET_FRAME, + ( eButtonType == FormButtonType_URL ) && ( !sTargetURL.isEmpty() ) + ); + } + break; + + // ----- Order ------ + case PROPERTY_ID_SORT: + // ----- Filter ------ + case PROPERTY_ID_FILTER: + { + Reference< XConnection > xConnection; + bool bAllowEmptyDS = ::dbtools::isEmbeddedInDatabase( m_xComponent, xConnection ); + + // if there's no escape processing, we cannot enter any values for this property + bool bDoEscapeProcessing( false ); + impl_getPropertyValue_throw( PROPERTY_ESCAPE_PROCESSING ) >>= bDoEscapeProcessing; + _rxInspectorUI->enablePropertyUI( + impl_getPropertyNameFromId_nothrow( _nPropId ), + bDoEscapeProcessing + ); + + // also care for the browse button - enabled if we have escape processing, and a valid + // data source signature + _rxInspectorUI->enablePropertyUIElements( + impl_getPropertyNameFromId_nothrow( _nPropId ), + PropertyLineElement::PrimaryButton, + impl_hasValidDataSourceSignature_nothrow( m_xComponent, bAllowEmptyDS ) + && bDoEscapeProcessing + ); + } + break; // case PROPERTY_ID_FILTER: + + // ----- Command ----- + case PROPERTY_ID_COMMAND: + { + sal_Int32 nCommandType( CommandType::COMMAND ); + if( ! (impl_getPropertyValue_throw( PROPERTY_COMMANDTYPE ) >>= nCommandType) ) + SAL_WARN("extensions.propctrlr", "impl_updateDependentProperty_nothrow: unable to get property " << PROPERTY_COMMANDTYPE); + + impl_ensureRowsetConnection_nothrow(); + Reference< XConnection > xConnection = m_xRowSetConnection.getTyped(); + bool bAllowEmptyDS = false; + if ( !xConnection.is() ) + bAllowEmptyDS = ::dbtools::isEmbeddedInDatabase( m_xComponent, xConnection ); + + bool doEnable = ( nCommandType == CommandType::COMMAND ) + && ( m_xRowSetConnection.is() + || xConnection.is() + || impl_hasValidDataSourceSignature_nothrow( m_xComponent, bAllowEmptyDS) + ); + + _rxInspectorUI->enablePropertyUIElements( + PROPERTY_COMMAND, + PropertyLineElement::PrimaryButton, + doEnable + ); + } + break; // case PROPERTY_ID_COMMAND + + // ----- DetailFields ----- + case PROPERTY_ID_DETAILFIELDS: + { + Reference< XConnection > xConnection; + bool bAllowEmptyDS = ::dbtools::isEmbeddedInDatabase( m_xComponent, xConnection ); + + // both our current form, and its parent form, need to have a valid + // data source signature + bool bDoEnableMasterDetailFields = + impl_hasValidDataSourceSignature_nothrow( m_xComponent, bAllowEmptyDS ) + && impl_hasValidDataSourceSignature_nothrow( Reference< XPropertySet >( m_xObjectParent, UNO_QUERY ), bAllowEmptyDS ); + + // in opposite to the other properties, here in real *two* properties are + // affected + _rxInspectorUI->enablePropertyUIElements( PROPERTY_DETAILFIELDS, PropertyLineElement::PrimaryButton, bDoEnableMasterDetailFields ); + _rxInspectorUI->enablePropertyUIElements( PROPERTY_MASTERFIELDS, PropertyLineElement::PrimaryButton, bDoEnableMasterDetailFields ); + } + break; + + default: + OSL_FAIL( "FormComponentPropertyHandler::impl_updateDependentProperty_nothrow: unexpected property to update!" ); + break; + + } // switch + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_updateDependentProperty_nothrow" ); + } + } + + void SAL_CALL FormComponentPropertyHandler::disposing() + { + PropertyHandlerComponent::disposing(); + if ( m_xCommandDesigner.is() && m_xCommandDesigner->isActive() ) + m_xCommandDesigner->dispose(); + } + + sal_Bool SAL_CALL FormComponentPropertyHandler::suspend( sal_Bool _bSuspend ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( _bSuspend ) + if ( m_xCommandDesigner.is() && m_xCommandDesigner->isActive() ) + return m_xCommandDesigner->suspend(); + return true; + } + + void FormComponentPropertyHandler::onNewComponent() + { + PropertyHandlerComponent::onNewComponent(); + if ( !m_xComponentPropertyInfo.is() && m_xComponent.is() ) + throw NullPointerException(); + + m_xPropertyState.set( m_xComponent, UNO_QUERY ); + m_eComponentClass = eUnknown; + m_bComponentIsSubForm = m_bHaveListSource = m_bHaveCommand = false; + m_nClassId = 0; + + try + { + // component class + m_eComponentClass = eUnknown; + + if ( impl_componentHasProperty_throw( PROPERTY_WIDTH ) + && impl_componentHasProperty_throw( PROPERTY_HEIGHT ) + && impl_componentHasProperty_throw( PROPERTY_POSITIONX ) + && impl_componentHasProperty_throw( PROPERTY_POSITIONY ) + && impl_componentHasProperty_throw( PROPERTY_STEP ) + && impl_componentHasProperty_throw( PROPERTY_TABINDEX ) + ) + { + m_eComponentClass = eDialogControl; + } + else + { + m_eComponentClass = eFormControl; + } + + + // (database) sub form? + Reference< XForm > xAsForm( m_xComponent, UNO_QUERY ); + if ( xAsForm.is() ) + { + Reference< XForm > xFormsParent( xAsForm->getParent(), css::uno::UNO_QUERY ); + m_bComponentIsSubForm = xFormsParent.is(); + } + + + // ClassId + Reference< XChild > xCompAsChild( m_xComponent, UNO_QUERY ); + if ( xCompAsChild.is() ) + m_xObjectParent = xCompAsChild->getParent(); + + + // ClassId + impl_classifyControlModel_throw(); + } + catch( const RuntimeException& ) + { + throw; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::onNewComponent" ); + } + } + + void FormComponentPropertyHandler::impl_classifyControlModel_throw( ) + { + if ( impl_componentHasProperty_throw( PROPERTY_CLASSID ) ) + { + if( ! (m_xComponent->getPropertyValue( PROPERTY_CLASSID ) >>= m_nClassId) ) + SAL_WARN("extensions.propctrlr", "impl_classifyControlModel_throw: unable to get property " << PROPERTY_CLASSID); + } + else if ( eDialogControl == m_eComponentClass ) + { + Reference< XServiceInfo > xServiceInfo( m_xComponent, UNO_QUERY ); + if ( xServiceInfo.is() ) + { + // it's a control model, and can tell about it's supported services + m_nClassId = FormComponentType::CONTROL; + + const char* aControlModelServiceNames[] = + { + "UnoControlButtonModel", + "UnoControlCheckBoxModel", + "UnoControlComboBoxModel", + "UnoControlCurrencyFieldModel", + "UnoControlDateFieldModel", + "UnoControlEditModel", + "UnoControlFileControlModel", + "UnoControlFixedTextModel", + "UnoControlGroupBoxModel", + "UnoControlImageControlModel", + "UnoControlListBoxModel", + "UnoControlNumericFieldModel", + "UnoControlPatternFieldModel", + "UnoControlRadioButtonModel", + "UnoControlScrollBarModel", + "UnoControlSpinButtonModel", + "UnoControlTimeFieldModel", + + "UnoControlFixedLineModel", + "UnoControlFormattedFieldModel", + "UnoControlProgressBarModel" + }; + const sal_Int16 nClassIDs[] = + { + FormComponentType::COMMANDBUTTON, + FormComponentType::CHECKBOX, + FormComponentType::COMBOBOX, + FormComponentType::CURRENCYFIELD, + FormComponentType::DATEFIELD, + FormComponentType::TEXTFIELD, + FormComponentType::FILECONTROL, + FormComponentType::FIXEDTEXT, + FormComponentType::GROUPBOX, + FormComponentType::IMAGECONTROL, + FormComponentType::LISTBOX, + FormComponentType::NUMERICFIELD, + FormComponentType::PATTERNFIELD, + FormComponentType::RADIOBUTTON, + FormComponentType::SCROLLBAR, + FormComponentType::SPINBUTTON, + FormComponentType::TIMEFIELD, + + ControlType::FIXEDLINE, + ControlType::FORMATTEDFIELD, + ControlType::PROGRESSBAR + }; + + sal_Int32 nKnownControlTypes = SAL_N_ELEMENTS( aControlModelServiceNames ); + OSL_ENSURE( nKnownControlTypes == SAL_N_ELEMENTS( nClassIDs ), + "FormComponentPropertyHandler::impl_classifyControlModel_throw: inconsistence" ); + + for ( sal_Int32 i = 0; i < nKnownControlTypes; ++i ) + { + OUString sServiceName = "com.sun.star.awt." + + OUString::createFromAscii( aControlModelServiceNames[ i ] ); + + if ( xServiceInfo->supportsService( sServiceName ) ) + { + m_nClassId = nClassIDs[ i ]; + break; + } + } + } + } + } + + void FormComponentPropertyHandler::impl_normalizePropertyValue_nothrow( Any& _rValue, PropertyId _nPropId ) const + { + switch ( _nPropId ) + { + case PROPERTY_ID_TABSTOP: + if ( !_rValue.hasValue() ) + { + switch ( m_nClassId ) + { + case FormComponentType::COMMANDBUTTON: + case FormComponentType::RADIOBUTTON: + case FormComponentType::CHECKBOX: + case FormComponentType::TEXTFIELD: + case FormComponentType::LISTBOX: + case FormComponentType::COMBOBOX: + case FormComponentType::FILECONTROL: + case FormComponentType::DATEFIELD: + case FormComponentType::TIMEFIELD: + case FormComponentType::NUMERICFIELD: + case ControlType::FORMATTEDFIELD: + case FormComponentType::CURRENCYFIELD: + case FormComponentType::PATTERNFIELD: + _rValue <<= true; + break; + default: + _rValue <<= false; + break; + } + } + break; + } + } + + bool FormComponentPropertyHandler::isReportModel() const + { + Reference xModel(impl_getContextDocument_nothrow()); + Reference xReportDef(xModel, css::uno::UNO_QUERY); + return xReportDef.is(); + } + + bool FormComponentPropertyHandler::impl_shouldExcludeProperty_nothrow( const Property& _rProperty ) const + { + OSL_ENSURE( _rProperty.Handle == m_pInfoService->getPropertyId( _rProperty.Name ), + "FormComponentPropertyHandler::impl_shouldExcludeProperty_nothrow: inconsistency in the property!" ); + + if ( _rProperty.Handle == PROPERTY_ID_CONTROLLABEL ) + // prevent that this is caught below + return false; + + if ( ( _rProperty.Type.getTypeClass() == TypeClass_INTERFACE ) + || ( _rProperty.Type.getTypeClass() == TypeClass_UNKNOWN ) + ) + return true; + + if ( ( _rProperty.Attributes & PropertyAttribute::TRANSIENT ) && ( m_eComponentClass != eDialogControl ) ) + // strange enough, dialog controls declare a lot of their properties as transient + return true; + + if ( _rProperty.Attributes & PropertyAttribute::READONLY ) + return true; + + switch ( _rProperty.Handle ) + { + case PROPERTY_ID_MASTERFIELDS: + case PROPERTY_ID_DETAILFIELDS: + if ( !m_bComponentIsSubForm ) + // no master and detail fields for forms which are no sub forms + return true; + break; + + case PROPERTY_ID_DATASOURCE: + { + // don't show DataSource if the component is part of an embedded form document + Reference< XConnection > xConn; + if ( isEmbeddedInDatabase( m_xComponent, xConn ) ) + return true; + } + break; + + case PROPERTY_ID_TEXT: + // don't show the "Text" property of formatted fields + if ( ControlType::FORMATTEDFIELD == m_nClassId ) + return true; + break; + + case PROPERTY_ID_FORMATKEY: + case PROPERTY_ID_EFFECTIVE_MIN: + case PROPERTY_ID_EFFECTIVE_MAX: + case PROPERTY_ID_EFFECTIVE_DEFAULT: + case PROPERTY_ID_EFFECTIVE_VALUE: + // only if the set has a formats supplier, too + if ( !impl_componentHasProperty_throw( PROPERTY_FORMATSSUPPLIER ) ) + return true; + // (form) date and time fields also have a formats supplier, but the format itself + // is reflected in another property + if ( ( FormComponentType::DATEFIELD == m_nClassId ) + || ( FormComponentType::TIMEFIELD == m_nClassId ) + ) + return true; + break; + + case PROPERTY_ID_SCALEIMAGE: + if ( impl_componentHasProperty_throw( PROPERTY_SCALE_MODE ) ) + // ScaleImage is superseded by ScaleMode + return true; + break; + + case PROPERTY_ID_WRITING_MODE: + if ( !SvtCTLOptions().IsCTLFontEnabled() ) + return true; + break; + } + + sal_uInt32 nPropertyUIFlags = m_pInfoService->getPropertyUIFlags( _rProperty.Handle ); + + // don't show experimental properties unless allowed to do so + if ( ( nPropertyUIFlags & PROP_FLAG_EXPERIMENTAL ) != 0 ) + return true; + + // no data properties if no Base is installed. + if ( ( nPropertyUIFlags & PROP_FLAG_DATA_PROPERTY ) != 0 ) + if ( !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::DATABASE ) ) + return true; + + if ((nPropertyUIFlags & PROP_FLAG_REPORT_INVISIBLE) != 0 && isReportModel()) + return true; + + return false; + } + + Reference< XRowSet > FormComponentPropertyHandler::impl_getRowSet_throw( ) const + { + Reference< XRowSet > xRowSet = m_xRowSet; + if ( !xRowSet.is() ) + { + xRowSet.set( m_xComponent, UNO_QUERY ); + if ( !xRowSet.is() ) + { + xRowSet.set( m_xObjectParent, UNO_QUERY ); + if ( !xRowSet.is() ) + { + // are we inspecting a grid column? + if (Reference< XGridColumnFactory >( m_xObjectParent, UNO_QUERY) .is()) + { // yes + Reference< XChild > xParentAsChild( m_xObjectParent, UNO_QUERY ); + if ( xParentAsChild.is() ) + xRowSet.set( xParentAsChild->getParent(), UNO_QUERY ); + } + } + if ( !xRowSet.is() ) + xRowSet = m_xRowSet; + } + DBG_ASSERT( xRowSet.is(), "FormComponentPropertyHandler::impl_getRowSet_throw: could not obtain the rowset for the introspectee!" ); + } + return xRowSet; + } + + + Reference< XRowSet > FormComponentPropertyHandler::impl_getRowSet_nothrow( ) const + { + Reference< XRowSet > xReturn; + try + { + xReturn = impl_getRowSet_throw(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_getRowSet_nothrow" ); + } + return xReturn; + } + + + void FormComponentPropertyHandler::impl_initFieldList_nothrow( std::vector< OUString >& _rFieldNames ) const + { + clearContainer( _rFieldNames ); + try + { + weld::WaitObject aWaitCursor(impl_getDefaultDialogFrame_nothrow()); + + // get the form of the control we're inspecting + Reference< XPropertySet > xFormSet( impl_getRowSet_throw(), UNO_QUERY ); + if ( !xFormSet.is() ) + return; + + OUString sObjectName; + if( ! (xFormSet->getPropertyValue( PROPERTY_COMMAND ) >>= sObjectName) ) + SAL_WARN("extensions.propctrlr", "impl_initFieldList_nothrow: unable to get property " << PROPERTY_COMMAND); + // when there is no command we don't need to ask for columns + if ( !sObjectName.isEmpty() && impl_ensureRowsetConnection_nothrow() ) + { + OUString aDatabaseName; + if( ! (xFormSet->getPropertyValue( PROPERTY_DATASOURCE ) >>= aDatabaseName) ) + SAL_WARN("extensions.propctrlr", "impl_initFieldList_nothrow: unable to get property " << PROPERTY_DATASOURCE); + sal_Int32 nObjectType = CommandType::COMMAND; + if( ! (xFormSet->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nObjectType) ) + SAL_WARN("extensions.propctrlr", "impl_initFieldList_nothrow: unable to get property " << PROPERTY_COMMANDTYPE); + + const Sequence aNames = ::dbtools::getFieldNamesByCommandDescriptor( m_xRowSetConnection, nObjectType, sObjectName ); + _rFieldNames.insert( _rFieldNames.end(), aNames.begin(), aNames.end() ); + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_initFieldList_nothrow" ); + } + } + + void FormComponentPropertyHandler::impl_displaySQLError_nothrow( const ::dbtools::SQLExceptionInfo& _rErrorDescriptor ) const + { + auto pTopLevel = impl_getDefaultDialogFrame_nothrow(); + ::dbtools::showError(_rErrorDescriptor, pTopLevel ? pTopLevel->GetXWindow() : nullptr, m_xContext); + } + + bool FormComponentPropertyHandler::impl_ensureRowsetConnection_nothrow() const + { + if ( !m_xRowSetConnection.is() ) + { + uno::Reference xConnection; + Any any = m_xContext->getValueByName( "ActiveConnection" ); + any >>= xConnection; + m_xRowSetConnection.reset(xConnection,::dbtools::SharedConnection::NoTakeOwnership); + } + if ( m_xRowSetConnection.is() ) + return true; + + Reference< XRowSet > xRowSet( impl_getRowSet_throw() ); + Reference< XPropertySet > xRowSetProps( xRowSet, UNO_QUERY ); + + // connect the row set - this is delegated to elsewhere - while observing errors + SQLExceptionInfo aError; + try + { + if ( xRowSetProps.is() ) + { + weld::WaitObject aWaitCursor(impl_getDefaultDialogFrame_nothrow()); + m_xRowSetConnection = ::dbtools::ensureRowSetConnection( xRowSet, m_xContext, nullptr ); + } + } + catch ( const SQLException& ) { aError = SQLExceptionInfo( ::cppu::getCaughtException() ); } + catch ( const WrappedTargetException& e ) { aError = SQLExceptionInfo( e.TargetException ); } + catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); } + + // report errors, if necessary + if ( aError.isValid() ) + { + OUString sDataSourceName; + try + { + xRowSetProps->getPropertyValue( PROPERTY_DATASOURCE ) >>= sDataSourceName; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_ensureRowsetConnection_nothrow: caught an exception during error handling!" ); + } + // additional info about what happened + INetURLObject aParser( sDataSourceName ); + if ( aParser.GetProtocol() != INetProtocol::NotValid ) + sDataSourceName = aParser.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset ); + OUString sInfo(PcrRes(RID_STR_UNABLETOCONNECT).replaceAll("$name$", sDataSourceName)); + SQLContext aContext; + aContext.Message = sInfo; + aContext.NextException = aError.get(); + impl_displaySQLError_nothrow( aContext ); + } + + return m_xRowSetConnection.is(); + } + + + void FormComponentPropertyHandler::impl_describeCursorSource_nothrow( LineDescriptor& _out_rProperty, const Reference< XPropertyControlFactory >& _rxControlFactory ) const + { + try + { + weld::WaitObject aWaitCursor(impl_getDefaultDialogFrame_nothrow()); + + + // Set the UI data + _out_rProperty.DisplayName = m_pInfoService->getPropertyTranslation( PROPERTY_ID_COMMAND ); + + _out_rProperty.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( PROPERTY_ID_COMMAND ) ); + _out_rProperty.PrimaryButtonId = UID_PROP_DLG_SQLCOMMAND; + + + sal_Int32 nCommandType = CommandType::COMMAND; + impl_getPropertyValue_throw( PROPERTY_COMMANDTYPE ) >>= nCommandType; + + switch ( nCommandType ) + { + case CommandType::TABLE: + case CommandType::QUERY: + { + std::vector< OUString > aNames; + if ( impl_ensureRowsetConnection_nothrow() ) + { + if ( nCommandType == CommandType::TABLE ) + impl_fillTableNames_throw( aNames ); + else + impl_fillQueryNames_throw( aNames ); + } + _out_rProperty.Control = PropertyHandlerHelper::createComboBoxControl( _rxControlFactory, std::move(aNames), true ); + } + break; + + default: + _out_rProperty.Control = _rxControlFactory->createPropertyControl( PropertyControlType::MultiLineTextField, false ); + break; + } + } + catch (const Exception&) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_describeCursorSource_nothrow"); + } + } + + + void FormComponentPropertyHandler::impl_fillTableNames_throw( std::vector< OUString >& _out_rNames ) const + { + OSL_PRECOND( m_xRowSetConnection.is(), "FormComponentPropertyHandler::impl_fillTableNames_throw: need a connection!" ); + _out_rNames.resize( 0 ); + + Reference< XTablesSupplier > xSupplyTables( m_xRowSetConnection, UNO_QUERY ); + Reference< XNameAccess > xTableNames; + if ( xSupplyTables.is() ) + xTableNames = xSupplyTables->getTables(); + DBG_ASSERT( xTableNames.is(), "FormComponentPropertyHandler::impl_fillTableNames_throw: no way to obtain the tables of the connection!" ); + if ( !xTableNames.is() ) + return; + + const Sequence aNames = xTableNames->getElementNames(); + _out_rNames.insert( _out_rNames.end(), aNames.begin(), aNames.end() ); + } + + + void FormComponentPropertyHandler::impl_fillQueryNames_throw( std::vector< OUString >& _out_rNames ) const + { + OSL_PRECOND( m_xRowSetConnection.is(), "FormComponentPropertyHandler::impl_fillQueryNames_throw: need a connection!" ); + _out_rNames.resize( 0 ); + + Reference< XQueriesSupplier > xSupplyQueries( m_xRowSetConnection, UNO_QUERY ); + Reference< XNameAccess > xQueryNames; + if ( xSupplyQueries.is() ) + { + xQueryNames = xSupplyQueries->getQueries(); + impl_fillQueryNames_throw(xQueryNames,_out_rNames); + } + } + + void FormComponentPropertyHandler::impl_fillQueryNames_throw( const Reference< XNameAccess >& _xQueryNames,std::vector< OUString >& _out_rNames,std::u16string_view _sName ) const + { + DBG_ASSERT( _xQueryNames.is(), "FormComponentPropertyHandler::impl_fillQueryNames_throw: no way to obtain the queries of the connection!" ); + if ( !_xQueryNames.is() ) + return; + + bool bAdd = !_sName.empty(); + + const Sequence aQueryNames =_xQueryNames->getElementNames(); + for ( const OUString& rQueryName : aQueryNames ) + { + OUStringBuffer sTemp; + if ( bAdd ) + { + sTemp.append(_sName); + sTemp.append("/"); + } + sTemp.append(rQueryName); + Reference< XNameAccess > xSubQueries(_xQueryNames->getByName(rQueryName),UNO_QUERY); + if ( xSubQueries.is() ) + impl_fillQueryNames_throw(xSubQueries,_out_rNames,sTemp.makeStringAndClear()); + else + _out_rNames.push_back( sTemp.makeStringAndClear() ); + } + } + + + void FormComponentPropertyHandler::impl_describeListSourceUI_throw( LineDescriptor& _out_rDescriptor, const Reference< XPropertyControlFactory >& _rxControlFactory ) const + { + OSL_PRECOND( m_xComponent.is(), "FormComponentPropertyHandler::impl_describeListSourceUI_throw: no component!" ); + + + // read out ListSourceTypes + Any aListSourceType( m_xComponent->getPropertyValue( PROPERTY_LISTSOURCETYPE ) ); + + sal_Int32 nListSourceType = sal_Int32(ListSourceType_VALUELIST); + ::cppu::enum2int( nListSourceType, aListSourceType ); + ListSourceType eListSourceType = static_cast(nListSourceType); + + _out_rDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( PROPERTY_ID_LISTSOURCE ); + _out_rDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( PROPERTY_ID_LISTSOURCE ) ); + + + // set enums + switch( eListSourceType ) + { + case ListSourceType_VALUELIST: + _out_rDescriptor.Control = _rxControlFactory->createPropertyControl( PropertyControlType::StringListField, false ); + break; + + case ListSourceType_TABLEFIELDS: + case ListSourceType_TABLE: + case ListSourceType_QUERY: + { + std::vector< OUString > aListEntries; + if ( impl_ensureRowsetConnection_nothrow() ) + { + if ( eListSourceType == ListSourceType_QUERY ) + impl_fillQueryNames_throw( aListEntries ); + else + impl_fillTableNames_throw( aListEntries ); + } + _out_rDescriptor.Control = PropertyHandlerHelper::createComboBoxControl( _rxControlFactory, std::move(aListEntries), false ); + } + break; + case ListSourceType_SQL: + case ListSourceType_SQLPASSTHROUGH: + impl_ensureRowsetConnection_nothrow(); + _out_rDescriptor.HasPrimaryButton = m_xRowSetConnection.is(); + break; + default: break; + } + } + + bool FormComponentPropertyHandler::impl_dialogListSelection_nothrow( const OUString& _rProperty, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + OSL_PRECOND(m_pInfoService, "FormComponentPropertyHandler::impl_dialogListSelection_" + "nothrow: no property meta data!"); + + OUString sPropertyUIName( m_pInfoService->getPropertyTranslation( m_pInfoService->getPropertyId( _rProperty ) ) ); + ListSelectionDialog aDialog(impl_getDefaultDialogFrame_nothrow(), m_xComponent, _rProperty, sPropertyUIName); + _rClearBeforeDialog.clear(); + return ( RET_OK == aDialog.run() ); + } + + bool FormComponentPropertyHandler::impl_dialogFilterOrSort_nothrow( bool _bFilter, OUString& _out_rSelectedClause, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + OSL_PRECOND( Reference< XRowSet >( m_xComponent, UNO_QUERY ).is(), + "FormComponentPropertyHandler::impl_dialogFilterOrSort_nothrow: to be called for forms only!" ); + + _out_rSelectedClause.clear(); + bool bSuccess = false; + SQLExceptionInfo aErrorInfo; + try + { + if ( !impl_ensureRowsetConnection_nothrow() ) + return false; + + // get a composer for the statement which the form is currently based on + Reference< XSingleSelectQueryComposer > xComposer( ::dbtools::getCurrentSettingsComposer( m_xComponent, m_xContext, nullptr ) ); + OSL_ENSURE( xComposer.is(), "FormComponentPropertyHandler::impl_dialogFilterOrSort_nothrow: could not obtain a composer!" ); + if ( !xComposer.is() ) + return false; + + OUString sPropertyUIName( m_pInfoService->getPropertyTranslation( _bFilter ? PROPERTY_ID_FILTER : PROPERTY_ID_SORT ) ); + + // create the dialog + Reference< XExecutableDialog > xDialog; + if ( _bFilter) + { + xDialog.set( sdb::FilterDialog::createDefault(m_xContext) ); + } + else + { + xDialog.set( sdb::OrderDialog::createDefault(m_xContext) ); + } + + + // initialize the dialog + Reference< XPropertySet > xDialogProps( xDialog, UNO_QUERY_THROW ); + xDialogProps->setPropertyValue("QueryComposer", Any( xComposer ) ); + xDialogProps->setPropertyValue("RowSet", Any( m_xComponent ) ); + if (auto pTopLevel = impl_getDefaultDialogFrame_nothrow()) + xDialogProps->setPropertyValue("ParentWindow", Any(pTopLevel->GetXWindow())); + xDialogProps->setPropertyValue("Title", Any( sPropertyUIName ) ); + + _rClearBeforeDialog.clear(); + bSuccess = ( xDialog->execute() != 0 ); + if ( bSuccess ) + _out_rSelectedClause = _bFilter ? xComposer->getFilter() : xComposer->getOrder(); + } + catch (const SQLContext& e) { aErrorInfo = e; } + catch (const SQLWarning& e) { aErrorInfo = e; } + catch (const SQLException& e) { aErrorInfo = e; } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_dialogFilterOrSort_nothrow" ); + } + + if ( aErrorInfo.isValid() ) + impl_displaySQLError_nothrow( aErrorInfo ); + + return bSuccess; + } + + + bool FormComponentPropertyHandler::impl_dialogLinkedFormFields_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + Reference< XForm > xDetailForm( m_xComponent, UNO_QUERY ); + Reference< XForm > xMasterForm( m_xObjectParent, UNO_QUERY ); + uno::Reference xMasterProp(m_xObjectParent,uno::UNO_QUERY); + OSL_PRECOND( xDetailForm.is() && xMasterForm.is(), "FormComponentPropertyHandler::impl_dialogLinkedFormFields_nothrow: no forms!" ); + if ( !xDetailForm.is() || !xMasterForm.is() ) + return false; + + FormLinkDialog aDialog(impl_getDefaultDialogFrame_nothrow(), m_xComponent, xMasterProp, m_xContext); + _rClearBeforeDialog.clear(); + return ( RET_OK == aDialog.run() ); + } + + bool FormComponentPropertyHandler::impl_dialogFormatting_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + bool bChanged = false; + try + { + // create the itemset for the dialog + SfxItemSet aCoreSet( + SfxGetpApp()->GetPool(), + svl::Items< + SID_ATTR_NUMBERFORMAT_VALUE, SID_ATTR_NUMBERFORMAT_INFO>); + // ripped this somewhere ... don't understand it :( + + // get the number formats supplier + Reference< XNumberFormatsSupplier > xSupplier; + m_xComponent->getPropertyValue( PROPERTY_FORMATSSUPPLIER ) >>= xSupplier; + + DBG_ASSERT(xSupplier.is(), "FormComponentPropertyHandler::impl_dialogFormatting_nothrow: invalid call !" ); + Reference< XUnoTunnel > xTunnel( xSupplier, UNO_QUERY_THROW ); + SvNumberFormatsSupplierObj* pSupplier = + reinterpret_cast< SvNumberFormatsSupplierObj* >( xTunnel->getSomething( SvNumberFormatsSupplierObj::getUnoTunnelId() ) ); + DBG_ASSERT( pSupplier != nullptr, "FormComponentPropertyHandler::impl_dialogFormatting_nothrow: invalid call !" ); + + sal_Int32 nFormatKey = 0; + impl_getPropertyValue_throw( PROPERTY_FORMATKEY ) >>= nFormatKey; + aCoreSet.Put( SfxUInt32Item( SID_ATTR_NUMBERFORMAT_VALUE, nFormatKey ) ); + + SvNumberFormatter* pFormatter = pSupplier->GetNumberFormatter(); + double dPreviewVal = OFormatSampleControl::getPreviewValue(pFormatter,nFormatKey); + SvxNumberInfoItem aFormatter( pFormatter, dPreviewVal, PcrRes(RID_STR_TEXT_FORMAT), SID_ATTR_NUMBERFORMAT_INFO ); + aCoreSet.Put( aFormatter ); + + // a tab dialog with a single page + SfxSingleTabDialogController aDialog(impl_getDefaultDialogFrame_nothrow(), &aCoreSet, + "cui/ui/formatnumberdialog.ui", "FormatNumberDialog"); + SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); + ::CreateTabPage fnCreatePage = pFact->GetTabPageCreatorFunc( RID_SVXPAGE_NUMBERFORMAT ); + if ( !fnCreatePage ) + throw RuntimeException(); // caught below + + aDialog.SetTabPage((*fnCreatePage)(aDialog.get_content_area(), &aDialog, &aCoreSet)); + + _rClearBeforeDialog.clear(); + if ( RET_OK == aDialog.run() ) + { + const SfxItemSet* pResult = aDialog.GetOutputItemSet(); + + if (const SvxNumberInfoItem* pInfoItem = pResult->GetItem( SID_ATTR_NUMBERFORMAT_INFO )) + { + for (sal_uInt32 key : pInfoItem->GetDelFormats()) + pFormatter->DeleteEntry(key); + } + + if ( const SfxUInt32Item* pItem = pResult->GetItemIfSet( SID_ATTR_NUMBERFORMAT_VALUE, false ) ) + { + _out_rNewValue <<= static_cast( pItem->GetValue() ); + bChanged = true; + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_dialogFormatting_nothrow" ); + } + return bChanged; + } + + bool FormComponentPropertyHandler::impl_browseForImage_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + bool bIsLink = true;// reflect the legacy behavior + OUString aStrTrans = m_pInfoService->getPropertyTranslation( PROPERTY_ID_IMAGE_URL ); + + weld::Window* pWin = impl_getDefaultDialogFrame_nothrow(); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW, + FileDialogFlags::Graphic, pWin); + aFileDlg.SetContext(sfx2::FileDialogHelper::FormsInsertImage); + aFileDlg.SetTitle(aStrTrans); + // non-linked images ( e.g. those located in the document + // stream ) only if document is available + bool bHandleNonLink; + { + Reference< XModel > xModel( impl_getContextDocument_nothrow() ); + bHandleNonLink = xModel.is(); + // Not implemented in reports + if (bHandleNonLink) + { + Reference< XReportDefinition > xReportDef( xModel, css::uno::UNO_QUERY ); + bHandleNonLink = !xReportDef.is(); + } + } + + Reference< XFilePickerControlAccess > xController(aFileDlg.GetFilePicker(), UNO_QUERY); + DBG_ASSERT(xController.is(), "FormComponentPropertyHandler::impl_browseForImage_nothrow: missing the controller interface on the file picker!"); + if (xController.is()) + { + // do a preview by default + xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_PREVIEW, 0, css::uno::Any(true)); + + xController->setValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0, css::uno::Any(bIsLink)); + xController->enableControl(ExtendedFilePickerElementIds::CHECKBOX_LINK, bHandleNonLink ); + + } + + OUString sCurValue; + if( ! (impl_getPropertyValue_throw( PROPERTY_IMAGE_URL ) >>= sCurValue) ) + SAL_WARN("extensions.propctrlr", "impl_browseForImage_nothrow: unable to get property " << PROPERTY_IMAGE_URL); + if (!sCurValue.isEmpty()) + { + aFileDlg.SetDisplayDirectory( sCurValue ); + // TODO: need to set the display directory _and_ the default name + } + + _rClearBeforeDialog.clear(); + bool bSuccess = ( ERRCODE_NONE == aFileDlg.Execute() ); + if ( bSuccess ) + { + if ( bHandleNonLink && xController.is() ) + { + xController->getValue(ExtendedFilePickerElementIds::CHECKBOX_LINK, 0) >>= bIsLink; + } + if ( !bIsLink ) + { + Graphic aGraphic; + aFileDlg.GetGraphic(aGraphic); + + Reference< graphic::XGraphicObject > xGrfObj = graphic::GraphicObject::create( m_xContext ); + xGrfObj->setGraphic( aGraphic.GetXGraphic() ); + + _out_rNewValue <<= xGrfObj; + + } + else + _out_rNewValue <<= aFileDlg.GetPath(); + } + return bSuccess; + } + + bool FormComponentPropertyHandler::impl_browseForTargetURL_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + weld::Window* pWin = impl_getDefaultDialogFrame_nothrow(); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, + FileDialogFlags::NONE, pWin); + + OUString sURL; + if( ! (impl_getPropertyValue_throw( PROPERTY_TARGET_URL ) >>= sURL) ) + SAL_WARN("extensions.propctrlr", "impl_browseForTargetURL_nothrow: unable to get property " << PROPERTY_TARGET_URL); + INetURLObject aParser( sURL ); + if ( INetProtocol::File == aParser.GetProtocol() ) + // set the initial directory only for file-URLs. Everything else + // is considered to be potentially expensive + aFileDlg.SetDisplayDirectory( sURL ); + + _rClearBeforeDialog.clear(); + bool bSuccess = ( ERRCODE_NONE == aFileDlg.Execute() ); + if ( bSuccess ) + _out_rNewValue <<= aFileDlg.GetPath(); + return bSuccess; + } + + bool FormComponentPropertyHandler::impl_executeFontDialog_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + bool bSuccess = false; + + // create an item set for use with the dialog + std::unique_ptr pSet; + rtl::Reference pPool; + std::vector* pDefaults = nullptr; + ControlCharacterDialog::createItemSet(pSet, pPool, pDefaults); + ControlCharacterDialog::translatePropertiesToItems(m_xComponent, pSet.get()); + + { // do this in an own block. The dialog needs to be destroyed before we call + // destroyItemSet + ControlCharacterDialog aDlg(impl_getDefaultDialogFrame_nothrow(), *pSet); + _rClearBeforeDialog.clear(); + if (RET_OK == aDlg.run()) + { + const SfxItemSet* pOut = aDlg.GetOutputItemSet(); + if ( pOut ) + { + std::vector< NamedValue > aFontPropertyValues; + ControlCharacterDialog::translateItemsToProperties( *pOut, aFontPropertyValues ); + _out_rNewValue <<= comphelper::containerToSequence(aFontPropertyValues); + bSuccess = true; + } + } + } + + ControlCharacterDialog::destroyItemSet(pSet, pPool, pDefaults); + return bSuccess; + } + + + bool FormComponentPropertyHandler::impl_browseForDatabaseDocument_throw( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + weld::Window* pWin = impl_getDefaultDialogFrame_nothrow(); + ::sfx2::FileDialogHelper aFileDlg( + ui::dialogs::TemplateDescription::FILEOPEN_READONLY_VERSION, FileDialogFlags::NONE, + "sdatabase", SfxFilterFlags::NONE, SfxFilterFlags::NONE, pWin); + + OUString sDataSource; + if( ! (impl_getPropertyValue_throw( PROPERTY_DATASOURCE ) >>= sDataSource) ) + SAL_WARN("extensions.propctrlr", "impl_browseForDatabaseDocument_throw: unable to get property " << PROPERTY_DATASOURCE); + INetURLObject aParser( sDataSource ); + if ( INetProtocol::File == aParser.GetProtocol() ) + // set the initial directory only for file-URLs. Everything else + // is considered to be potentially expensive + aFileDlg.SetDisplayDirectory( sDataSource ); + + std::shared_ptr pFilter = SfxFilter::GetFilterByName("StarOffice XML (Base)"); + OSL_ENSURE(pFilter,"Filter: StarOffice XML (Base) could not be found!"); + if ( pFilter ) + { + aFileDlg.SetCurrentFilter(pFilter->GetUIName()); + //aFileDlg.AddFilter(pFilter->GetFilterName(),pFilter->GetDefaultExtension()); + } + + _rClearBeforeDialog.clear(); + bool bSuccess = ( ERRCODE_NONE == aFileDlg.Execute() ); + if ( bSuccess ) + _out_rNewValue <<= aFileDlg.GetPath(); + return bSuccess; + } + + bool FormComponentPropertyHandler::impl_dialogColorChooser_throw( sal_Int32 _nColorPropertyId, Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + ::Color aColor; + if( ! (impl_getPropertyValue_throw( impl_getPropertyNameFromId_nothrow( _nColorPropertyId )) >>= aColor) ) + SAL_WARN("extensions.propctrlr", "impl_dialogColorChooser_throw: unable to get property " << _nColorPropertyId); + SvColorDialog aColorDlg; + aColorDlg.SetColor( aColor ); + + _rClearBeforeDialog.clear(); + weld::Window* pParent = impl_getDefaultDialogFrame_nothrow(); + if (!aColorDlg.Execute(pParent)) + return false; + + _out_rNewValue <<= aColorDlg.GetColor(); + return true; + } + + bool FormComponentPropertyHandler::impl_dialogChooseLabelControl_nothrow( Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + weld::Window* pParent = impl_getDefaultDialogFrame_nothrow(); + OSelectLabelDialog dlgSelectLabel(pParent, m_xComponent); + _rClearBeforeDialog.clear(); + bool bSuccess = (RET_OK == dlgSelectLabel.run()); + if ( bSuccess ) + _out_rNewValue <<= dlgSelectLabel.GetSelected(); + return bSuccess; + } + + + Reference< XControlContainer > FormComponentPropertyHandler::impl_getContextControlContainer_nothrow() const + { + Reference< XControlContainer > xControlContext; + Any any = m_xContext->getValueByName( "ControlContext" ); + any >>= xControlContext; + return xControlContext; + } + + + bool FormComponentPropertyHandler::impl_dialogChangeTabOrder_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const + { + OSL_PRECOND( impl_getContextControlContainer_nothrow().is(), "FormComponentPropertyHandler::impl_dialogChangeTabOrder_nothrow: invalid control context!" ); + + Reference< XTabControllerModel > xTabControllerModel( impl_getRowSet_nothrow(), UNO_QUERY ); + TabOrderDialog aDialog(impl_getDefaultDialogFrame_nothrow(), xTabControllerModel, + impl_getContextControlContainer_nothrow(), m_xContext); + _rClearBeforeDialog.clear(); + return RET_OK == aDialog.run(); + } + + namespace + { + + //- ISQLCommandPropertyUI + + class ISQLCommandPropertyUI : public ISQLCommandAdapter + { + public: + /** returns the empty-string-terminated list of names of properties + whose UI is to be disabled while the SQL command property is + being edited. + */ + virtual OUString* getPropertiesToDisable() = 0; + }; + + + //- SQLCommandPropertyUI + + class SQLCommandPropertyUI : public ISQLCommandPropertyUI + { + protected: + explicit SQLCommandPropertyUI( const Reference< XPropertySet >& _rxObject ) + : m_xObject(_rxObject) + { + if ( !m_xObject.is() ) + throw NullPointerException(); + } + + protected: + Reference< XPropertySet > m_xObject; + }; + + + //- FormSQLCommandUI - declaration + + class FormSQLCommandUI : public SQLCommandPropertyUI + { + public: + explicit FormSQLCommandUI( const Reference< XPropertySet >& _rxForm ); + + // ISQLCommandAdapter + virtual OUString getSQLCommand() const override; + virtual bool getEscapeProcessing() const override; + virtual void setSQLCommand( const OUString& _rCommand ) const override; + virtual void setEscapeProcessing( const bool _bEscapeProcessing ) const override; + + // ISQLCommandPropertyUI + virtual OUString* getPropertiesToDisable() override; + }; + + + //- FormSQLCommandUI - implementation + + + FormSQLCommandUI::FormSQLCommandUI( const Reference< XPropertySet >& _rxForm ) + :SQLCommandPropertyUI( _rxForm ) + { + } + + + OUString FormSQLCommandUI::getSQLCommand() const + { + OUString sCommand; + if( ! (m_xObject->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand) ) + SAL_WARN("extensions.propctrlr", "getSQLCommand: unable to get property " << PROPERTY_COMMAND); + return sCommand; + } + + + bool FormSQLCommandUI::getEscapeProcessing() const + { + bool bEscapeProcessing( false ); + if( ! (m_xObject->getPropertyValue( PROPERTY_ESCAPE_PROCESSING ) >>= bEscapeProcessing) ) + SAL_WARN("extensions.propctrlr", "getSQLCommand: unable to get property " << PROPERTY_ESCAPE_PROCESSING); + return bEscapeProcessing; + } + + + void FormSQLCommandUI::setSQLCommand( const OUString& _rCommand ) const + { + m_xObject->setPropertyValue( PROPERTY_COMMAND, Any( _rCommand ) ); + } + + + void FormSQLCommandUI::setEscapeProcessing( const bool _bEscapeProcessing ) const + { + m_xObject->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, Any( _bEscapeProcessing ) ); + } + + + OUString* FormSQLCommandUI::getPropertiesToDisable() + { + static OUString s_aCommandProps[] = { + OUString(PROPERTY_DATASOURCE), + OUString(PROPERTY_COMMAND), + OUString(PROPERTY_COMMANDTYPE), + OUString(PROPERTY_ESCAPE_PROCESSING), + OUString() + }; + return s_aCommandProps; + } + + //- ValueListCommandUI - declaration + + class ValueListCommandUI : public SQLCommandPropertyUI + { + public: + explicit ValueListCommandUI( const Reference< XPropertySet >& _rxListOrCombo ); + + // ISQLCommandAdapter + virtual OUString getSQLCommand() const override; + virtual bool getEscapeProcessing() const override; + virtual void setSQLCommand( const OUString& _rCommand ) const override; + virtual void setEscapeProcessing( const bool _bEscapeProcessing ) const override; + + // ISQLCommandPropertyUI + virtual OUString* getPropertiesToDisable() override; + private: + mutable bool m_bPropertyValueIsList; + }; + + + //- ValueListCommandUI - implementation + + + ValueListCommandUI::ValueListCommandUI( const Reference< XPropertySet >& _rxListOrCombo ) + :SQLCommandPropertyUI( _rxListOrCombo ) + ,m_bPropertyValueIsList( false ) + { + } + + + OUString ValueListCommandUI::getSQLCommand() const + { + OUString sValue; + m_bPropertyValueIsList = false; + + // for combo boxes, the property is a mere string + Any aValue( m_xObject->getPropertyValue( PROPERTY_LISTSOURCE ) ); + if ( aValue >>= sValue ) + return sValue; + + Sequence< OUString > aValueList; + if ( aValue >>= aValueList ) + { + m_bPropertyValueIsList = true; + if ( aValueList.hasElements() ) + sValue = aValueList[0]; + return sValue; + } + + OSL_FAIL( "ValueListCommandUI::getSQLCommand: unexpected property type!" ); + return sValue; + } + + + bool ValueListCommandUI::getEscapeProcessing() const + { + ListSourceType eType = ListSourceType_SQL; + if( ! (m_xObject->getPropertyValue( PROPERTY_LISTSOURCETYPE ) >>= eType) ) + SAL_WARN("extensions.propctrlr", "getEscapeProcessing: unable to get property " << PROPERTY_LISTSOURCETYPE); + OSL_ENSURE( ( eType == ListSourceType_SQL ) || ( eType == ListSourceType_SQLPASSTHROUGH ), + "ValueListCommandUI::getEscapeProcessing: unexpected list source type!" ); + return ( eType == ListSourceType_SQL ); + } + + + void ValueListCommandUI::setSQLCommand( const OUString& _rCommand ) const + { + Any aValue; + if ( m_bPropertyValueIsList ) + aValue <<= Sequence< OUString >( &_rCommand, 1 ); + else + aValue <<= _rCommand; + m_xObject->setPropertyValue( PROPERTY_LISTSOURCE, aValue ); + } + + + void ValueListCommandUI::setEscapeProcessing( const bool _bEscapeProcessing ) const + { + m_xObject->setPropertyValue( PROPERTY_LISTSOURCETYPE, Any( + _bEscapeProcessing ? ListSourceType_SQL : ListSourceType_SQLPASSTHROUGH ) ); + } + + + OUString* ValueListCommandUI::getPropertiesToDisable() + { + static OUString s_aListSourceProps[] = { + OUString(PROPERTY_LISTSOURCETYPE), + OUString(PROPERTY_LISTSOURCE), + OUString() + }; + return s_aListSourceProps; + } + } + + + bool FormComponentPropertyHandler::impl_doDesignSQLCommand_nothrow( const Reference< XObjectInspectorUI >& _rxInspectorUI, PropertyId _nDesignForProperty ) + { + try + { + if ( m_xCommandDesigner.is() ) + { + if ( m_xCommandDesigner->isActive() ) + { + m_xCommandDesigner->raise(); + return true; + } + m_xCommandDesigner->dispose(); + m_xCommandDesigner.set( nullptr ); + } + + if ( !impl_ensureRowsetConnection_nothrow() ) + return false; + + Reference< XPropertySet > xComponentProperties( m_xComponent, UNO_SET_THROW ); + + ::rtl::Reference< ISQLCommandPropertyUI > xCommandUI; + switch ( _nDesignForProperty ) + { + case PROPERTY_ID_COMMAND: + xCommandUI = new FormSQLCommandUI( xComponentProperties ); + break; + case PROPERTY_ID_LISTSOURCE: + xCommandUI = new ValueListCommandUI( xComponentProperties ); + break; + default: + OSL_FAIL( "FormComponentPropertyHandler::OnDesignerClosed: invalid property id!" ); + return false; + } + + m_xCommandDesigner.set( new SQLCommandDesigner( m_xContext, xCommandUI, m_xRowSetConnection, LINK( this, FormComponentPropertyHandler, OnDesignerClosed ) ) ); + + DBG_ASSERT( _rxInspectorUI.is(), "FormComponentPropertyHandler::OnDesignerClosed: no access to the property browser ui!" ); + if ( m_xCommandDesigner->isActive() && _rxInspectorUI.is() ) + { + m_xBrowserUI = _rxInspectorUI; + // disable everything which would affect this property + const OUString* pToDisable = xCommandUI->getPropertiesToDisable(); + while ( !pToDisable->isEmpty() ) + { + m_xBrowserUI->enablePropertyUIElements( *pToDisable++, PropertyLineElement::All, false ); + } + + // but enable the browse button for the property itself - so it can be used to raise the query designer + OUString sPropertyName( impl_getPropertyNameFromId_nothrow( _nDesignForProperty ) ); + m_xBrowserUI->enablePropertyUIElements( sPropertyName, PropertyLineElement::PrimaryButton, true ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return m_xCommandDesigner.is(); + } + + + IMPL_LINK_NOARG( FormComponentPropertyHandler, OnDesignerClosed, SQLCommandDesigner&, void ) + { + OSL_ENSURE( m_xBrowserUI.is() && m_xCommandDesigner.is(), "FormComponentPropertyHandler::OnDesignerClosed: too many NULLs!" ); + if ( !(m_xBrowserUI.is() && m_xCommandDesigner.is()) ) + return; + + try + { + ::rtl::Reference< ISQLCommandPropertyUI > xCommandUI( + dynamic_cast< ISQLCommandPropertyUI* >( m_xCommandDesigner->getPropertyAdapter().get() ) ); + if ( !xCommandUI.is() ) + throw NullPointerException(); + + const OUString* pToEnable = xCommandUI->getPropertiesToDisable(); + while ( !pToEnable->isEmpty() ) + { + m_xBrowserUI->enablePropertyUIElements( *pToEnable++, PropertyLineElement::All, true ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + bool FormComponentPropertyHandler::impl_hasValidDataSourceSignature_nothrow( const Reference< XPropertySet >& _xFormProperties, bool _bAllowEmptyDataSourceName ) + { + bool bHas = false; + if ( _xFormProperties.is() ) + { + try + { + OUString sPropertyValue; + // first, we need the name of an existent data source + if ( _xFormProperties->getPropertySetInfo()->hasPropertyByName(PROPERTY_DATASOURCE) ) + _xFormProperties->getPropertyValue( PROPERTY_DATASOURCE ) >>= sPropertyValue; + bHas = ( !sPropertyValue.isEmpty() ) || _bAllowEmptyDataSourceName; + + // then, the command should not be empty + if ( bHas ) + { + if ( _xFormProperties->getPropertySetInfo()->hasPropertyByName(PROPERTY_COMMAND) ) + _xFormProperties->getPropertyValue( PROPERTY_COMMAND ) >>= sPropertyValue; + bHas = !sPropertyValue.isEmpty(); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormComponentPropertyHandler::impl_hasValidDataSourceSignature_nothrow" ); + } + } + return bHas; + } + + OUString FormComponentPropertyHandler::impl_getDocumentURL_nothrow() const + { + OUString sURL; + try + { + Reference< XModel > xDocument( impl_getContextDocument_nothrow() ); + if ( xDocument.is() ) + sURL = xDocument->getURL(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return sURL; + } + + ::cppu::IPropertyArrayHelper* FormComponentPropertyHandler::createArrayHelper( ) const + { + uno::Sequence< beans::Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); + + } + + ::cppu::IPropertyArrayHelper & FormComponentPropertyHandler::getInfoHelper() + { + return *getArrayHelper(); + } + + uno::Reference< beans::XPropertySetInfo > SAL_CALL FormComponentPropertyHandler::getPropertySetInfo( ) + { + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_FormComponentPropertyHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::FormComponentPropertyHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formcomponenthandler.hxx b/extensions/source/propctrlr/formcomponenthandler.hxx new file mode 100644 index 000000000..bc7367abb --- /dev/null +++ b/extensions/source/propctrlr/formcomponenthandler.hxx @@ -0,0 +1,435 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in 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 "propertyhandler.hxx" +#include "sqlcommanddesign.hxx" +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace pcr +{ + + + //= ComponentClassification + + enum ComponentClassification + { + eFormControl, + eDialogControl, + eUnknown + }; + + + //= FormComponentPropertyHandler + + class FormComponentPropertyHandler; + typedef ::comphelper::OPropertyArrayUsageHelper FormComponentPropertyHandler_PROP; + /** default ->XPropertyHandler for all form components. + */ + class FormComponentPropertyHandler : public PropertyHandlerComponent, + public ::comphelper::OPropertyContainer, + public FormComponentPropertyHandler_PROP + { + private: + /// access to property states + css::uno::Reference< css::beans::XPropertyState > m_xPropertyState; + /// the parent of our component + css::uno::Reference< css::uno::XInterface > m_xObjectParent; + + /// the database connection. Owned by us if and only if we created it ourself. + mutable ::dbtools::SharedConnection m_xRowSetConnection; + css::uno::Reference< css::sdbc::XRowSet > m_xRowSet; + /** helper component encapsulating the handling for the QueryDesign component for + interactively designing an SQL command + */ + ::rtl::Reference< SQLCommandDesigner > m_xCommandDesigner; + css::uno::Reference< css::inspection::XObjectInspectorUI > m_xBrowserUI; + + /// the string indicating a "default" (VOID) value in list-like controls + OUString m_sDefaultValueString; + /// all properties to whose control's we added ->m_sDefaultValueString + std::set< OUString > m_aPropertiesWithDefListEntry; + /// type of our component + ComponentClassification m_eComponentClass; + /// is our component a (database) sub form? + bool m_bComponentIsSubForm : 1; + /// our component has a "ListSource" property + bool m_bHaveListSource : 1; + /// our component has a "Command" property + bool m_bHaveCommand : 1; + /// the class id of the component - if applicable + sal_Int16 m_nClassId; + + public: + explicit FormComponentPropertyHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + DECLARE_XINTERFACE( ) + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + protected: + virtual ~FormComponentPropertyHandler() override; + + protected: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override; + + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + // XPropertyHandler overridables + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override; + virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override; + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupersededProperties() override; + virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties() override; + virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + virtual css::inspection::InteractiveSelectionResult + SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override; + virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override; + + // XComponent + virtual void SAL_CALL disposing() override; + + // PropertyHandler + virtual css::uno::Sequence< css::beans::Property > + doDescribeSupportedProperties() const override; + virtual void onNewComponent() override; + + private: + /** classifies our component, in case it's a control model, by ClassId + + Note that UNO dialog controls are also classified, though they don't have the ClassId property + */ + void impl_classifyControlModel_throw(); + + bool isReportModel() const; + + /** const-version of ->getPropertyValue + */ + css::uno::Any impl_getPropertyValue_throw( const OUString& _rPropertyName ) const; + + // some property values are faked, and not used in the way they're provided by our component + void impl_normalizePropertyValue_nothrow( css::uno::Any& _rValue, PropertyId _nPropId ) const; + + /** determines whether we should exclude a given property from our "supported properties" + */ + bool impl_shouldExcludeProperty_nothrow( const css::beans::Property& _rProperty ) const; + + /** initializes the list of field names, if we're handling a control which supports the + DataField property + */ + void impl_initFieldList_nothrow( std::vector< OUString >& rFieldNames ) const; + + /** obtains the RowSet to which our component belongs + + If the component is a RowSet itself, it's returned directly. Else, the parent + is examined for the XRowSet interface. If the parent is no XRowSet, then + a check is made whether our component is a grid control column, and if so, + the parent of the grid control is examined for the XRowSet interface. + + Normally, at least one of those methods should succeed. + */ + css::uno::Reference< css::sdbc::XRowSet > impl_getRowSet_throw( ) const; + + /** nothrow-version of ->impl_getRowSet_throw + */ + css::uno::Reference< css::sdbc::XRowSet > impl_getRowSet_nothrow( ) const; + + /** connects the row set belonging to our introspected data aware form component, + and remembers the connection in ->m_xRowSetConnection. + + If the row set already is connected, ->m_xRowSetConnection will be set, too, but + not take the ownership of the connection. + + If ->m_xRowSetConnection is already set, nothing happens, so if you want to + force creation of a connection, you need to clear ->m_xRowSetConnection. + */ + bool impl_ensureRowsetConnection_nothrow() const; + + /** fills an ->LineDescriptor with information to represent a cursor source + of our form - that is, a table, a query, or an SQL statement. + + As an example, if our form has currently a CommandType of TABLE, then the + value list in the LineDescriptor will contain a list of all tables + of the data source which the form is bound to. + + @seealso impl_fillTableNames_throw + @seealso impl_fillQueryNames_throw + */ + void impl_describeCursorSource_nothrow( + css::inspection::LineDescriptor& _out_rProperty, + const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory + ) const; + + /** describes the UI for selecting a table name + + @precond + m_xRowSetConnection is not + */ + void impl_fillTableNames_throw( std::vector< OUString >& _out_rNames ) const; + + /** describes the UI for selecting a query name + + @precond + m_xRowSetConnection is not + */ + void impl_fillQueryNames_throw( std::vector< OUString >& _out_rNames ) const; + + /** describes the UI for selecting a query name + + @precond + m_xRowSetConnection is not + */ + void impl_fillQueryNames_throw( const css::uno::Reference< css::container::XNameAccess >& _xQueryNames + ,std::vector< OUString >& _out_rNames + ,std::u16string_view _sName = std::u16string_view() ) const; + + /** describes the UI for selecting a ListSource (for list-like form controls) + @precond + ->m_xRowSetConnection is not + @precond + ->m_xComponent is not + */ + void impl_describeListSourceUI_throw( + css::inspection::LineDescriptor& _out_rDescriptor, + const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory + ) const; + + /** displays a database-related error to the user + */ + void impl_displaySQLError_nothrow( const ::dbtools::SQLExceptionInfo& _rErrorDescriptor ) const; + + /** let's the user chose a selection of entries from a string list, and stores this + selection in the given property + @return + if and only if the user successfully changed the property + */ + bool impl_dialogListSelection_nothrow( const OUString& _rProperty, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** executes a dialog for choosing a filter or sort criterion for a database form + @param _bFilter + if the Filter property should be used, if it's the Order + property + @param _out_rSelectedClause + the filter or order clause as chosen by the user + @precond + we're really inspecting a database form (well, a RowSet at least) + @return + if and only if the user successfully chose a clause + */ + bool impl_dialogFilterOrSort_nothrow( bool _bFilter, OUString& _out_rSelectedClause, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** executes a dialog which allows the user to choose the columns linking + a sub to a master form, and sets the respective MasterFields / SlaveFields + properties at the form. + @precond + we're inspecting (sub) database form + @return + if and only if the user successfully enter master and slave fields + */ + bool impl_dialogLinkedFormFields_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** executes a dialog which allows the user to modify the FormatKey + property of our component, by choosing a (number) format. + @precond + Our component actually has a FormatKey property. + @param _out_rNewValue + the new property value, if the user chose a new formatting + @return + if and only if a new formatting has been chosen by the user. + In this case, ->_out_rNewValue is filled with the new property value + */ + bool impl_dialogFormatting_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** executes a dialog which allows to the user to change the ImageURL property + of our component by browsing for an image file. + @precond + our component actually has an ImageURL property + @param _out_rNewValue + the new property value, if the user chose a new image url + @return + if and only if a new image URL has been chosen by the user. + In this case, ->_out_rNewValue is filled with the new property value + */ + bool impl_browseForImage_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** executes a dialog which allows the user to change the TargetURL property of + our component + @precond + our component actually has a TargetURL property + @param _out_rNewValue + the new property value, if the user chose a new TargetURL + @return + if and only if a new TargetURL has been chosen by the user. + In this case, ->_out_rNewValue is filled with the new property value + */ + bool impl_browseForTargetURL_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** executes a dialog which allows the user to change the font, plus related properties, + of our component + @precond + our component actually has a Font property + @param _out_rNewValue + a value describing the new font, as Sequence< NamedValue > + @return + if and only if the user successfully changed the font of our component + */ + bool impl_executeFontDialog_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** allows the user browsing for a database document + @precond + our component actually has a DataSource property + @param _out_rNewValue + the new property value, if the user chose a new DataSource + @return + if and only if a new DataSource has been chosen by the user. + In this case, ->_out_rNewValue is filled with the new property value + */ + bool impl_browseForDatabaseDocument_throw( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** raises a dialog which allows the user to choose a color + @param _nColorPropertyId + the ID of the color property + @param _out_rNewValue + the chosen color value + @return + if and only if a color was chosen by the user + */ + bool impl_dialogColorChooser_throw( sal_Int32 _nColorPropertyId, css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** raises a dialog which allows the user to choose a label control for our component + @param _out_rNewValue + the chosen label control, if any + @return + if and only if a label control was chosen by the user + */ + bool impl_dialogChooseLabelControl_nothrow( css::uno::Any& _out_rNewValue, ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** raises a dialog which lets the user chose the tab order of controls of a form + @precond + we have a view control container in which our controls live + @return + if and only if the user successfully changed the tab order + @seealso impl_getContextControlContainer_nothrow + */ + bool impl_dialogChangeTabOrder_nothrow( ::osl::ClearableMutexGuard& _rClearBeforeDialog ) const; + + /** retrieves the context for controls, whose model(s) we're inspecting + + If we're inspecting a control model, this is usually part of a set of controls + and control models, where the controls live in a certain context (a ->XControlContainer). + If we know this context, we can enable additional special functionality. + + The ->XComponentContext in which we were created is examined for a value + named "ControlContext", and this value is returned. + */ + css::uno::Reference< css::awt::XControlContainer > + impl_getContextControlContainer_nothrow() const; + + /** opens a query design window for interactively designing the SQL command of a + database form + @param _rxUIUpdate + access to the property browser UI + @param _nDesignForProperty + the ID for the property for which the designer is opened + @return + if the window was successfully opened, or was previously open, + otherwise + */ + bool impl_doDesignSQLCommand_nothrow( + const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, + PropertyId _nDesignForProperty + ); + + /** updates a property (UI) whose state depends on more than one other property + + ->actuatingPropertyChanged is called for certain properties in whose changes + we expressed interes (->getActuatingProperty). Now such a property change can + result in simple UI updates, for instance another property being enabled or disabled. + + However, it can also result in a more complex change: The current (UI) state might + depend on the value of more than one other property. Those dependent properties (their + UI, more precisely) are updated in this method. + + @param _nPropid + the ->PropertyId of the dependent property whose UI state is to be updated + + @param _rxInspectorUI + provides access to the property browser UI. Must not be . + */ + void impl_updateDependentProperty_nothrow( PropertyId _nPropId, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) const; + + /** determines whether the given form has a valid data source signature. + + Valid here means that the DataSource property denotes an existing data source, and the + Command property is not empty. No check is made whether the value of the Command property + denotes an existent object, since this would be way too expensive. + + @param _xFormProperties + the form to check. Must not be . + @param _bAllowEmptyDataSourceName + determine whether an empty data source name is allowed (), and should not + lead to rejection + */ + static bool impl_hasValidDataSourceSignature_nothrow( + const css::uno::Reference< css::beans::XPropertySet >& _xFormProperties, + bool _bAllowEmptyDataSourceName ); + + /** returns the URL of our context document + @return + */ + OUString impl_getDocumentURL_nothrow() const; + + private: + DECL_LINK( OnDesignerClosed, SQLCommandDesigner&, void ); + + private: + FormComponentPropertyHandler( const FormComponentPropertyHandler& ) = delete; + FormComponentPropertyHandler& operator=( const FormComponentPropertyHandler& ) = delete; + + private: + using ::comphelper::OPropertyContainer::addPropertyChangeListener; + using ::comphelper::OPropertyContainer::removePropertyChangeListener; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formcontroller.cxx b/extensions/source/propctrlr/formcontroller.cxx new file mode 100644 index 000000000..6e94aa0d1 --- /dev/null +++ b/extensions/source/propctrlr/formcontroller.cxx @@ -0,0 +1,241 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "formcontroller.hxx" +#include "pcrcommon.hxx" +#include "formstrings.hxx" +#include "defaultforminspection.hxx" + +#include +#include +#include + + +namespace pcr +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::TypeClass_INTERFACE; + using ::com::sun::star::uno::TypeClass_STRING; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::inspection::XObjectInspectorModel; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::beans::Property; + using ::com::sun::star::uno::Any; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::uno::Type; + using ::com::sun::star::util::VetoException; + using ::com::sun::star::beans::PropertyVetoException; + using ::com::sun::star::uno::UNO_QUERY; + + namespace PropertyAttribute = css::beans::PropertyAttribute; + + + //= FormController + + + FormController::FormController( const Reference< XComponentContext >& _rxContext, + const OUString& sImplementationName, + const css::uno::Sequence& aSupportedServiceNames, + bool _bUseFormFormComponentHandlers ) + :OPropertyBrowserController( _rxContext ) + ,FormController_PropertyBase1( m_aBHelper ) + ,m_sImplementationName( sImplementationName ) + ,m_aSupportedServiceNames( aSupportedServiceNames ) + { + osl_atomic_increment( &m_refCount ); + { + Reference< XObjectInspectorModel > xModel( + *(new DefaultFormComponentInspectorModel( _bUseFormFormComponentHandlers )), + UNO_QUERY_THROW + ); + setInspectorModel( xModel ); + } + osl_atomic_decrement( &m_refCount ); + } + + + FormController::~FormController() + { + } + + + IMPLEMENT_FORWARD_XINTERFACE2( FormController, OPropertyBrowserController, FormController_PropertyBase1 ) + + + Sequence< Type > SAL_CALL FormController::getTypes( ) + { + ::cppu::OTypeCollection aTypes( + cppu::UnoType::get(), + cppu::UnoType::get(), + cppu::UnoType::get(), + OPropertyBrowserController::getTypes()); + return aTypes.getTypes(); + } + + + IMPLEMENT_GET_IMPLEMENTATION_ID( FormController ) + + + OUString SAL_CALL FormController::getImplementationName( ) + { + return m_sImplementationName; + } + + + Sequence< OUString > SAL_CALL FormController::getSupportedServiceNames( ) + { + Sequence< OUString > aSupported( m_aSupportedServiceNames ); + aSupported.realloc( aSupported.getLength() + 1 ); + aSupported.getArray()[ aSupported.getLength() - 1 ] = "com.sun.star.inspection.ObjectInspector"; + return aSupported; + } + + + Reference< XPropertySetInfo > SAL_CALL FormController::getPropertySetInfo( ) + { + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); + } + + + ::cppu::IPropertyArrayHelper& SAL_CALL FormController::getInfoHelper() + { + return *getArrayHelper(); + } + + + ::cppu::IPropertyArrayHelper* FormController::createArrayHelper( ) const + { + Sequence< Property > aProps{ + Property( + PROPERTY_CURRENTPAGE, + OWN_PROPERTY_ID_CURRENTPAGE, + ::cppu::UnoType::get(), + PropertyAttribute::TRANSIENT + ), + Property( + PROPERTY_INTROSPECTEDOBJECT, + OWN_PROPERTY_ID_INTROSPECTEDOBJECT, + cppu::UnoType::get(), + PropertyAttribute::TRANSIENT | PropertyAttribute::CONSTRAINED + ) + }; + return new ::cppu::OPropertyArrayHelper( aProps ); + } + + + sal_Bool SAL_CALL FormController::convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) + { + switch ( nHandle ) + { + case OWN_PROPERTY_ID_INTROSPECTEDOBJECT: + if ( rValue.getValueTypeClass() != TypeClass_INTERFACE ) + throw IllegalArgumentException(); + break; + case OWN_PROPERTY_ID_CURRENTPAGE: + if ( rValue.getValueTypeClass() != TypeClass_STRING ) + throw IllegalArgumentException(); + break; + } + + getFastPropertyValue( rOldValue, nHandle ); + rConvertedValue = rValue; + return true; + } + + + void SAL_CALL FormController::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue) + { + switch ( _nHandle ) + { + case OWN_PROPERTY_ID_INTROSPECTEDOBJECT: + { + Reference< XObjectInspectorModel > xModel( getInspectorModel() ); + if ( xModel.is() ) + { + try + { + m_xCurrentInspectee.set( _rValue, UNO_QUERY ); + Sequence< Reference< XInterface > > aObjects; + if ( m_xCurrentInspectee.is() ) + { + aObjects = { m_xCurrentInspectee }; + } + + Reference< XObjectInspector > xInspector( *this, UNO_QUERY_THROW ); + xInspector->inspect( aObjects ); + } + catch( const VetoException& e ) + { + throw PropertyVetoException( e.Message, e.Context ); + } + } + } + break; + case OWN_PROPERTY_ID_CURRENTPAGE: + restoreViewData( _rValue ); + break; + } + } + + + void SAL_CALL FormController::getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const + { + switch ( nHandle ) + { + case OWN_PROPERTY_ID_INTROSPECTEDOBJECT: + rValue <<= m_xCurrentInspectee; + break; + + case OWN_PROPERTY_ID_CURRENTPAGE: + rValue = const_cast< FormController* >( this )->getViewData(); + break; + } + } + + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_FormController_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::FormController( context, + "org.openoffice.comp.extensions.FormController", + { "com.sun.star.form.PropertyBrowserController" }, + true ) ); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_DialogController_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::FormController( context, + "org.openoffice.comp.extensions.DialogController", + { "com.sun.star.awt.PropertyBrowserController" }, + false ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formcontroller.hxx b/extensions/source/propctrlr/formcontroller.hxx new file mode 100644 index 000000000..8c285160e --- /dev/null +++ b/extensions/source/propctrlr/formcontroller.hxx @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "propcontroller.hxx" + +#include +#include +#include + + +namespace pcr +{ + + + //= FormController + + class FormController; + typedef ::cppu::OPropertySetHelper FormController_PropertyBase1; + typedef ::comphelper::OPropertyArrayUsageHelper< FormController > FormController_PropertyBase2; + + /** Legacy implementation of com.sun.star.form.PropertyBrowserController + + Nowadays only a wrapper around an ObjectInspector using a + DefaultFormComponentInspectorModel. + */ + class FormController :public OPropertyBrowserController + ,public FormController_PropertyBase1 + ,public FormController_PropertyBase2 + { + private: + css::uno::Reference< css::beans::XPropertySet > + m_xCurrentInspectee; + OUString m_sImplementationName; + css::uno::Sequence m_aSupportedServiceNames; + public: + FormController( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const OUString& sImplementName, + const css::uno::Sequence& aSupportedServiceNames, + bool _bUseFormFormComponentHandlers + ); + + protected: + virtual ~FormController() override; + + DECLARE_XINTERFACE() + DECLARE_XTYPEPROVIDER() + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + // XPropertySet and friends + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + virtual 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; + private: + using FormController_PropertyBase1::getFastPropertyValue; + }; + + + //= DialogController + + /** Legacy implementation of com.sun.star.awt.PropertyBrowserController + */ + class DialogController + { + private: + DialogController( const DialogController& ) = delete; + DialogController& operator=( const DialogController& ) = delete; + }; + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formgeometryhandler.cxx b/extensions/source/propctrlr/formgeometryhandler.cxx new file mode 100644 index 000000000..26c432405 --- /dev/null +++ b/extensions/source/propctrlr/formgeometryhandler.cxx @@ -0,0 +1,820 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "propertyhandler.hxx" +#include "formmetadata.hxx" +#include "formstrings.hxx" +#include "handlerhelper.hxx" +#include "cellbindinghelper.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace pcr +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::beans::Property; + using ::com::sun::star::awt::XControlModel; + using ::com::sun::star::drawing::XControlShape; + using ::com::sun::star::container::XMap; + using ::com::sun::star::inspection::LineDescriptor; + using ::com::sun::star::inspection::XPropertyControlFactory; + using ::com::sun::star::lang::NullPointerException; + using ::com::sun::star::beans::Optional; + using ::com::sun::star::inspection::XNumericControl; + using ::com::sun::star::drawing::XShape; + using ::com::sun::star::beans::PropertyChangeEvent; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::beans::XPropertyChangeListener; + using ::com::sun::star::text::TextContentAnchorType; + using ::com::sun::star::text::TextContentAnchorType_AT_PARAGRAPH; + using ::com::sun::star::text::TextContentAnchorType_AS_CHARACTER; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::inspection::XObjectInspectorUI; + using ::com::sun::star::lang::XServiceInfo; + using ::com::sun::star::sheet::XSpreadsheet; + using ::com::sun::star::table::XColumnRowRange; + using ::com::sun::star::table::XTableColumns; + using ::com::sun::star::table::XTableRows; + using ::com::sun::star::container::XIndexAccess; + using ::com::sun::star::container::XChild; + using ::com::sun::star::form::XGridColumnFactory; + + namespace MeasureUnit = css::util::MeasureUnit; + + #define ANCHOR_TO_SHEET 0 + #define ANCHOR_TO_CELL 1 + + + //= BroadcastHelperBase + + namespace { + + class BroadcastHelperBase + { + protected: + explicit BroadcastHelperBase( ::osl::Mutex& _rMutex ) + :maBHelper( _rMutex ) + { + } + + protected: + ::cppu::OBroadcastHelper& getBroadcastHelper() { return maBHelper; } + + private: + ::cppu::OBroadcastHelper maBHelper; + }; + + } + + //= ShapeGeometryChangeNotifier - declaration + + /** helper class to work around the ...unfortunate implementation of property change broadcasts + in the XShape implementation, which broadcasts way too generous and unspecified + */ + typedef ::comphelper::ComponentBase ShapeGeometryChangeNotifier_CBase; + typedef ::cppu::WeakImplHelper < css::beans::XPropertyChangeListener + > ShapeGeometryChangeNotifier_IBase; + + namespace { + + class ShapeGeometryChangeNotifier :public BroadcastHelperBase + ,public ShapeGeometryChangeNotifier_CBase + ,public ShapeGeometryChangeNotifier_IBase + { + public: + ShapeGeometryChangeNotifier( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rParentMutex, const Reference< XShape >& _shape ) + :BroadcastHelperBase( _rParentMutex ) + ,ShapeGeometryChangeNotifier_CBase( BroadcastHelperBase::getBroadcastHelper(), ::comphelper::ComponentBase::NoInitializationNeeded() ) + ,m_rParent( _rParent ) + ,m_aPropertyChangeListeners( _rParentMutex ) + ,m_xShape( _shape ) + { + ENSURE_OR_THROW( m_xShape.is(), "illegal shape!" ); + impl_init_nothrow(); + } + + // property change broadcasting + void addPropertyChangeListener( const Reference< XPropertyChangeListener >& _listener ) + { + m_aPropertyChangeListeners.addInterface( _listener ); + } + void removePropertyChangeListener( const Reference< XPropertyChangeListener >& _listener ) + { + m_aPropertyChangeListeners.removeInterface( _listener ); + } + + // XComponent equivalent + void dispose() + { + ::osl::MutexGuard aGuard( getMutex() ); + impl_dispose_nothrow(); + } + + // XInterface + virtual void SAL_CALL acquire( ) noexcept override + { + m_rParent.acquire(); + } + + virtual void SAL_CALL release( ) noexcept override + { + m_rParent.release(); + } + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const PropertyChangeEvent& _event ) override; + + // XEventListener + virtual void SAL_CALL disposing( const EventObject& _event ) override; + + protected: + virtual ~ShapeGeometryChangeNotifier() override + { + if ( !getBroadcastHelper().bDisposed ) + { + acquire(); + dispose(); + } + } + + protected: + ::cppu::OBroadcastHelper& getBroadcastHelper() { return BroadcastHelperBase::getBroadcastHelper(); } + + private: + void impl_init_nothrow(); + void impl_dispose_nothrow(); + + private: + ::cppu::OWeakObject& m_rParent; + ::comphelper::OInterfaceContainerHelper2 m_aPropertyChangeListeners; + Reference< XShape > m_xShape; + }; + + } + + //= FormGeometryHandler - declaration + + namespace { + + class FormGeometryHandler; + + } + + /** a property handler for any virtual string properties + */ + + namespace { + + class FormGeometryHandler : public PropertyHandlerComponent + { + public: + explicit FormGeometryHandler( + const Reference< XComponentContext >& _rxContext + ); + + protected: + virtual ~FormGeometryHandler() override; + + protected: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override; + + // XPropertyHandler overriables + virtual Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) override; + virtual LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual Sequence< OUString > SAL_CALL getActuatingProperties( ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& _rOldValue, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override; + + // OComponentHandler overridables + virtual void SAL_CALL disposing() override; + + // PropertyHandler overridables + virtual Sequence< Property > doDescribeSupportedProperties() const override; + + protected: + virtual void onNewComponent() override; + + private: + bool impl_haveTextAnchorType_nothrow() const; + bool impl_haveSheetAnchorType_nothrow() const; + void impl_setSheetAnchorType_nothrow( const sal_Int32 _nAnchorType ) const; + + private: + Reference< XControlShape > m_xAssociatedShape; + Reference< XPropertySet > m_xShapeProperties; + ::rtl::Reference< ShapeGeometryChangeNotifier > m_xChangeNotifier; + }; + + } + + //= FormGeometryHandler - implementation + + + FormGeometryHandler::FormGeometryHandler( const Reference< XComponentContext >& _rxContext ) + :PropertyHandlerComponent( _rxContext ) + { + } + + + FormGeometryHandler::~FormGeometryHandler( ) + { + if ( !rBHelper.bDisposed ) + { + acquire(); + dispose(); + } + + } + + + void FormGeometryHandler::onNewComponent() + { + if ( m_xChangeNotifier.is() ) + { + m_xChangeNotifier->dispose(); + m_xChangeNotifier.clear(); + } + m_xAssociatedShape.clear(); + m_xShapeProperties.clear(); + + PropertyHandlerComponent::onNewComponent(); + + try + { + Reference< XControlModel > xControlModel( m_xComponent, UNO_QUERY ); + if ( xControlModel.is() ) + { + // do not ask the map for shapes for grid control columns... + Reference< XChild > xCompChild( m_xComponent, UNO_QUERY_THROW ); + Reference< XGridColumnFactory > xCheckGrid( xCompChild->getParent(), UNO_QUERY ); + if ( !xCheckGrid.is() ) + { + Reference< XMap > xControlMap; + Any any = m_xContext->getValueByName( "ControlShapeAccess" ); + any >>= xControlMap; + m_xAssociatedShape.set( xControlMap->get( Any( xControlModel ) ), UNO_QUERY_THROW ); + m_xShapeProperties.set( m_xAssociatedShape, UNO_QUERY_THROW ); + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + if ( m_xAssociatedShape.is() ) + m_xChangeNotifier = new ShapeGeometryChangeNotifier( *this, m_aMutex, m_xAssociatedShape ); + } + + + OUString FormGeometryHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.FormGeometryHandler"; + } + + + Sequence< OUString > FormGeometryHandler::getSupportedServiceNames( ) + { + return { "com.sun.star.form.inspection.FormGeometryHandler" }; + } + + + Any SAL_CALL FormGeometryHandler::getPropertyValue( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + ENSURE_OR_THROW2( m_xAssociatedShape.is(), "internal error: properties, but no shape!", *this ); + ENSURE_OR_THROW2( m_xShapeProperties.is(), "internal error: no shape properties!", *this ); + + Any aReturn; + try + { + switch ( nPropId ) + { + case PROPERTY_ID_POSITIONX: + aReturn <<= m_xAssociatedShape->getPosition().X; + break; + case PROPERTY_ID_POSITIONY: + aReturn <<= m_xAssociatedShape->getPosition().Y; + break; + case PROPERTY_ID_WIDTH: + aReturn <<= m_xAssociatedShape->getSize().Width; + break; + case PROPERTY_ID_HEIGHT: + aReturn <<= m_xAssociatedShape->getSize().Height; + break; + case PROPERTY_ID_TEXT_ANCHOR_TYPE: + aReturn = m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR_TYPE ); + OSL_ENSURE( aReturn.hasValue(), "FormGeometryHandler::getPropertyValue: illegal anchor type!" ); + break; + case PROPERTY_ID_SHEET_ANCHOR_TYPE: + { + Reference< XSpreadsheet > xAnchorSheet( m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR ), UNO_QUERY ); + aReturn <<= sal_Int32( xAnchorSheet.is() ? ANCHOR_TO_SHEET : ANCHOR_TO_CELL ); + } + break; + + default: + OSL_FAIL( "FormGeometryHandler::getPropertyValue: huh?" ); + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return aReturn; + } + + + void SAL_CALL FormGeometryHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + ENSURE_OR_THROW2( m_xAssociatedShape.is(), "internal error: properties, but no shape!", *this ); + ENSURE_OR_THROW2( m_xShapeProperties.is(), "internal error: properties, but no shape!", *this ); + + try + { + switch ( nPropId ) + { + case PROPERTY_ID_POSITIONX: + case PROPERTY_ID_POSITIONY: + { + sal_Int32 nPosition(0); + OSL_VERIFY( _rValue >>= nPosition ); + + css::awt::Point aPos( m_xAssociatedShape->getPosition() ); + if ( nPropId == PROPERTY_ID_POSITIONX ) + aPos.X = nPosition; + else + aPos.Y = nPosition; + m_xAssociatedShape->setPosition( aPos ); + } + break; + + case PROPERTY_ID_WIDTH: + case PROPERTY_ID_HEIGHT: + { + sal_Int32 nSize(0); + OSL_VERIFY( _rValue >>= nSize ); + + css::awt::Size aSize( m_xAssociatedShape->getSize() ); + if ( nPropId == PROPERTY_ID_WIDTH ) + aSize.Width = nSize; + else + aSize.Height = nSize; + m_xAssociatedShape->setSize( aSize ); + } + break; + + case PROPERTY_ID_TEXT_ANCHOR_TYPE: + m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR_TYPE, _rValue ); + break; + + case PROPERTY_ID_SHEET_ANCHOR_TYPE: + { + sal_Int32 nSheetAnchorType = 0; + OSL_VERIFY( _rValue >>= nSheetAnchorType ); + impl_setSheetAnchorType_nothrow( nSheetAnchorType ); + } + break; + + default: + OSL_FAIL( "FormGeometryHandler::getPropertyValue: huh?" ); + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + LineDescriptor SAL_CALL FormGeometryHandler::describePropertyLine( const OUString& _rPropertyName, + const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + LineDescriptor aLineDesc( PropertyHandler::describePropertyLine( _rPropertyName, _rxControlFactory ) ); + try + { + bool bIsSize = false; + switch ( nPropId ) + { + case PROPERTY_ID_WIDTH: + case PROPERTY_ID_HEIGHT: + bIsSize = true; + [[fallthrough]]; + case PROPERTY_ID_POSITIONX: + case PROPERTY_ID_POSITIONY: + { + Optional< double > aZero( true, 0 ); + Optional< double > aValueNotPresent( false, 0 ); + aLineDesc.Control = PropertyHandlerHelper::createNumericControl( + _rxControlFactory, 2, bIsSize ? aZero : aValueNotPresent, aValueNotPresent ); + + Reference< XNumericControl > xNumericControl( aLineDesc.Control, UNO_QUERY_THROW ); + xNumericControl->setValueUnit( MeasureUnit::MM_100TH ); + xNumericControl->setDisplayUnit( impl_getDocumentMeasurementUnit_throw() ); + } + break; + + case PROPERTY_ID_TEXT_ANCHOR_TYPE: + case PROPERTY_ID_SHEET_ANCHOR_TYPE: + // default handling from PropertyHandler is sufficient + break; + + default: + OSL_FAIL( "FormGeometryHandler::describePropertyLine: huh?" ); + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return aLineDesc; + } + + + void SAL_CALL FormGeometryHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _listener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_PRECOND( m_xChangeNotifier.is(), "FormGeometryHandler::addPropertyChangeListener: no notified, implies no shape!?" ); + if ( m_xChangeNotifier.is() ) + m_xChangeNotifier->addPropertyChangeListener( _listener ); + } + + + void SAL_CALL FormGeometryHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _listener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_PRECOND( m_xChangeNotifier.is(), "FormGeometryHandler::removePropertyChangeListener: no notified, implies no shape!?" ); + if ( m_xChangeNotifier.is() ) + m_xChangeNotifier->removePropertyChangeListener( _listener ); + } + + + Sequence< OUString > SAL_CALL FormGeometryHandler::getActuatingProperties( ) + { + Sequence< OUString > aInterestedIn { PROPERTY_TEXT_ANCHOR_TYPE }; + return aInterestedIn; + } + + + void SAL_CALL FormGeometryHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool /*_bFirstTimeInit*/ ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nActuatingPropId( impl_getPropertyId_nothrow( _rActuatingPropertyName ) ); + + switch ( nActuatingPropId ) + { + case PROPERTY_ID_TEXT_ANCHOR_TYPE: + { + TextContentAnchorType eAnchorType( TextContentAnchorType_AT_PARAGRAPH ); + OSL_VERIFY( _rNewValue >>= eAnchorType ); + _rxInspectorUI->enablePropertyUI( PROPERTY_POSITIONX, eAnchorType != TextContentAnchorType_AS_CHARACTER ); + } + break; + case -1: + throw RuntimeException(); + break; + default: + OSL_FAIL( "FormGeometryHandler::actuatingPropertyChanged: not registered for this property!" ); + break; + } + } + + + Sequence< Property > FormGeometryHandler::doDescribeSupportedProperties() const + { + if ( !m_xAssociatedShape.is() ) + return Sequence< Property >(); + + std::vector< Property > aProperties; + + addInt32PropertyDescription( aProperties, PROPERTY_POSITIONX ); + addInt32PropertyDescription( aProperties, PROPERTY_POSITIONY ); + addInt32PropertyDescription( aProperties, PROPERTY_WIDTH ); + addInt32PropertyDescription( aProperties, PROPERTY_HEIGHT ); + + if ( impl_haveTextAnchorType_nothrow() ) + implAddPropertyDescription( aProperties, PROPERTY_TEXT_ANCHOR_TYPE, ::cppu::UnoType< TextContentAnchorType >::get() ); + + if ( impl_haveSheetAnchorType_nothrow() ) + addInt32PropertyDescription( aProperties, PROPERTY_SHEET_ANCHOR_TYPE ); + + return comphelper::containerToSequence(aProperties); + } + + + void SAL_CALL FormGeometryHandler::disposing() + { + PropertyHandlerComponent::disposing(); + + if ( m_xChangeNotifier.is() ) + { + m_xChangeNotifier->dispose(); + m_xChangeNotifier.clear(); + } + } + + + bool FormGeometryHandler::impl_haveTextAnchorType_nothrow() const + { + ENSURE_OR_THROW( m_xShapeProperties.is(), "not to be called without shape properties" ); + try + { + Reference< XPropertySetInfo > xPSI( m_xShapeProperties->getPropertySetInfo(), UNO_SET_THROW ); + if ( xPSI->hasPropertyByName( PROPERTY_ANCHOR_TYPE ) ) + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return false; + } + + + bool FormGeometryHandler::impl_haveSheetAnchorType_nothrow() const + { + ENSURE_OR_THROW( m_xShapeProperties.is(), "not to be called without shape properties" ); + try + { + Reference< XPropertySetInfo > xPSI( m_xShapeProperties->getPropertySetInfo(), UNO_SET_THROW ); + if ( !xPSI->hasPropertyByName( PROPERTY_ANCHOR ) ) + return false; + Reference< XServiceInfo > xSI( m_xAssociatedShape, UNO_QUERY_THROW ); + if ( xSI->supportsService("com.sun.star.sheet.Shape") ) + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return false; + } + + + namespace + { + sal_Int32 lcl_getLowerBoundRowOrColumn( const Reference< XIndexAccess >& _rxRowsOrColumns, const bool _bRows, + const css::awt::Point& _rRelativePosition ) + { + sal_Int32 nAccumulated = 0; + + const sal_Int32& rRelativePos = _bRows ? _rRelativePosition.Y : _rRelativePosition.X; + + sal_Int32 nElements = _rxRowsOrColumns->getCount(); + sal_Int32 currentPos = 0; + for ( currentPos=0; currentPos xRowOrColumn( _rxRowsOrColumns->getByIndex( currentPos ), UNO_QUERY_THROW ); + + bool bIsVisible = true; + OSL_VERIFY( xRowOrColumn->getPropertyValue( PROPERTY_IS_VISIBLE ) >>= bIsVisible ); + if ( !bIsVisible ) + continue; + + sal_Int32 nHeightOrWidth( 0 ); + OSL_VERIFY( xRowOrColumn->getPropertyValue( _bRows ? OUString(PROPERTY_HEIGHT) : OUString(PROPERTY_WIDTH) ) >>= nHeightOrWidth ); + + if ( nAccumulated + nHeightOrWidth > rRelativePos ) + break; + + nAccumulated += nHeightOrWidth; + } + + return currentPos; + } + } + + + void FormGeometryHandler::impl_setSheetAnchorType_nothrow( const sal_Int32 _nAnchorType ) const + { + ENSURE_OR_THROW( m_xShapeProperties.is(), "illegal to be called without shape properties." ); + try + { + CellBindingHelper aHelper( m_xComponent, impl_getContextDocument_nothrow() ); + // find the sheet which the control belongs to + Reference< XSpreadsheet > xSheet; + aHelper.getControlSheetIndex( xSheet ); + + switch ( _nAnchorType ) + { + case ANCHOR_TO_SHEET: + OSL_ENSURE( xSheet.is(), + "FormGeometryHandler::impl_setSheetAnchorType_nothrow: sheet not found!" ); + if ( xSheet.is() ) + { + css::awt::Point aPreservePosition( m_xAssociatedShape->getPosition() ); + m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR, Any( xSheet ) ); + m_xAssociatedShape->setPosition( aPreservePosition ); + } + break; + + case ANCHOR_TO_CELL: + { + Reference< XColumnRowRange > xColsRows( xSheet, UNO_QUERY_THROW ); + + // get the current anchor + Reference< XSpreadsheet > xCurrentAnchor; + OSL_VERIFY( m_xShapeProperties->getPropertyValue( PROPERTY_ANCHOR ) >>= xCurrentAnchor ); + OSL_ENSURE( xCurrentAnchor.is(), "FormGeometryHandler::impl_setSheetAnchorType_nothrow: only to be called when currently anchored to a sheet!" ); + + // get the current position + css::awt::Point aRelativePosition( m_xAssociatedShape->getPosition() ); + + Reference< XTableColumns > xCols( xColsRows->getColumns(), UNO_SET_THROW ); + sal_Int32 nNewAnchorCol = lcl_getLowerBoundRowOrColumn( xCols, false, aRelativePosition ); + + Reference< XTableRows > xRows( xColsRows->getRows(), UNO_SET_THROW ); + sal_Int32 nNewAnchorRow = lcl_getLowerBoundRowOrColumn( xRows, true, aRelativePosition ); + + Any aNewAnchorCell( xSheet->getCellByPosition( nNewAnchorCol, nNewAnchorRow ) ); + m_xShapeProperties->setPropertyValue( PROPERTY_ANCHOR, aNewAnchorCell ); + } + break; + + default: + OSL_FAIL( "FormGeometryHandler::impl_setSheetAnchorType_nothrow: illegal anchor type!" ); + break; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + //= ShapeGeometryChangeNotifier - implementation + + namespace + { + struct EventTranslation + { + OUString sPropertyName; + Any aNewPropertyValue; + + EventTranslation( const OUString& _propertyName, const Any& _newPropertyValue ) + :sPropertyName( _propertyName ) + ,aNewPropertyValue( _newPropertyValue ) + { + } + }; + } + + + void SAL_CALL ShapeGeometryChangeNotifier::propertyChange( const PropertyChangeEvent& _event ) + { + ::comphelper::ComponentMethodGuard aGuard( *this ); + + std::vector< EventTranslation > aEventTranslations; + aEventTranslations.reserve(2); + + if ( _event.PropertyName == "Position" ) + { + css::awt::Point aPos = m_xShape->getPosition(); + aEventTranslations.push_back( EventTranslation( PROPERTY_POSITIONX, Any( aPos.X ) ) ); + aEventTranslations.push_back( EventTranslation( PROPERTY_POSITIONY, Any( aPos.Y ) ) ); + } + else if ( _event.PropertyName == "Size" ) + { + css::awt::Size aSize = m_xShape->getSize(); + aEventTranslations.push_back( EventTranslation( PROPERTY_WIDTH, Any( aSize.Width ) ) ); + aEventTranslations.push_back( EventTranslation( PROPERTY_HEIGHT, Any( aSize.Height ) ) ); + } + else if ( _event.PropertyName == PROPERTY_ANCHOR_TYPE ) + { + aEventTranslations.push_back( EventTranslation( PROPERTY_TEXT_ANCHOR_TYPE, _event.NewValue ) ); + } + else if ( _event.PropertyName == PROPERTY_ANCHOR ) + { + aEventTranslations.push_back( EventTranslation( PROPERTY_SHEET_ANCHOR_TYPE, _event.NewValue ) ); + } + + PropertyChangeEvent aTranslatedEvent( _event ); + aTranslatedEvent.Source = m_rParent; + + aGuard.clear(); + for (auto const& eventTranslation : aEventTranslations) + { + aTranslatedEvent.PropertyName = eventTranslation.sPropertyName; + aTranslatedEvent.NewValue = eventTranslation.aNewPropertyValue; + m_aPropertyChangeListeners.notifyEach( &XPropertyChangeListener::propertyChange, aTranslatedEvent ); + } + } + + + void SAL_CALL ShapeGeometryChangeNotifier::disposing( const EventObject& /*_event*/ ) + { + ::comphelper::ComponentMethodGuard aGuard( *this ); + impl_dispose_nothrow(); + } + + + void ShapeGeometryChangeNotifier::impl_init_nothrow() + { + osl_atomic_increment( &m_refCount ); + try + { + Reference< XPropertySet > xShapeProperties( m_xShape, UNO_QUERY_THROW ); + xShapeProperties->addPropertyChangeListener( OUString(), this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + osl_atomic_decrement( &m_refCount ); + } + + + void ShapeGeometryChangeNotifier::impl_dispose_nothrow() + { + try + { + Reference< XPropertySet > xShapeProperties( m_xShape, UNO_QUERY_THROW ); + xShapeProperties->removePropertyChangeListener( OUString(), this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + getBroadcastHelper().bDisposed = true; + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_FormGeometryHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::FormGeometryHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formlinkdialog.cxx b/extensions/source/propctrlr/formlinkdialog.cxx new file mode 100644 index 000000000..319ade956 --- /dev/null +++ b/extensions/source/propctrlr/formlinkdialog.cxx @@ -0,0 +1,630 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "formlinkdialog.hxx" + +#include "modulepcr.hxx" +#include +#include "formstrings.hxx" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pcr +{ + + + 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::sdbcx; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::container; + + + //= FieldLinkRow + + class FieldLinkRow + { + private: + std::unique_ptr m_xDetailColumn; + std::unique_ptr m_xMasterColumn; + + Link m_aLinkChangeHandler; + + public: + FieldLinkRow(std::unique_ptr xDetailColumn, + std::unique_ptr xMasterColumn); + + + void SetLinkChangeHandler( const Link& _rHdl ) { m_aLinkChangeHandler = _rHdl; } + + enum LinkParticipant + { + eDetailField, + eMasterField + }; + /** retrieves the selected field name for either the master or the detail field + @return if and only a valid field is selected + */ + bool GetFieldName( LinkParticipant _eWhich, OUString& /* [out] */ _rName ) const; + void SetFieldName( LinkParticipant _eWhich, const OUString& _rName ); + + void fillList( LinkParticipant _eWhich, const Sequence< OUString >& _rFieldNames ); + + void Show() + { + m_xDetailColumn->show(); + m_xMasterColumn->show(); + } + + private: + DECL_LINK( OnFieldNameChanged, weld::ComboBox&, void ); + }; + + + FieldLinkRow::FieldLinkRow(std::unique_ptr xDetailColumn, + std::unique_ptr xMasterColumn) + : m_xDetailColumn(std::move(xDetailColumn)) + , m_xMasterColumn(std::move(xMasterColumn)) + { + m_xDetailColumn->connect_changed( LINK( this, FieldLinkRow, OnFieldNameChanged ) ); + m_xMasterColumn->connect_changed( LINK( this, FieldLinkRow, OnFieldNameChanged ) ); + } + + void FieldLinkRow::fillList( LinkParticipant _eWhich, const Sequence< OUString >& _rFieldNames ) + { + weld::ComboBox* pBox = ( _eWhich == eDetailField ) ? m_xDetailColumn.get() : m_xMasterColumn.get(); + + const OUString* pFieldName = _rFieldNames.getConstArray(); + const OUString* pFieldNameEnd = pFieldName + _rFieldNames.getLength(); + for ( ; pFieldName != pFieldNameEnd; ++pFieldName ) + pBox->append_text( *pFieldName ); + } + + bool FieldLinkRow::GetFieldName( LinkParticipant _eWhich, OUString& /* [out] */ _rName ) const + { + const weld::ComboBox* pBox = ( _eWhich == eDetailField ) ? m_xDetailColumn.get() : m_xMasterColumn.get(); + _rName = pBox->get_active_text(); + return !_rName.isEmpty(); + } + + void FieldLinkRow::SetFieldName( LinkParticipant _eWhich, const OUString& _rName ) + { + weld::ComboBox* pBox = ( _eWhich == eDetailField ) ? m_xDetailColumn.get() : m_xMasterColumn.get(); + pBox->set_entry_text( _rName ); + } + + IMPL_LINK_NOARG( FieldLinkRow, OnFieldNameChanged, weld::ComboBox&, void ) + { + m_aLinkChangeHandler.Call( *this ); + } + + //= FormLinkDialog + + FormLinkDialog::FormLinkDialog(weld::Window* _pParent, const Reference< XPropertySet >& _rxDetailForm, + const Reference< XPropertySet >& _rxMasterForm, const Reference< XComponentContext >& _rxContext, + const OUString& _sExplanation, + const OUString& _sDetailLabel, + const OUString& _sMasterLabel) + : GenericDialogController(_pParent, "modules/spropctrlr/ui/formlinksdialog.ui", "FormLinks") + , m_xContext ( _rxContext ) + , m_xDetailForm( _rxDetailForm ) + , m_xMasterForm( _rxMasterForm ) + , m_sDetailLabel(_sDetailLabel) + , m_sMasterLabel(_sMasterLabel) + , m_xExplanation(m_xBuilder->weld_label("explanationLabel")) + , m_xDetailLabel(m_xBuilder->weld_label("detailLabel")) + , m_xMasterLabel(m_xBuilder->weld_label("masterLabel")) + , m_xRow1(std::make_unique(m_xBuilder->weld_combo_box("detailCombobox1"), + m_xBuilder->weld_combo_box("masterCombobox1"))) + , m_xRow2(std::make_unique(m_xBuilder->weld_combo_box("detailCombobox2"), + m_xBuilder->weld_combo_box("masterCombobox2"))) + , m_xRow3(std::make_unique(m_xBuilder->weld_combo_box("detailCombobox3"), + m_xBuilder->weld_combo_box("masterCombobox3"))) + , m_xRow4(std::make_unique(m_xBuilder->weld_combo_box("detailCombobox4"), + m_xBuilder->weld_combo_box("masterCombobox4"))) + , m_xOK(m_xBuilder->weld_button("ok")) + , m_xSuggest(m_xBuilder->weld_button("suggestButton")) + { + m_xRow1->Show(); + m_xRow2->Show(); + m_xRow3->Show(); + m_xRow4->Show(); + m_xDialog->set_size_request(600, -1); + + if ( !_sExplanation.isEmpty() ) + m_xExplanation->set_label(_sExplanation); + + m_xSuggest->connect_clicked(LINK(this, FormLinkDialog, OnSuggest)); + m_xRow1->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) ); + m_xRow2->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) ); + m_xRow3->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) ); + m_xRow4->SetLinkChangeHandler( LINK( this, FormLinkDialog, OnFieldChanged ) ); + + Application::PostUserEvent(LINK(this, FormLinkDialog, OnInitialize)); + + updateOkButton(); + } + + FormLinkDialog::~FormLinkDialog() + { + } + + void FormLinkDialog::commitLinkPairs() + { + // collect the field lists from the rows + std::vector< OUString > aDetailFields; aDetailFields.reserve( 4 ); + std::vector< OUString > aMasterFields; aMasterFields.reserve( 4 ); + + const FieldLinkRow* aRows[] = { + m_xRow1.get(), m_xRow2.get(), m_xRow3.get(), m_xRow4.get() + }; + + for (const FieldLinkRow* aRow : aRows) + { + OUString sDetailField, sMasterField; + aRow->GetFieldName( FieldLinkRow::eDetailField, sDetailField ); + aRow->GetFieldName( FieldLinkRow::eMasterField, sMasterField ); + if ( sDetailField.isEmpty() && sMasterField.isEmpty() ) + continue; + + aDetailFields.push_back( sDetailField ); + aMasterFields.push_back( sMasterField ); + } + + // and set as property values + try + { + if ( m_xDetailForm.is() ) + { + m_xDetailForm->setPropertyValue( PROPERTY_DETAILFIELDS, Any( Sequence< OUString >( aDetailFields.data(), aDetailFields.size() ) ) ); + m_xDetailForm->setPropertyValue( PROPERTY_MASTERFIELDS, Any( Sequence< OUString >( aMasterFields.data(), aMasterFields.size() ) ) ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", + "caught an exception while setting the properties!"); + } + } + + short FormLinkDialog::run() + { + short nResult = GenericDialogController::run(); + + if ( RET_OK == nResult ) + commitLinkPairs(); + + return nResult; + } + + void FormLinkDialog::initializeFieldLists() + { + Sequence< OUString > sDetailFields; + getFormFields( m_xDetailForm, sDetailFields ); + + Sequence< OUString > sMasterFields; + getFormFields( m_xMasterForm, sMasterFields ); + + FieldLinkRow* aRows[] = { + m_xRow1.get(), m_xRow2.get(), m_xRow3.get(), m_xRow4.get() + }; + for (FieldLinkRow* aRow : aRows) + { + aRow->fillList( FieldLinkRow::eDetailField, sDetailFields ); + aRow->fillList( FieldLinkRow::eMasterField, sMasterFields ); + } + + } + + + void FormLinkDialog::initializeColumnLabels() + { + // label for the detail form + OUString sDetailType = getFormDataSourceType( m_xDetailForm ); + if ( sDetailType.isEmpty() ) + { + if ( m_sDetailLabel.isEmpty() ) + { + m_sDetailLabel = PcrRes(STR_DETAIL_FORM); + } + sDetailType = m_sDetailLabel; + } + m_xDetailLabel->set_label( sDetailType ); + + // label for the master form + OUString sMasterType = getFormDataSourceType( m_xMasterForm ); + if ( sMasterType.isEmpty() ) + { + if ( m_sMasterLabel.isEmpty() ) + { + m_sMasterLabel = PcrRes(STR_MASTER_FORM); + } + sMasterType = m_sMasterLabel; + } + m_xMasterLabel->set_label( sMasterType ); + } + + void FormLinkDialog::initializeFieldRowsFrom( std::vector< OUString >& _rDetailFields, std::vector< OUString >& _rMasterFields ) + { + // our UI does allow 4 fields max + _rDetailFields.resize( 4 ); + _rMasterFields.resize( 4 ); + + FieldLinkRow* aRows[] = { + m_xRow1.get(), m_xRow2.get(), m_xRow3.get(), m_xRow4.get() + }; + for ( sal_Int32 i = 0; i < 4; ++i ) + { + aRows[ i ]->SetFieldName( FieldLinkRow::eDetailField, _rDetailFields[i] ); + aRows[ i ]->SetFieldName( FieldLinkRow::eMasterField, _rMasterFields[i] ); + } + } + + + void FormLinkDialog::initializeLinks() + { + try + { + Sequence< OUString > aDetailFields; + Sequence< OUString > aMasterFields; + + if ( m_xDetailForm.is() ) + { + m_xDetailForm->getPropertyValue( PROPERTY_DETAILFIELDS ) >>= aDetailFields; + m_xDetailForm->getPropertyValue( PROPERTY_MASTERFIELDS ) >>= aMasterFields; + } + + std::vector< OUString > aDetailFields1; + comphelper::sequenceToContainer(aDetailFields1, aDetailFields); + std::vector< OUString > aMasterFields1; + comphelper::sequenceToContainer(aMasterFields1, aMasterFields); + initializeFieldRowsFrom( aDetailFields1, aMasterFields1 ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::initializeLinks" ); + } + } + + + void FormLinkDialog::updateOkButton() + { + // in all rows, there must be either two valid selections, or none at all + // If there is at least one row with exactly one valid selection, then the + // OKButton needs to be disabled + bool bEnable = true; + + const FieldLinkRow* aRows[] = { + m_xRow1.get(), m_xRow2.get(), m_xRow3.get(), m_xRow4.get() + }; + + for ( sal_Int32 i = 0; ( i < 4 ) && bEnable; ++i ) + { + OUString sNotInterestedInRightNow; + if ( aRows[ i ]->GetFieldName( FieldLinkRow::eDetailField, sNotInterestedInRightNow ) + != aRows[ i ]->GetFieldName( FieldLinkRow::eMasterField, sNotInterestedInRightNow ) + ) + bEnable = false; + } + + m_xOK->set_sensitive(bEnable); + } + + OUString FormLinkDialog::getFormDataSourceType( const Reference< XPropertySet >& _rxForm ) + { + OUString sReturn; + if ( !_rxForm.is() ) + return sReturn; + + try + { + sal_Int32 nCommandType = CommandType::COMMAND; + OUString sCommand; + + _rxForm->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType; + _rxForm->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand; + + if ( ( nCommandType == CommandType::TABLE ) + || ( nCommandType == CommandType::QUERY ) + ) + sReturn = sCommand; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getFormDataSourceType" ); + } + return sReturn; + } + + void FormLinkDialog::getFormFields( const Reference< XPropertySet >& _rxForm, Sequence< OUString >& /* [out] */ _rNames ) const + { + _rNames.realloc( 0 ); + + ::dbtools::SQLExceptionInfo aErrorInfo; + OUString sCommand; + try + { + weld::WaitObject aWaitCursor(m_xDialog.get()); + + OSL_ENSURE( _rxForm.is(), "FormLinkDialog::getFormFields: invalid form!" ); + + sal_Int32 nCommandType = CommandType::COMMAND; + + _rxForm->getPropertyValue( PROPERTY_COMMANDTYPE ) >>= nCommandType; + _rxForm->getPropertyValue( PROPERTY_COMMAND ) >>= sCommand; + + Reference< XConnection > xConnection; + ensureFormConnection( _rxForm, xConnection ); + + _rNames = ::dbtools::getFieldNamesByCommandDescriptor( + xConnection, + nCommandType, + sCommand, + &aErrorInfo + ); + } + catch (const SQLContext& e) { aErrorInfo = e; } + catch (const SQLWarning& e) { aErrorInfo = e; } + catch (const SQLException& e ) { aErrorInfo = e; } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getFormFields: caught a non-SQL exception!" ); + } + + if ( !aErrorInfo.isValid() ) + return; + + OUString sErrorMessage; + { + sErrorMessage = PcrRes(STR_ERROR_RETRIEVING_COLUMNS); + sErrorMessage = sErrorMessage.replaceFirst("#", sCommand); + } + + SQLContext aContext; + aContext.Message = sErrorMessage; + aContext.NextException = aErrorInfo.get(); + ::dbtools::showError(aContext, m_xDialog->GetXWindow(), m_xContext); + } + + void FormLinkDialog::ensureFormConnection( const Reference< XPropertySet >& _rxFormProps, Reference< XConnection >& /* [out] */ _rxConnection ) const + { + OSL_PRECOND( _rxFormProps.is(), "FormLinkDialog::ensureFormConnection: invalid form!" ); + if ( !_rxFormProps.is() ) + return; + if ( _rxFormProps->getPropertySetInfo()->hasPropertyByName(PROPERTY_ACTIVE_CONNECTION) ) + _rxConnection.set(_rxFormProps->getPropertyValue(PROPERTY_ACTIVE_CONNECTION),UNO_QUERY); + + if ( !_rxConnection.is() ) + _rxConnection = ::dbtools::connectRowset( Reference< XRowSet >( _rxFormProps, UNO_QUERY ), m_xContext, nullptr ); + } + + + void FormLinkDialog::getConnectionMetaData( const Reference< XPropertySet >& _rxFormProps, Reference< XDatabaseMetaData >& /* [out] */ _rxMeta ) + { + if ( _rxFormProps.is() ) + { + Reference< XConnection > xConnection; + if ( !::dbtools::isEmbeddedInDatabase( _rxFormProps, xConnection ) ) + _rxFormProps->getPropertyValue( PROPERTY_ACTIVE_CONNECTION ) >>= xConnection; + if ( xConnection.is() ) + _rxMeta = xConnection->getMetaData(); + } + } + + + Reference< XPropertySet > FormLinkDialog::getCanonicUnderlyingTable( const Reference< XPropertySet >& _rxFormProps ) const + { + Reference< XPropertySet > xTable; + try + { + Reference< XTablesSupplier > xTablesInForm( ::dbtools::getCurrentSettingsComposer( _rxFormProps, m_xContext, nullptr ), UNO_QUERY ); + Reference< XNameAccess > xTables; + if ( xTablesInForm.is() ) + xTables = xTablesInForm->getTables(); + Sequence< OUString > aTableNames; + if ( xTables.is() ) + aTableNames = xTables->getElementNames(); + + if ( aTableNames.getLength() == 1 ) + { + xTables->getByName( aTableNames[ 0 ] ) >>= xTable; + OSL_ENSURE( xTable.is(), "FormLinkDialog::getCanonicUnderlyingTable: invalid table!" ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getCanonicUnderlyingTable" ); + } + return xTable; + } + + + bool FormLinkDialog::getExistingRelation( const Reference< XPropertySet >& _rxLHS, const Reference< XPropertySet >& /*_rxRHS*/, + // TODO: fix the usage of _rxRHS. This is issue #i81956#. + std::vector< OUString >& _rLeftFields, std::vector< OUString >& _rRightFields ) + { + try + { + Reference< XKeysSupplier > xSuppKeys( _rxLHS, UNO_QUERY ); + Reference< XIndexAccess > xKeys; + if ( xSuppKeys.is() ) + xKeys = xSuppKeys->getKeys(); + + if ( xKeys.is() ) + { + Reference< XPropertySet > xKey; + Reference< XColumnsSupplier > xKeyColSupp( xKey, UNO_QUERY ); + Reference< XIndexAccess > xKeyColumns; + Reference< XPropertySet > xKeyColumn; + OUString sColumnName, sRelatedColumnName; + + const sal_Int32 keyCount = xKeys->getCount(); + for ( sal_Int32 key = 0; key < keyCount; ++key ) + { + xKeys->getByIndex( key ) >>= xKey; + sal_Int32 nKeyType = 0; + xKey->getPropertyValue("Type") >>= nKeyType; + if ( nKeyType != KeyType::FOREIGN ) + continue; + + xKeyColumns.clear(); + xKeyColSupp.set(xKey, css::uno::UNO_QUERY); + if ( xKeyColSupp.is() ) + xKeyColumns.set(xKeyColSupp->getColumns(), css::uno::UNO_QUERY); + OSL_ENSURE( xKeyColumns.is(), "FormLinkDialog::getExistingRelation: could not obtain the columns for the key!" ); + + if ( !xKeyColumns.is() ) + continue; + + const sal_Int32 columnCount = xKeyColumns->getCount(); + _rLeftFields.resize( columnCount ); + _rRightFields.resize( columnCount ); + for ( sal_Int32 column = 0; column < columnCount; ++column ) + { + xKeyColumn.clear(); + xKeyColumns->getByIndex( column ) >>= xKeyColumn; + OSL_ENSURE( xKeyColumn.is(), "FormLinkDialog::getExistingRelation: invalid key column!" ); + if ( xKeyColumn.is() ) + { + xKeyColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumnName; + xKeyColumn->getPropertyValue("RelatedColumn") >>= sRelatedColumnName; + + _rLeftFields[ column ] = sColumnName; + _rRightFields[ column ] = sRelatedColumnName; + } + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::getExistingRelation" ); + } + + return ( !_rLeftFields.empty() ) && ( !_rLeftFields[ 0 ].isEmpty() ); + } + + + void FormLinkDialog::initializeSuggest() + { + if ( !m_xDetailForm.is() || !m_xMasterForm.is() ) + return; + + try + { + // only show the button when both forms are based on the same data source + OUString sMasterDS, sDetailDS; + m_xMasterForm->getPropertyValue( PROPERTY_DATASOURCE ) >>= sMasterDS; + m_xDetailForm->getPropertyValue( PROPERTY_DATASOURCE ) >>= sDetailDS; + bool bEnable = ( sMasterDS == sDetailDS ); + + // only show the button when the connection supports relations + if ( bEnable ) + { + Reference< XDatabaseMetaData > xMeta; + getConnectionMetaData( m_xDetailForm, xMeta ); + OSL_ENSURE( xMeta.is(), "FormLinkDialog::initializeSuggest: unable to retrieve the meta data for the connection!" ); + try + { + bEnable = xMeta.is() && xMeta->supportsIntegrityEnhancementFacility(); + } + catch(const Exception&) + { + bEnable = false; + } + } + + // only enable the button if there is a "canonic" table underlying both forms + Reference< XPropertySet > xDetailTable, xMasterTable; + if ( bEnable ) + { + xDetailTable = getCanonicUnderlyingTable( m_xDetailForm ); + xMasterTable = getCanonicUnderlyingTable( m_xMasterForm ); + bEnable = xDetailTable.is() && xMasterTable.is(); + } + + // only enable the button if there is a relation between both tables + m_aRelationDetailColumns.clear(); + m_aRelationMasterColumns.clear(); + if ( bEnable ) + { + bEnable = getExistingRelation( xDetailTable, xMasterTable, m_aRelationDetailColumns, m_aRelationMasterColumns ); + SAL_WARN_IF( m_aRelationMasterColumns.size() != m_aRelationDetailColumns.size(), + "extensions.propctrlr", + "FormLinkDialog::initializeSuggest: nonsense!" ); + if ( m_aRelationMasterColumns.empty() ) + { // okay, there is no relation "pointing" (via a foreign key) from the detail table to the master table + // but perhaps the other way round (would make less sense, but who knows ...) + bEnable = getExistingRelation( xMasterTable, xDetailTable, m_aRelationMasterColumns, m_aRelationDetailColumns ); + } + } + + // only enable the button if the relation contains at most 4 field pairs + if ( bEnable ) + { + bEnable = ( m_aRelationMasterColumns.size() <= 4 ); + } + + m_xSuggest->set_sensitive(bEnable); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "FormLinkDialog::initializeSuggest" ); + } + } + + IMPL_LINK_NOARG( FormLinkDialog, OnSuggest, weld::Button&, void ) + { + initializeFieldRowsFrom( m_aRelationDetailColumns, m_aRelationMasterColumns ); + } + + IMPL_LINK_NOARG( FormLinkDialog, OnFieldChanged, FieldLinkRow&, void ) + { + updateOkButton(); + } + + IMPL_LINK_NOARG( FormLinkDialog, OnInitialize, void*, void ) + { + initializeColumnLabels(); + initializeFieldLists(); + initializeLinks(); + initializeSuggest(); + } + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formlinkdialog.hxx b/extensions/source/propctrlr/formlinkdialog.hxx new file mode 100644 index 000000000..80cc086cc --- /dev/null +++ b/extensions/source/propctrlr/formlinkdialog.hxx @@ -0,0 +1,127 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in 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 pcr +{ + class FieldLinkRow; + + //= FormLinkDialog + + class FormLinkDialog : public weld::GenericDialogController + { + private: + css::uno::Reference< css::uno::XComponentContext > + m_xContext; + css::uno::Reference< css::beans::XPropertySet > + m_xDetailForm; + css::uno::Reference< css::beans::XPropertySet > + m_xMasterForm; + + std::vector< OUString > m_aRelationDetailColumns; + std::vector< OUString > m_aRelationMasterColumns; + + OUString m_sDetailLabel; + OUString m_sMasterLabel; + + std::unique_ptr m_xExplanation; + std::unique_ptr m_xDetailLabel; + std::unique_ptr m_xMasterLabel; + std::unique_ptr m_xRow1; + std::unique_ptr m_xRow2; + std::unique_ptr m_xRow3; + std::unique_ptr m_xRow4; + std::unique_ptr m_xOK; + std::unique_ptr m_xSuggest; + + public: + FormLinkDialog( + weld::Window* _pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxDetailForm, + const css::uno::Reference< css::beans::XPropertySet >& _rxMasterForm, + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const OUString& _sExplanation = OUString(), + const OUString& _sDetailLabel = OUString(), + const OUString& _sMasterLabel = OUString() + ); + + virtual ~FormLinkDialog() override; + + // Dialog overridables + virtual short run() override; + + private: + DECL_LINK( OnSuggest, weld::Button&, void ); + DECL_LINK( OnFieldChanged, FieldLinkRow&, void ); + DECL_LINK( OnInitialize, void*, void); + + void updateOkButton(); + void initializeFieldLists(); + void initializeColumnLabels(); + void initializeLinks(); + void initializeSuggest(); + void commitLinkPairs(); + + void initializeFieldRowsFrom( + std::vector< OUString >& _rDetailFields, + std::vector< OUString >& _rMasterFields + ); + + static OUString getFormDataSourceType( + const css::uno::Reference< css::beans::XPropertySet >& _rxForm + ); + + void getFormFields( + const css::uno::Reference< css::beans::XPropertySet >& _rxForm, + css::uno::Sequence< OUString >& /* [out] */ _rNames + ) const; + + void ensureFormConnection( + const css::uno::Reference< css::beans::XPropertySet >& _rxFormProps, + css::uno::Reference< css::sdbc::XConnection >& /* [out] */ _rxConnection + ) const; + + static void getConnectionMetaData( + const css::uno::Reference< css::beans::XPropertySet >& _rxFormProps, + css::uno::Reference< css::sdbc::XDatabaseMetaData >& /* [out] */ _rxMeta + ); + + css::uno::Reference< css::beans::XPropertySet > + getCanonicUnderlyingTable( const css::uno::Reference< css::beans::XPropertySet >& _rxFormProps ) const; + static bool getExistingRelation( + const css::uno::Reference< css::beans::XPropertySet >& _rxLHS, + const css::uno::Reference< css::beans::XPropertySet >& _rxRHS, + std::vector< OUString >& /* [out] */ _rLeftFields, + std::vector< OUString >& /* [out] */ _rRightFields + ); + }; + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formmetadata.cxx b/extensions/source/propctrlr/formmetadata.cxx new file mode 100644 index 000000000..13a7b32e7 --- /dev/null +++ b/extensions/source/propctrlr/formmetadata.cxx @@ -0,0 +1,694 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "formmetadata.hxx" +#include "formstrings.hxx" +#include "modulepcr.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pcr +{ + using namespace ::com::sun::star::uno; + + + //= OPropertyInfoImpl + + struct OPropertyInfoImpl + { + OUString sName; + OUString sTranslation; + OUString sHelpId; + sal_Int32 nId; + sal_uInt16 nPos; + sal_uInt32 nUIFlags; + + OPropertyInfoImpl( + const OUString& rName, + sal_Int32 _nId, + const OUString& aTranslation, + sal_uInt16 nPosId, + const OUString&, + sal_uInt32 _nUIFlags); + }; + + + OPropertyInfoImpl::OPropertyInfoImpl(const OUString& _rName, sal_Int32 _nId, + const OUString& aString, sal_uInt16 nP, const OUString& sHid, sal_uInt32 _nUIFlags) + :sName(_rName) + ,sTranslation(aString) + ,sHelpId(sHid) + ,nId(_nId) + ,nPos(nP) + ,nUIFlags(_nUIFlags) + { + } + + namespace { + + // Compare PropertyInfo + struct PropertyInfoLessByName + { + bool operator()( const OPropertyInfoImpl& _rLHS, const OPropertyInfoImpl& _rRHS ) + { + return _rLHS.sName.compareTo( _rRHS.sName ) < 0; + } + }; + + } + + //= OPropertyInfoService + +#define DEF_INFO( ident, uinameres, pos, helpid, flags ) \ + OPropertyInfoImpl( PROPERTY_##ident, PROPERTY_ID_##ident, \ + PcrRes( RID_STR_##uinameres ), pos, HID_PROP_##helpid, flags ) + +#define DEF_INFO_1( ident, uinameres, pos, helpid, flag1 ) \ + DEF_INFO( ident, uinameres, pos, helpid, PROP_FLAG_##flag1 ) + +#define DEF_INFO_2( ident, uinameres, pos, helpid, flag1, flag2 ) \ + DEF_INFO( ident, uinameres, pos, helpid, PROP_FLAG_##flag1 | PROP_FLAG_##flag2 ) + +#define DEF_INFO_3( ident, uinameres, pos, helpid, flag1, flag2, flag3 ) \ + DEF_INFO( ident, uinameres, pos, helpid, PROP_FLAG_##flag1 | PROP_FLAG_##flag2 | PROP_FLAG_##flag3 ) + +#define DEF_INFO_4( ident, uinameres, pos, helpid, flag1, flag2, flag3, flag4 ) \ + DEF_INFO( ident, uinameres, pos, helpid, PROP_FLAG_##flag1 | PROP_FLAG_##flag2 | PROP_FLAG_##flag3 | PROP_FLAG_##flag4 ) + + sal_uInt16 OPropertyInfoService::s_nCount = 0; + OPropertyInfoImpl* OPropertyInfoService::s_pPropertyInfos = nullptr; + + const OPropertyInfoImpl* OPropertyInfoService::getPropertyInfo() + { + if ( s_pPropertyInfos ) + return s_pPropertyInfos; + + static OPropertyInfoImpl aPropertyInfos[] = + { + /* + DEF_INFO_?( propname and id, resource id, pos, help id, flags ), + */ + DEF_INFO_3( NAME, NAME, 0, NAME, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( TITLE, TITLE, 1, TITLE, FORM_VISIBLE, DIALOG_VISIBLE ), + DEF_INFO_3( LABEL, LABEL, 2, LABEL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( CONTROLLABEL, LABELCONTROL, 3, CONTROLLABEL, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( WRITING_MODE, WRITING_MODE, 4, WRITING_MODE, FORM_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( GROUP_NAME, GROUP_NAME, 5, GROUP_NAME, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( TEXT, TEXT, 6, TEXT, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( MAXTEXTLEN, MAXTEXTLEN, 7, MAXTEXTLEN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( EDITMASK, EDITMASK, 8, EDITMASK, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( LITERALMASK, LITERALMASK, 9, LITERALMASK, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( STRICTFORMAT, STRICTFORMAT, 10, STRICTFORMAT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( ENABLED, ENABLED, 11, ENABLED, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( ENABLE_VISIBLE, ENABLE_VISIBLE, 12, ENABLE_VISIBLE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( READONLY, READONLY, 13, READONLY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( PRINTABLE, PRINTABLE, 14, PRINTABLE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( STEP, STEP, 15, STEP, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( WHEEL_BEHAVIOR, WHEEL_BEHAVIOR, 16, WHEEL_BEHAVIOR, FORM_VISIBLE | PROP_FLAG_REPORT_INVISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( TABSTOP, TABSTOP, 17, TABSTOP, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( TABINDEX, TABINDEX, 18, TABINDEX, FORM_VISIBLE, DIALOG_VISIBLE ), + + DEF_INFO_2( BOUND_CELL, BOUND_CELL, 19, BOUND_CELL, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_3( CELL_EXCHANGE_TYPE,CELL_EXCHANGE_TYPE, 20, CELL_EXCHANGE_TYPE,FORM_VISIBLE, DATA_PROPERTY, ENUM ), + DEF_INFO_2( LIST_CELL_RANGE, LIST_CELL_RANGE, 21, LIST_CELL_RANGE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_3( CONTROLSOURCE, CONTROLSOURCE, 22, CONTROLSOURCE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( EMPTY_IS_NULL, EMPTY_IS_NULL, 23, EMPTY_IS_NULL, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( INPUT_REQUIRED, INPUT_REQUIRED, 24, INPUT_REQUIRED, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( REFVALUE, REFVALUE, 25, REFVALUE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( UNCHECKEDREFVALUE, UNCHECKEDREFVALUE, 26, UNCHECKEDREFVALUE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( DATASOURCE, DATASOURCE, 27, DATASOURCE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_4( COMMANDTYPE, CURSORSOURCETYPE, 28, CURSORSOURCETYPE, FORM_VISIBLE, DATA_PROPERTY, ENUM, COMPOSEABLE ), + DEF_INFO_3( COMMAND, CURSORSOURCE, 29, CURSORSOURCE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( ESCAPE_PROCESSING, ESCAPE_PROCESSING, 30, ESCAPE_PROCESSING, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( FILTER, FILTER, 31, FILTER, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( SORT, SORT_CRITERIA, 32, SORT_CRITERIA, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_2( MASTERFIELDS, MASTERFIELDS, 33, MASTERFIELDS, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( DETAILFIELDS, SLAVEFIELDS, 34, SLAVEFIELDS, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_3( ALLOWADDITIONS, ALLOW_ADDITIONS, 35, ALLOW_ADDITIONS, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( ALLOWEDITS, ALLOW_EDITS, 36, ALLOW_EDITS, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( ALLOWDELETIONS, ALLOW_DELETIONS, 37, ALLOW_DELETIONS, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( INSERTONLY, DATAENTRY, 38, DATAENTRY, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_4( NAVIGATION, NAVIGATION, 39, NAVIGATION, FORM_VISIBLE, DATA_PROPERTY, ENUM, COMPOSEABLE ), + DEF_INFO_4( CYCLE, CYCLE, 40, CYCLE, FORM_VISIBLE, DATA_PROPERTY, ENUM, COMPOSEABLE ), + DEF_INFO_3( FILTERPROPOSAL, FILTERPROPOSAL, 41, FILTERPROPOSAL, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_4( LISTSOURCETYPE, LISTSOURCETYPE, 42, LISTSOURCETYPE, FORM_VISIBLE, DATA_PROPERTY, ENUM, COMPOSEABLE ), + DEF_INFO_3( LISTSOURCE, LISTSOURCE, 43, LISTSOURCE, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + DEF_INFO_3( BOUNDCOLUMN, BOUNDCOLUMN, 44, BOUNDCOLUMN, FORM_VISIBLE, DATA_PROPERTY, COMPOSEABLE ), + + // + // XML node binding + DEF_INFO_2( LIST_BINDING, LIST_BINDING, 45, LIST_BINDING, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XML_DATA_MODEL, XML_DATA_MODEL, 46, XML_DATA_MODEL, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( BINDING_NAME, BINDING_NAME, 47, BINDING_NAME, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( BIND_EXPRESSION, BIND_EXPRESSION, 48, BIND_EXPRESSION, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_REQUIRED, XSD_REQUIRED, 49, XSD_REQUIRED, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_RELEVANT, XSD_RELEVANT, 50, XSD_RELEVANT, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_READONLY, XSD_READONLY, 51, XSD_READONLY, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_CONSTRAINT, XSD_CONSTRAINT, 52, XSD_CONSTRAINT, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_CALCULATION, XSD_CALCULATION, 53, XSD_CALCULATION, FORM_VISIBLE, DATA_PROPERTY ), + + // data type + DEF_INFO_2( XSD_DATA_TYPE, XSD_DATA_TYPE, 54, XSD_DATA_TYPE, FORM_VISIBLE, DATA_PROPERTY ), + // data types facets + // common + DEF_INFO_3( XSD_WHITESPACES, XSD_WHITESPACES, 55, XSD_WHITESPACES, FORM_VISIBLE, DATA_PROPERTY, ENUM ), + DEF_INFO_2( XSD_PATTERN, XSD_PATTERN, 56, XSD_PATTERN, FORM_VISIBLE, DATA_PROPERTY ), + // string + DEF_INFO_2( XSD_LENGTH, XSD_LENGTH, 57, XSD_LENGTH, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_LENGTH, XSD_MIN_LENGTH, 58, XSD_MIN_LENGTH, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MAX_LENGTH, XSD_MAX_LENGTH, 59, XSD_MAX_LENGTH, FORM_VISIBLE, DATA_PROPERTY ), + // decimal + DEF_INFO_2( XSD_TOTAL_DIGITS, XSD_TOTAL_DIGITS, 60, XSD_TOTAL_DIGITS, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_FRACTION_DIGITS,XSD_FRACTION_DIGITS,61,XSD_FRACTION_DIGITS,FORM_VISIBLE, DATA_PROPERTY ), + // int value types (year, month, day) + DEF_INFO_2( XSD_MAX_INCLUSIVE_INT, XSD_MAX_INCLUSIVE, 62, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MAX_EXCLUSIVE_INT, XSD_MAX_EXCLUSIVE, 63, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_INCLUSIVE_INT, XSD_MIN_INCLUSIVE, 64, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_EXCLUSIVE_INT, XSD_MIN_EXCLUSIVE, 65, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + // double value types (double, float, decimal) + DEF_INFO_2( XSD_MAX_INCLUSIVE_DOUBLE, XSD_MAX_INCLUSIVE, 66, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MAX_EXCLUSIVE_DOUBLE, XSD_MAX_EXCLUSIVE, 67, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_INCLUSIVE_DOUBLE, XSD_MIN_INCLUSIVE, 68, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_EXCLUSIVE_DOUBLE, XSD_MIN_EXCLUSIVE, 69, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + // date value type + DEF_INFO_2( XSD_MAX_INCLUSIVE_DATE, XSD_MAX_INCLUSIVE, 70, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MAX_EXCLUSIVE_DATE, XSD_MAX_EXCLUSIVE, 71, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_INCLUSIVE_DATE, XSD_MIN_INCLUSIVE, 72, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_EXCLUSIVE_DATE, XSD_MIN_EXCLUSIVE, 73, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + // time value type + DEF_INFO_2( XSD_MAX_INCLUSIVE_TIME, XSD_MAX_INCLUSIVE, 74, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MAX_EXCLUSIVE_TIME, XSD_MAX_EXCLUSIVE, 75, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_INCLUSIVE_TIME, XSD_MIN_INCLUSIVE, 76, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_EXCLUSIVE_TIME, XSD_MIN_EXCLUSIVE, 77, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + // dateTime value type + DEF_INFO_2( XSD_MAX_INCLUSIVE_DATE_TIME, XSD_MAX_INCLUSIVE, 78, XSD_MAX_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MAX_EXCLUSIVE_DATE_TIME, XSD_MAX_EXCLUSIVE, 79, XSD_MAX_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_INCLUSIVE_DATE_TIME, XSD_MIN_INCLUSIVE, 80, XSD_MIN_INCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + DEF_INFO_2( XSD_MIN_EXCLUSIVE_DATE_TIME, XSD_MIN_EXCLUSIVE, 81, XSD_MIN_EXCLUSIVE, FORM_VISIBLE, DATA_PROPERTY ), + // + + DEF_INFO_2( HIDDEN_VALUE, VALUE, 82, HIDDEN_VALUE, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( VALUE, VALUE, 83, VALUE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( VALUEMIN, VALUEMIN, 84, VALUEMIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( VALUEMAX, VALUEMAX, 85, VALUEMAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( VALUESTEP, VALUESTEP, 86, VALUESTEP, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( DEFAULT_VALUE, DEFAULTVALUE, 87, DEFAULT_LONG_VALUE,FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( DECIMAL_ACCURACY, DECIMAL_ACCURACY, 88, DECIMAL_ACCURACY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SHOWTHOUSANDSEP, SHOWTHOUSANDSEP, 89, SHOWTHOUSANDSEP, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + + DEF_INFO_3( CURRENCYSYMBOL, CURRENCYSYMBOL, 90, CURRENCYSYMBOL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( CURRSYM_POSITION, CURRSYM_POSITION, 91, CURRSYM_POSITION, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + + DEF_INFO_2( DATE, DATE, 92, DATE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( DATEMIN, DATEMIN, 93, DATEMIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( DATEMAX, DATEMAX, 94, DATEMAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_4( DATEFORMAT, DATEFORMAT, 95, DATEFORMAT, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_2( DEFAULT_DATE, DEFAULTDATE, 96, DEFAULT_DATE, FORM_VISIBLE, COMPOSEABLE ), + + DEF_INFO_2( TIME, TIME, 97, TIME, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( TIMEMIN, TIMEMIN, 98, TIMEMIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( TIMEMAX, TIMEMAX, 99, TIMEMAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_4( TIMEFORMAT, TIMEFORMAT, 100, TIMEFORMAT, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_2( DEFAULT_TIME, DEFAULTTIME, 101, DEFAULT_TIME, FORM_VISIBLE, COMPOSEABLE ), + + DEF_INFO_1( EFFECTIVE_VALUE, VALUE, 102, VALUE, DIALOG_VISIBLE ), + DEF_INFO_3( EFFECTIVE_MIN, VALUEMIN, 103, EFFECTIVEMIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( EFFECTIVE_MAX, VALUEMAX, 104, EFFECTIVEMAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( EFFECTIVE_DEFAULT, DEFAULTVALUE, 105, EFFECTIVEDEFAULT, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( FORMATKEY, FORMATKEY, 106, FORMATKEY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + + DEF_INFO_3( PROGRESSVALUE, PROGRESSVALUE, 107, PROGRESSVALUE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( PROGRESSVALUE_MIN, PROGRESSVALUE_MIN, 108, PROGRESSVALUE_MIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( PROGRESSVALUE_MAX, PROGRESSVALUE_MAX, 109, PROGRESSVALUE_MAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + + DEF_INFO_2( SCROLLVALUE, SCROLLVALUE, 110, SCROLLVALUE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SCROLLVALUE_MIN, SCROLLVALUE_MIN, 111, SCROLLVALUE_MIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SCROLLVALUE_MAX, SCROLLVALUE_MAX, 112, SCROLLVALUE_MAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SCROLL_WIDTH, SCROLL_WIDTH, 113, SCROLL_WIDTH, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SCROLL_HEIGHT, SCROLL_HEIGHT, 114, SCROLL_HEIGHT, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SCROLL_TOP, SCROLL_TOP, 115, SCROLL_TOP, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SCROLL_LEFT, SCROLL_LEFT, 116, SCROLL_LEFT, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( DEFAULT_SCROLLVALUE,DEFAULT_SCROLLVALUE,117,DEFAULT_SCROLLVALUE,FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( LINEINCREMENT, LINEINCREMENT, 118, LINEINCREMENT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( BLOCKINCREMENT, BLOCKINCREMENT, 119, BLOCKINCREMENT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + + DEF_INFO_2( SPINVALUE, VALUE, 120, SPINVALUE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SPINVALUE_MIN, VALUEMIN, 121, SPINVALUE_MIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SPINVALUE_MAX, VALUEMAX, 122, SPINVALUE_MAX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( DEFAULT_SPINVALUE,DEFAULTVALUE, 123, DEFAULT_SPINVALUE, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SPININCREMENT, VALUESTEP, 124, SPININCREMENT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + + DEF_INFO_3( SPIN, SPIN, 125, SPIN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( REPEAT, REPEAT, 126, REPEAT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( REPEAT_DELAY, REPEAT_DELAY, 127, REPEAT_DELAY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( VISIBLESIZE, VISIBLESIZE, 128, VISIBLESIZE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_4( ORIENTATION, ORIENTATION, 129, ORIENTATION, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( FOCUSONCLICK, FOCUSONCLICK, 130, FOCUSONCLICK, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( TOGGLE, TOGGLE, 131, TOGGLE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( DEFAULT_STATE, DEFAULT_STATE, 132, DEFAULT_STATE, FORM_VISIBLE, ENUM, COMPOSEABLE ), + + DEF_INFO_3( TEXT_ANCHOR_TYPE, ANCHOR_TYPE, 133, ANCHOR_TYPE, FORM_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( SHEET_ANCHOR_TYPE, ANCHOR_TYPE, 134, ANCHOR_TYPE, FORM_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( POSITIONX, POSITIONX, 135, POSITIONX, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( POSITIONY, POSITIONY, 136, POSITIONY, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( WIDTH, WIDTH, 137, WIDTH, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( HEIGHT, HEIGHT, 138, HEIGHT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + + DEF_INFO_1( LISTINDEX, LISTINDEX, 139, LISTINDEX, FORM_VISIBLE ), + DEF_INFO_3( STRINGITEMLIST, STRINGITEMLIST, 140, STRINGITEMLIST, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( DEFAULT_TEXT, DEFAULTTEXT, 141, DEFAULTVALUE, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( FONT, FONT, 142, FONT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_4( VISUALEFFECT, VISUALEFFECT, 143, VISUALEFFECT, FORM_VISIBLE, DIALOG_VISIBLE, ENUM_ONE, COMPOSEABLE ), + DEF_INFO_4( ALIGN, ALIGN, 144, ALIGN, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_4( VERTICAL_ALIGN, VERTICAL_ALIGN, 145, VERTICAL_ALIGN, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( ROWHEIGHT, ROWHEIGHT, 146, ROWHEIGHT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( BACKGROUNDCOLOR, BACKGROUNDCOLOR, 147, BACKGROUNDCOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SYMBOLCOLOR, SYMBOLCOLOR, 148, SYMBOLCOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( FILLCOLOR, FILLCOLOR, 149, FILLCOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( LINECOLOR, LINECOLOR, 150, LINECOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_4( BORDER, BORDER, 151, BORDER, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( BORDERCOLOR, BORDERCOLOR, 152, BORDERCOLOR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( ICONSIZE, ICONSIZE, 153, ICONSIZE, FORM_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_2( SHOW_POSITION, SHOW_POSITION, 154, SHOW_POSITION, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SHOW_NAVIGATION, SHOW_NAVIGATION, 155, SHOW_NAVIGATION, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SHOW_RECORDACTIONS,SHOW_RECORDACTIONS, 156, SHOW_RECORDACTIONS,FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SHOW_FILTERSORT, SHOW_FILTERSORT, 157, SHOW_FILTERSORT, FORM_VISIBLE, COMPOSEABLE ), + + DEF_INFO_3( DROPDOWN, DROPDOWN, 158, DROPDOWN, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( LINECOUNT, LINECOUNT, 159, LINECOUNT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( AUTOCOMPLETE, AUTOCOMPLETE, 160, AUTOCOMPLETE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( MULTILINE, MULTILINE, 161, MULTILINE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( WORDBREAK, WORDBREAK, 162, WORDBREAK, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( TEXTTYPE, TEXTTYPE, 163, TEXTTYPE, FORM_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( LINEEND_FORMAT, LINEEND_FORMAT, 164, LINEEND_FORMAT, FORM_VISIBLE, ENUM_ONE, COMPOSEABLE ), + DEF_INFO_3( MULTISELECTION, MULTISELECTION, 165, MULTISELECTION, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_4( SHOW_SCROLLBARS, SHOW_SCROLLBARS, 166, SHOW_SCROLLBARS, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( HSCROLL, HSCROLL, 167, HSCROLL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( VSCROLL, VSCROLL, 168, VSCROLL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( BUTTONTYPE, BUTTONTYPE, 169, BUTTONTYPE, FORM_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_2( XFORMS_BUTTONTYPE, BUTTONTYPE, 170, BUTTONTYPE, FORM_VISIBLE, ENUM ), + DEF_INFO_1( SUBMISSION_ID, SUBMISSION_ID, 171, SUBMISSION_ID, FORM_VISIBLE ), + DEF_INFO_2( PUSHBUTTONTYPE, PUSHBUTTONTYPE, 172, PUSHBUTTONTYPE, DIALOG_VISIBLE, ENUM ), + DEF_INFO_2( TARGET_URL, TARGET_URL, 173, TARGET_URL, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_1( TARGET_FRAME, TARGET_FRAME, 174, TARGET_FRAME, FORM_VISIBLE ), + DEF_INFO_2( SUBMIT_ACTION, SUBMIT_ACTION, 175, SUBMIT_ACTION, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SUBMIT_TARGET, SUBMIT_TARGET, 176, SUBMIT_TARGET, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SUBMIT_ENCODING, SUBMIT_ENCODING, 177, SUBMIT_ENCODING, FORM_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( SUBMIT_METHOD, SUBMIT_METHOD, 178, SUBMIT_METHOD, FORM_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( STATE, STATE, 179, STATE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( DEFAULTBUTTON, DEFAULT_BUTTON, 180, DEFAULT_BUTTON, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( IMAGE_URL, IMAGE_URL, 181, IMAGE_URL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_4( IMAGEPOSITION, IMAGEPOSITION, 182, IMAGEPOSITION, FORM_VISIBLE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_3( SCALEIMAGE, SCALEIMAGE, 183, SCALEIMAGE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_4( SCALE_MODE, SCALEIMAGE, 184, SCALEIMAGE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE, ENUM ), + DEF_INFO_2( DEFAULT_SELECT_SEQ,DEFAULT_SELECT_SEQ, 185, DEFAULT_SELECT_SEQ,FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SELECTEDITEMS, SELECTEDITEMS, 186, SELECTEDITEMS, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( ECHO_CHAR, ECHO_CHAR, 187, ECHO_CHAR, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( HIDEINACTIVESELECTION, HIDEINACTIVESELECTION, 188, HIDEINACTIVESELECTION, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( TRISTATE, TRISTATE, 189, TRISTATE, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( HASNAVIGATION, NAVIGATION, 190, NAVIGATIONBAR, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( RECORDMARKER, RECORDMARKER, 191, RECORDMARKER, FORM_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( TAG, TAG, 192, TAG, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( HELPTEXT, HELPTEXT, 193, HELPTEXT, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( HELPURL, HELPURL, 194, HELPURL, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SELECTION_TYPE, SELECTION_TYPE, 195, SELECTION_TYPE, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_2( ROOT_DISPLAYED, ROOT_DISPLAYED, 196, ROOT_DISPLAYED, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SHOWS_HANDLES, SHOWS_HANDLES, 197, SHOWS_HANDLES, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SHOWS_ROOT_HANDLES, SHOWS_ROOT_HANDLES, 198, SHOWS_ROOT_HANDLES, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( EDITABLE, EDITABLE, 199, EDITABLE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( INVOKES_STOP_NOT_EDITING, INVOKES_STOP_NOT_EDITING, 200, INVOKES_STOP_NOT_EDITING, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( DECORATION, DECORATION, 201, DECORATION, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( NOLABEL, NOLABEL, 202, NOLABEL, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_3( SELECTIONMODEL, SELECTIONMODEL, 203, SELECTIONMODEL, DIALOG_VISIBLE, ENUM, COMPOSEABLE ), + DEF_INFO_2( USEGRIDLINE, USEGRIDLINE, 204, USEGRIDLINE, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( GRIDLINECOLOR, GRIDLINECOLOR, 205, GRIDLINECOLOR, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SHOWCOLUMNHEADER, SHOWCOLUMNHEADER, 206, SHOWCOLUMNHEADER, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( SHOWROWHEADER, SHOWROWHEADER, 207, SHOWROWHEADER, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( HEADERBACKGROUNDCOLOR, HEADERBACKGROUNDCOLOR, 208, HEADERBACKGROUNDCOLOR, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( HEADERTEXTCOLOR, HEADERTEXTCOLOR, 209, HEADERTEXTCOLOR, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( ACTIVESELECTIONBACKGROUNDCOLOR, ACTIVESELECTIONBACKGROUNDCOLOR, 210, ACTIVESELECTIONBACKGROUNDCOLOR, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( ACTIVESELECTIONTEXTCOLOR, ACTIVESELECTIONTEXTCOLOR, 211, ACTIVESELECTIONTEXTCOLOR, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( INACTIVESELECTIONBACKGROUNDCOLOR, INACTIVESELECTIONBACKGROUNDCOLOR, 212, INACTIVESELECTIONBACKGROUNDCOLOR, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( INACTIVESELECTIONTEXTCOLOR, INACTIVESELECTIONTEXTCOLOR, 213, INACTIVESELECTIONTEXTCOLOR, DIALOG_VISIBLE, COMPOSEABLE ), + DEF_INFO_2( URL, URL, 214, URL, DIALOG_VISIBLE, COMPOSEABLE ), + + DEF_INFO_3( AUTOGROW, AUTOGROW, 215, AUTOGROW, FORM_VISIBLE, DIALOG_VISIBLE, COMPOSEABLE) + }; + + s_pPropertyInfos = aPropertyInfos; + s_nCount = SAL_N_ELEMENTS(aPropertyInfos); + + // sort + std::sort( s_pPropertyInfos, s_pPropertyInfos + s_nCount, PropertyInfoLessByName() ); + +#if OSL_DEBUG_LEVEL > 0 + for ( const OPropertyInfoImpl* pCheck = s_pPropertyInfos; pCheck != s_pPropertyInfos + s_nCount - 1; ++pCheck ) + { + OSL_ENSURE( pCheck->sName != ( pCheck + 1 )->sName, "OPropertyInfoService::getPropertyInfo: duplicate entry in the table!" ); + } +#endif + + return s_pPropertyInfos; + } + + + sal_Int32 OPropertyInfoService::getPropertyId(const OUString& _rName) const + { + const OPropertyInfoImpl* pInfo = getPropertyInfo(_rName); + return pInfo ? pInfo->nId : -1; + } + + + OUString OPropertyInfoService::getPropertyTranslation(sal_Int32 _nId) const + { + const OPropertyInfoImpl* pInfo = getPropertyInfo(_nId); + return pInfo ? pInfo->sTranslation : OUString(); + } + + OUString OPropertyInfoService::getPropertyHelpId(sal_Int32 _nId) const + { + const OPropertyInfoImpl* pInfo = getPropertyInfo(_nId); + return pInfo ? pInfo->sHelpId : OUString(); + } + + sal_Int16 OPropertyInfoService::getPropertyPos(sal_Int32 _nId) const + { + const OPropertyInfoImpl* pInfo = getPropertyInfo(_nId); + return pInfo ? pInfo->nPos : 0xFFFF; + } + + sal_uInt32 OPropertyInfoService::getPropertyUIFlags(sal_Int32 _nId) const + { + const OPropertyInfoImpl* pInfo = getPropertyInfo(_nId); + return pInfo ? pInfo->nUIFlags : 0; + } + + std::vector< OUString > OPropertyInfoService::getPropertyEnumRepresentations(sal_Int32 _nId) const + { + OSL_ENSURE( ( ( getPropertyUIFlags( _nId ) & PROP_FLAG_ENUM ) != 0 ) || ( _nId == PROPERTY_ID_TARGET_FRAME ), + "OPropertyInfoService::getPropertyEnumRepresentations: this is no enum property!" ); + + if (_nId == PROPERTY_ID_SUBMIT_METHOD) + { + return { "Get", "Post" }; + } + const TranslateId* pStringItemsResId = nullptr; + int nElements = 0; + switch ( _nId ) + { + case PROPERTY_ID_IMAGEPOSITION: + pStringItemsResId = RID_RSC_ENUM_IMAGE_POSITION; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_IMAGE_POSITION); + break; + case PROPERTY_ID_BORDER: + pStringItemsResId = RID_RSC_ENUM_BORDER_TYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_BORDER_TYPE); + break; + case PROPERTY_ID_ICONSIZE: + pStringItemsResId = RID_RSC_ENUM_ICONSIZE_TYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_ICONSIZE_TYPE); + break; + case PROPERTY_ID_COMMANDTYPE: + pStringItemsResId = RID_RSC_ENUM_COMMAND_TYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_COMMAND_TYPE); + break; + case PROPERTY_ID_LISTSOURCETYPE: + pStringItemsResId = RID_RSC_ENUM_LISTSOURCE_TYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_LISTSOURCE_TYPE); + break; + case PROPERTY_ID_ALIGN: + pStringItemsResId = RID_RSC_ENUM_ALIGNMENT; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_ALIGNMENT); + break; + case PROPERTY_ID_VERTICAL_ALIGN: + pStringItemsResId = RID_RSC_ENUM_VERTICAL_ALIGN; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_VERTICAL_ALIGN); + break; + case PROPERTY_ID_BUTTONTYPE: + pStringItemsResId = RID_RSC_ENUM_BUTTONTYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_BUTTONTYPE); + break; + case PROPERTY_ID_PUSHBUTTONTYPE: + pStringItemsResId = RID_RSC_ENUM_PUSHBUTTONTYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_PUSHBUTTONTYPE); + break; + case PROPERTY_ID_SUBMIT_ENCODING: + pStringItemsResId = RID_RSC_ENUM_SUBMIT_ENCODING; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SUBMIT_ENCODING); + break; + case PROPERTY_ID_DATEFORMAT: + pStringItemsResId = RID_RSC_ENUM_DATEFORMAT_LIST; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_DATEFORMAT_LIST); + break; + case PROPERTY_ID_TIMEFORMAT: + pStringItemsResId = RID_RSC_ENUM_TIMEFORMAT_LIST; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_TIMEFORMAT_LIST); + break; + case PROPERTY_ID_DEFAULT_STATE: + case PROPERTY_ID_STATE: + pStringItemsResId = RID_RSC_ENUM_CHECKED; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_CHECKED); + break; + case PROPERTY_ID_CYCLE: + pStringItemsResId = RID_RSC_ENUM_CYCLE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_CYCLE); + break; + case PROPERTY_ID_NAVIGATION: + pStringItemsResId = RID_RSC_ENUM_NAVIGATION; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_NAVIGATION); + break; + case PROPERTY_ID_TARGET_FRAME: + pStringItemsResId = RID_RSC_ENUM_SUBMIT_TARGET; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SUBMIT_TARGET); + break; + case PROPERTY_ID_ORIENTATION: + pStringItemsResId = RID_RSC_ENUM_ORIENTATION; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_ORIENTATION); + break; + case PROPERTY_ID_CELL_EXCHANGE_TYPE: + pStringItemsResId = RID_RSC_ENUM_CELL_EXCHANGE_TYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_CELL_EXCHANGE_TYPE); + break; + case PROPERTY_ID_SHOW_SCROLLBARS: + pStringItemsResId = RID_RSC_ENUM_SCROLLBARS; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SCROLLBARS); + break; + case PROPERTY_ID_VISUALEFFECT: + pStringItemsResId = RID_RSC_ENUM_VISUALEFFECT; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_VISUALEFFECT); + break; + case PROPERTY_ID_TEXTTYPE: + pStringItemsResId = RID_RSC_ENUM_TEXTTYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_TEXTTYPE); + break; + case PROPERTY_ID_LINEEND_FORMAT: + pStringItemsResId = RID_RSC_ENUM_LINEEND_FORMAT; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_LINEEND_FORMAT); + break; + case PROPERTY_ID_XSD_WHITESPACES: + pStringItemsResId = RID_RSC_ENUM_WHITESPACE_HANDLING; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_WHITESPACE_HANDLING); + break; + case PROPERTY_ID_SELECTION_TYPE: + case PROPERTY_ID_SELECTIONMODEL: + pStringItemsResId = RID_RSC_ENUM_SELECTION_TYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SELECTION_TYPE); + break; + case PROPERTY_ID_SCALE_MODE: + pStringItemsResId = RID_RSC_ENUM_SCALE_MODE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SCALE_MODE); + break; + case PROPERTY_ID_WRITING_MODE: + pStringItemsResId = RID_RSC_ENUM_WRITING_MODE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_WRITING_MODE); + break; + case PROPERTY_ID_WHEEL_BEHAVIOR: + pStringItemsResId = RID_RSC_ENUM_WHEEL_BEHAVIOR; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_WHEEL_BEHAVIOR); + break; + case PROPERTY_ID_TEXT_ANCHOR_TYPE: + pStringItemsResId = RID_RSC_ENUM_TEXT_ANCHOR_TYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_TEXT_ANCHOR_TYPE); + break; + case PROPERTY_ID_SHEET_ANCHOR_TYPE: + pStringItemsResId = RID_RSC_ENUM_SHEET_ANCHOR_TYPE; + nElements = SAL_N_ELEMENTS(RID_RSC_ENUM_SHEET_ANCHOR_TYPE); + break; + default: + OSL_FAIL( "OPropertyInfoService::getPropertyEnumRepresentations: unknown enum property!" ); + break; + } + + std::vector< OUString > aReturn; + + aReturn.reserve(nElements); + for (int i = 0; i < nElements; ++i) + { + aReturn.push_back(PcrRes(pStringItemsResId[i])); + } + + return aReturn; + } + + bool OPropertyInfoService::isComposeable( const OUString& _rPropertyName ) const + { + sal_Int32 nId = getPropertyId( _rPropertyName ); + if ( nId == -1 ) + return false; + + sal_uInt32 nFlags = getPropertyUIFlags( nId ); + return ( nFlags & PROP_FLAG_COMPOSEABLE ) != 0; + } + + + const OPropertyInfoImpl* OPropertyInfoService::getPropertyInfo(const OUString& _rName) + { + // Initialization + if(!s_pPropertyInfos) + getPropertyInfo(); + OPropertyInfoImpl aSearch(_rName, 0, OUString(), 0, "", 0); + + const OPropertyInfoImpl* pInfo = std::lower_bound( + s_pPropertyInfos, s_pPropertyInfos + s_nCount, aSearch, PropertyInfoLessByName() ); + + if ( pInfo == s_pPropertyInfos + s_nCount ) + return nullptr; + + if ( pInfo->sName != _rName ) + return nullptr; + + return pInfo; + } + + + const OPropertyInfoImpl* OPropertyInfoService::getPropertyInfo(sal_Int32 _nId) + { + // Initialization + if(!s_pPropertyInfos) + getPropertyInfo(); + + // TODO: a real structure which allows quick access by name as well as by id + for (sal_uInt16 i = 0; i < s_nCount; i++) + if (s_pPropertyInfos[i].nId == _nId) + return &s_pPropertyInfos[i]; + + return nullptr; + } + + + //= DefaultEnumRepresentation + + + DefaultEnumRepresentation::DefaultEnumRepresentation( const IPropertyInfoService& _rInfo, const Type& _rType, sal_Int32 _nPropertyId ) + :m_rMetaData( _rInfo ) + ,m_aType( _rType ) + ,m_nPropertyId( _nPropertyId ) + { + } + + + DefaultEnumRepresentation::~DefaultEnumRepresentation() + { + } + + + std::vector< OUString > DefaultEnumRepresentation::getDescriptions() const + { + return m_rMetaData.getPropertyEnumRepresentations( m_nPropertyId ); + } + + + void DefaultEnumRepresentation::getValueFromDescription( const OUString& _rDescription, Any& _out_rValue ) const + { + sal_uInt32 nPropertyUIFlags = m_rMetaData.getPropertyUIFlags( m_nPropertyId ); + std::vector< OUString > aEnumStrings = m_rMetaData.getPropertyEnumRepresentations( m_nPropertyId ); + std::vector< OUString >::const_iterator pos = std::find( aEnumStrings.begin(), aEnumStrings.end(), _rDescription ); + if ( pos != aEnumStrings.end() ) + { + sal_Int32 nPos = pos - aEnumStrings.begin(); + if ( ( nPropertyUIFlags & PROP_FLAG_ENUM_ONE ) == PROP_FLAG_ENUM_ONE ) + // enum value starting with 1 + ++nPos; + + switch ( m_aType.getTypeClass() ) + { + case TypeClass_ENUM: + _out_rValue = ::cppu::int2enum( nPos, m_aType ); + break; + + case TypeClass_SHORT: + _out_rValue <<= static_cast(nPos); + break; + + case TypeClass_UNSIGNED_SHORT: + _out_rValue <<= static_cast(nPos); + break; + + case TypeClass_UNSIGNED_LONG: + _out_rValue <<= static_cast(nPos); + break; + + default: + _out_rValue <<= nPos; + break; + } + } + else + { + OSL_FAIL( "DefaultEnumRepresentation::getValueFromDescription: could not translate the enum string!" ); + _out_rValue.clear(); + } + } + + + OUString DefaultEnumRepresentation::getDescriptionForValue( const Any& _rEnumValue ) const + { + OUString sReturn; + sal_Int32 nIntValue = -1; + OSL_VERIFY( ::cppu::enum2int( nIntValue, _rEnumValue ) ); + + sal_uInt32 nUIFlags = m_rMetaData.getPropertyUIFlags( m_nPropertyId ); + if ( ( nUIFlags & PROP_FLAG_ENUM_ONE ) == PROP_FLAG_ENUM_ONE ) + // enum value starting with 1 + --nIntValue; + + std::vector< OUString > aEnumStrings = m_rMetaData.getPropertyEnumRepresentations( m_nPropertyId ); + if ( ( nIntValue >= 0 ) && ( o3tl::make_unsigned(nIntValue) < aEnumStrings.size() ) ) + { + sReturn = aEnumStrings[ nIntValue ]; + } + else + { + OSL_FAIL( "DefaultEnumRepresentation::getDescriptionForValue: could not translate an enum value" ); + } + return sReturn; + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formmetadata.hxx b/extensions/source/propctrlr/formmetadata.hxx new file mode 100644 index 000000000..0f7aa67d2 --- /dev/null +++ b/extensions/source/propctrlr/formmetadata.hxx @@ -0,0 +1,345 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "propertyinfo.hxx" +#include "enumrepresentation.hxx" + + +namespace pcr +{ + + + struct OPropertyInfoImpl; + + + //= OPropertyInfoService + + class OPropertyInfoService final + :public IPropertyInfoService + { + static sal_uInt16 s_nCount; + static OPropertyInfoImpl* s_pPropertyInfos; + // TODO: a real structure which allows quick access by name as well as by id + + public: + // IPropertyInfoService + virtual sal_Int32 getPropertyId(const OUString& _rName) const override; + virtual OUString getPropertyTranslation(sal_Int32 _nId) const override; + virtual OUString getPropertyHelpId(sal_Int32 _nId) const override; + virtual sal_Int16 getPropertyPos(sal_Int32 _nId) const override; + virtual sal_uInt32 getPropertyUIFlags(sal_Int32 _nId) const override; + virtual std::vector< OUString > getPropertyEnumRepresentations(sal_Int32 _nId) const override; + + bool isComposeable( const OUString& _rPropertyName ) const; + + private: + static const OPropertyInfoImpl* getPropertyInfo(); + + static const OPropertyInfoImpl* getPropertyInfo(const OUString& _rName); + static const OPropertyInfoImpl* getPropertyInfo(sal_Int32 _nId); + }; + + + //= DefaultEnumRepresentation + + /** an implementation of the IPropertyEnumRepresentation + + To be used with properties which, in formmetadata.cxx, are declared as ENUM. + */ + class DefaultEnumRepresentation : public IPropertyEnumRepresentation + { + private: + const IPropertyInfoService& m_rMetaData; + css::uno::Type m_aType; + const sal_Int32 m_nPropertyId; + + public: + /** constructs an instance + + @param _rInfo + An instance implementing IPropertyInfoService. Must live at least as + long as the DefaultEnumRepresentation should live. + */ + DefaultEnumRepresentation( const IPropertyInfoService& _rInfo, const css::uno::Type& _rType, sal_Int32 _nPropertyId ); + + protected: + virtual ~DefaultEnumRepresentation() override; + + protected: + // IPropertyEnumRepresentation implementqation + virtual std::vector< OUString > + getDescriptions() const override; + virtual void getValueFromDescription( const OUString& _rDescription, css::uno::Any& _out_rValue ) const override; + virtual OUString getDescriptionForValue( const css::uno::Any& _rEnumValue ) const override; + + private: + DefaultEnumRepresentation( const DefaultEnumRepresentation& ) = delete; + DefaultEnumRepresentation& operator=( const DefaultEnumRepresentation& ) = delete; + }; + + + //= UI flags (for all browsable properties) + + +#define PROP_FLAG_NONE 0x00000000 // no special flag +#define PROP_FLAG_FORM_VISIBLE 0x00000001 // the property is visible when inspecting a form object +#define PROP_FLAG_DIALOG_VISIBLE 0x00000002 // the property is visible when inspecting a dialog object +#define PROP_FLAG_DATA_PROPERTY 0x00000004 // the property is to appear on the "Data" page +#define PROP_FLAG_ENUM 0x00000020 // the property is some kind of enum property, i.e. its + // value is chosen from a fixed list of possible values +#define PROP_FLAG_ENUM_ONE 0x00000060 // the property is an enum property starting with 1 + // (note that this includes PROP_FLAG_ENUM) +#define PROP_FLAG_COMPOSEABLE 0x00000080 // the property is "composeable", i.e. an intersection of property + // sets should expose it, if all elements do +#define PROP_FLAG_EXPERIMENTAL 0x00000100 // the property is experimental, i.e. should not appear in the + // UI, unless experimental properties are enabled by a configuration + // option +#define PROP_FLAG_REPORT_INVISIBLE 0x00000200 // the property should not appear in the Report Designer UI + + + //= property ids (for all browsable properties) + + + #define PROPERTY_ID_NAME 1 + #define PROPERTY_ID_LABEL 2 + #define PROPERTY_ID_CONTROLLABEL 3 + #define PROPERTY_ID_MAXTEXTLEN 4 + #define PROPERTY_ID_EDITMASK 5 + #define PROPERTY_ID_LITERALMASK 6 + #define PROPERTY_ID_STRICTFORMAT 7 + #define PROPERTY_ID_ENABLED 8 + #define PROPERTY_ID_READONLY 9 + #define PROPERTY_ID_PRINTABLE 10 + #define PROPERTY_ID_CONTROLSOURCE 11 + #define PROPERTY_ID_TABSTOP 12 + #define PROPERTY_ID_TABINDEX 13 + #define PROPERTY_ID_DATASOURCE 14 + #define PROPERTY_ID_COMMAND 15 + #define PROPERTY_ID_COMMANDTYPE 16 + #define PROPERTY_ID_FILTER 17 + #define PROPERTY_ID_SORT 18 + #define PROPERTY_ID_INSERTONLY 19 + #define PROPERTY_ID_ALLOWADDITIONS 20 + #define PROPERTY_ID_ALLOWEDITS 21 + #define PROPERTY_ID_ALLOWDELETIONS 22 + #define PROPERTY_ID_GROUP_NAME 23 + #define PROPERTY_ID_NAVIGATION 24 + #define PROPERTY_ID_CYCLE 25 + #define PROPERTY_ID_HIDDEN_VALUE 26 + #define PROPERTY_ID_VALUEMIN 27 + #define PROPERTY_ID_VALUEMAX 28 + #define PROPERTY_ID_VALUESTEP 29 + #define PROPERTY_ID_DEFAULT_VALUE 30 + #define PROPERTY_ID_DECIMAL_ACCURACY 31 + #define PROPERTY_ID_SHOWTHOUSANDSEP 32 + #define PROPERTY_ID_REFVALUE 33 + #define PROPERTY_ID_CURRENCYSYMBOL 34 + #define PROPERTY_ID_CURRSYM_POSITION 35 + #define PROPERTY_ID_DATEMIN 36 + #define PROPERTY_ID_DATEMAX 37 + #define PROPERTY_ID_DATEFORMAT 38 + #define PROPERTY_ID_SELECTEDITEMS 39 + #define PROPERTY_ID_DEFAULT_DATE 40 + #define PROPERTY_ID_TIMEMIN 41 + #define PROPERTY_ID_TIMEMAX 42 + #define PROPERTY_ID_TIMEFORMAT 43 + #define PROPERTY_ID_DEFAULT_TIME 44 + #define PROPERTY_ID_EFFECTIVE_MIN 45 + #define PROPERTY_ID_EFFECTIVE_MAX 46 + #define PROPERTY_ID_EFFECTIVE_DEFAULT 47 + #define PROPERTY_ID_FORMATKEY 48 + #define PROPERTY_ID_CLASSID 50 + #define PROPERTY_ID_HEIGHT 51 + #define PROPERTY_ID_WIDTH 52 + #define PROPERTY_ID_BOUNDCOLUMN 53 + #define PROPERTY_ID_LISTSOURCETYPE 54 + #define PROPERTY_ID_LISTSOURCE 55 + #define PROPERTY_ID_LISTINDEX 56 + #define PROPERTY_ID_STRINGITEMLIST 57 + #define PROPERTY_ID_DEFAULT_TEXT 58 + #define PROPERTY_ID_FONT 59 + #define PROPERTY_ID_ALIGN 60 + #define PROPERTY_ID_ROWHEIGHT 61 + #define PROPERTY_ID_BACKGROUNDCOLOR 62 + #define PROPERTY_ID_FILLCOLOR 63 + #define PROPERTY_ID_ESCAPE_PROCESSING 64 + #define PROPERTY_ID_LINECOLOR 65 + #define PROPERTY_ID_BORDER 66 + #define PROPERTY_ID_DROPDOWN 67 + #define PROPERTY_ID_AUTOCOMPLETE 68 + #define PROPERTY_ID_LINECOUNT 69 + #define PROPERTY_ID_WORDBREAK 70 + #define PROPERTY_ID_MULTILINE 71 + #define PROPERTY_ID_MULTISELECTION 72 + #define PROPERTY_ID_AUTOLINEBREAK 73 + #define PROPERTY_ID_HSCROLL 74 + #define PROPERTY_ID_VSCROLL 75 + #define PROPERTY_ID_SPIN 76 + #define PROPERTY_ID_BUTTONTYPE 77 + #define PROPERTY_ID_TARGET_URL 78 + #define PROPERTY_ID_TARGET_FRAME 79 + #define PROPERTY_ID_SUBMIT_ACTION 80 + #define PROPERTY_ID_SUBMIT_TARGET 81 + #define PROPERTY_ID_SUBMIT_METHOD 82 + #define PROPERTY_ID_SUBMIT_ENCODING 83 + #define PROPERTY_ID_DEFAULT_STATE 84 + #define PROPERTY_ID_DEFAULTBUTTON 85 + #define PROPERTY_ID_IMAGE_URL 86 + #define PROPERTY_ID_DEFAULT_SELECT_SEQ 87 + #define PROPERTY_ID_ECHO_CHAR 88 + #define PROPERTY_ID_EMPTY_IS_NULL 89 + #define PROPERTY_ID_TRISTATE 90 + #define PROPERTY_ID_MASTERFIELDS 91 + #define PROPERTY_ID_DETAILFIELDS 92 + #define PROPERTY_ID_RECORDMARKER 93 + #define PROPERTY_ID_FILTERPROPOSAL 94 + #define PROPERTY_ID_TAG 95 + #define PROPERTY_ID_HELPTEXT 96 + #define PROPERTY_ID_HELPURL 97 + #define PROPERTY_ID_HASNAVIGATION 98 + #define PROPERTY_ID_POSITIONX 99 + #define PROPERTY_ID_POSITIONY 100 + #define PROPERTY_ID_TITLE 101 + #define PROPERTY_ID_STEP 102 + #define PROPERTY_ID_PROGRESSVALUE 103 + #define PROPERTY_ID_PROGRESSVALUE_MIN 104 + #define PROPERTY_ID_PROGRESSVALUE_MAX 105 + #define PROPERTY_ID_SCROLLVALUE 106 + #define PROPERTY_ID_SCROLLVALUE_MAX 107 + #define PROPERTY_ID_LINEINCREMENT 108 + #define PROPERTY_ID_BLOCKINCREMENT 109 + #define PROPERTY_ID_VISIBLESIZE 110 + #define PROPERTY_ID_ORIENTATION 111 + #define PROPERTY_ID_IMAGEPOSITION 112 + #define PROPERTY_ID_DATE 113 + #define PROPERTY_ID_STATE 114 + #define PROPERTY_ID_TIME 115 + #define PROPERTY_ID_VALUE 116 + #define PROPERTY_ID_SCALEIMAGE 117 + #define PROPERTY_ID_PUSHBUTTONTYPE 118 + #define PROPERTY_ID_EFFECTIVE_VALUE 119 + #define PROPERTY_ID_TEXT 120 + #define PROPERTY_ID_BOUND_CELL 121 + #define PROPERTY_ID_LIST_CELL_RANGE 122 + #define PROPERTY_ID_CELL_EXCHANGE_TYPE 123 + #define PROPERTY_ID_SCROLLVALUE_MIN 124 + #define PROPERTY_ID_DEFAULT_SCROLLVALUE 125 + #define PROPERTY_ID_REPEAT_DELAY 126 + #define PROPERTY_ID_SYMBOLCOLOR 127 + #define PROPERTY_ID_SPINVALUE 128 + #define PROPERTY_ID_SPINVALUE_MIN 129 + #define PROPERTY_ID_SPINVALUE_MAX 130 + #define PROPERTY_ID_DEFAULT_SPINVALUE 131 + #define PROPERTY_ID_SPININCREMENT 132 + #define PROPERTY_ID_REPEAT 133 + #define PROPERTY_ID_SHOW_SCROLLBARS 134 + #define PROPERTY_ID_ICONSIZE 135 + #define PROPERTY_ID_SHOW_POSITION 136 + #define PROPERTY_ID_SHOW_NAVIGATION 137 + #define PROPERTY_ID_SHOW_RECORDACTIONS 138 + #define PROPERTY_ID_SHOW_FILTERSORT 139 + #define PROPERTY_ID_TEXTTYPE 140 + #define PROPERTY_ID_LINEEND_FORMAT 141 + #define PROPERTY_ID_TOGGLE 142 + #define PROPERTY_ID_FOCUSONCLICK 143 + #define PROPERTY_ID_HIDEINACTIVESELECTION 144 + #define PROPERTY_ID_VISUALEFFECT 145 + #define PROPERTY_ID_BORDERCOLOR 146 + #define PROPERTY_ID_XML_DATA_MODEL 147 + #define PROPERTY_ID_BIND_EXPRESSION 148 + #define PROPERTY_ID_XSD_REQUIRED 149 + #define PROPERTY_ID_XSD_RELEVANT 150 + #define PROPERTY_ID_XSD_READONLY 151 + #define PROPERTY_ID_XSD_CONSTRAINT 152 + #define PROPERTY_ID_XSD_CALCULATION 153 + #define PROPERTY_ID_XSD_DATA_TYPE 154 + #define PROPERTY_ID_XSD_WHITESPACES 155 + #define PROPERTY_ID_XSD_PATTERN 156 + #define PROPERTY_ID_XSD_LENGTH 157 + #define PROPERTY_ID_XSD_MIN_LENGTH 158 + #define PROPERTY_ID_XSD_MAX_LENGTH 159 + #define PROPERTY_ID_XSD_TOTAL_DIGITS 160 + #define PROPERTY_ID_XSD_FRACTION_DIGITS 161 + #define PROPERTY_ID_XSD_MAX_INCLUSIVE_INT 162 + #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_INT 163 + #define PROPERTY_ID_XSD_MIN_INCLUSIVE_INT 164 + #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_INT 165 + #define PROPERTY_ID_XSD_MAX_INCLUSIVE_DOUBLE 166 + #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_DOUBLE 167 + #define PROPERTY_ID_XSD_MIN_INCLUSIVE_DOUBLE 168 + #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_DOUBLE 169 + #define PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE 170 + #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE 171 + #define PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE 172 + #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE 173 + #define PROPERTY_ID_XSD_MAX_INCLUSIVE_TIME 174 + #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_TIME 175 + #define PROPERTY_ID_XSD_MIN_INCLUSIVE_TIME 176 + #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_TIME 177 + #define PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE_TIME 178 + #define PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE_TIME 179 + #define PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE_TIME 180 + #define PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE_TIME 181 + #define PROPERTY_ID_UNCHECKEDREFVALUE 182 + #define PROPERTY_ID_SUBMISSION_ID 183 + #define PROPERTY_ID_XFORMS_BUTTONTYPE 184 + #define PROPERTY_ID_LIST_BINDING 185 + #define PROPERTY_ID_VERTICAL_ALIGN 186 + #define PROPERTY_ID_BINDING_NAME 187 + #define PROPERTY_ID_DECORATION 188 + #define PROPERTY_ID_SELECTION_TYPE 189 + #define PROPERTY_ID_ROOT_DISPLAYED 190 + #define PROPERTY_ID_SHOWS_HANDLES 191 + #define PROPERTY_ID_SHOWS_ROOT_HANDLES 192 + #define PROPERTY_ID_EDITABLE 193 + #define PROPERTY_ID_INVOKES_STOP_NOT_EDITING 194 + #define PROPERTY_ID_NOLABEL 195 + #define PROPERTY_ID_SCALE_MODE 196 + #define PROPERTY_ID_INPUT_REQUIRED 197 + #define PROPERTY_ID_WRITING_MODE 198 + #define PROPERTY_ID_ENABLE_VISIBLE 199 + #define PROPERTY_ID_WHEEL_BEHAVIOR 200 + #define PROPERTY_ID_TEXT_ANCHOR_TYPE 201 + #define PROPERTY_ID_SHEET_ANCHOR_TYPE 202 + #define PROPERTY_ID_SCROLL_WIDTH 203 + #define PROPERTY_ID_SCROLL_HEIGHT 204 + #define PROPERTY_ID_SCROLL_TOP 205 + #define PROPERTY_ID_SCROLL_LEFT 206 + #define PROPERTY_ID_TYPEDITEMLIST 207 + #define PROPERTY_ID_SELECTIONMODEL 208 + #define PROPERTY_ID_USEGRIDLINE 209 + #define PROPERTY_ID_GRIDLINECOLOR 210 + #define PROPERTY_ID_SHOWCOLUMNHEADER 211 + #define PROPERTY_ID_SHOWROWHEADER 212 + #define PROPERTY_ID_HEADERBACKGROUNDCOLOR 213 + #define PROPERTY_ID_HEADERTEXTCOLOR 214 + #define PROPERTY_ID_ACTIVESELECTIONBACKGROUNDCOLOR 215 + #define PROPERTY_ID_ACTIVESELECTIONTEXTCOLOR 216 + #define PROPERTY_ID_INACTIVESELECTIONBACKGROUNDCOLOR 217 + #define PROPERTY_ID_INACTIVESELECTIONTEXTCOLOR 218 + #define PROPERTY_ID_URL 219 + #define PROPERTY_ID_AUTOGROW 220 + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/formstrings.hxx b/extensions/source/propctrlr/formstrings.hxx new file mode 100644 index 000000000..df151ab95 --- /dev/null +++ b/extensions/source/propctrlr/formstrings.hxx @@ -0,0 +1,302 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +inline constexpr OUStringLiteral PROPERTY_DEFAULTCONTROL = u"DefaultControl"; +inline constexpr OUStringLiteral PROPERTY_INTROSPECTEDOBJECT = u"IntrospectedObject"; +inline constexpr OUStringLiteral PROPERTY_CURRENTPAGE = u"CurrentPage"; +inline constexpr OUStringLiteral PROPERTY_CONTROLCONTEXT = u"ControlContext"; + +// properties +inline constexpr OUStringLiteral PROPERTY_CLASSID = u"ClassId"; +inline constexpr OUStringLiteral PROPERTY_CONTROLLABEL = u"LabelControl"; +inline constexpr OUStringLiteral PROPERTY_LABEL = u"Label"; +inline constexpr OUStringLiteral PROPERTY_TABINDEX = u"TabIndex"; +inline constexpr OUStringLiteral PROPERTY_WHEEL_BEHAVIOR = u"MouseWheelBehavior"; +inline constexpr OUStringLiteral PROPERTY_TAG = u"Tag"; +inline constexpr OUStringLiteral PROPERTY_NAME = u"Name"; +inline constexpr OUStringLiteral PROPERTY_GROUP_NAME = u"GroupName"; +inline constexpr OUStringLiteral PROPERTY_VALUE = u"Value"; +inline constexpr OUStringLiteral PROPERTY_TEXT = u"Text"; +inline constexpr OUStringLiteral PROPERTY_NAVIGATION = u"NavigationBarMode"; +inline constexpr OUStringLiteral PROPERTY_CYCLE = u"Cycle"; +inline constexpr OUStringLiteral PROPERTY_CONTROLSOURCE = u"DataField"; +inline constexpr OUStringLiteral PROPERTY_INPUT_REQUIRED = u"InputRequired"; +inline constexpr OUStringLiteral PROPERTY_ENABLED = u"Enabled"; +inline constexpr OUStringLiteral PROPERTY_ENABLE_VISIBLE = u"EnableVisible"; +inline constexpr OUStringLiteral PROPERTY_READONLY = u"ReadOnly"; +inline constexpr OUStringLiteral PROPERTY_FILTER = u"Filter"; +inline constexpr OUStringLiteral PROPERTY_WIDTH = u"Width"; +inline constexpr OUStringLiteral PROPERTY_MULTILINE = u"MultiLine"; +inline constexpr OUStringLiteral PROPERTY_WORDBREAK = u"WordBreak"; +inline constexpr OUStringLiteral PROPERTY_TARGET_URL = u"TargetURL"; +inline constexpr OUStringLiteral PROPERTY_TARGET_FRAME = u"TargetFrame"; +inline constexpr OUStringLiteral PROPERTY_MAXTEXTLEN = u"MaxTextLen"; +inline constexpr OUStringLiteral PROPERTY_EDITMASK = u"EditMask"; +inline constexpr OUStringLiteral PROPERTY_SPIN = u"Spin"; +inline constexpr OUStringLiteral PROPERTY_TRISTATE = u"TriState"; +inline constexpr OUStringLiteral PROPERTY_HIDDEN_VALUE = u"HiddenValue"; +inline constexpr OUStringLiteral PROPERTY_BUTTONTYPE = u"ButtonType"; +inline constexpr OUStringLiteral PROPERTY_XFORMS_BUTTONTYPE = u"XFormsButtonType"; +inline constexpr OUStringLiteral PROPERTY_STRINGITEMLIST = u"StringItemList"; +inline constexpr OUStringLiteral PROPERTY_TYPEDITEMLIST = u"TypedItemList"; +inline constexpr OUStringLiteral PROPERTY_DEFAULT_TEXT = u"DefaultText"; +inline constexpr OUStringLiteral PROPERTY_DEFAULT_STATE = u"DefaultState"; +inline constexpr OUStringLiteral PROPERTY_FORMATKEY = u"FormatKey"; +inline constexpr OUStringLiteral PROPERTY_FORMATSSUPPLIER = u"FormatsSupplier"; +inline constexpr OUStringLiteral PROPERTY_SUBMIT_ACTION = u"SubmitAction"; +inline constexpr OUStringLiteral PROPERTY_SUBMIT_TARGET = u"SubmitTarget"; +inline constexpr OUStringLiteral PROPERTY_SUBMIT_METHOD = u"SubmitMethod"; +inline constexpr OUStringLiteral PROPERTY_SUBMIT_ENCODING = u"SubmitEncoding"; +inline constexpr OUStringLiteral PROPERTY_IMAGE_URL = u"ImageURL"; +inline constexpr OUStringLiteral PROPERTY_GRAPHIC = u"Graphic"; +inline constexpr OUStringLiteral PROPERTY_EMPTY_IS_NULL = u"ConvertEmptyToNull"; +inline constexpr OUStringLiteral PROPERTY_LISTSOURCETYPE = u"ListSourceType"; +inline constexpr OUStringLiteral PROPERTY_LISTSOURCE = u"ListSource"; +inline constexpr OUStringLiteral PROPERTY_DEFAULT_SELECT_SEQ = u"DefaultSelection"; +inline constexpr OUStringLiteral PROPERTY_MULTISELECTION = u"MultiSelection"; +inline constexpr OUStringLiteral PROPERTY_ALIGN = u"Align"; +inline constexpr OUStringLiteral PROPERTY_VERTICAL_ALIGN = u"VerticalAlign"; +inline constexpr OUStringLiteral PROPERTY_DEFAULT_DATE = u"DefaultDate"; +inline constexpr OUStringLiteral PROPERTY_DEFAULT_TIME = u"DefaultTime"; +inline constexpr OUStringLiteral PROPERTY_DEFAULT_VALUE = u"DefaultValue"; +inline constexpr OUStringLiteral PROPERTY_DECIMAL_ACCURACY = u"DecimalAccuracy"; +inline constexpr OUStringLiteral PROPERTY_REFVALUE = u"RefValue"; +inline constexpr OUStringLiteral PROPERTY_UNCHECKEDREFVALUE = u"SecondaryRefValue"; +inline constexpr OUStringLiteral PROPERTY_VALUEMIN = u"ValueMin"; +inline constexpr OUStringLiteral PROPERTY_VALUEMAX = u"ValueMax"; +inline constexpr OUStringLiteral PROPERTY_STRICTFORMAT = u"StrictFormat"; +inline constexpr OUStringLiteral PROPERTY_ALLOWADDITIONS = u"AllowInserts"; +inline constexpr OUStringLiteral PROPERTY_ALLOWEDITS = u"AllowUpdates"; +inline constexpr OUStringLiteral PROPERTY_ALLOWDELETIONS = u"AllowDeletes"; +inline constexpr OUStringLiteral PROPERTY_MASTERFIELDS = u"MasterFields"; +inline constexpr OUStringLiteral PROPERTY_LITERALMASK = u"LiteralMask"; +inline constexpr OUStringLiteral PROPERTY_VALUESTEP = u"ValueStep"; +inline constexpr OUStringLiteral PROPERTY_SHOWTHOUSANDSEP = u"ShowThousandsSeparator"; +inline constexpr OUStringLiteral PROPERTY_CURRENCYSYMBOL = u"CurrencySymbol"; +inline constexpr OUStringLiteral PROPERTY_DATEFORMAT = u"DateFormat"; +inline constexpr OUStringLiteral PROPERTY_DATEMIN = u"DateMin"; +inline constexpr OUStringLiteral PROPERTY_DATEMAX = u"DateMax"; +inline constexpr OUStringLiteral PROPERTY_TIMEFORMAT = u"TimeFormat"; +inline constexpr OUStringLiteral PROPERTY_TIMEMIN = u"TimeMin"; +inline constexpr OUStringLiteral PROPERTY_TIMEMAX = u"TimeMax"; +inline constexpr OUStringLiteral PROPERTY_LINECOUNT = u"LineCount"; +inline constexpr OUStringLiteral PROPERTY_BOUNDCOLUMN = u"BoundColumn"; +inline constexpr OUStringLiteral PROPERTY_BACKGROUNDCOLOR = u"BackgroundColor"; +inline constexpr OUStringLiteral PROPERTY_FILLCOLOR = u"FillColor"; +inline constexpr OUStringLiteral PROPERTY_TEXTCOLOR = u"TextColor"; +inline constexpr OUStringLiteral PROPERTY_LINECOLOR = u"LineColor"; +inline constexpr OUStringLiteral PROPERTY_BORDER = u"Border"; +inline constexpr OUStringLiteral PROPERTY_ICONSIZE = u"IconSize"; +inline constexpr OUStringLiteral PROPERTY_DROPDOWN = u"Dropdown"; +inline constexpr OUStringLiteral PROPERTY_HSCROLL = u"HScroll"; +inline constexpr OUStringLiteral PROPERTY_VSCROLL = u"VScroll"; +inline constexpr OUStringLiteral PROPERTY_SHOW_SCROLLBARS = u"ShowScrollbars"; +inline constexpr OUStringLiteral PROPERTY_TABSTOP = u"Tabstop"; +inline constexpr OUStringLiteral PROPERTY_AUTOCOMPLETE = u"Autocomplete"; +inline constexpr OUStringLiteral PROPERTY_PRINTABLE = u"Printable"; +inline constexpr OUStringLiteral PROPERTY_ECHO_CHAR = u"EchoChar"; +inline constexpr OUStringLiteral PROPERTY_ROWHEIGHT = u"RowHeight"; +inline constexpr OUStringLiteral PROPERTY_HELPTEXT = u"HelpText"; +inline constexpr OUStringLiteral PROPERTY_FONT = u"FontDescriptor"; +inline constexpr OUStringLiteral PROPERTY_FONT_NAME = u"FontName"; +inline constexpr OUStringLiteral PROPERTY_FONT_STYLENAME = u"FontStyleName"; +inline constexpr OUStringLiteral PROPERTY_FONT_FAMILY = u"FontFamily"; +inline constexpr OUStringLiteral PROPERTY_FONT_CHARSET = u"FontCharset"; +inline constexpr OUStringLiteral PROPERTY_FONT_HEIGHT = u"FontHeight"; +inline constexpr OUStringLiteral PROPERTY_FONT_WEIGHT = u"FontWeight"; +inline constexpr OUStringLiteral PROPERTY_FONT_SLANT = u"FontSlant"; +inline constexpr OUStringLiteral PROPERTY_FONT_UNDERLINE = u"FontUnderline"; +inline constexpr OUStringLiteral PROPERTY_FONT_STRIKEOUT = u"FontStrikeout"; +inline constexpr OUStringLiteral PROPERTY_FONT_RELIEF = u"FontRelief"; +inline constexpr OUStringLiteral PROPERTY_FONT_EMPHASIS_MARK = u"FontEmphasisMark"; +inline constexpr OUStringLiteral PROPERTY_TEXTLINECOLOR = u"TextLineColor"; +inline constexpr OUStringLiteral PROPERTY_HELPURL = u"HelpURL"; +inline constexpr OUStringLiteral PROPERTY_RECORDMARKER = u"HasRecordMarker"; +inline constexpr OUStringLiteral PROPERTY_EFFECTIVE_DEFAULT = u"EffectiveDefault"; +inline constexpr OUStringLiteral PROPERTY_EFFECTIVE_MIN = u"EffectiveMin"; +inline constexpr OUStringLiteral PROPERTY_EFFECTIVE_MAX = u"EffectiveMax"; +inline constexpr OUStringLiteral PROPERTY_FILTERPROPOSAL = u"UseFilterValueProposal"; +inline constexpr OUStringLiteral PROPERTY_CURRSYM_POSITION = u"PrependCurrencySymbol"; +inline constexpr OUStringLiteral PROPERTY_COMMAND = u"Command"; +inline constexpr OUStringLiteral PROPERTY_COMMANDTYPE = u"CommandType"; +inline constexpr OUStringLiteral PROPERTY_INSERTONLY = u"IgnoreResult"; +inline constexpr OUStringLiteral PROPERTY_ESCAPE_PROCESSING = u"EscapeProcessing"; +inline constexpr OUStringLiteral PROPERTY_TITLE = u"Title"; +inline constexpr OUStringLiteral PROPERTY_SORT = u"Order"; +inline constexpr OUStringLiteral PROPERTY_DATASOURCE = u"DataSourceName"; +inline constexpr OUStringLiteral PROPERTY_DETAILFIELDS = u"DetailFields"; +inline constexpr OUStringLiteral PROPERTY_DEFAULTBUTTON = u"DefaultButton"; +inline constexpr OUStringLiteral PROPERTY_LISTINDEX = u"ListIndex"; +inline constexpr OUStringLiteral PROPERTY_HEIGHT = u"Height"; +inline constexpr OUStringLiteral PROPERTY_HASNAVIGATION = u"HasNavigationBar"; +inline constexpr OUStringLiteral PROPERTY_POSITIONX = u"PositionX"; +inline constexpr OUStringLiteral PROPERTY_POSITIONY = u"PositionY"; +inline constexpr OUStringLiteral PROPERTY_AUTOGROW = u"AutoGrow"; +inline constexpr OUStringLiteral PROPERTY_STEP = u"Step"; +inline constexpr OUStringLiteral PROPERTY_WORDLINEMODE = u"FontWordLineMode"; +inline constexpr OUStringLiteral PROPERTY_PROGRESSVALUE = u"ProgressValue"; +inline constexpr OUStringLiteral PROPERTY_PROGRESSVALUE_MIN = u"ProgressValueMin"; +inline constexpr OUStringLiteral PROPERTY_PROGRESSVALUE_MAX = u"ProgressValueMax"; +inline constexpr OUStringLiteral PROPERTY_SCROLLVALUE = u"ScrollValue"; +inline constexpr OUStringLiteral PROPERTY_DEFAULT_SCROLLVALUE = u"DefaultScrollValue"; +inline constexpr OUStringLiteral PROPERTY_SCROLLVALUE_MIN = u"ScrollValueMin"; +inline constexpr OUStringLiteral PROPERTY_SCROLLVALUE_MAX = u"ScrollValueMax"; +inline constexpr OUStringLiteral PROPERTY_SCROLL_WIDTH = u"ScrollWidth"; +inline constexpr OUStringLiteral PROPERTY_SCROLL_HEIGHT = u"ScrollHeight"; +inline constexpr OUStringLiteral PROPERTY_SCROLL_TOP = u"ScrollTop"; +inline constexpr OUStringLiteral PROPERTY_SCROLL_LEFT = u"ScrollLeft"; +inline constexpr OUStringLiteral PROPERTY_LINEINCREMENT = u"LineIncrement"; +inline constexpr OUStringLiteral PROPERTY_BLOCKINCREMENT = u"BlockIncrement"; +inline constexpr OUStringLiteral PROPERTY_VISIBLESIZE = u"VisibleSize"; +inline constexpr OUStringLiteral PROPERTY_ORIENTATION = u"Orientation"; +inline constexpr OUStringLiteral PROPERTY_IMAGEPOSITION = u"ImagePosition"; +inline constexpr OUStringLiteral PROPERTY_ACTIVE_CONNECTION = u"ActiveConnection"; +inline constexpr OUStringLiteral PROPERTY_ACTIVECOMMAND = u"ActiveCommand"; +inline constexpr OUStringLiteral PROPERTY_DATE = u"Date"; +inline constexpr OUStringLiteral PROPERTY_STATE = u"State"; +inline constexpr OUStringLiteral PROPERTY_TIME = u"Time"; +inline constexpr OUStringLiteral PROPERTY_SCALEIMAGE = u"ScaleImage"; +inline constexpr OUStringLiteral PROPERTY_SCALE_MODE = u"ScaleMode"; +inline constexpr OUStringLiteral PROPERTY_PUSHBUTTONTYPE = u"PushButtonType"; +inline constexpr OUStringLiteral PROPERTY_EFFECTIVE_VALUE = u"EffectiveValue"; +inline constexpr OUStringLiteral PROPERTY_SELECTEDITEMS = u"SelectedItems"; +inline constexpr OUStringLiteral PROPERTY_REPEAT = u"Repeat"; +inline constexpr OUStringLiteral PROPERTY_REPEAT_DELAY = u"RepeatDelay"; +inline constexpr OUStringLiteral PROPERTY_SYMBOLCOLOR = u"SymbolColor"; +inline constexpr OUStringLiteral PROPERTY_SPINVALUE = u"SpinValue"; +inline constexpr OUStringLiteral PROPERTY_SPINVALUE_MIN = u"SpinValueMin"; +inline constexpr OUStringLiteral PROPERTY_SPINVALUE_MAX = u"SpinValueMax"; +inline constexpr OUStringLiteral PROPERTY_DEFAULT_SPINVALUE = u"DefaultSpinValue"; +inline constexpr OUStringLiteral PROPERTY_SPININCREMENT = u"SpinIncrement"; +inline constexpr OUStringLiteral PROPERTY_SHOW_POSITION = u"ShowPosition"; +inline constexpr OUStringLiteral PROPERTY_SHOW_NAVIGATION = u"ShowNavigation"; +inline constexpr OUStringLiteral PROPERTY_SHOW_RECORDACTIONS = u"ShowRecordActions"; +inline constexpr OUStringLiteral PROPERTY_SHOW_FILTERSORT = u"ShowFilterSort"; +inline constexpr OUStringLiteral PROPERTY_LINEEND_FORMAT = u"LineEndFormat"; +inline constexpr OUStringLiteral PROPERTY_DECORATION = u"Decoration"; +inline constexpr OUStringLiteral PROPERTY_NOLABEL = u"NoLabel"; +inline constexpr OUStringLiteral PROPERTY_URL = u"URL"; + +inline constexpr OUStringLiteral PROPERTY_SELECTION_TYPE = u"SelectionType"; +inline constexpr OUStringLiteral PROPERTY_ROOT_DISPLAYED = u"RootDisplayed"; +inline constexpr OUStringLiteral PROPERTY_SHOWS_HANDLES = u"ShowsHandles"; +inline constexpr OUStringLiteral PROPERTY_SHOWS_ROOT_HANDLES = u"ShowsRootHandles"; +inline constexpr OUStringLiteral PROPERTY_EDITABLE = u"Editable"; +inline constexpr OUStringLiteral PROPERTY_INVOKES_STOP_NOT_EDITING = u"InvokesStopNodeEditing"; + +inline constexpr OUStringLiteral PROPERTY_TOGGLE = u"Toggle"; +inline constexpr OUStringLiteral PROPERTY_FOCUSONCLICK = u"FocusOnClick"; +inline constexpr OUStringLiteral PROPERTY_HIDEINACTIVESELECTION = u"HideInactiveSelection"; +inline constexpr OUStringLiteral PROPERTY_VISUALEFFECT = u"VisualEffect"; +inline constexpr OUStringLiteral PROPERTY_BORDERCOLOR = u"BorderColor"; + +inline constexpr OUStringLiteral PROPERTY_ADDRESS = u"Address"; +inline constexpr OUStringLiteral PROPERTY_REFERENCE_SHEET = u"ReferenceSheet"; +inline constexpr OUStringLiteral PROPERTY_UI_REPRESENTATION = u"UserInterfaceRepresentation"; + +inline constexpr OUStringLiteral PROPERTY_XML_DATA_MODEL = u"XMLDataModel"; +inline constexpr OUStringLiteral PROPERTY_BINDING_NAME = u"BindingName"; +inline constexpr OUStringLiteral PROPERTY_BIND_EXPRESSION = u"BindingExpression"; +inline constexpr OUStringLiteral PROPERTY_LIST_BINDING = u"ListBinding"; +inline constexpr OUStringLiteral PROPERTY_XSD_REQUIRED = u"RequiredExpression"; +inline constexpr OUStringLiteral PROPERTY_XSD_RELEVANT = u"RelevantExpression"; +inline constexpr OUStringLiteral PROPERTY_XSD_READONLY = u"ReadonlyExpression"; +inline constexpr OUStringLiteral PROPERTY_XSD_CONSTRAINT = u"ConstraintExpression"; +inline constexpr OUStringLiteral PROPERTY_XSD_CALCULATION = u"CalculateExpression"; +inline constexpr OUStringLiteral PROPERTY_XSD_DATA_TYPE = u"Type"; +inline constexpr OUStringLiteral PROPERTY_XSD_WHITESPACES = u"WhiteSpace"; +inline constexpr OUStringLiteral PROPERTY_XSD_PATTERN = u"Pattern"; +inline constexpr OUStringLiteral PROPERTY_XSD_LENGTH = u"Length"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_LENGTH = u"MinLength"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_LENGTH = u"MaxLength"; +inline constexpr OUStringLiteral PROPERTY_XSD_TOTAL_DIGITS = u"TotalDigits"; +inline constexpr OUStringLiteral PROPERTY_XSD_FRACTION_DIGITS = u"FractionDigits"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_INT = u"MaxInclusiveInt"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_INT = u"MaxExclusiveInt"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_INT = u"MinInclusiveInt"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_INT = u"MinExclusiveInt"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_DOUBLE = u"MaxInclusiveDouble"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_DOUBLE = u"MaxExclusiveDouble"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_DOUBLE = u"MinInclusiveDouble"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_DOUBLE = u"MinExclusiveDouble"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_DATE = u"MaxInclusiveDate"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_DATE = u"MaxExclusiveDate"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_DATE = u"MinInclusiveDate"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_DATE = u"MinExclusiveDate"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_TIME = u"MaxInclusiveTime"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_TIME = u"MaxExclusiveTime"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_TIME = u"MinInclusiveTime"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_TIME = u"MinExclusiveTime"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_INCLUSIVE_DATE_TIME = u"MaxInclusiveDateTime"; +inline constexpr OUStringLiteral PROPERTY_XSD_MAX_EXCLUSIVE_DATE_TIME = u"MaxExclusiveDateTime"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_INCLUSIVE_DATE_TIME = u"MinInclusiveDateTime"; +inline constexpr OUStringLiteral PROPERTY_XSD_MIN_EXCLUSIVE_DATE_TIME = u"MinExclusiveDateTime"; +inline constexpr OUStringLiteral PROPERTY_SUBMISSION_ID = u"SubmissionID"; +inline constexpr OUStringLiteral PROPERTY_BINDING_ID = u"BindingID"; +inline constexpr OUStringLiteral PROPERTY_WRITING_MODE = u"WritingMode"; +inline constexpr OUStringLiteral PROPERTY_TEXT_ANCHOR_TYPE = u"TextAnchorType"; +inline constexpr OUStringLiteral PROPERTY_SHEET_ANCHOR_TYPE = u"SheetAnchorType"; +inline constexpr OUStringLiteral PROPERTY_ANCHOR_TYPE = u"AnchorType"; +inline constexpr OUStringLiteral PROPERTY_ANCHOR = u"Anchor"; +inline constexpr OUStringLiteral PROPERTY_IS_VISIBLE = u"IsVisible"; + +inline constexpr OUStringLiteral PROPERTY_MODEL = u"Model"; + +inline constexpr OUStringLiteral PROPERTY_CELL_EXCHANGE_TYPE = u"ExchangeSelectionIndex"; +inline constexpr OUStringLiteral PROPERTY_BOUND_CELL = u"BoundCell"; +inline constexpr OUStringLiteral PROPERTY_LIST_CELL_RANGE = u"CellRange"; +inline constexpr OUStringLiteral PROPERTY_TEXTTYPE = u"TextType"; +inline constexpr OUStringLiteral PROPERTY_RICHTEXT = u"RichText"; +inline constexpr OUStringLiteral PROPERTY_ROWSET = u"RowSet"; +inline constexpr OUStringLiteral PROPERTY_SELECTIONMODEL = u"SelectionModel"; +inline constexpr OUStringLiteral PROPERTY_USEGRIDLINE = u"UseGridLines"; +inline constexpr OUStringLiteral PROPERTY_GRIDLINECOLOR = u"GridLineColor"; +inline constexpr OUStringLiteral PROPERTY_SHOWCOLUMNHEADER = u"ShowColumnHeader"; +inline constexpr OUStringLiteral PROPERTY_SHOWROWHEADER = u"ShowRowHeader"; +inline constexpr OUStringLiteral PROPERTY_HEADERBACKGROUNDCOLOR = u"HeaderBackgroundColor"; +inline constexpr OUStringLiteral PROPERTY_HEADERTEXTCOLOR = u"HeaderTextColor"; +inline constexpr OUStringLiteral PROPERTY_ACTIVESELECTIONBACKGROUNDCOLOR = u"ActiveSelectionBackgroundColor"; +inline constexpr OUStringLiteral PROPERTY_ACTIVESELECTIONTEXTCOLOR = u"ActiveSelectionTextColor"; +inline constexpr OUStringLiteral PROPERTY_INACTIVESELECTIONBACKGROUNDCOLOR = u"InactiveSelectionBackgroundColor"; +inline constexpr OUStringLiteral PROPERTY_INACTIVESELECTIONTEXTCOLOR = u"InactiveSelectionTextColor"; + +// services +inline constexpr OUStringLiteral SERVICE_COMPONENT_GROUPBOX = u"com.sun.star.form.component.GroupBox"; +inline constexpr OUStringLiteral SERVICE_COMPONENT_FIXEDTEXT = u"com.sun.star.form.component.FixedText"; +inline constexpr OUStringLiteral SERVICE_COMPONENT_FORMATTEDFIELD = u"com.sun.star.form.component.FormattedField"; + +inline constexpr OUStringLiteral SERVICE_TEXT_DOCUMENT = u"com.sun.star.text.TextDocument"; +inline constexpr OUStringLiteral SERVICE_WEB_DOCUMENT = u"com.sun.star.text.WebDocument"; +inline constexpr OUStringLiteral SERVICE_SPREADSHEET_DOCUMENT = u"com.sun.star.sheet.SpreadsheetDocument"; +inline constexpr OUStringLiteral SERVICE_DRAWING_DOCUMENT = u"com.sun.star.drawing.DrawingDocument"; +inline constexpr OUStringLiteral SERVICE_PRESENTATION_DOCUMENT = u"com.sun.star.presentation.PresentationDocument"; + +inline constexpr OUStringLiteral SERVICE_SHEET_CELL_BINDING = u"com.sun.star.table.CellValueBinding"; +inline constexpr OUStringLiteral SERVICE_SHEET_CELL_INT_BINDING = u"com.sun.star.table.ListPositionCellBinding"; +inline constexpr OUStringLiteral SERVICE_SHEET_CELLRANGE_LISTSOURCE = u"com.sun.star.table.CellRangeListSource"; +inline constexpr OUStringLiteral SERVICE_ADDRESS_CONVERSION = u"com.sun.star.table.CellAddressConversion"; +inline constexpr OUStringLiteral SERVICE_RANGEADDRESS_CONVERSION = u"com.sun.star.table.CellRangeAddressConversion"; + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/genericpropertyhandler.cxx b/extensions/source/propctrlr/genericpropertyhandler.cxx new file mode 100644 index 000000000..8320e5154 --- /dev/null +++ b/extensions/source/propctrlr/genericpropertyhandler.cxx @@ -0,0 +1,619 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "enumrepresentation.hxx" +#include "genericpropertyhandler.hxx" +#include "handlerhelper.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace pcr +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::reflection; + using namespace ::com::sun::star::inspection; + using ::com::sun::star::awt::XActionListener; + using ::com::sun::star::awt::ActionEvent; + + namespace { + + class EnumRepresentation : public IPropertyEnumRepresentation + { + private: + Reference< XEnumTypeDescription > m_xTypeDescription; + Type m_aEnumType; + + public: + EnumRepresentation( const Reference< XComponentContext >& _rxContext, const Type& _rEnumType ); + EnumRepresentation(const EnumRepresentation&) = delete; + EnumRepresentation& operator=(const EnumRepresentation&) = delete; + + // IPropertyEnumRepresentation implementqation + virtual std::vector< OUString > + getDescriptions() const override; + virtual void getValueFromDescription( const OUString& _rDescription, css::uno::Any& _out_rValue ) const override; + virtual OUString getDescriptionForValue( const css::uno::Any& _rEnumValue ) const override; + + private: + void impl_getValues( Sequence< sal_Int32 >& _out_rValues ) const; + }; + + } + + EnumRepresentation::EnumRepresentation( const Reference< XComponentContext >& _rxContext, const Type& _rEnumType ) + :m_aEnumType( _rEnumType ) + { + try + { + if ( _rxContext.is() ) + { + Reference< XHierarchicalNameAccess > xTypeDescProv( + _rxContext->getValueByName("/singletons/com.sun.star.reflection.theTypeDescriptionManager"), + UNO_QUERY_THROW ); + + m_xTypeDescription.set( xTypeDescProv->getByHierarchicalName( m_aEnumType.getTypeName() ), UNO_QUERY_THROW ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EnumRepresentation::EnumRepresentation" ); + } + } + + std::vector< OUString > EnumRepresentation::getDescriptions() const + { + Sequence< OUString > aNames; + try + { + if ( m_xTypeDescription.is() ) + aNames = m_xTypeDescription->getEnumNames(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EnumRepresentation::getDescriptions" ); + } + + return std::vector< OUString >( std::cbegin(aNames), std::cend(aNames) ); + } + + void EnumRepresentation::impl_getValues( Sequence< sal_Int32 >& _out_rValues ) const + { + _out_rValues.realloc( 0 ); + try + { + if ( m_xTypeDescription.is() ) + _out_rValues = m_xTypeDescription->getEnumValues(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "EnumRepresentation::impl_getValues" ); + } + } + + void EnumRepresentation::getValueFromDescription( const OUString& _rDescription, Any& _out_rValue ) const + { + std::vector< OUString > aDescriptions( getDescriptions() ); + + sal_Int32 index = std::find( aDescriptions.begin(), aDescriptions.end(), + _rDescription ) - aDescriptions.begin(); + + Sequence< sal_Int32 > aValues; + impl_getValues( aValues ); + + if ( ( index >= 0 ) && ( index < aValues.getLength() ) ) + _out_rValue = ::cppu::int2enum( aValues[ index ], m_aEnumType ); + else + { + OSL_FAIL( "EnumRepresentation::getValueFromDescription: cannot convert!" ); + _out_rValue.clear(); + } + } + + OUString EnumRepresentation::getDescriptionForValue( const Any& _rEnumValue ) const + { + OUString sDescription; + + sal_Int32 nAsInt = 0; + OSL_VERIFY( ::cppu::enum2int( nAsInt, _rEnumValue ) ); + + Sequence< sal_Int32 > aValues; + impl_getValues( aValues ); + + sal_Int32 index = std::find( std::cbegin(aValues), std::cend(aValues), nAsInt ) - std::cbegin(aValues); + + std::vector< OUString > aDescriptions( getDescriptions() ); + if ( ( index >= 0 ) && ( o3tl::make_unsigned(index) < aDescriptions.size() ) ) + sDescription = aDescriptions[ index ]; + else + { + OSL_FAIL( "EnumRepresentation::getDescriptionForValue: cannot convert!" ); + } + return sDescription; + } + + typedef ::cppu::WeakImplHelper < XActionListener + > UrlClickHandler_Base; + + namespace { + + class UrlClickHandler : public UrlClickHandler_Base + { + Reference m_xContext; + public: + UrlClickHandler( const Reference& _rContext, const Reference< XHyperlinkControl >& _rxControl ); + + protected: + virtual ~UrlClickHandler() override; + + // XActionListener + virtual void SAL_CALL actionPerformed( const ActionEvent& rEvent ) override; + + // XEventListener + virtual void SAL_CALL disposing( const EventObject& Source ) override; + + protected: + void impl_dispatch_throw( const OUString& _rURL ); + }; + + } + + UrlClickHandler::UrlClickHandler( const Reference& _rContext, const Reference< XHyperlinkControl >& _rxControl ) + :m_xContext( _rContext ) + { + if ( !_rxControl.is() ) + throw NullPointerException(); + + osl_atomic_increment( &m_refCount ); + { + _rxControl->addActionListener( this ); + } + osl_atomic_decrement( &m_refCount ); + OSL_ENSURE( m_refCount > 0, "UrlClickHandler::UrlClickHandler: leaking!" ); + + } + + UrlClickHandler::~UrlClickHandler() + { + } + + void SAL_CALL UrlClickHandler::actionPerformed( const ActionEvent& rEvent ) + { + Reference< XPropertyControl > xControl( rEvent.Source, UNO_QUERY_THROW ); + Any aControlValue( xControl->getValue() ); + + OUString sURL; + if ( aControlValue.hasValue() && !( aControlValue >>= sURL ) ) + throw RuntimeException( OUString(), *this ); + + if ( sURL.isEmpty() ) + return; + + impl_dispatch_throw( sURL ); + } + + void SAL_CALL UrlClickHandler::disposing( const EventObject& /*Source*/ ) + { + // not interested in + } + + void UrlClickHandler::impl_dispatch_throw( const OUString& _rURL ) + { + Reference< XURLTransformer > xTransformer( URLTransformer::create(m_xContext) ); + URL aURL; aURL.Complete = ".uno:OpenHyperlink"; + xTransformer->parseStrict( aURL ); + + Reference< XDesktop2 > xDispProv = Desktop::create( m_xContext ); + Reference< XDispatch > xDispatch( xDispProv->queryDispatch( aURL, OUString(), 0 ), UNO_SET_THROW ); + + Sequence aDispatchArgs{ comphelper::makePropertyValue("URL", _rURL) }; + + xDispatch->dispatch( aURL, aDispatchArgs ); + } + + + GenericPropertyHandler::GenericPropertyHandler( const Reference< XComponentContext >& _rxContext ) + :GenericPropertyHandler_Base( m_aMutex ) + ,m_xContext( _rxContext ) + ,m_aPropertyListeners( m_aMutex ) + ,m_bPropertyMapInitialized( false ) + { + m_xTypeConverter = Converter::create(_rxContext); + } + + GenericPropertyHandler::~GenericPropertyHandler() + { + } + + OUString SAL_CALL GenericPropertyHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.GenericPropertyHandler"; + } + + sal_Bool SAL_CALL GenericPropertyHandler::supportsService( const OUString& ServiceName ) + { + return cppu::supportsService(this, ServiceName); + } + + Sequence< OUString > SAL_CALL GenericPropertyHandler::getSupportedServiceNames( ) + { + return { "com.sun.star.inspection.GenericPropertyHandler" }; + } + + void SAL_CALL GenericPropertyHandler::inspect( const Reference< XInterface >& _rxIntrospectee ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !_rxIntrospectee.is() ) + throw NullPointerException(); + + // revoke old property change listeners + ::comphelper::OInterfaceIteratorHelper2 iterRemove( m_aPropertyListeners ); + ::comphelper::OInterfaceIteratorHelper2 iterReAdd( m_aPropertyListeners ); // this holds a copy of the container ... + while ( iterRemove.hasMoreElements() ) + m_xComponent->removePropertyChangeListener( OUString(), static_cast< XPropertyChangeListener* >( iterRemove.next() ) ); + + m_xComponentIntrospectionAccess.clear(); + m_xComponent.clear(); + m_xPropertyState.clear(); + + // create an introspection adapter for the component + Reference< XIntrospection > xIntrospection = theIntrospection::get( m_xContext ); + + Reference< XIntrospectionAccess > xIntrospectionAccess( xIntrospection->inspect( Any( _rxIntrospectee ) ) ); + if ( !xIntrospectionAccess.is() ) + throw RuntimeException("The introspection service could not handle the given component.", *this ); + + m_xComponent.set( xIntrospectionAccess->queryAdapter( cppu::UnoType::get() ), UNO_QUERY_THROW ); + // now that we survived so far, remember m_xComponentIntrospectionAccess + m_xComponentIntrospectionAccess = xIntrospectionAccess; + m_xPropertyState.set(m_xComponent, css::uno::UNO_QUERY); + + m_bPropertyMapInitialized = false; + m_aProperties.clear(); + + // re-add the property change listeners + while ( iterReAdd.hasMoreElements() ) + m_xComponent->addPropertyChangeListener( OUString(), static_cast< XPropertyChangeListener* >( iterReAdd.next() ) ); + } + + Any SAL_CALL GenericPropertyHandler::getPropertyValue( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xComponent.is() ) + throw UnknownPropertyException(_rPropertyName); + + return m_xComponent->getPropertyValue( _rPropertyName ); + } + + void SAL_CALL GenericPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_xComponent.is() ) + throw UnknownPropertyException(_rPropertyName); + + m_xComponent->setPropertyValue( _rPropertyName, _rValue ); + } + + ::rtl::Reference< IPropertyEnumRepresentation > GenericPropertyHandler::impl_getEnumConverter( const Type& _rEnumType ) + { + ::rtl::Reference< IPropertyEnumRepresentation >& rConverter = m_aEnumConverters[ _rEnumType ]; + if ( !rConverter.is() ) + rConverter = new EnumRepresentation( m_xContext, _rEnumType ); + return rConverter; + } + + Any SAL_CALL GenericPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_ensurePropertyMap(); + + PropertyMap::const_iterator pos = m_aProperties.find( _rPropertyName ); + if ( pos == m_aProperties.end() ) + throw UnknownPropertyException(_rPropertyName); + + Any aPropertyValue; + if ( !_rControlValue.hasValue() ) + // NULL is converted to NULL + return aPropertyValue; + + if ( pos->second.Type.getTypeClass() == TypeClass_ENUM ) + { + OUString sControlValue; + OSL_VERIFY( _rControlValue >>= sControlValue ); + impl_getEnumConverter( pos->second.Type )->getValueFromDescription( sControlValue, aPropertyValue ); + } + else + aPropertyValue = PropertyHandlerHelper::convertToPropertyValue( m_xContext, m_xTypeConverter, pos->second, _rControlValue ); + + return aPropertyValue; + } + + Any SAL_CALL GenericPropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_ensurePropertyMap(); + + PropertyMap::const_iterator pos = m_aProperties.find( _rPropertyName ); + if ( pos == m_aProperties.end() ) + throw UnknownPropertyException(_rPropertyName); + + Any aControlValue; + if ( !_rPropertyValue.hasValue() ) + // NULL is converted to NULL + return aControlValue; + + if ( pos->second.Type.getTypeClass() == TypeClass_ENUM ) + { + aControlValue <<= impl_getEnumConverter( pos->second.Type )->getDescriptionForValue( _rPropertyValue ); + } + else + aControlValue = PropertyHandlerHelper::convertToControlValue( m_xContext, m_xTypeConverter, _rPropertyValue, _rControlValueType ); + return aControlValue; + } + + PropertyState SAL_CALL GenericPropertyHandler::getPropertyState( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyState eState = PropertyState_DIRECT_VALUE; + if ( m_xPropertyState.is() ) + eState = m_xPropertyState->getPropertyState( _rPropertyName ); + return eState; + } + + void SAL_CALL GenericPropertyHandler::addPropertyChangeListener(const Reference< XPropertyChangeListener >& _rxListener) + { + if ( !_rxListener.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + m_aPropertyListeners.addInterface( _rxListener ); + if ( m_xComponent.is() ) + { + try + { + m_xComponent->addPropertyChangeListener( OUString(), _rxListener ); + } + catch( const UnknownPropertyException& ) + { + OSL_FAIL( "GenericPropertyHandler::addPropertyChangeListener:\nThe inspected component does not allow registering for all properties at once! This violates the interface contract!" ); + } + } + } + + void SAL_CALL GenericPropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_xComponent.is() ) + { + try + { + m_xComponent->removePropertyChangeListener( OUString(), _rxListener ); + } + catch( const UnknownPropertyException& ) + { + OSL_FAIL( "GenericPropertyHandler::removePropertyChangeListener:\nThe inspected component does not allow de-registering for all properties at once! This violates the interface contract!" ); + } + } + m_aPropertyListeners.removeInterface( _rxListener ); + } + + void GenericPropertyHandler::impl_ensurePropertyMap() + { + if ( m_bPropertyMapInitialized ) + return; + + m_bPropertyMapInitialized = true; + try + { + Reference< XPropertySetInfo > xPSI; + if ( m_xComponent.is() ) + xPSI = m_xComponent->getPropertySetInfo(); + Sequence< Property > aProperties; + if ( xPSI.is() ) + aProperties = xPSI->getProperties(); + DBG_ASSERT( aProperties.hasElements(), "GenericPropertyHandler::getSupportedProperties: no properties!" ); + + for ( auto const & property : std::as_const(aProperties) ) + { + switch ( property.Type.getTypeClass() ) + { + case TypeClass_BOOLEAN: + case TypeClass_BYTE: + case TypeClass_SHORT: + case TypeClass_UNSIGNED_SHORT: + case TypeClass_LONG: + case TypeClass_UNSIGNED_LONG: + case TypeClass_HYPER: + case TypeClass_UNSIGNED_HYPER: + case TypeClass_FLOAT: + case TypeClass_DOUBLE: + case TypeClass_ENUM: + case TypeClass_STRING: + // allowed, we can handle this type + break; + + case TypeClass_SEQUENCE: + { + TypeClass eElementTypeClass = ::comphelper::getSequenceElementType( property.Type ).getTypeClass(); + if ( ( eElementTypeClass != TypeClass_STRING ) + && ( eElementTypeClass != TypeClass_BYTE ) + && ( eElementTypeClass != TypeClass_SHORT ) + && ( eElementTypeClass != TypeClass_UNSIGNED_SHORT ) + && ( eElementTypeClass != TypeClass_LONG ) + && ( eElementTypeClass != TypeClass_UNSIGNED_LONG ) + ) + // can only handle the above + continue; + } + break; + + default: + // next property, we don't support this type + continue; + } + + m_aProperties.emplace( property.Name, property ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "GenericPropertyHandler::impl_ensurePropertyMap" ); + } + } + + Sequence< Property > SAL_CALL GenericPropertyHandler::getSupportedProperties() + { + ::osl::MutexGuard aGuard( m_aMutex ); + impl_ensurePropertyMap(); + + return comphelper::mapValuesToSequence( m_aProperties ); + } + + Sequence< OUString > SAL_CALL GenericPropertyHandler::getSupersededProperties( ) + { + // no superseded properties at all. This handler offers the very basic PropertyHandler + // functionality, so it's much more likely that other handlers want to supersede + // *our* properties... + return Sequence< OUString >( ); + } + + Sequence< OUString > SAL_CALL GenericPropertyHandler::getActuatingProperties( ) + { + // This basic PropertyHandler implementation is too dumb^Wgeneric to know + // anything about property dependencies + return Sequence< OUString >( ); + } + + LineDescriptor SAL_CALL GenericPropertyHandler::describePropertyLine( const OUString& _rPropertyName, + const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + if ( !_rxControlFactory.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + impl_ensurePropertyMap(); + + PropertyMap::const_iterator pos = m_aProperties.find( _rPropertyName ); + if ( pos == m_aProperties.end() ) + throw UnknownPropertyException(_rPropertyName); + + LineDescriptor aDescriptor; + aDescriptor.DisplayName = _rPropertyName; + switch ( pos->second.Type.getTypeClass() ) + { + case TypeClass_ENUM: + aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory, + impl_getEnumConverter( pos->second.Type )->getDescriptions(), + PropertyHandlerHelper::requiresReadOnlyControl( pos->second.Attributes ), + false ); + break; + case TypeClass_STRING: + { + // some special handling for URL properties + bool bIsURLProperty = _rPropertyName.endsWith( "URL" ); + if ( bIsURLProperty ) + { + aDescriptor.Control = _rxControlFactory->createPropertyControl( + PropertyControlType::HyperlinkField, PropertyHandlerHelper::requiresReadOnlyControl( pos->second.Attributes ) ); + + Reference< XHyperlinkControl > xControl( aDescriptor.Control, UNO_QUERY_THROW ); + new UrlClickHandler( m_xContext, xControl ); + } + } + break; + default: + break; + } + // fallback + if ( !aDescriptor.Control.is() ) + PropertyHandlerHelper::describePropertyLine( pos->second, aDescriptor, _rxControlFactory ); + + aDescriptor.Category = "General"; + return aDescriptor; + } + + sal_Bool SAL_CALL GenericPropertyHandler::isComposable( const OUString& /*_rPropertyName*/ ) + { + return false; + } + + InteractiveSelectionResult SAL_CALL GenericPropertyHandler::onInteractivePropertySelection( const OUString& /*_rPropertyName*/, sal_Bool /*_bPrimary*/, Any& /*_rData*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/ ) + { + OSL_FAIL( "GenericPropertyHandler::onInteractivePropertySelection: I'm too dumb to know anything about property browse buttons!" ); + return InteractiveSelectionResult_Cancelled; + } + + void SAL_CALL GenericPropertyHandler::actuatingPropertyChanged( const OUString& /*_rActuatingPropertyName*/, const Any& /*_rNewValue*/, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/, sal_Bool /*_bFirstTimeInit*/ ) + { + OSL_FAIL( "GenericPropertyHandler::actuatingPropertyChanged: no no no, I did not register for any actuating properties!" ); + } + + sal_Bool SAL_CALL GenericPropertyHandler::suspend( sal_Bool /*_bSuspend*/ ) + { + return true; + } + + void SAL_CALL GenericPropertyHandler::disposing() + { + m_aPropertyListeners.clear(); + // not disposeAndClear: the listeners are (virtually) listeners at our introspectee, not + // at this handler instance + } + + IMPLEMENT_FORWARD_XCOMPONENT( GenericPropertyHandler, GenericPropertyHandler_Base ); + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_GenericPropertyHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::GenericPropertyHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/genericpropertyhandler.hxx b/extensions/source/propctrlr/genericpropertyhandler.hxx new file mode 100644 index 000000000..b2114be3c --- /dev/null +++ b/extensions/source/propctrlr/genericpropertyhandler.hxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "pcrcommontypes.hxx" +#include "pcrcommon.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace pcr +{ + + + struct TypeLess + { + bool operator()( const css::uno::Type& _rLHS, const css::uno::Type& _rRHS ) const + { + return _rLHS.getTypeName() < _rRHS.getTypeName(); + } + }; + + class IPropertyEnumRepresentation; + + //= GenericPropertyHandler + + typedef ::cppu::WeakComponentImplHelper < css::inspection::XPropertyHandler + , css::lang::XServiceInfo + > GenericPropertyHandler_Base; + class GenericPropertyHandler final : public GenericPropertyHandler_Base + { + mutable ::osl::Mutex m_aMutex; + + /// the service factory for creating services + css::uno::Reference< css::uno::XComponentContext > m_xContext; + /// need this to keep alive as long as m_xComponent lives + css::uno::Reference< css::beans::XIntrospectionAccess > m_xComponentIntrospectionAccess; + /// the properties of the object we're handling + css::uno::Reference< css::beans::XPropertySet > m_xComponent; + /// cached interface of ->m_xComponent + css::uno::Reference< css::beans::XPropertyState > m_xPropertyState; + /// type converter, needed on various occasions + css::uno::Reference< css::script::XTypeConverter > m_xTypeConverter; + /// cache of our supported properties + PropertyMap m_aProperties; + /// property change listeners + ::comphelper::OInterfaceContainerHelper2 m_aPropertyListeners; + std::map< css::uno::Type, ::rtl::Reference< IPropertyEnumRepresentation >, TypeLess > + m_aEnumConverters; + + /// has ->m_aProperties been initialized? + bool m_bPropertyMapInitialized : 1; + + public: + explicit GenericPropertyHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + virtual ~GenericPropertyHandler() override; + + private: + // XPropertyHandler overridables + virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override; + virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override; + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual css::uno::Sequence< css::beans::Property > + SAL_CALL getSupportedProperties() override; + virtual css::uno::Sequence< OUString > + SAL_CALL getSupersededProperties() override; + virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties() override; + virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + virtual sal_Bool SAL_CALL isComposable( const OUString& _rPropertyName ) override; + virtual css::inspection::InteractiveSelectionResult + SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override; + virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override; + + // XComponent + DECLARE_XCOMPONENT() + virtual void SAL_CALL disposing() 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; + + /** ensures that ->m_aProperties is initialized + @precond + our mutex is locked + */ + void impl_ensurePropertyMap(); + + /** retrieves the enum converter for the given ENUM type + */ + ::rtl::Reference< IPropertyEnumRepresentation > + impl_getEnumConverter( const css::uno::Type& _rEnumType ); + + GenericPropertyHandler( const GenericPropertyHandler& ) = delete; + GenericPropertyHandler& operator=( const GenericPropertyHandler& ) = delete; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/handlerhelper.cxx b/extensions/source/propctrlr/handlerhelper.cxx new file mode 100644 index 000000000..89f149b92 --- /dev/null +++ b/extensions/source/propctrlr/handlerhelper.cxx @@ -0,0 +1,314 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "handlerhelper.hxx" +#include +#include "modulepcr.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::inspection; + + + //= PropertyHandlerHelper + + + void PropertyHandlerHelper::describePropertyLine( const Property& _rProperty, + LineDescriptor& /* [out] */ _out_rDescriptor, const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + // display the pure property name - no L10N + _out_rDescriptor.DisplayName = _rProperty.Name; + + OSL_PRECOND( _rxControlFactory.is(), "PropertyHandlerHelper::describePropertyLine: no factory -> no control!" ); + if ( !_rxControlFactory.is() ) + return; + + bool bReadOnlyControl = requiresReadOnlyControl( _rProperty.Attributes ); + + // special handling for booleans (this will become a list) + if ( _rProperty.Type.getTypeClass() == TypeClass_BOOLEAN ) + { + _out_rDescriptor.Control = createListBoxControl(_rxControlFactory, RID_RSC_ENUM_YESNO, SAL_N_ELEMENTS(RID_RSC_ENUM_YESNO), bReadOnlyControl); + return; + } + + sal_Int16 nControlType = PropertyControlType::TextField; + switch ( _rProperty.Type.getTypeClass() ) + { + case TypeClass_BYTE: + case TypeClass_SHORT: + case TypeClass_UNSIGNED_SHORT: + case TypeClass_LONG: + case TypeClass_UNSIGNED_LONG: + case TypeClass_HYPER: + case TypeClass_UNSIGNED_HYPER: + case TypeClass_FLOAT: + case TypeClass_DOUBLE: + nControlType = PropertyControlType::NumericField; + break; + + case TypeClass_SEQUENCE: + nControlType = PropertyControlType::StringListField; + break; + + default: + OSL_FAIL( "PropertyHandlerHelper::describePropertyLine: don't know how to represent this at the UI!" ); + [[fallthrough]]; + + case TypeClass_STRING: + nControlType = PropertyControlType::TextField; + break; + } + + // create a control + _out_rDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, bReadOnlyControl ); + } + + + namespace + { + Reference< XPropertyControl > lcl_implCreateListLikeControl( + const Reference< XPropertyControlFactory >& _rxControlFactory, + std::vector< OUString >&& _rInitialListEntries, + bool _bReadOnlyControl, + bool _bSorted, + bool _bTrueIfListBoxFalseIfComboBox + ) + { + Reference< XStringListControl > xListControl( + _rxControlFactory->createPropertyControl( + _bTrueIfListBoxFalseIfComboBox ? PropertyControlType::ListBox : PropertyControlType::ComboBox, _bReadOnlyControl + ), + UNO_QUERY_THROW + ); + + if ( _bSorted ) + std::sort( _rInitialListEntries.begin(), _rInitialListEntries.end() ); + + for (auto const& initialEntry : _rInitialListEntries) + xListControl->appendListEntry(initialEntry); + return xListControl; + } + } + + Reference< XPropertyControl > PropertyHandlerHelper::createListBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory, + std::vector< OUString >&& _rInitialListEntries, bool _bReadOnlyControl, bool _bSorted ) + { + return lcl_implCreateListLikeControl(_rxControlFactory, std::move(_rInitialListEntries), _bReadOnlyControl, _bSorted, true); + } + + Reference< XPropertyControl > PropertyHandlerHelper::createListBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory, + const TranslateId* pTransIds, size_t nElements, bool _bReadOnlyControl ) + { + std::vector aInitialListEntries; + for (size_t i = 0; i < nElements; ++i) + aInitialListEntries.push_back(PcrRes(pTransIds[i])); + return lcl_implCreateListLikeControl(_rxControlFactory, std::move(aInitialListEntries), _bReadOnlyControl, /*_bSorted*/false, true); + } + + Reference< XPropertyControl > PropertyHandlerHelper::createComboBoxControl( const Reference< XPropertyControlFactory >& _rxControlFactory, + std::vector< OUString >&& _rInitialListEntries, bool _bSorted ) + { + return lcl_implCreateListLikeControl( _rxControlFactory, std::move(_rInitialListEntries), /*_bReadOnlyControl*/false, _bSorted, false ); + } + + + Reference< XPropertyControl > PropertyHandlerHelper::createNumericControl( const Reference< XPropertyControlFactory >& _rxControlFactory, + sal_Int16 _nDigits, const Optional< double >& _rMinValue, const Optional< double >& _rMaxValue ) + { + Reference< XNumericControl > xNumericControl( + _rxControlFactory->createPropertyControl( PropertyControlType::NumericField, /*_bReadOnlyControl*/false ), + UNO_QUERY_THROW + ); + + xNumericControl->setDecimalDigits( _nDigits ); + xNumericControl->setMinValue( _rMinValue ); + xNumericControl->setMaxValue( _rMaxValue ); + + return xNumericControl; + } + + + Any PropertyHandlerHelper::convertToPropertyValue( const Reference< XComponentContext >& _rxContext,const Reference< XTypeConverter >& _rxTypeConverter, + const Property& _rProperty, const Any& _rControlValue ) + { + Any aPropertyValue( _rControlValue ); + if ( !aPropertyValue.hasValue() ) + // NULL is converted to NULL + return aPropertyValue; + + if ( aPropertyValue.getValueType().equals( _rProperty.Type ) ) + // nothing to do, type is already as desired + return aPropertyValue; + + if ( _rControlValue.getValueType().getTypeClass() == TypeClass_STRING ) + { + OUString sControlValue; + _rControlValue >>= sControlValue; + + Reference< XStringRepresentation > xConversionHelper = StringRepresentation::create( _rxContext,_rxTypeConverter ); + aPropertyValue = xConversionHelper->convertToPropertyValue( sControlValue, _rProperty.Type ); + } + else + { + try + { + if ( _rxTypeConverter.is() ) + aPropertyValue = _rxTypeConverter->convertTo( _rControlValue, _rProperty.Type ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", + "caught an exception while converting via TypeConverter!"); + } + } + + return aPropertyValue; + } + + + Any PropertyHandlerHelper::convertToControlValue( const Reference< XComponentContext >& _rxContext,const Reference< XTypeConverter >& _rxTypeConverter, + const Any& _rPropertyValue, const Type& _rControlValueType ) + { + Any aControlValue( _rPropertyValue ); + if ( !aControlValue.hasValue() ) + // NULL is converted to NULL + return aControlValue; + + if ( _rControlValueType.getTypeClass() == TypeClass_STRING ) + { + Reference< XStringRepresentation > xConversionHelper = StringRepresentation::create( _rxContext,_rxTypeConverter ); + aControlValue <<= xConversionHelper->convertToControlValue( _rPropertyValue ); + } + else + { + try + { + if ( _rxTypeConverter.is() ) + aControlValue = _rxTypeConverter->convertTo( _rPropertyValue, _rControlValueType ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", + "caught an exception while converting via TypeConverter!"); + } + } + + return aControlValue; + } + + + void PropertyHandlerHelper::setContextDocumentModified( const Reference & rContext ) + { + try + { + Reference< XModifiable > xDocumentModifiable( getContextDocument_throw(rContext), UNO_QUERY_THROW ); + xDocumentModifiable->setModified( true ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + Reference< XInterface > PropertyHandlerHelper::getContextDocument( const Reference & rContext ) + { + Reference< XInterface > xI; + try + { + xI = getContextDocument_throw( rContext ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PropertyHandler::getContextValueByName" ); + } + return xI; + } + + Reference< XInterface > PropertyHandlerHelper::getContextDocument_throw( const Reference & rContext ) + { + Reference< XInterface > xI; + Any aReturn = rContext->getValueByName( "ContextDocument" ); + aReturn >>= xI; + return xI; + } + + weld::Window* PropertyHandlerHelper::getDialogParentFrame(const Reference& rContext) + { + weld::Window* pInspectorWindow = nullptr; + try + { + Reference< XWindow > xInspectorWindow(rContext->getValueByName( "DialogParentWindow" ), UNO_QUERY_THROW); + pInspectorWindow = Application::GetFrameWeld(xInspectorWindow); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return pInspectorWindow; + } + + std::unique_ptr PropertyHandlerHelper::makeBuilder(const OUString& rUIFile, const Reference& rContext) + { + Reference xWindow(rContext->getValueByName("BuilderParent"), UNO_QUERY_THROW); + weld::TransportAsXWindow& rTunnel = dynamic_cast(*xWindow); + return Application::CreateBuilder(rTunnel.getWidget(), rUIFile); + } + + void PropertyHandlerHelper::setBuilderParent(const css::uno::Reference& rContext, weld::Widget* pParent) + { + Reference xName(rContext, UNO_QUERY_THROW); + Reference xWindow(new weld::TransportAsXWindow(pParent)); + xName->insertByName("BuilderParent", Any(xWindow)); + } + + void PropertyHandlerHelper::clearBuilderParent(const css::uno::Reference& rContext) + { + Reference xName(rContext, UNO_QUERY_THROW); + xName->removeByName("BuilderParent"); + } + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/handlerhelper.hxx b/extensions/source/propctrlr/handlerhelper.hxx new file mode 100644 index 000000000..555b8ee82 --- /dev/null +++ b/extensions/source/propctrlr/handlerhelper.hxx @@ -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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace weld { class Builder; class Widget; class Window; } +namespace com::sun::star { + namespace inspection { + struct LineDescriptor; + } +} + +namespace pcr +{ + + + //= PropertyHandlerHelper + + class PropertyHandlerHelper + { + public: + /** helper for implementing XPropertyHandler::describePropertyLine in a generic way + */ + static void describePropertyLine( + const css::beans::Property& _rProperty, + css::inspection::LineDescriptor& /* [out] */ _out_rDescriptor, + const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory + ); + + /** helper for implementing XPropertyHandler::convertToPropertyValue + */ + static css::uno::Any convertToPropertyValue( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const css::uno::Reference< css::script::XTypeConverter >& _rxTypeConverter, + const css::beans::Property& _rProperty, + const css::uno::Any& _rControlValue + ); + + /// helper for implementing XPropertyHandler::convertToControlValue + static css::uno::Any convertToControlValue( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const css::uno::Reference< css::script::XTypeConverter >& _rxTypeConverter, + const css::uno::Any& _rPropertyValue, + const css::uno::Type& _rControlValueType + ); + + /** creates an PropertyControlType::ListBox-type control + and fills it with initial values + + @param _rxControlFactory + A control factory. Must not be . + + @param _rInitialListEntries + the initial values of the control + + @param _bReadOnlyControl + determines whether the control should be read-only + + @param _bSorted + determines whether the list entries should be sorted + + @return + the newly created control + */ + static css::uno::Reference< css::inspection::XPropertyControl > + createListBoxControl( + const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory, + std::vector< OUString >&& _rInitialListEntries, + bool _bReadOnlyControl, + bool _bSorted + ); + + /** creates an PropertyControlType::ListBox-type control + and fills it with initial values. + + @param _rxControlFactory + A control factory. Must not be . + + @param pTransIds + the initial translation ids for the value of the control + + @param nElements + the count of initial values of the control + + @param _bReadOnlyControl + determines whether the control should be read-only + + @return + the newly created control + */ + static css::uno::Reference< css::inspection::XPropertyControl > + createListBoxControl( + const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory, + const TranslateId* pTransIds, size_t nElements, + bool _bReadOnlyControl + ); + + /** creates an PropertyControlType::ComboBox-type control + and fills it with initial values + + @param _rxControlFactory + A control factory. Must not be . + + @param _rInitialListEntries + the initial values of the control + + @param _bSorted + determines whether the list entries should be sorted + + @return + the newly created control + */ + static css::uno::Reference< css::inspection::XPropertyControl > + createComboBoxControl( + const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory, + std::vector< OUString >&& _rInitialListEntries, + bool _bSorted + ); + + /** creates an PropertyControlType::NumericField-type control + and initializes it + + @param _rxControlFactory + A control factory. Must not be . + @param _nDigits + number of decimal digits for the control + (XNumericControl::DecimalDigits) + @param _rMinValue + minimum value which can be entered in the control + (XNumericControl::MinValue) + @param _rMaxValue + maximum value which can be entered in the control + (XNumericControl::MaxValue) + + @return + the newly created control + */ + static css::uno::Reference< css::inspection::XPropertyControl > + createNumericControl( + const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory, + sal_Int16 _nDigits, + const css::beans::Optional< double >& _rMinValue, + const css::beans::Optional< double >& _rMaxValue + ); + + /** marks the document passed in our UNO context as modified + + The method looks up a value called "ContextDocument" in the given UNO component context, + queries it for the ->css::util::XModifiable interface, and calls its + setModified method. If either of those steps fails, this is asserted in a non-product + version, and silently ignore otherwise. + + @param _rContext + the component context which was used to create the component calling this method + */ + static void setContextDocumentModified( + const css::uno::Reference< css::uno::XComponentContext > & _rContext + ); + + static css::uno::Reference< css::uno::XInterface > getContextDocument( const css::uno::Reference & _rContext ); + + /// @throws css::uno::RuntimeException + static css::uno::Reference< css::uno::XInterface > getContextDocument_throw( const css::uno::Reference & _rContext ); + + /** gets the window of the ObjectInspector in which a property handler lives + + The method looks up a value called "DialogParentWindow" in the given UNO component context, + queries it for XWindow, and returns the respective weld::Window*. If either of those steps fails, + this is asserted in a non-product version, and silently ignore otherwise. + + @param _rContext + the component context which was used to create the component calling this method + */ + static weld::Window* getDialogParentFrame( const css::uno::Reference< css::uno::XComponentContext > & _rContext ); + + + /** determines whether given PropertyAttributes require a to-be-created + XPropertyControl to be read-only + + @param _nPropertyAttributes + the attributes of the property which should be reflected by a to-be-created + XPropertyControl + */ + static bool requiresReadOnlyControl( sal_Int16 _nPropertyAttributes ) + { + return ( _nPropertyAttributes & css::beans::PropertyAttribute::READONLY ) != 0; + } + + static std::unique_ptr makeBuilder(const OUString& rUIFile, const css::uno::Reference& rContext); + + static void setBuilderParent(const css::uno::Reference& rContext, weld::Widget* pParent); + + static void clearBuilderParent(const css::uno::Reference& rContext); + + private: + PropertyHandlerHelper( const PropertyHandlerHelper& ) = delete; + PropertyHandlerHelper& operator=( const PropertyHandlerHelper& ) = delete; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/inspectorhelpwindow.cxx b/extensions/source/propctrlr/inspectorhelpwindow.cxx new file mode 100644 index 000000000..a57c4ffed --- /dev/null +++ b/extensions/source/propctrlr/inspectorhelpwindow.cxx @@ -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 . + */ +#include "inspectorhelpwindow.hxx" + + +namespace pcr +{ + //= InspectorHelpWindow + InspectorHelpWindow::InspectorHelpWindow(weld::Builder& rBuilder) + : m_xHelpFrame(rBuilder.weld_widget("helpframe")) + , m_xHelpText(rBuilder.weld_text_view("helptext")) + { + } + + InspectorHelpWindow::~InspectorHelpWindow() + { + } + + void InspectorHelpWindow::SetText(const OUString& rStr) + { + m_xHelpText->set_text(rStr); + } + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/inspectorhelpwindow.hxx b/extensions/source/propctrlr/inspectorhelpwindow.hxx new file mode 100644 index 000000000..98b8efbab --- /dev/null +++ b/extensions/source/propctrlr/inspectorhelpwindow.hxx @@ -0,0 +1,44 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +namespace pcr +{ + //= InspectorHelpWindow + class InspectorHelpWindow + { + private: + std::unique_ptr m_xHelpFrame; + std::unique_ptr m_xHelpText; + + public: + explicit InspectorHelpWindow(weld::Builder& rBuilder); + ~InspectorHelpWindow(); + + void SetText(const OUString& rStr); + + void Show(bool bShow) { m_xHelpFrame->set_visible(bShow); } + bool IsVisible() const { return m_xHelpFrame->get_visible(); } + }; + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/inspectormodelbase.cxx b/extensions/source/propctrlr/inspectormodelbase.cxx new file mode 100644 index 000000000..f8780ff99 --- /dev/null +++ b/extensions/source/propctrlr/inspectormodelbase.cxx @@ -0,0 +1,246 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "inspectormodelbase.hxx" + +#include + +#include +#include + + +namespace pcr +{ + + +#define MODEL_PROPERTY_ID_HAS_HELP_SECTION 2000 +#define MODEL_PROPERTY_ID_MIN_HELP_TEXT_LINES 2001 +#define MODEL_PROPERTY_ID_MAX_HELP_TEXT_LINES 2002 +#define MODEL_PROPERTY_ID_IS_READ_ONLY 2003 + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::beans::XPropertySetInfo; + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::beans::Property; + + namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute; + + + //= InspectorModelProperties + + /** helper class for implementing the property set related functionality + of an ImplInspectorModel + */ + class InspectorModelProperties : public ::comphelper::OPropertyContainerHelper + { + private: + ::osl::Mutex& m_rMutex; + bool m_bHasHelpSection; + sal_Int32 m_nMinHelpTextLines; + sal_Int32 m_nMaxHelpTextLines; + bool m_bIsReadOnly; + std::unique_ptr< ::cppu::IPropertyArrayHelper > + m_pPropertyInfo; + + public: + explicit InspectorModelProperties( ::osl::Mutex& _rMutex ); + + using ::comphelper::OPropertyContainerHelper::convertFastPropertyValue; + using ::comphelper::OPropertyContainerHelper::setFastPropertyValue; + using ::comphelper::OPropertyContainerHelper::getFastPropertyValue; + + public: + bool hasHelpSection() const { return m_bHasHelpSection; } + bool isReadOnly() const { return m_bIsReadOnly; } + sal_Int32 getMinHelpTextLines() const { return m_nMinHelpTextLines; } + sal_Int32 getMaxHelpTextLines() const { return m_nMaxHelpTextLines; } + + css::uno::Reference< css::beans::XPropertySetInfo > + getPropertySetInfo(); + ::cppu::IPropertyArrayHelper& + getInfoHelper(); + + void constructWithHelpSection( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines ); + }; + + + //= InspectorModelProperties + + + InspectorModelProperties::InspectorModelProperties( ::osl::Mutex& _rMutex ) + :m_rMutex( _rMutex ) + ,m_bHasHelpSection( false ) + ,m_nMinHelpTextLines( 3 ) + ,m_nMaxHelpTextLines( 8 ) + ,m_bIsReadOnly( false ) + { + registerProperty( + "HasHelpSection", + MODEL_PROPERTY_ID_HAS_HELP_SECTION, + PropertyAttribute::READONLY, + &m_bHasHelpSection, cppu::UnoType::get() + ); + registerProperty( + "MinHelpTextLines", + MODEL_PROPERTY_ID_MIN_HELP_TEXT_LINES, + PropertyAttribute::READONLY, + &m_nMinHelpTextLines, cppu::UnoType::get() + ); + registerProperty( + "MaxHelpTextLines", + MODEL_PROPERTY_ID_MAX_HELP_TEXT_LINES, + PropertyAttribute::READONLY, + &m_nMaxHelpTextLines, cppu::UnoType::get() + ); + registerProperty( + "IsReadOnly", + MODEL_PROPERTY_ID_IS_READ_ONLY, + PropertyAttribute::BOUND, + &m_bIsReadOnly, cppu::UnoType::get() + ); + } + + + void InspectorModelProperties::constructWithHelpSection( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines ) + { + m_bHasHelpSection = true; + m_nMinHelpTextLines = _nMinHelpTextLines; + m_nMaxHelpTextLines = _nMaxHelpTextLines; + // no need to notify this, those properties are not bound. Also, the method should + // only be used during construction phase, where we don't expect to have any listeners. + } + + + ::cppu::IPropertyArrayHelper& InspectorModelProperties::getInfoHelper() + { + ::osl::MutexGuard aGuard( m_rMutex ); + if (m_pPropertyInfo == nullptr) + { + Sequence< Property > aProperties; + describeProperties( aProperties ); + + m_pPropertyInfo.reset( new ::cppu::OPropertyArrayHelper( aProperties ) ); + } + return *m_pPropertyInfo; + } + + + Reference< XPropertySetInfo > InspectorModelProperties::getPropertySetInfo() + { + return ::cppu::OPropertySetHelper::createPropertySetInfo( getInfoHelper() ); + } + + + //= ImplInspectorModel + + ImplInspectorModel::ImplInspectorModel() + :ImplInspectorModel_PBase( GetBroadcastHelper() ) + ,m_pProperties( new InspectorModelProperties( m_aMutex ) ) + { + } + + + ImplInspectorModel::~ImplInspectorModel() + { + } + + + IMPLEMENT_FORWARD_XINTERFACE2( ImplInspectorModel, ImplInspectorModel_Base, ImplInspectorModel_PBase ) + + + IMPLEMENT_FORWARD_XTYPEPROVIDER2( ImplInspectorModel, ImplInspectorModel_Base, ImplInspectorModel_PBase ) + + + Reference< XPropertySetInfo > SAL_CALL ImplInspectorModel::getPropertySetInfo( ) + { + return m_pProperties->getPropertySetInfo(); + } + + + ::cppu::IPropertyArrayHelper& SAL_CALL ImplInspectorModel::getInfoHelper() + { + return m_pProperties->getInfoHelper(); + } + + + sal_Bool SAL_CALL ImplInspectorModel::convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue ) + { + return m_pProperties->convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue ); + } + + + void SAL_CALL ImplInspectorModel::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue ) + { + m_pProperties->setFastPropertyValue( nHandle, rValue ); + } + + + void SAL_CALL ImplInspectorModel::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const + { + m_pProperties->getFastPropertyValue( rValue, nHandle ); + } + + + sal_Bool SAL_CALL ImplInspectorModel::getHasHelpSection() + { + return m_pProperties->hasHelpSection(); + } + + + ::sal_Int32 SAL_CALL ImplInspectorModel::getMinHelpTextLines() + { + return m_pProperties->getMinHelpTextLines(); + } + + + ::sal_Int32 SAL_CALL ImplInspectorModel::getMaxHelpTextLines() + { + return m_pProperties->getMaxHelpTextLines(); + } + + + sal_Bool SAL_CALL ImplInspectorModel::getIsReadOnly() + { + return m_pProperties->isReadOnly(); + } + + + void SAL_CALL ImplInspectorModel::setIsReadOnly( sal_Bool IsReadOnly ) + { + setFastPropertyValue( MODEL_PROPERTY_ID_IS_READ_ONLY, Any( IsReadOnly ) ); + } + + sal_Bool SAL_CALL ImplInspectorModel::supportsService( const OUString& ServiceName ) + { + return cppu::supportsService(this, ServiceName); + } + + + void ImplInspectorModel::enableHelpSectionProperties( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines ) + { + m_pProperties->constructWithHelpSection( _nMinHelpTextLines, _nMaxHelpTextLines ); + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/inspectormodelbase.hxx b/extensions/source/propctrlr/inspectormodelbase.hxx new file mode 100644 index 000000000..527668b2f --- /dev/null +++ b/extensions/source/propctrlr/inspectormodelbase.hxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +#include +#include + +#include +#include + +#include + + +namespace pcr +{ + + + class InspectorModelProperties; + + //= ImplInspectorModel + + typedef ::cppu::WeakImplHelper < css::inspection::XObjectInspectorModel + , css::lang::XInitialization + , css::lang::XServiceInfo + > ImplInspectorModel_Base; + typedef ::cppu::OPropertySetHelper ImplInspectorModel_PBase; + + class ImplInspectorModel + :public ::comphelper::OMutexAndBroadcastHelper + ,public ImplInspectorModel_Base + ,public ImplInspectorModel_PBase + { + std::unique_ptr< InspectorModelProperties > m_pProperties; + + protected: + virtual ~ImplInspectorModel() override; + + public: + ImplInspectorModel(); + + DECLARE_XINTERFACE() + DECLARE_XTYPEPROVIDER() + + // css::beans::XPropertySet and friends + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + 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::inspection::XObjectInspectorModel + virtual sal_Bool SAL_CALL getHasHelpSection() override; + virtual ::sal_Int32 SAL_CALL getMinHelpTextLines() override; + virtual ::sal_Int32 SAL_CALL getMaxHelpTextLines() override; + virtual sal_Bool SAL_CALL getIsReadOnly() override; + virtual void SAL_CALL setIsReadOnly( sal_Bool IsReadOnly ) override; + + // css::lang::XServiceInfo + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + + protected: + void enableHelpSectionProperties( sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines ); + + private: + using ImplInspectorModel_PBase::getFastPropertyValue; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/linedescriptor.hxx b/extensions/source/propctrlr/linedescriptor.hxx new file mode 100644 index 000000000..a73eda7cf --- /dev/null +++ b/extensions/source/propctrlr/linedescriptor.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +namespace pcr +{ + //= OLineDescriptor + struct OLineDescriptor : public css::inspection::LineDescriptor + { + OUString sName; // the name of the property + css::uno::Reference< css::inspection::XPropertyHandler > + xPropertyHandler; // the handler for this property + css::uno::Any aValue; // the current value of the property + + bool bUnknownValue : 1; // is the property value currently "unknown"? (PropertyState_AMBIGUOUS) + bool bReadOnly : 1; + + OLineDescriptor() + :bUnknownValue( false ) + ,bReadOnly( false ) + { + } + + void assignFrom( const css::inspection::LineDescriptor& _rhs ) + { + css::inspection::LineDescriptor::operator=( _rhs ); + } + }; + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/listselectiondlg.cxx b/extensions/source/propctrlr/listselectiondlg.cxx new file mode 100644 index 000000000..18ab1d778 --- /dev/null +++ b/extensions/source/propctrlr/listselectiondlg.cxx @@ -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 . + */ + +#include "listselectiondlg.hxx" + +#include "formstrings.hxx" +#include +#include + +namespace pcr +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + + ListSelectionDialog::ListSelectionDialog(weld::Window* pParent, const Reference< XPropertySet >& _rxListBox, + const OUString& _rPropertyName, const OUString& _rPropertyUIName) + : GenericDialogController(pParent, "modules/spropctrlr/ui/listselectdialog.ui", "ListSelectDialog") + , m_xListBox ( _rxListBox ) + , m_sPropertyName( _rPropertyName ) + , m_xFrame(m_xBuilder->weld_frame("frame")) + , m_xEntries(m_xBuilder->weld_tree_view("treeview")) + { + OSL_PRECOND( m_xListBox.is(), "ListSelectionDialog::ListSelectionDialog: invalid list box!" ); + + m_xEntries->set_size_request(m_xEntries->get_approximate_digit_width() * 40, m_xEntries->get_height_rows(9)); + + m_xDialog->set_title(_rPropertyUIName); + m_xFrame->set_label(_rPropertyUIName); + + initialize( ); + } + + ListSelectionDialog::~ListSelectionDialog() + { + } + + short ListSelectionDialog::run() + { + short nResult = GenericDialogController::run(); + + if ( RET_OK == nResult ) + commitSelection(); + + return nResult; + } + + + void ListSelectionDialog::initialize( ) + { + if ( !m_xListBox.is() ) + return; + + try + { + // initialize the multi-selection flag + bool bMultiSelection = false; + OSL_VERIFY( m_xListBox->getPropertyValue( PROPERTY_MULTISELECTION ) >>= bMultiSelection ); + m_xEntries->set_selection_mode(bMultiSelection ? SelectionMode::Single : SelectionMode::Multiple); + + // fill the list box with all entries + Sequence< OUString > aListEntries; + OSL_VERIFY( m_xListBox->getPropertyValue( PROPERTY_STRINGITEMLIST ) >>= aListEntries ); + fillEntryList( aListEntries ); + + // select entries according to the property + Sequence< sal_Int16 > aSelection; + OSL_VERIFY( m_xListBox->getPropertyValue( m_sPropertyName ) >>= aSelection ); + selectEntries( aSelection ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "ListSelectionDialog::initialize" ); + } + } + + void ListSelectionDialog::commitSelection() + { + if ( !m_xListBox.is() ) + return; + + std::vector< sal_Int16 > aSelection; + collectSelection( aSelection ); + + try + { + m_xListBox->setPropertyValue( m_sPropertyName, Any( comphelper::containerToSequence(aSelection) ) ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "ListSelectionDialog::commitSelection" ); + } + } + + void ListSelectionDialog::fillEntryList( const Sequence< OUString >& _rListEntries ) + { + m_xEntries->freeze(); + m_xEntries->clear(); + for (auto const & entry : _rListEntries) + m_xEntries->append_text(entry); + m_xEntries->thaw(); + } + + void ListSelectionDialog::collectSelection( std::vector< sal_Int16 >& /* [out] */ _rSelection ) + { + auto aSelection = m_xEntries->get_selected_rows(); + _rSelection.resize(aSelection.size()); + for (auto row : aSelection) + _rSelection.push_back(row); + } + + void ListSelectionDialog::selectEntries( const Sequence< sal_Int16 >& /* [in ] */ _rSelection ) + { + m_xEntries->unselect_all(); + for (auto const & selection : _rSelection) + m_xEntries->select(selection); + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/listselectiondlg.hxx b/extensions/source/propctrlr/listselectiondlg.hxx new file mode 100644 index 000000000..51469c091 --- /dev/null +++ b/extensions/source/propctrlr/listselectiondlg.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +namespace pcr +{ + class ListSelectionDialog : public weld::GenericDialogController + { + private: + css::uno::Reference m_xListBox; + OUString m_sPropertyName; + std::unique_ptr m_xFrame; + std::unique_ptr m_xEntries; + + public: + ListSelectionDialog( + weld::Window* _pParent, + const css::uno::Reference< css::beans::XPropertySet >& _rxListBox, + const OUString& _rPropertyName, + const OUString& _rPropertyUIName + ); + virtual ~ListSelectionDialog() override; + + virtual short run() override; + + private: + void initialize( ); + void commitSelection(); + + void fillEntryList ( const css::uno::Sequence< OUString >& _rListEntries ); + + void selectEntries ( const css::uno::Sequence< sal_Int16 >& /* [in ] */ _rSelection ); + void collectSelection( std::vector< sal_Int16 >& /* [out] */ _rSelection ); + }; + +} // namespacepcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/modulepcr.cxx b/extensions/source/propctrlr/modulepcr.cxx new file mode 100644 index 000000000..da8336e10 --- /dev/null +++ b/extensions/source/propctrlr/modulepcr.cxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "modulepcr.hxx" + +#include + +namespace pcr +{ +OUString PcrRes(TranslateId aId) { return Translate::get(aId, Translate::Create("pcr")); } + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/modulepcr.hxx b/extensions/source/propctrlr/modulepcr.hxx new file mode 100644 index 000000000..d0b854893 --- /dev/null +++ b/extensions/source/propctrlr/modulepcr.hxx @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace pcr +{ +OUString PcrRes(TranslateId pId); +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/newdatatype.cxx b/extensions/source/propctrlr/newdatatype.cxx new file mode 100644 index 000000000..09c774d3a --- /dev/null +++ b/extensions/source/propctrlr/newdatatype.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 "newdatatype.hxx" + +namespace pcr +{ + + + //= NewDataTypeDialog + + + NewDataTypeDialog::NewDataTypeDialog(weld::Window* pParent, const OUString& _rNameBase, const std::vector< OUString >& _rProhibitedNames) + : GenericDialogController(pParent, "modules/spropctrlr/ui/datatypedialog.ui", "DataTypeDialog") + , m_aProhibitedNames( _rProhibitedNames.begin(), _rProhibitedNames.end() ) + , m_xName(m_xBuilder->weld_entry("entry")) + , m_xOK(m_xBuilder->weld_button("ok")) + { + m_xName->connect_changed(LINK(this, NewDataTypeDialog, OnNameModified)); + + // find an initial name + // for this, first remove trailing digits + sal_Int32 nStripUntil = _rNameBase.getLength(); + while ( nStripUntil > 0 ) + { + sal_Unicode nChar = _rNameBase[ --nStripUntil ]; + if ( ( nChar < '0' ) || ( nChar > '9' ) ) + { + if ( nChar == ' ' ) + --nStripUntil; // strip the space, too + break; + } + } + + OUString sNameBase = OUString::Concat(_rNameBase.subView( 0, nStripUntil ? nStripUntil + 1 : 0 )) + " "; + OUString sInitialName; + sal_Int32 nPostfixNumber = 1; + do + { + sInitialName = sNameBase + OUString::number(nPostfixNumber++); + } + while ( m_aProhibitedNames.find( sInitialName ) != m_aProhibitedNames.end() ); + + m_xName->set_text(sInitialName); + OnNameModified(*m_xName); + } + + NewDataTypeDialog::~NewDataTypeDialog() + { + } + + IMPL_LINK_NOARG(NewDataTypeDialog, OnNameModified, weld::Entry&, void) + { + OUString sCurrentName = GetName(); + bool bNameIsOK = ( !sCurrentName.isEmpty() ) + && ( m_aProhibitedNames.find( sCurrentName ) == m_aProhibitedNames.end() ); + + m_xOK->set_sensitive(bNameIsOK); + } +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/newdatatype.hxx b/extensions/source/propctrlr/newdatatype.hxx new file mode 100644 index 000000000..e6d46f1af --- /dev/null +++ b/extensions/source/propctrlr/newdatatype.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include +#include + + +namespace pcr +{ + //= NewDataTypeDialog + class NewDataTypeDialog : public weld::GenericDialogController + { + private: + std::set m_aProhibitedNames; + + std::unique_ptr m_xName; + std::unique_ptr m_xOK; + public: + NewDataTypeDialog(weld::Window* _pParent, const OUString& _rNameBase, + const std::vector< OUString >& _rProhibitedNames ); + virtual ~NewDataTypeDialog() override; + + OUString GetName() const { return m_xName->get_text(); } + + private: + DECL_LINK(OnNameModified, weld::Entry&, void); + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/objectinspectormodel.cxx b/extensions/source/propctrlr/objectinspectormodel.cxx new file mode 100644 index 000000000..adad6e66f --- /dev/null +++ b/extensions/source/propctrlr/objectinspectormodel.cxx @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "pcrcommon.hxx" +#include "inspectormodelbase.hxx" + +#include +#include +#include + + +namespace pcr +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Any; + using ::com::sun::star::inspection::PropertyCategoryDescriptor; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::lang::IllegalArgumentException; + using ::com::sun::star::ucb::AlreadyInitializedException; + + + //= ObjectInspectorModel + + namespace { + + class ObjectInspectorModel : public ImplInspectorModel + { + private: + Sequence< Any > m_aFactories; + + public: + ObjectInspectorModel(); + + // XObjectInspectorModel + virtual Sequence< Any > SAL_CALL getHandlerFactories() override; + virtual Sequence< PropertyCategoryDescriptor > SAL_CALL describeCategories( ) override; + virtual ::sal_Int32 SAL_CALL getPropertyOrderIndex( const OUString& PropertyName ) override; + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override; + + protected: + void createDefault(); + void createWithHandlerFactories( const Sequence< Any >& _rFactories ); + void createWithHandlerFactoriesAndHelpSection( const Sequence< Any >& _rFactories, sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines ); + + private: + /** checks a given condition to be , and throws an IllegalArgumentException if not + */ + void impl_verifyArgument_throw( bool _bCondition, sal_Int16 _nArgumentPosition ); + }; + + } + + //= ObjectInspectorModel + + ObjectInspectorModel::ObjectInspectorModel() + { + } + + + Sequence< Any > SAL_CALL ObjectInspectorModel::getHandlerFactories() + { + return m_aFactories; + } + + + Sequence< PropertyCategoryDescriptor > SAL_CALL ObjectInspectorModel::describeCategories( ) + { + // no category info provided by this default implementation + return Sequence< PropertyCategoryDescriptor >( ); + } + + + ::sal_Int32 SAL_CALL ObjectInspectorModel::getPropertyOrderIndex( const OUString& /*PropertyName*/ ) + { + // no ordering provided by this default implementation + return 0; + } + + + void SAL_CALL ObjectInspectorModel::initialize( const Sequence< Any >& _arguments ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( m_aFactories.hasElements() ) + throw AlreadyInitializedException(); + + StlSyntaxSequence< Any > arguments( _arguments ); + if ( arguments.empty() ) + { // constructor: "createDefault()" + createDefault(); + return; + } + + Sequence< Any > factories; + impl_verifyArgument_throw( arguments[0] >>= factories, 1 ); + + if ( arguments.size() == 1 ) + { // constructor: "createWithHandlerFactories( any[] )" + createWithHandlerFactories( factories ); + return; + } + + if ( arguments.size() == 3 ) + { // constructor: "createWithHandlerFactoriesAndHelpSection( any[], long, long )" + sal_Int32 nMinHelpTextLines( 0 ), nMaxHelpTextLines( 0 ); + impl_verifyArgument_throw( arguments[1] >>= nMinHelpTextLines, 2 ); + impl_verifyArgument_throw( arguments[2] >>= nMaxHelpTextLines, 3 ); + createWithHandlerFactoriesAndHelpSection( factories, nMinHelpTextLines, nMaxHelpTextLines ); + return; + } + + impl_verifyArgument_throw( false, 2 ); + } + + + OUString SAL_CALL ObjectInspectorModel::getImplementationName( ) + { + return "org.openoffice.comp.extensions.ObjectInspectorModel"; + } + + + Sequence< OUString > SAL_CALL ObjectInspectorModel::getSupportedServiceNames( ) + { + return { "com.sun.star.inspection.ObjectInspectorModel" }; + } + + + void ObjectInspectorModel::createDefault() + { + m_aFactories = { Any(OUString( "com.sun.star.inspection.GenericPropertyHandler" )) }; + } + + + void ObjectInspectorModel::createWithHandlerFactories( const Sequence< Any >& _rFactories ) + { + impl_verifyArgument_throw( _rFactories.hasElements(), 1 ); + m_aFactories = _rFactories; + } + + + void ObjectInspectorModel::createWithHandlerFactoriesAndHelpSection( const Sequence< Any >& _rFactories, sal_Int32 _nMinHelpTextLines, sal_Int32 _nMaxHelpTextLines ) + { + impl_verifyArgument_throw( _rFactories.hasElements(), 1 ); + impl_verifyArgument_throw( _nMinHelpTextLines >= 1, 2 ); + impl_verifyArgument_throw( _nMaxHelpTextLines >= 1, 3 ); + impl_verifyArgument_throw( _nMinHelpTextLines <= _nMaxHelpTextLines, 2 ); + + m_aFactories = _rFactories; + enableHelpSectionProperties( _nMinHelpTextLines, _nMaxHelpTextLines ); + } + + + void ObjectInspectorModel::impl_verifyArgument_throw( bool _bCondition, sal_Int16 _nArgumentPosition ) + { + if ( !_bCondition ) + throw IllegalArgumentException( OUString(), *this, _nArgumentPosition ); + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_ObjectInspectorModel_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::ObjectInspectorModel()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/pcr.component b/extensions/source/propctrlr/pcr.component new file mode 100644 index 000000000..3d0214ded --- /dev/null +++ b/extensions/source/propctrlr/pcr.component @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/source/propctrlr/pcrcommon.cxx b/extensions/source/propctrlr/pcrcommon.cxx new file mode 100644 index 000000000..4151e6827 --- /dev/null +++ b/extensions/source/propctrlr/pcrcommon.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 "pcrcommon.hxx" + +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::util; + + + //= HelpIdUrl + + + OString HelpIdUrl::getHelpId( std::u16string_view _rHelpURL ) + { + INetURLObject aHID( _rHelpURL ); + if ( aHID.GetProtocol() == INetProtocol::Hid ) + return OUStringToOString( aHID.GetURLPath(), RTL_TEXTENCODING_UTF8 ); + else + return OUStringToOString( _rHelpURL, RTL_TEXTENCODING_UTF8 ); + } + + + OUString HelpIdUrl::getHelpURL( std::u16string_view sHelpId ) + { + OUStringBuffer aBuffer; + INetURLObject aHID( sHelpId ); + if ( aHID.GetProtocol() == INetProtocol::NotValid ) + aBuffer.append( INET_HID_SCHEME ); + aBuffer.append( sHelpId ); + return aBuffer.makeStringAndClear(); + } + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/pcrcommon.hxx b/extensions/source/propctrlr/pcrcommon.hxx new file mode 100644 index 000000000..f9ec2838c --- /dev/null +++ b/extensions/source/propctrlr/pcrcommon.hxx @@ -0,0 +1,121 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#define EDITOR_LIST_APPEND (SAL_MAX_UINT16) +#define EDITOR_LIST_ENTRY_NOTFOUND (SAL_MAX_UINT16) + +#include + +#include +#include +#include + +namespace pcr +{ + + + #define OWN_PROPERTY_ID_INTROSPECTEDOBJECT 0x0010 + #define OWN_PROPERTY_ID_CURRENTPAGE 0x0011 + #define OWN_PROPERTY_ID_CONTROLCONTEXT 0x0012 + #define OWN_PROPERTY_ID_TABBINGMODEL 0x0013 + + + //= types + + typedef ::comphelper::OInterfaceContainerHelper3 < css::beans::XPropertyChangeListener + > PropertyChangeListeners; + + + //= helper + + // small helper to make the "swap" call on an STL container a single-line call, which + // in its canonic form "aFoo.swap( Container() )" doesn't compile with GCC + template< class CONTAINER > + void clearContainer( CONTAINER& _rContainer ) + { + CONTAINER().swap(_rContainer); + } + + + //= HelpIdUrl + + /// small helper to translate help ids into help urls + class HelpIdUrl + { + public: + static OString getHelpId( std::u16string_view _rHelpURL ); + static OUString getHelpURL( std::u16string_view ); + }; + + + //= StlSyntaxSequence + + template< class ELEMENT > + class StlSyntaxSequence : public css::uno::Sequence< ELEMENT > + { + private: + typedef css::uno::Sequence< ELEMENT > UnoBase; + + public: + StlSyntaxSequence() : UnoBase() { } + explicit StlSyntaxSequence( const UnoBase& rSeq ) : UnoBase( rSeq ) { } + explicit StlSyntaxSequence( sal_Int32 len ) : UnoBase( len ) { } + + typedef const ELEMENT* const_iterator; + typedef ELEMENT* iterator; + + const_iterator begin() const { return UnoBase::getConstArray(); } + const_iterator end() const { return UnoBase::getConstArray() + UnoBase::getLength(); } + + iterator begin() { return UnoBase::getArray(); } + iterator end() { return UnoBase::getArray() + UnoBase::getLength(); } + + sal_Int32 size() const { return UnoBase::getLength(); } + bool empty() const { return !UnoBase::hasElements(); } + }; + + + //= UNO helpers + +#define DECLARE_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; + +#define IMPLEMENT_FORWARD_XCOMPONENT( classname, baseclass ) \ + void SAL_CALL classname::dispose( ) \ + { \ + baseclass::WeakComponentImplHelperBase::dispose(); \ + } \ + void SAL_CALL classname::addEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) \ + { \ + baseclass::WeakComponentImplHelperBase::addEventListener( Listener ); \ + } \ + void SAL_CALL classname::removeEventListener( const css::uno::Reference< css::lang::XEventListener >& Listener ) \ + { \ + baseclass::WeakComponentImplHelperBase::removeEventListener( Listener ); \ + } \ + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/pcrcommontypes.hxx b/extensions/source/propctrlr/pcrcommontypes.hxx new file mode 100644 index 000000000..e2aa3570e --- /dev/null +++ b/extensions/source/propctrlr/pcrcommontypes.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 . + */ + +#pragma once + +#include +#include + +#include + +namespace pcr +{ +typedef std::unordered_map PropertyMap; + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/pcrstrings.hxx b/extensions/source/propctrlr/pcrstrings.hxx new file mode 100644 index 000000000..3bb0a888c --- /dev/null +++ b/extensions/source/propctrlr/pcrstrings.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 . + */ + +#pragma once + +#include + +namespace pcr +{ + + + // properties + constexpr OUStringLiteral PROPERTY_TABBINGMODEL = u"TabbingModel"; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/pcrunodialogs.cxx b/extensions/source/propctrlr/pcrunodialogs.cxx new file mode 100644 index 000000000..9083cb284 --- /dev/null +++ b/extensions/source/propctrlr/pcrunodialogs.cxx @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include "pcrunodialogs.hxx" +#include "formstrings.hxx" +#include "pcrstrings.hxx" +#include "taborder.hxx" +#include "pcrcommon.hxx" + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + + + //= OTabOrderDialog + + + OTabOrderDialog::OTabOrderDialog( const Reference< XComponentContext >& _rxContext ) + :OGenericUnoDialog( _rxContext ) + { + registerProperty( PROPERTY_CONTROLCONTEXT, OWN_PROPERTY_ID_CONTROLCONTEXT, + PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT, + &m_xControlContext, cppu::UnoType::get() ); + + registerProperty( PROPERTY_TABBINGMODEL, OWN_PROPERTY_ID_TABBINGMODEL, + PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT, + &m_xTabbingModel, cppu::UnoType::get() ); + } + + OTabOrderDialog::~OTabOrderDialog() + { + if (m_xDialog) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (m_xDialog) + destroyDialog(); + } + } + + Sequence SAL_CALL OTabOrderDialog::getImplementationId( ) + { + return css::uno::Sequence(); + } + + OUString SAL_CALL OTabOrderDialog::getImplementationName() + { + return "org.openoffice.comp.form.ui.OTabOrderDialog"; + } + + + css::uno::Sequence SAL_CALL OTabOrderDialog::getSupportedServiceNames() + { + return { "com.sun.star.form.ui.TabOrderDialog", "com.sun.star.form.TabOrderDialog" }; + } + + + Reference SAL_CALL OTabOrderDialog::getPropertySetInfo() + { + Reference xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; + } + + ::cppu::IPropertyArrayHelper& OTabOrderDialog::getInfoHelper() + { + return *getArrayHelper(); + } + + ::cppu::IPropertyArrayHelper* OTabOrderDialog::createArrayHelper( ) const + { + Sequence< Property > aProps; + describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper( aProps ); + } + + std::unique_ptr OTabOrderDialog::createDialog(const css::uno::Reference& rParent) + { + return std::make_unique(Application::GetFrameWeld(rParent), m_xTabbingModel, m_xControlContext, m_aContext); + } + + void OTabOrderDialog::initialize( const Sequence< Any >& aArguments ) + { + Reference xTabbingModel; + Reference xControlContext; + Reference xParentWindow; + if (aArguments.getLength() == 3 && (aArguments[0] >>= xTabbingModel) && (aArguments[1] >>= xControlContext) && (aArguments[2] >>= xParentWindow)) + { + Sequence< Any > aNewArguments{ + Any(NamedValue( + "TabbingModel", + Any( xTabbingModel ) + )), + Any(NamedValue( + "ControlContext", + Any( xControlContext ) + )), + Any(NamedValue( + "ParentWindow", + Any( xParentWindow ) + )) + }; + OTabOrderDialog_DBase::initialize(aNewArguments); + } + else + OTabOrderDialog_DBase::initialize(aArguments); + } + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propcrltr_OTabOrderDialog_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::OTabOrderDialog(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/pcrunodialogs.hxx b/extensions/source/propctrlr/pcrunodialogs.hxx new file mode 100644 index 000000000..87c99db35 --- /dev/null +++ b/extensions/source/propctrlr/pcrunodialogs.hxx @@ -0,0 +1,79 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include +#include + + +namespace pcr +{ + + + //= OTabOrderDialog + + class OTabOrderDialog; + typedef ::svt::OGenericUnoDialog OTabOrderDialog_DBase; + typedef ::comphelper::OPropertyArrayUsageHelper< OTabOrderDialog > OTabOrderDialog_PBase; + + class OTabOrderDialog + :public OTabOrderDialog_DBase + ,public OTabOrderDialog_PBase + { + protected: + // + css::uno::Reference< css::awt::XTabControllerModel > + m_xTabbingModel; + css::uno::Reference< css::awt::XControlContainer > + m_xControlContext; + // + + public: + explicit OTabOrderDialog( const css::uno::Reference< css::uno::XComponentContext >& _rxContext ); + virtual ~OTabOrderDialog() override; + + // XTypeProvider + virtual css::uno::Sequence SAL_CALL getImplementationId( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + protected: + // OGenericUnoDialog overridables + virtual std::unique_ptr createDialog(const css::uno::Reference& rParent) override; + }; + + +} // namespacepcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propcontroller.cxx b/extensions/source/propctrlr/propcontroller.cxx new file mode 100644 index 000000000..6bbcdcf5d --- /dev/null +++ b/extensions/source/propctrlr/propcontroller.cxx @@ -0,0 +1,1652 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "propcontroller.hxx" +#include "handlerhelper.hxx" +#include "standardcontrol.hxx" +#include "linedescriptor.hxx" +#include +#include "propertyeditor.hxx" +#include "modulepcr.hxx" +#include "formstrings.hxx" +#include "formbrowsertools.hxx" +#include "propertycomposer.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace pcr +{ + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::inspection; + using namespace ::com::sun::star::ucb; + using namespace ::comphelper; + + //= OPropertyBrowserController + OPropertyBrowserController::OPropertyBrowserController( const Reference< XComponentContext >& _rxContext ) + :m_xContext(_rxContext) + ,m_aDisposeListeners( m_aMutex ) + ,m_aControlObservers( m_aMutex ) + ,m_bContainerFocusListening( false ) + ,m_bSuspendingPropertyHandlers( false ) + ,m_bConstructed( false ) + ,m_bBindingIntrospectee( false ) + { + } + + OPropertyBrowserController::~OPropertyBrowserController() + { + // stop listening for property changes + acquire(); + stopInspection( true ); + } + + IMPLEMENT_FORWARD_REFCOUNT( OPropertyBrowserController, OPropertyBrowserController_Base ) + + Any SAL_CALL OPropertyBrowserController::queryInterface( const Type& _rType ) + { + Any aReturn = OPropertyBrowserController_Base::queryInterface( _rType ); + if ( !aReturn.hasValue() ) + aReturn = ::cppu::queryInterface( + _rType, + static_cast< XObjectInspectorUI* >( this ) + ); + return aReturn; + } + + + void OPropertyBrowserController::startContainerWindowListening() + { + if (m_bContainerFocusListening) + return; + + if (m_xFrame.is()) + { + Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow(); + if (xContainerWindow.is()) + { + xContainerWindow->addFocusListener(this); + m_bContainerFocusListening = true; + } + } + + DBG_ASSERT(m_bContainerFocusListening, "OPropertyBrowserController::startContainerWindowListening: unable to start listening (inconsistence)!"); + } + + + void OPropertyBrowserController::stopContainerWindowListening() + { + if (!m_bContainerFocusListening) + return; + + if (m_xFrame.is()) + { + Reference< XWindow > xContainerWindow = m_xFrame->getContainerWindow(); + if (xContainerWindow.is()) + { + xContainerWindow->removeFocusListener(this); + m_bContainerFocusListening = false; + } + } + + DBG_ASSERT(!m_bContainerFocusListening, "OPropertyBrowserController::stopContainerWindowListening: unable to stop listening (inconsistence)!"); + } + + + Reference< XObjectInspectorModel > SAL_CALL OPropertyBrowserController::getInspectorModel() + { + return m_xModel; + } + + + void OPropertyBrowserController::impl_initializeView_nothrow() + { + OSL_PRECOND( haveView(), "OPropertyBrowserController::impl_initializeView_nothrow: not to be called when we have no view!" ); + if ( !haveView() ) + return; + + if ( !m_xModel.is() ) + // allowed + return; + + try + { + getPropertyBox().EnableHelpSection( m_xModel->getHasHelpSection() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + bool OPropertyBrowserController::impl_isReadOnlyModel_throw() const + { + if ( !m_xModel.is() ) + return false; + + return m_xModel->getIsReadOnly(); + } + + + void OPropertyBrowserController::impl_startOrStopModelListening_nothrow( bool _bDoListen ) const + { + try + { + Reference< XPropertySet > xModelProperties( m_xModel, UNO_QUERY ); + if ( !xModelProperties.is() ) + // okay, so the model doesn't want to change its properties + // dynamically - fine with us + return; + + void (SAL_CALL XPropertySet::*pListenerOperation)( const OUString&, const Reference< XPropertyChangeListener >& ) + = _bDoListen ? &XPropertySet::addPropertyChangeListener : &XPropertySet::removePropertyChangeListener; + + (xModelProperties.get()->*pListenerOperation)( + OUString( "IsReadOnly" ), + const_cast< OPropertyBrowserController* >( this ) + ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + void OPropertyBrowserController::impl_bindToNewModel_nothrow( const Reference< XObjectInspectorModel >& _rxInspectorModel ) + { + impl_startOrStopModelListening_nothrow( false ); + m_xModel = _rxInspectorModel; + impl_startOrStopModelListening_nothrow( true ); + + // initialize the view, if we already have one + if ( haveView() ) + impl_initializeView_nothrow(); + + // inspect again, if we already have inspectees + if ( !m_aInspectedObjects.empty() ) + impl_rebindToInspectee_nothrow( std::vector(m_aInspectedObjects) ); + } + + + void SAL_CALL OPropertyBrowserController::setInspectorModel( const Reference< XObjectInspectorModel >& _inspectorModel ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_xModel == _inspectorModel ) + return; + + impl_bindToNewModel_nothrow( _inspectorModel ); + } + + + Reference< XObjectInspectorUI > SAL_CALL OPropertyBrowserController::getInspectorUI() + { + // we're derived from this interface, though we do not expose it in queryInterface and getTypes. + return this; + } + + + void SAL_CALL OPropertyBrowserController::inspect( const Sequence< Reference< XInterface > >& _rObjects ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( m_bSuspendingPropertyHandlers || !suspendAll_nothrow() ) + { // we already are trying to suspend the component (this is somewhere up the stack) + // OR one of our property handlers raised a veto against closing. Well, we *need* to close + // it in order to inspect another object. + throw VetoException(); + } + if ( m_bBindingIntrospectee ) + throw VetoException(); + + m_bBindingIntrospectee = true; + impl_rebindToInspectee_nothrow( InterfaceArray( _rObjects.begin(), _rObjects.end() ) ); + m_bBindingIntrospectee = false; + + } + + + Reference< XDispatch > SAL_CALL OPropertyBrowserController::queryDispatch( const URL& /*URL*/, const OUString& /*TargetFrameName*/, ::sal_Int32 /*SearchFlags*/ ) + { + // we don't have any dispatches at all, right now + return Reference< XDispatch >(); + } + + + Sequence< Reference< XDispatch > > SAL_CALL OPropertyBrowserController::queryDispatches( const Sequence< DispatchDescriptor >& Requests ) + { + Sequence< Reference< XDispatch > > aReturn; + sal_Int32 nLen = Requests.getLength(); + aReturn.realloc( nLen ); + + Reference< XDispatch >* pReturn = aReturn.getArray(); + const Reference< XDispatch >* pReturnEnd = aReturn.getArray() + nLen; + const DispatchDescriptor* pDescripts = Requests.getConstArray(); + + for ( ; pReturn != pReturnEnd; ++ pReturn, ++pDescripts ) + *pReturn = queryDispatch( pDescripts->FeatureURL, pDescripts->FrameName, pDescripts->SearchFlags ); + + return aReturn; + } + + + void SAL_CALL OPropertyBrowserController::initialize( const Sequence< Any >& _arguments ) + { + if ( m_bConstructed ) + throw AlreadyInitializedException(); + + StlSyntaxSequence< Any > arguments( _arguments ); + if ( arguments.empty() ) + { // constructor: "createDefault()" + m_bConstructed = true; + return; + } + + Reference< XObjectInspectorModel > xModel; + if ( arguments.size() == 1 ) + { // constructor: "createWithModel( XObjectInspectorModel )" + if ( !( arguments[0] >>= xModel ) ) + throw IllegalArgumentException( OUString(), *this, 0 ); + createWithModel( xModel ); + return; + } + + throw IllegalArgumentException( OUString(), *this, 0 ); + } + + + void OPropertyBrowserController::createWithModel( const Reference< XObjectInspectorModel >& _rxModel ) + { + osl_atomic_increment( &m_refCount ); + { + setInspectorModel( _rxModel ); + } + osl_atomic_decrement( &m_refCount ); + + m_bConstructed = true; + } + + + void SAL_CALL OPropertyBrowserController::attachFrame( const Reference< XFrame >& _rxFrame ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + if (_rxFrame.is() && haveView()) + throw RuntimeException("Unable to attach to a second frame.",*this); + + // revoke as focus listener from the old container window + stopContainerWindowListening(); + + m_xPropView.reset(); + m_xBuilder.reset(); + + m_xFrame = _rxFrame; + if (!m_xFrame.is()) + return; + + // TODO: this construction perhaps should be done outside. Don't know the exact meaning of attachFrame. + // Maybe it is intended to only announce the frame to the controller, and the instance doing this + // announcement is responsible for calling setComponent, too. + Reference xContainerWindow = m_xFrame->getContainerWindow(); + + OUString sUIFile("modules/spropctrlr/ui/formproperties.ui"); + std::unique_ptr xBuilder; + + if (weld::TransportAsXWindow* pTunnel = dynamic_cast(xContainerWindow.get())) + { + xBuilder = Application::CreateBuilder(pTunnel->getWidget(), sUIFile); + } + else + { + VclPtr pParentWin = VCLUnoHelper::GetWindow(xContainerWindow); + if (!pParentWin) + throw RuntimeException("The frame is invalid. Unable to extract the container window.",*this); + xBuilder = Application::CreateInterimBuilder(pParentWin, sUIFile, true); + } + + Construct(xContainerWindow, std::move(xBuilder)); + + startContainerWindowListening(); + + UpdateUI(); + } + + sal_Bool SAL_CALL OPropertyBrowserController::attachModel( const Reference< XModel >& _rxModel ) + { + Reference< XObjectInspectorModel > xModel( _rxModel, UNO_QUERY ); + if ( !xModel.is() ) + return false; + + setInspectorModel( xModel ); + return getInspectorModel() == _rxModel; + } + + + bool OPropertyBrowserController::suspendAll_nothrow() + { + // if there is a handle inside its "onInteractivePropertySelection" method, + // then veto + // Normally, we could expect every handler to do this itself, but being + // realistic, it's safer to handle this here in general. + if ( m_xInteractiveHandler.is() ) + return false; + + m_bSuspendingPropertyHandlers = true; + bool bHandlerVeto = !suspendPropertyHandlers_nothrow( true ); + m_bSuspendingPropertyHandlers = false; + return !bHandlerVeto; + } + + + bool OPropertyBrowserController::suspendPropertyHandlers_nothrow( bool _bSuspend ) + { + PropertyHandlerArray aAllHandlers; // will contain every handler exactly once + for (auto const& propertyHandler : m_aPropertyHandlers) + { + if ( std::find( aAllHandlers.begin(), aAllHandlers.end(), propertyHandler.second ) != aAllHandlers.end() ) + // already visited this particular handler (m_aPropertyHandlers usually contains + // the same handler more than once) + continue; + aAllHandlers.push_back(propertyHandler.second); + } + + for (auto const& handler : aAllHandlers) + { + try + { + if ( !handler->suspend( _bSuspend ) ) + if ( _bSuspend ) + // if we're not suspending, but reactivating, ignore the error + return false; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::suspendPropertyHandlers_nothrow" ); + } + } + return true; + } + + + sal_Bool SAL_CALL OPropertyBrowserController::suspend( sal_Bool _bSuspend ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_ENSURE( haveView(), "OPropertyBrowserController::suspend: don't have a view anymore!" ); + + if ( !_bSuspend ) + { // this means a "suspend" is to be "revoked" + suspendPropertyHandlers_nothrow( false ); + // we ourself cannot revoke our suspend + return false; + } + + if ( !suspendAll_nothrow() ) + return false; + + // commit the editor's content + if ( haveView() ) + getPropertyBox().CommitModified(); + + // stop listening + stopContainerWindowListening(); + + // outta here + return true; + } + + + Any SAL_CALL OPropertyBrowserController::getViewData( ) + { + return Any( m_sPageSelection ); + } + + + void SAL_CALL OPropertyBrowserController::restoreViewData( const Any& Data ) + { + OUString sPageSelection; + if ( ( Data >>= sPageSelection ) && !sPageSelection.isEmpty() ) + { + m_sPageSelection = sPageSelection; + selectPageFromViewData(); + } + } + + Reference< XModel > SAL_CALL OPropertyBrowserController::getModel( ) + { + // have no model + return Reference< XModel >(); + } + + Reference< XFrame > SAL_CALL OPropertyBrowserController::getFrame( ) + { + return m_xFrame; + } + + void SAL_CALL OPropertyBrowserController::dispose() + { + SolarMutexGuard aSolarGuard; + + // stop inspecting the current object + stopInspection( false ); + + // say our dispose listeners goodbye + css::lang::EventObject aEvt; + aEvt.Source = static_cast< ::cppu::OWeakObject* >(this); + m_aDisposeListeners.disposeAndClear(aEvt); + m_aControlObservers.disposeAndClear(aEvt); + + m_xPropView.reset(); + m_xBuilder.reset(); + + if ( m_xView.is() ) + m_xView->removeEventListener( static_cast< XPropertyChangeListener* >( this ) ); + m_xView.clear( ); + + m_aInspectedObjects.clear(); + impl_bindToNewModel_nothrow( nullptr ); + } + + void SAL_CALL OPropertyBrowserController::addEventListener( const Reference< XEventListener >& _rxListener ) + { + m_aDisposeListeners.addInterface(_rxListener); + } + + void SAL_CALL OPropertyBrowserController::removeEventListener( const Reference< XEventListener >& _rxListener ) + { + m_aDisposeListeners.removeInterface(_rxListener); + } + + OUString SAL_CALL OPropertyBrowserController::getImplementationName( ) + { + return "org.openoffice.comp.extensions.ObjectInspector"; + } + + sal_Bool SAL_CALL OPropertyBrowserController::supportsService( const OUString& ServiceName ) + { + return cppu::supportsService(this, ServiceName); + } + + + Sequence< OUString > SAL_CALL OPropertyBrowserController::getSupportedServiceNames( ) + { + return { "com.sun.star.inspection.ObjectInspector" }; + } + + + void SAL_CALL OPropertyBrowserController::focusGained( const FocusEvent& _rSource ) + { + Reference< XWindow > xSourceWindow(_rSource.Source, UNO_QUERY); + Reference< XWindow > xContainerWindow; + if (m_xFrame.is()) + xContainerWindow = m_xFrame->getContainerWindow(); + + if ( xContainerWindow.get() == xSourceWindow.get() ) + { // our container window got the focus + if ( haveView() ) + getPropertyBox().GrabFocus(); + } + } + + + void SAL_CALL OPropertyBrowserController::focusLost( const FocusEvent& /*_rSource*/ ) + { + // not interested in + } + + + void SAL_CALL OPropertyBrowserController::disposing( const EventObject& _rSource ) + { + if ( m_xView.is() && ( m_xView == _rSource.Source ) ) + { + m_xView = nullptr; + m_xPropView.reset(); + m_xBuilder.reset(); + } + + auto it = std::find_if(m_aInspectedObjects.begin(), m_aInspectedObjects.end(), + [&_rSource](const InterfaceArray::value_type& rxObj) { return rxObj == _rSource.Source; }); + if (it != m_aInspectedObjects.end()) + m_aInspectedObjects.erase(it); + } + + + IMPL_LINK_NOARG(OPropertyBrowserController, OnPageActivation, LinkParamNone*, void) + { + updateViewDataFromActivePage(); + } + + + void OPropertyBrowserController::updateViewDataFromActivePage() + { + if (!haveView()) + return; + + OUString sOldSelection = m_sPageSelection; + m_sPageSelection.clear(); + + const sal_uInt16 nCurrentPage = m_xPropView->getActivePage(); + if ( sal_uInt16(-1) != nCurrentPage ) + { + for (auto const& pageId : m_aPageIds) + { + if ( nCurrentPage == pageId.second ) + { + m_sPageSelection = pageId.first; + break; + } + } + } + + if ( !m_sPageSelection.isEmpty() ) + m_sLastValidPageSelection = m_sPageSelection; + else if ( !sOldSelection.isEmpty() ) + m_sLastValidPageSelection = sOldSelection; + } + + + sal_uInt16 OPropertyBrowserController::impl_getPageIdForCategory_nothrow( const OUString& _rCategoryName ) const + { + sal_uInt16 nPageId = sal_uInt16(-1); + HashString2Int16::const_iterator pagePos = m_aPageIds.find( _rCategoryName ); + if ( pagePos != m_aPageIds.end() ) + nPageId = pagePos->second; + return nPageId; + } + + void OPropertyBrowserController::selectPageFromViewData() + { + sal_uInt16 nNewPage = impl_getPageIdForCategory_nothrow( m_sPageSelection ); + + if ( haveView() && ( nNewPage != sal_uInt16(-1) ) ) + m_xPropView->activatePage( nNewPage ); + + // just in case ... + updateViewDataFromActivePage(); + } + + void OPropertyBrowserController::Construct(const Reference& rContainerWindow, std::unique_ptr xBuilder) + { + DBG_ASSERT(!haveView(), "OPropertyBrowserController::Construct: already have a view!"); + assert(xBuilder && "OPropertyBrowserController::Construct: invalid parent window!"); + + m_xBuilder = std::move(xBuilder); + + m_xPropView.reset(new OPropertyBrowserView(m_xContext, *m_xBuilder)); + m_xPropView->setPageActivationHandler(LINK(this, OPropertyBrowserController, OnPageActivation)); + + // add as dispose listener for our view. The view is disposed by the frame we're plugged into, + // and this disposal _deletes_ the view, so it would be deadly if we use our m_xPropView member + // after that + m_xView = rContainerWindow; + if (m_xView.is()) + m_xView->addEventListener( static_cast< XPropertyChangeListener* >( this ) ); + + getPropertyBox().SetLineListener(this); + getPropertyBox().SetControlObserver(this); + impl_initializeView_nothrow(); + } + + void SAL_CALL OPropertyBrowserController::propertyChange( const PropertyChangeEvent& _rEvent ) + { + if ( _rEvent.Source == m_xModel ) + { + if ( _rEvent.PropertyName == "IsReadOnly" ) + // this is a huge cudgel, admitted. + // The problem is that in case we were previously read-only, all our controls + // were created read-only, too. We cannot simply switch them to not-read-only. + // Even if they had an API for this, we do not know whether they were + // originally created read-only, or if they are read-only just because + // the model was. + impl_rebindToInspectee_nothrow( std::vector(m_aInspectedObjects) ); + return; + } + + if ( m_sCommittingProperty == _rEvent.PropertyName ) + return; + + if ( !haveView() ) + return; + + Any aNewValue( _rEvent.NewValue ); + if ( impl_hasPropertyHandlerFor_nothrow( _rEvent.PropertyName ) ) + { + // forward the new value to the property box, to reflect the change in the UI + aNewValue = impl_getPropertyValue_throw( _rEvent.PropertyName ); + + // check whether the state is ambiguous. This is interesting in case we display the properties + // for multiple objects at once: In this case, we'll get a notification from one of the objects, + // but need to care for the "composed" value, which can be "ambiguous". + PropertyHandlerRef xHandler( impl_getHandlerForProperty_throw( _rEvent.PropertyName ), UNO_SET_THROW ); + PropertyState ePropertyState( xHandler->getPropertyState( _rEvent.PropertyName ) ); + bool bAmbiguousValue = ( PropertyState_AMBIGUOUS_VALUE == ePropertyState ); + + getPropertyBox().SetPropertyValue( _rEvent.PropertyName, aNewValue, bAmbiguousValue ); + } + + // if it's an actuating property, then update the UI for any dependent + // properties + if ( impl_isActuatingProperty_nothrow( _rEvent.PropertyName ) ) + impl_broadcastPropertyChange_nothrow( _rEvent.PropertyName, aNewValue, _rEvent.OldValue, false ); + } + + Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::createPropertyControl( ::sal_Int16 ControlType, sal_Bool bCreateReadOnly ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XPropertyControl > xControl; + + // read-only-ness + bCreateReadOnly |= impl_isReadOnlyModel_throw() ? 1 : 0; + + switch ( ControlType ) + { + case PropertyControlType::MultiLineTextField: + case PropertyControlType::StringListField: + { + bool bMultiLineTextField = ControlType == PropertyControlType::MultiLineTextField; + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/multiline.ui", m_xContext)); + auto pContainer = xBuilder->weld_container("multiline"); + rtl::Reference pControl = new OMultilineEditControl(std::move(pContainer), std::move(xBuilder), + bMultiLineTextField ? eMultiLineText : eStringList, bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + case PropertyControlType::ListBox: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/listbox.ui", m_xContext)); + auto pComboBox = xBuilder->weld_combo_box("listbox"); + rtl::Reference pControl = new OListboxControl(std::move(pComboBox), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + case PropertyControlType::ComboBox: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/combobox.ui", m_xContext)); + auto pComboBox = xBuilder->weld_combo_box("combobox"); + rtl::Reference pControl = new OComboboxControl(std::move(pComboBox), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + case PropertyControlType::TextField: + case PropertyControlType::CharacterField: + { + bool bCharacterField = ControlType == PropertyControlType::CharacterField; + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/textfield.ui", m_xContext)); + auto pEntry = xBuilder->weld_entry("textfield"); + rtl::Reference pControl = new OEditControl(std::move(pEntry), std::move(xBuilder), bCharacterField, bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + case PropertyControlType::NumericField: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/numericfield.ui", m_xContext)); + auto pSpinButton = xBuilder->weld_metric_spin_button("numericfield", FieldUnit::NONE); + rtl::Reference pControl = new ONumericControl(std::move(pSpinButton), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + case PropertyControlType::DateTimeField: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/datetimefield.ui", m_xContext)); + auto pContainer = xBuilder->weld_container("datetimefield"); + rtl::Reference pControl = new ODateTimeControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + case PropertyControlType::DateField: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/datefield.ui", m_xContext)); + auto pContainer = xBuilder->weld_container("datefield"); + rtl::Reference pControl = new ODateControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + case PropertyControlType::TimeField: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/timefield.ui", m_xContext)); + auto pTimeSpinButton = xBuilder->weld_formatted_spin_button("timefield"); + rtl::Reference pControl = new OTimeControl(std::move(pTimeSpinButton), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + case PropertyControlType::ColorListBox: + { + auto lambda = [this]{ return PropertyHandlerHelper::getDialogParentFrame(m_xContext); }; + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/colorlistbox.ui", m_xContext)); + auto pMenuButton = xBuilder->weld_menu_button("colorlistbox"); + rtl::Reference pControl = new OColorControl(std::make_unique(std::move(pMenuButton), lambda), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + case PropertyControlType::HyperlinkField: + { + std::unique_ptr xBuilder(PropertyHandlerHelper::makeBuilder("modules/spropctrlr/ui/hyperlinkfield.ui", m_xContext)); + auto pContainer = xBuilder->weld_container("hyperlinkfield"); + rtl::Reference pControl = new OHyperlinkControl(std::move(pContainer), std::move(xBuilder), bCreateReadOnly); + pControl->SetModifyHandler(); + xControl = pControl; + break; + } + + default: + throw IllegalArgumentException( OUString(), *this, 1 ); + } + + return xControl; + } + + + void OPropertyBrowserController::impl_toggleInspecteeListening_nothrow( bool _bOn ) + { + for (auto const& inspectedObject : m_aInspectedObjects) + { + try + { + Reference< XComponent > xComp( inspectedObject, UNO_QUERY ); + if ( xComp.is() ) + { + if ( _bOn ) + xComp->addEventListener( static_cast< XPropertyChangeListener* >( this ) ); + else + xComp->removeEventListener( static_cast< XPropertyChangeListener* >( this ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + } + + + void OPropertyBrowserController::stopInspection( bool _bCommitModified ) + { + if ( haveView() ) + { + if ( _bCommitModified ) + // commit the editor's content + getPropertyBox().CommitModified(); + + // hide the property box so that it does not flicker + getPropertyBox().Hide(); + + // clear the property box + getPropertyBox().ClearAll(); + } + + // destroy the view first + if ( haveView() ) + { + // remove the pages + for (auto const& pageId : m_aPageIds) + getPropertyBox().RemovePage( pageId.second ); + clearContainer( m_aPageIds ); + } + + clearContainer( m_aProperties ); + + // de-register as dispose-listener from our inspected objects + impl_toggleInspecteeListening_nothrow( false ); + + // handlers are obsolete, so is our "composer" for their UI requests + if (m_pUIRequestComposer) + m_pUIRequestComposer->dispose(); + m_pUIRequestComposer.reset(); + + // clean up the property handlers + PropertyHandlerArray aAllHandlers; // will contain every handler exactly once + for (auto const& propertyHandler : m_aPropertyHandlers) + if ( std::find( aAllHandlers.begin(), aAllHandlers.end(), propertyHandler.second ) == aAllHandlers.end() ) + aAllHandlers.push_back( propertyHandler.second ); + + for (auto const& handler : aAllHandlers) + { + try + { + handler->removePropertyChangeListener( this ); + handler->dispose(); + } + catch( const DisposedException& ) + { + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + clearContainer( m_aPropertyHandlers ); + clearContainer( m_aDependencyHandlers ); + } + + + bool OPropertyBrowserController::impl_hasPropertyHandlerFor_nothrow( const OUString& _rPropertyName ) const + { + PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName ); + return ( handlerPos != m_aPropertyHandlers.end() ); + } + + + OPropertyBrowserController::PropertyHandlerRef const & OPropertyBrowserController::impl_getHandlerForProperty_throw( const OUString& _rPropertyName ) const + { + PropertyHandlerRepository::const_iterator handlerPos = m_aPropertyHandlers.find( _rPropertyName ); + if ( handlerPos == m_aPropertyHandlers.end() ) + throw RuntimeException(); + return handlerPos->second; + } + + + Any OPropertyBrowserController::impl_getPropertyValue_throw( const OUString& _rPropertyName ) + { + PropertyHandlerRef handler = impl_getHandlerForProperty_throw( _rPropertyName ); + return handler->getPropertyValue( _rPropertyName ); + } + + + void OPropertyBrowserController::impl_rebindToInspectee_nothrow( InterfaceArray&& _rObjects ) + { + try + { + // stop inspecting the old object(s) + stopInspection( true ); + + // inspect the new object(s) + m_aInspectedObjects = std::move(_rObjects); + doInspection(); + + // update the user interface + UpdateUI(); + } + + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", ""); + } + } + + + void OPropertyBrowserController::doInspection() + { + try + { + + // obtain the properties of the object + std::vector< Property > aProperties; + + PropertyHandlerArray aPropertyHandlers; + getPropertyHandlers( m_aInspectedObjects, aPropertyHandlers ); + + PropertyHandlerArray::iterator aHandler( aPropertyHandlers.begin() ); + while ( aHandler != aPropertyHandlers.end() ) + { + DBG_ASSERT( aHandler->get(), "OPropertyBrowserController::doInspection: invalid handler!" ); + + StlSyntaxSequence< Property > aThisHandlersProperties( (*aHandler)->getSupportedProperties() ); + + if ( aThisHandlersProperties.empty() ) + { + // this handler doesn't know anything about the current inspectee -> ignore it + (*aHandler)->dispose(); + aHandler = aPropertyHandlers.erase( aHandler ); + continue; + } + + // append these properties to our "all properties" array + aProperties.reserve( aProperties.size() + aThisHandlersProperties.size() ); + for (const auto & aThisHandlersProperty : aThisHandlersProperties) + { + auto noPrevious = std::none_of( + aProperties.begin(), + aProperties.end(), + FindPropertyByName( aThisHandlersProperty.Name ) + ); + if ( noPrevious ) + { + aProperties.push_back( aThisHandlersProperty ); + continue; + } + + // there already was another (previous) handler which supported this property. + // Don't add it to aProperties, again. + + // Also, ensure that handlers which previously expressed interest in *changes* + // of this property are not notified. + // This is 'cause we have a new handler which is responsible for this property, + // which means it can give it a completely different meaning than the previous + // handler for this property is prepared for. + std::pair< PropertyHandlerMultiRepository::iterator, PropertyHandlerMultiRepository::iterator > + aDepHandlers = m_aDependencyHandlers.equal_range( aThisHandlersProperty.Name ); + m_aDependencyHandlers.erase( aDepHandlers.first, aDepHandlers.second ); + } + + // determine the superseded properties + StlSyntaxSequence< OUString > aSupersededByThisHandler( (*aHandler)->getSupersededProperties() ); + for (const auto & superseded : aSupersededByThisHandler) + { + std::vector< Property >::iterator existent = std::find_if( + aProperties.begin(), + aProperties.end(), + FindPropertyByName( superseded ) + ); + if ( existent != aProperties.end() ) + // one of the properties superseded by this handler was supported by a previous + // one -> erase + aProperties.erase( existent ); + } + + // be notified of changes which this handler is responsible for + (*aHandler)->addPropertyChangeListener( this ); + + // remember this handler for every of the properties which it is responsible + // for + for (const auto & aThisHandlersProperty : aThisHandlersProperties) + { + m_aPropertyHandlers[ aThisHandlersProperty.Name ] = *aHandler; + // note that this implies that if two handlers support the same property, + // the latter wins + } + + // see if the handler expresses interest in any actuating properties + StlSyntaxSequence< OUString > aInterestingActuations( (*aHandler)->getActuatingProperties() ); + for (const auto & aInterestingActuation : aInterestingActuations) + { + m_aDependencyHandlers.emplace( aInterestingActuation, *aHandler ); + } + + ++aHandler; + } + + // create a new composer for UI requests coming from the handlers + m_pUIRequestComposer.reset( new ComposedPropertyUIUpdate( getInspectorUI(), this ) ); + + // sort the properties by relative position, as indicated by the model + sal_Int32 nPos = 0; + for (auto const& sourceProps : aProperties) + { + sal_Int32 nRelativePropertyOrder = nPos; + if ( m_xModel.is() ) + nRelativePropertyOrder = m_xModel->getPropertyOrderIndex( sourceProps.Name ); + m_aProperties.emplace(nRelativePropertyOrder, sourceProps); + ++nPos; + } + + // be notified when one of our inspectees dies + impl_toggleInspecteeListening_nothrow( true ); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", ""); + } + } + + + css::awt::Size SAL_CALL OPropertyBrowserController::getMinimumSize() + { + css::awt::Size aSize; + if( m_xPropView ) + return m_xPropView->getMinimumSize(); + else + return aSize; + } + + + css::awt::Size SAL_CALL OPropertyBrowserController::getPreferredSize() + { + return getMinimumSize(); + } + + + css::awt::Size SAL_CALL OPropertyBrowserController::calcAdjustedSize( const css::awt::Size& _rNewSize ) + { + awt::Size aMinSize = getMinimumSize( ); + awt::Size aAdjustedSize( _rNewSize ); + if ( aAdjustedSize.Width < aMinSize.Width ) + aAdjustedSize.Width = aMinSize.Width; + if ( aAdjustedSize.Height < aMinSize.Height ) + aAdjustedSize.Height = aMinSize.Height; + return aAdjustedSize; + } + + + void OPropertyBrowserController::describePropertyLine( const Property& _rProperty, OLineDescriptor& _rDescriptor ) + { + try + { + PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rProperty.Name ); + if ( handler == m_aPropertyHandlers.end() ) + throw RuntimeException(); // caught below + + _rDescriptor.assignFrom( handler->second->describePropertyLine( _rProperty.Name, this ) ); + + + _rDescriptor.xPropertyHandler = handler->second; + _rDescriptor.sName = _rProperty.Name; + _rDescriptor.aValue = _rDescriptor.xPropertyHandler->getPropertyValue( _rProperty.Name ); + + if ( _rDescriptor.DisplayName.isEmpty() ) + { + #ifdef DBG_UTIL + SAL_WARN( "extensions.propctrlr", "OPropertyBrowserController::describePropertyLine: handler did not provide a display name for '" + <<_rProperty.Name << "'!" ); + #endif + _rDescriptor.DisplayName = _rProperty.Name; + } + + PropertyState ePropertyState( _rDescriptor.xPropertyHandler->getPropertyState( _rProperty.Name ) ); + if ( PropertyState_AMBIGUOUS_VALUE == ePropertyState ) + { + _rDescriptor.bUnknownValue = true; + _rDescriptor.aValue.clear(); + } + + _rDescriptor.bReadOnly = impl_isReadOnlyModel_throw(); + + // for ui-testing try and distinguish different instances of the controls + auto xWindow = _rDescriptor.Control->getControlWindow(); + if (weld::TransportAsXWindow* pTunnel = dynamic_cast(xWindow.get())) + { + weld::Widget* m_pControlWindow = pTunnel->getWidget(); + if (m_pControlWindow) + m_pControlWindow->set_buildable_name(m_pControlWindow->get_buildable_name() + "-" + _rDescriptor.DisplayName.toUtf8()); + } + + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::describePropertyLine" ); + } + } + + + void OPropertyBrowserController::impl_buildCategories_throw() + { + OSL_PRECOND( m_aPageIds.empty(), "OPropertyBrowserController::impl_buildCategories_throw: duplicate call!" ); + + StlSyntaxSequence< PropertyCategoryDescriptor > aCategories; + if ( m_xModel.is() ) + aCategories = StlSyntaxSequence< PropertyCategoryDescriptor >(m_xModel->describeCategories()); + + for (auto const& category : aCategories) + { + OSL_ENSURE( m_aPageIds.find( category.ProgrammaticName ) == m_aPageIds.end(), + "OPropertyBrowserController::impl_buildCategories_throw: duplicate programmatic name!" ); + + m_aPageIds[ category.ProgrammaticName ] = + getPropertyBox().AppendPage( category.UIName, HelpIdUrl::getHelpId( category.HelpURL ) ); + } + } + + + void OPropertyBrowserController::UpdateUI() + { + try + { + if ( !haveView() ) + // too early, will return later + return; + + // create our tab pages + impl_buildCategories_throw(); + // (and allow for pages to be actually unused) + std::set< sal_uInt16 > aUsedPages; + + // when building the UI below, remember which properties are actuating, + // to allow for an initial actuatingPropertyChanged call + std::vector< OUString > aActuatingProperties; + std::vector< Any > aActuatingPropertyValues; + + // ask the handlers to describe the property UI, and insert the resulting + // entries into our list boxes + for (auto const& property : m_aProperties) + { + OLineDescriptor aDescriptor; + describePropertyLine( property.second, aDescriptor ); + + bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( property.second.Name ); + + SAL_WARN_IF( aDescriptor.Category.isEmpty(), "extensions.propctrlr", + "OPropertyBrowserController::UpdateUI: empty category provided for property '" + << property.second.Name << "'!"); + // finally insert this property control + sal_uInt16 nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category ); + if ( nTargetPageId == sal_uInt16(-1) ) + { + // this category does not yet exist. This is allowed, as an inspector model might be lazy, and not provide + // any category information of its own. In this case, we have a fallback ... + m_aPageIds[ aDescriptor.Category ] = + getPropertyBox().AppendPage( aDescriptor.Category, OString() ); + nTargetPageId = impl_getPageIdForCategory_nothrow( aDescriptor.Category ); + } + + getPropertyBox().InsertEntry( aDescriptor, nTargetPageId ); + aUsedPages.insert( nTargetPageId ); + + // if it's an actuating property, remember it + if ( bIsActuatingProperty ) + { + aActuatingProperties.push_back( property.second.Name ); + aActuatingPropertyValues.push_back( impl_getPropertyValue_throw( property.second.Name ) ); + } + } + + // update any dependencies for the actuating properties which we encountered + { + std::vector< Any >::const_iterator aPropertyValue = aActuatingPropertyValues.begin(); + for (auto const& actuatingProperty : aActuatingProperties) + { + impl_broadcastPropertyChange_nothrow( actuatingProperty, *aPropertyValue, *aPropertyValue, true ); + ++aPropertyValue; + } + } + + // remove any unused pages (which we did not encounter properties for) + HashString2Int16 aSurvivingPageIds; + for (auto const& pageId : m_aPageIds) + { + if ( aUsedPages.find( pageId.second ) == aUsedPages.end() ) + getPropertyBox().RemovePage( pageId.second ); + else + aSurvivingPageIds.insert(pageId); + } + m_aPageIds.swap( aSurvivingPageIds ); + + getPropertyBox().Show(); + + // activate the first page + if ( !m_aPageIds.empty() ) + { + Sequence< PropertyCategoryDescriptor > aCategories( m_xModel->describeCategories() ); + if ( aCategories.hasElements() ) + m_xPropView->activatePage( m_aPageIds[ aCategories[0].ProgrammaticName ] ); + else + // allowed: if we default-created the pages ... + m_xPropView->activatePage( m_aPageIds.begin()->second ); + } + + // activate the previously active page (if possible) + if ( !m_sLastValidPageSelection.isEmpty() ) + m_sPageSelection = m_sLastValidPageSelection; + selectPageFromViewData(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + void OPropertyBrowserController::Clicked( const OUString& _rName, bool _bPrimary ) + { + try + { + // since the browse buttons do not get the focus when clicked with the mouse, + // we need to commit the changes in the current property field + getPropertyBox().CommitModified(); + + PropertyHandlerRepository::const_iterator handler = m_aPropertyHandlers.find( _rName ); + DBG_ASSERT( handler != m_aPropertyHandlers.end(), "OPropertyBrowserController::Clicked: a property without handler? This will crash!" ); + + ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer ); + + Any aData; + m_xInteractiveHandler = handler->second; + InteractiveSelectionResult eResult = + handler->second->onInteractivePropertySelection( _rName, _bPrimary, aData, + m_pUIRequestComposer->getUIForPropertyHandler( handler->second ) ); + + switch ( eResult ) + { + case InteractiveSelectionResult_Cancelled: + case InteractiveSelectionResult_Success: + // okay, nothing to do + break; + case InteractiveSelectionResult_ObtainedValue: + handler->second->setPropertyValue( _rName, aData ); + break; + case InteractiveSelectionResult_Pending: + // also okay, we expect that the handler has disabled the UI as necessary + break; + default: + OSL_FAIL( "OPropertyBrowserController::Clicked: unknown result value!" ); + break; + } + } + catch (const Exception&) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + m_xInteractiveHandler = nullptr; + } + + + bool OPropertyBrowserController::hasPropertyByName( const OUString& _rName ) + { + for (auto const& property : m_aProperties) + if ( property.second.Name == _rName ) + return true; + return false; + } + + + void OPropertyBrowserController::Commit( const OUString& rName, const Any& _rValue ) + { + try + { + OUString sPlcHolder = PcrRes(RID_EMBED_IMAGE_PLACEHOLDER); + bool bIsPlaceHolderValue = false; + + if ( rName == PROPERTY_IMAGE_URL ) + { + // if the prop value is the PlaceHolder + // can ignore it + OUString sVal; + _rValue >>= sVal; + if ( sVal == sPlcHolder ) + bIsPlaceHolderValue = true; + } + m_sCommittingProperty = rName; + + bool bIsActuatingProperty = impl_isActuatingProperty_nothrow( rName ); + + Any aOldValue; + if ( bIsActuatingProperty ) + aOldValue = impl_getPropertyValue_throw( rName ); + + // do we have a dedicated handler for this property, which we can delegate some tasks to? + PropertyHandlerRef handler = impl_getHandlerForProperty_throw( rName ); + + + // set the value ( only if it's not a placeholder ) + if ( !bIsPlaceHolderValue ) + handler->setPropertyValue( rName, _rValue ); + + + // re-retrieve the value + Any aNormalizedValue = handler->getPropertyValue( rName ); + + // care for any inter-property dependencies + if ( bIsActuatingProperty ) + impl_broadcastPropertyChange_nothrow( rName, aNormalizedValue, aOldValue, false ); + + // and display it again. This ensures proper formatting + getPropertyBox().SetPropertyValue( rName, aNormalizedValue, false ); + } + catch(const PropertyVetoException& eVetoException) + { + std::unique_ptr xInfoBox(Application::CreateMessageDialog(m_xPropView->getPropertyBox().getWidget(), + VclMessageType::Info, VclButtonsType::Ok, + eVetoException.Message)); + xInfoBox->run(); + PropertyHandlerRef handler = impl_getHandlerForProperty_throw( rName ); + Any aNormalizedValue = handler->getPropertyValue( rName ); + getPropertyBox().SetPropertyValue( rName, aNormalizedValue, false ); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", ""); + } + + m_sCommittingProperty.clear(); + } + + + void OPropertyBrowserController::focusGained( const Reference< XPropertyControl >& Control ) + { + m_aControlObservers.notifyEach( &XPropertyControlObserver::focusGained, Control ); + } + + + void OPropertyBrowserController::valueChanged( const Reference< XPropertyControl >& Control ) + { + m_aControlObservers.notifyEach( &XPropertyControlObserver::valueChanged, Control ); + } + + + namespace + { + Reference< XPropertyHandler > lcl_createHandler( const Reference& _rContext, const Any& _rFactoryDescriptor ) + { + Reference< XPropertyHandler > xHandler; + + OUString sServiceName; + Reference< XSingleServiceFactory > xServiceFac; + Reference< XSingleComponentFactory > xComponentFac; + + if ( _rFactoryDescriptor >>= sServiceName ) + xHandler.set( _rContext->getServiceManager()->createInstanceWithContext( sServiceName, _rContext ), UNO_QUERY ); + else if ( _rFactoryDescriptor >>= xServiceFac ) + xHandler.set(xServiceFac->createInstance(), css::uno::UNO_QUERY); + else if ( _rFactoryDescriptor >>= xComponentFac ) + xHandler.set(xComponentFac->createInstanceWithContext( _rContext ), css::uno::UNO_QUERY); + OSL_ENSURE(xHandler.is(),"lcl_createHandler: Can not create handler"); + return xHandler; + } + } + + + void OPropertyBrowserController::getPropertyHandlers( const InterfaceArray& _rObjects, PropertyHandlerArray& _rHandlers ) + { + _rHandlers.resize( 0 ); + if ( _rObjects.empty() ) + return; + + Sequence< Any > aHandlerFactories; + if ( m_xModel.is() ) + aHandlerFactories = m_xModel->getHandlerFactories(); + + for ( auto const & handlerFactory : std::as_const(aHandlerFactories) ) + { + if ( _rObjects.size() == 1 ) + { // we're inspecting only one object -> one handler + Reference< XPropertyHandler > xHandler( lcl_createHandler( m_xContext, handlerFactory ) ); + if ( xHandler.is() ) + { + xHandler->inspect( _rObjects[0] ); + _rHandlers.push_back( xHandler ); + } + } + else + { + // create a single handler for every single object + std::vector< Reference< XPropertyHandler > > aSingleHandlers( _rObjects.size() ); + std::vector< Reference< XPropertyHandler > >::iterator pHandler = aSingleHandlers.begin(); + + for (auto const& elem : _rObjects) + { + *pHandler = lcl_createHandler( m_xContext, handlerFactory ); + if ( pHandler->is() ) + { + (*pHandler)->inspect(elem); + ++pHandler; + } + } + aSingleHandlers.resize( pHandler - aSingleHandlers.begin() ); + + // then create a handler which composes information out of those single handlers + if ( !aSingleHandlers.empty() ) + _rHandlers.push_back( new PropertyComposer( std::move(aSingleHandlers) ) ); + } + } + + // note that the handlers will not be used by our caller, if they indicate that there are no + // properties they feel responsible for + } + + + bool OPropertyBrowserController::impl_findObjectProperty_nothrow( const OUString& _rName, OrderedPropertyMap::const_iterator* _pProperty ) + { + OrderedPropertyMap::const_iterator search = std::find_if(m_aProperties.begin(), m_aProperties.end(), + [&_rName](const OrderedPropertyMap::value_type& rEntry) { return rEntry.second.Name == _rName; }); + if ( _pProperty ) + *_pProperty = search; + return ( search != m_aProperties.end() ); + } + + + void OPropertyBrowserController::rebuildPropertyUI( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !haveView() ) + throw RuntimeException(); + + OrderedPropertyMap::const_iterator propertyPos; + if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) ) + return; + + OLineDescriptor aDescriptor; + try + { + describePropertyLine( propertyPos->second, aDescriptor ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "OPropertyBrowserController::rebuildPropertyUI" ); + } + + getPropertyBox().ChangeEntry( aDescriptor ); + } + + + void OPropertyBrowserController::enablePropertyUI( const OUString& _rPropertyName, sal_Bool _bEnable ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !haveView() ) + throw RuntimeException(); + + if ( !impl_findObjectProperty_nothrow( _rPropertyName ) ) + return; + + getPropertyBox().EnablePropertyLine( _rPropertyName, _bEnable ); + } + + + void OPropertyBrowserController::enablePropertyUIElements( const OUString& _rPropertyName, sal_Int16 _nElements, sal_Bool _bEnable ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !haveView() ) + throw RuntimeException(); + + if ( !impl_findObjectProperty_nothrow( _rPropertyName ) ) + return; + + getPropertyBox().EnablePropertyControls( _rPropertyName, _nElements, _bEnable ); + } + + + void OPropertyBrowserController::showPropertyUI( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !haveView() ) + throw RuntimeException(); + + // look up the property in our object properties + OrderedPropertyMap::const_iterator propertyPos; + if ( !impl_findObjectProperty_nothrow( _rPropertyName, &propertyPos ) ) + return; + + if ( getPropertyBox().GetPropertyPos( _rPropertyName ) != EDITOR_LIST_ENTRY_NOTFOUND ) + { + rebuildPropertyUI( _rPropertyName ); + return; + } + + OLineDescriptor aDescriptor; + describePropertyLine( propertyPos->second, aDescriptor ); + + // look for the position to insert the property + + // side note: The methods GetPropertyPos and InsertEntry of the OPropertyEditor work + // only on the current page. This implies that it's impossible to use this method here + // to show property lines which are *not* on the current page. + // This is sufficient for now, but should be changed in the future. + + // by definition, the properties in m_aProperties are in the order in which they appear in the UI + // So all we need is a predecessor of pProperty in m_aProperties + sal_uInt16 nUIPos = EDITOR_LIST_ENTRY_NOTFOUND; + do + { + if ( propertyPos != m_aProperties.begin() ) + --propertyPos; + nUIPos = getPropertyBox().GetPropertyPos( propertyPos->second.Name ); + } + while ( ( nUIPos == EDITOR_LIST_ENTRY_NOTFOUND ) && ( propertyPos != m_aProperties.begin() ) ); + + if ( nUIPos == EDITOR_LIST_ENTRY_NOTFOUND ) + // insert at the very top + nUIPos = 0; + else + // insert right after the predecessor we found + ++nUIPos; + + getPropertyBox().InsertEntry( + aDescriptor, impl_getPageIdForCategory_nothrow( aDescriptor.Category ), nUIPos ); + } + + + void OPropertyBrowserController::hidePropertyUI( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !haveView() ) + throw RuntimeException(); + + if ( !impl_findObjectProperty_nothrow( _rPropertyName ) ) + return; + + getPropertyBox().RemoveEntry( _rPropertyName ); + } + + + void OPropertyBrowserController::showCategory( const OUString& rCategory, sal_Bool bShow ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !haveView() ) + throw RuntimeException(); + + sal_uInt16 nPageId = impl_getPageIdForCategory_nothrow( rCategory ); + OSL_ENSURE( nPageId != sal_uInt16(-1), "OPropertyBrowserController::showCategory: invalid category!" ); + + getPropertyBox().ShowPropertyPage( nPageId, bShow ); + } + + + Reference< XPropertyControl > SAL_CALL OPropertyBrowserController::getPropertyControl( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !haveView() ) + throw RuntimeException(); + + Reference< XPropertyControl > xControl( getPropertyBox().GetPropertyControl( _rPropertyName ) ); + return xControl; + } + + + void SAL_CALL OPropertyBrowserController::registerControlObserver( const Reference< XPropertyControlObserver >& Observer ) + { + m_aControlObservers.addInterface( Observer ); + } + + + void SAL_CALL OPropertyBrowserController::revokeControlObserver( const Reference< XPropertyControlObserver >& Observer ) + { + m_aControlObservers.removeInterface( Observer ); + } + + + void SAL_CALL OPropertyBrowserController::setHelpSectionText( const OUString& _rHelpText ) + { + SolarMutexGuard aSolarGuard; + ::osl::MutexGuard aGuard( m_aMutex ); + + if ( !haveView() ) + throw DisposedException(); + + if ( !getPropertyBox().HasHelpSection() ) + throw NoSupportException(); + + getPropertyBox().SetHelpText( _rHelpText ); + } + + + void OPropertyBrowserController::impl_broadcastPropertyChange_nothrow( const OUString& _rPropertyName, const Any& _rNewValue, const Any& _rOldValue, bool _bFirstTimeInit ) const + { + // are there one or more handlers which are interested in the actuation? + std::pair< PropertyHandlerMultiRepository::const_iterator, PropertyHandlerMultiRepository::const_iterator > aInterestedHandlers = + m_aDependencyHandlers.equal_range( _rPropertyName ); + if ( aInterestedHandlers.first == aInterestedHandlers.second ) + // none of our handlers is interested in this + return; + + ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer ); + try + { + // collect the responses from all interested handlers + PropertyHandlerMultiRepository::const_iterator handler = aInterestedHandlers.first; + while ( handler != aInterestedHandlers.second ) + { + handler->second->actuatingPropertyChanged( _rPropertyName, _rNewValue, _rOldValue, + m_pUIRequestComposer->getUIForPropertyHandler( handler->second ), + _bFirstTimeInit ); + ++handler; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_OPropertyBrowserController_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::OPropertyBrowserController(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propcontroller.hxx b/extensions/source/propctrlr/propcontroller.hxx new file mode 100644 index 000000000..a56a83979 --- /dev/null +++ b/extensions/source/propctrlr/propcontroller.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 . + */ + +#pragma once + +#include "composeduiupdate.hxx" +#include "proplinelistener.hxx" +#include "propcontrolobserver.hxx" +#include "browserview.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace pcr +{ + class OPropertyEditor; + struct OLineDescriptor; + + typedef ::cppu::WeakImplHelper < css::lang::XServiceInfo + , css::awt::XFocusListener + , css::awt::XLayoutConstrains + , css::beans::XPropertyChangeListener + , css::inspection::XPropertyControlFactory + , css::inspection::XObjectInspector + , css::lang::XInitialization + > OPropertyBrowserController_Base; + + class OPropertyBrowserController + :public ::comphelper::OMutexAndBroadcastHelper + ,public OPropertyBrowserController_Base + ,public css::inspection::XObjectInspectorUI + // that's intentionally *not* part of the OPropertyBrowserController_Base + // We do not want this to be available in queryInterface, getTypes, and the like. + ,public IPropertyLineListener + ,public IPropertyControlObserver + ,public IPropertyExistenceCheck + { + private: + typedef std::multimap< sal_Int32, css::beans::Property > OrderedPropertyMap; + typedef std::vector< css::uno::Reference< css::uno::XInterface > > + InterfaceArray; + + protected: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + + private: + css::uno::Reference< css::frame::XFrame > m_xFrame; + css::uno::Reference< css::awt::XWindow > m_xView; + + ::comphelper::OInterfaceContainerHelper2 m_aDisposeListeners; + ::comphelper::OInterfaceContainerHelper2 m_aControlObservers; + // meta data about the properties + std::unique_ptr m_xBuilder; + std::unique_ptr m_xPropView; + + OUString m_sPageSelection; + OUString m_sLastValidPageSelection; + + typedef css::uno::Reference< css::inspection::XPropertyHandler > + PropertyHandlerRef; + typedef std::vector< PropertyHandlerRef > PropertyHandlerArray; + typedef std::unordered_map< OUString, PropertyHandlerRef > + PropertyHandlerRepository; + typedef std::unordered_multimap< OUString, PropertyHandlerRef > + PropertyHandlerMultiRepository; + PropertyHandlerRepository m_aPropertyHandlers; + PropertyHandlerMultiRepository m_aDependencyHandlers; + PropertyHandlerRef m_xInteractiveHandler; + + std::unique_ptr< ComposedPropertyUIUpdate > m_pUIRequestComposer; + + /// our InspectorModel + css::uno::Reference< css::inspection::XObjectInspectorModel > + m_xModel; + /// the object(s) we're currently inspecting + InterfaceArray m_aInspectedObjects; + /// the properties of the currently inspected object(s) + OrderedPropertyMap m_aProperties; + /// the property we're just committing + OUString m_sCommittingProperty; + + typedef std::unordered_map< OUString, sal_uInt16 > HashString2Int16; + HashString2Int16 m_aPageIds; + + bool m_bContainerFocusListening; + bool m_bSuspendingPropertyHandlers; + bool m_bConstructed; + bool m_bBindingIntrospectee; + + protected: + DECLARE_XINTERFACE() + + // 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; + + // XController + virtual void SAL_CALL attachFrame( const css::uno::Reference< css::frame::XFrame >& xFrame ) override; + virtual sal_Bool SAL_CALL attachModel( const css::uno::Reference< css::frame::XModel >& xModel ) override; + virtual sal_Bool SAL_CALL suspend( sal_Bool bSuspend ) override; + virtual css::uno::Any SAL_CALL getViewData( ) override; + virtual void SAL_CALL restoreViewData( const css::uno::Any& Data ) override; + virtual css::uno::Reference< css::frame::XModel > SAL_CALL getModel( ) override; + virtual css::uno::Reference< css::frame::XFrame > SAL_CALL getFrame( ) 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; + + // XFocusListener + virtual void SAL_CALL focusGained( const css::awt::FocusEvent& _rSource ) override; + virtual void SAL_CALL focusLost( const css::awt::FocusEvent& _rSource ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // XLayoutConstrains + virtual css::awt::Size SAL_CALL getMinimumSize( ) override; + virtual css::awt::Size SAL_CALL getPreferredSize( ) override; + virtual css::awt::Size SAL_CALL calcAdjustedSize( const css::awt::Size& rNewSize ) override; + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& _rEvent ) override; + + /** XPropertyControlFactory + */ + virtual css::uno::Reference< css::inspection::XPropertyControl > SAL_CALL createPropertyControl( ::sal_Int16 ControlType, sal_Bool CreateReadOnly ) override; + + public: + explicit OPropertyBrowserController( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext); + + protected: + virtual ~OPropertyBrowserController() override; + + // IPropertyLineListener + virtual void Clicked( const OUString& _rName, bool _bPrimary ) override; + virtual void Commit( const OUString& _rName, const css::uno::Any& _rVal ) override; + + // IPropertyControlObserver + virtual void focusGained( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) override; + virtual void valueChanged( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) override; + + // IPropertyExistenceCheck + virtual bool hasPropertyByName( const OUString& _rName ) override; + + // XObjectInspectorUI + virtual void SAL_CALL enablePropertyUI( const OUString& _rPropertyName, sal_Bool _bEnable ) override; + virtual void SAL_CALL enablePropertyUIElements( const OUString& _rPropertyName, ::sal_Int16 _nElements, sal_Bool _bEnable ) override; + virtual void SAL_CALL rebuildPropertyUI( const OUString& _rPropertyName ) override; + virtual void SAL_CALL showPropertyUI( const OUString& _rPropertyName ) override; + virtual void SAL_CALL hidePropertyUI( const OUString& _rPropertyName ) override; + virtual void SAL_CALL showCategory( const OUString& _rCategory, sal_Bool _bShow ) override; + virtual css::uno::Reference< css::inspection::XPropertyControl > SAL_CALL getPropertyControl( const OUString& _rPropertyName ) override; + virtual void SAL_CALL registerControlObserver( const css::uno::Reference< css::inspection::XPropertyControlObserver >& Observer ) override; + virtual void SAL_CALL revokeControlObserver( const css::uno::Reference< css::inspection::XPropertyControlObserver >& Observer ) override; + virtual void SAL_CALL setHelpSectionText( const OUString& HelpText ) override; + + // XObjectInspector + virtual css::uno::Reference< css::inspection::XObjectInspectorModel > SAL_CALL getInspectorModel() override; + virtual void SAL_CALL setInspectorModel( const css::uno::Reference< css::inspection::XObjectInspectorModel >& _inspectormodel ) override; + virtual css::uno::Reference< css::inspection::XObjectInspectorUI > SAL_CALL getInspectorUI() override; + virtual void SAL_CALL inspect( const css::uno::Sequence< css::uno::Reference< css::uno::XInterface > >& Objects ) override; + + // XDispatchProvider + 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; + + // XInitialization + virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override; + + private: + void UpdateUI(); + + void startContainerWindowListening(); + void stopContainerWindowListening(); + + // stop the inspection + void stopInspection( bool _bCommitModified ); + + bool haveView() const { return bool(m_xPropView); } + OPropertyEditor& getPropertyBox() { return m_xPropView->getPropertyBox(); } + + // does the inspection of the objects as indicated by our model + void doInspection(); + + // bind the browser to m_xIntrospecteeAsProperty + void impl_rebindToInspectee_nothrow( InterfaceArray&& _rObjects ); + + /** retrieves special property handlers for our introspectee + */ + void getPropertyHandlers( const InterfaceArray& _rObjects, PropertyHandlerArray& _rHandlers ); + + /** called when a property changed, to broadcast any handlers which might have + registered for this property + + @param _bFirstTimeInit + if set to , this is a real change in the property value, not just a call + for purposes of initialization. + */ + void impl_broadcastPropertyChange_nothrow( const OUString& _rPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, bool _bFirstTimeInit ) const; + + /** determines whether the given property is an actuating property, that is, at least one + handler expressed interest in changes to this property's value. + */ + bool impl_isActuatingProperty_nothrow( const OUString& _rPropertyName ) const + { + return ( m_aDependencyHandlers.find( _rPropertyName ) != m_aDependencyHandlers.end() ); + } + + /** retrieves the value of the given property, by asking the appropriate XPropertyHandler + @param _rPropertyName + the name whose handler is to be obtained. Must be the name of a property + for which a handler is registered. + @throws + RuntimeException if there is no handler for the given property + @return + the value of this property + */ + css::uno::Any + impl_getPropertyValue_throw( const OUString& _rPropertyName ); + + /// calls XPropertyHandler::suspend for all our property handlers + bool suspendPropertyHandlers_nothrow( bool _bSuspend ); + + /// suspends the complete inspector + bool suspendAll_nothrow(); + + /** selects a page according to our current view data + */ + void selectPageFromViewData(); + + /** updates our view data from the currently active page + */ + void updateViewDataFromActivePage(); + + /// describes the UI for the given property + void describePropertyLine( const css::beans::Property& _rPropertyName, OLineDescriptor& _rDescriptor ); + + /** retrieves the position of the property given by name in m_aProperties + @return + if and only if the property could be found. In this case, _pProperty (if + not contains the iterator pointing to this property. + */ + bool impl_findObjectProperty_nothrow( const OUString& _rName, OrderedPropertyMap::const_iterator* _pProperty = nullptr ); + + void Construct(const css::uno::Reference& rContainerWindow, std::unique_ptr xBuilder); + + /** retrieves the property handler for a given property name + @param _rPropertyName + the name whose handler is to be obtained. Must be the name of a property + for which a handler is registered. + @throws + RuntimeException if there is no handler for the given property + @return + the handler which is responsible for the given property + */ + PropertyHandlerRef const & + impl_getHandlerForProperty_throw( const OUString& _rPropertyName ) const; + + /** determines whether we have a handler for the given property + @param _rPropertyName + the name of the property for which the existence of a handler should be checked + */ + bool + impl_hasPropertyHandlerFor_nothrow( const OUString& _rPropertyName ) const; + + /** builds up m_aPageIds from InspectorModel::describeCategories, and insert all the + respective tab pages into our view + @precond + m_aPageIds is empty + @throws css::uno::RuntimeException + if one of the callees of this method throws this exception + */ + void + impl_buildCategories_throw(); + + /** retrieves the id of the tab page which represents a given category. + @param _rCategoryName + the programmatic name of a category. + @return + the id of the tab page, or (sal_uInt16)-1 if there + is no tab page for the given category + */ + sal_uInt16 + impl_getPageIdForCategory_nothrow( const OUString& _rCategoryName ) const; + + /** adds or removes ourself as XEventListener to/from all our inspectees + */ + void impl_toggleInspecteeListening_nothrow( bool _bOn ); + + /** binds the instance to a new model + */ + void impl_bindToNewModel_nothrow( const css::uno::Reference< css::inspection::XObjectInspectorModel >& _rxInspectorModel ); + + /** initializes our view, as indicated by the model's view-relevant properties + + It's allowed to call this method when no model exists, yet. In this case, nothing + happens. + */ + void impl_initializeView_nothrow(); + + /** determines whether the view should be readonly. + + Effectively, this means that the method simply checks the IsReadOnly attribute of the model. + If there is no model, is returned. + + @throws css::uno::RuntimeException + in case asking the model for its IsReadOnly attribute throws a css::uno::RuntimeException + itself. + */ + bool impl_isReadOnlyModel_throw() const; + + /** starts or stops listening at the model + */ + void impl_startOrStopModelListening_nothrow( bool _bDoListen ) const; + + private: + DECL_LINK(OnPageActivation, LinkParamNone*, void); + + private: + // constructors + void createWithModel( const css::uno::Reference< css::inspection::XObjectInspectorModel >& _rxModel ); + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propcontrolobserver.hxx b/extensions/source/propctrlr/propcontrolobserver.hxx new file mode 100644 index 000000000..93e11053d --- /dev/null +++ b/extensions/source/propctrlr/propcontrolobserver.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + + +namespace pcr +{ + + + //= IPropertyControlObserver + + /** non-UNO version of the XPropertyControlObserver + */ + class IPropertyControlObserver + { + public: + virtual void focusGained( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) = 0; + virtual void valueChanged( const css::uno::Reference< css::inspection::XPropertyControl >& Control ) = 0; + + protected: + ~IPropertyControlObserver() {} + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propertycomposer.cxx b/extensions/source/propctrlr/propertycomposer.cxx new file mode 100644 index 000000000..d77280d9f --- /dev/null +++ b/extensions/source/propctrlr/propertycomposer.cxx @@ -0,0 +1,484 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "propertycomposer.hxx" + +#include +#include +#include +#include +#include + +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::inspection; + + + //= helper + + namespace + { + + struct SetPropertyValue + { + OUString sPropertyName; + const Any& rValue; + SetPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) : sPropertyName( _rPropertyName ), rValue( _rValue ) { } + void operator()( const Reference< XPropertyHandler >& _rHandler ) + { + _rHandler->setPropertyValue( sPropertyName, rValue ); + } + }; + + + template < class BagType > + void putIntoBag( const Sequence< typename BagType::value_type >& _rArray, BagType& /* [out] */ _rBag ) + { + std::copy( _rArray.begin(), _rArray.end(), + std::insert_iterator< BagType >( _rBag, _rBag.begin() ) ); + } + + + template < class BagType > + void copyBagToArray( const BagType& /* [out] */ _rBag, Sequence< typename BagType::value_type >& _rArray ) + { + _rArray.realloc( _rBag.size() ); + std::copy( _rBag.begin(), _rBag.end(), _rArray.getArray() ); + } + } + + + //= PropertyComposer + + + // TODO: there are various places where we determine the first handler in our array which + // supports a given property id. This is, at the moment, done with searching all handlers, + // which is O( n * k ) at worst (n being the number of handlers, k being the maximum number + // of supported properties per handler). Shouldn't we cache this? So that it is O( log k )? + + + PropertyComposer::PropertyComposer( std::vector< Reference< XPropertyHandler > >&& _rSlaveHandlers ) + :PropertyComposer_Base ( m_aMutex ) + ,m_aSlaveHandlers ( std::move(_rSlaveHandlers) ) + ,m_aPropertyListeners ( m_aMutex ) + ,m_bSupportedPropertiesAreKnown ( false ) + { + if ( m_aSlaveHandlers.empty() ) + throw IllegalArgumentException(); + + osl_atomic_increment( &m_refCount ); + { + Reference< XPropertyChangeListener > xMeMyselfAndI( this ); + for (auto const& slaveHandler : m_aSlaveHandlers) + { + if ( !slaveHandler.is() ) + throw NullPointerException(); + slaveHandler->addPropertyChangeListener( xMeMyselfAndI ); + } + } + osl_atomic_decrement( &m_refCount ); + } + + + void SAL_CALL PropertyComposer::inspect( const Reference< XInterface >& _rxIntrospectee ) + { + MethodGuard aGuard( *this ); + + for (auto const& slaveHandler : m_aSlaveHandlers) + { + slaveHandler->inspect( _rxIntrospectee ); + } + } + + + Any SAL_CALL PropertyComposer::getPropertyValue( const OUString& _rPropertyName ) + { + MethodGuard aGuard( *this ); + return m_aSlaveHandlers[0]->getPropertyValue( _rPropertyName ); + } + + + void SAL_CALL PropertyComposer::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + MethodGuard aGuard( *this ); + std::for_each( m_aSlaveHandlers.begin(), m_aSlaveHandlers.end(), SetPropertyValue( _rPropertyName, _rValue ) ); + } + + + Any SAL_CALL PropertyComposer::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue ) + { + MethodGuard aGuard( *this ); + return m_aSlaveHandlers[0]->convertToPropertyValue( _rPropertyName, _rControlValue ); + } + + + Any SAL_CALL PropertyComposer::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType ) + { + MethodGuard aGuard( *this ); + return m_aSlaveHandlers[0]->convertToControlValue( _rPropertyName, _rPropertyValue, _rControlValueType ); + } + + + PropertyState SAL_CALL PropertyComposer::getPropertyState( const OUString& _rPropertyName ) + { + MethodGuard aGuard( *this ); + + // assume DIRECT for the moment. This will stay this way if *all* slaves + // tell the property has DIRECT state, and if *all* values equal + PropertyState eState = PropertyState_DIRECT_VALUE; + + // check the master state + Reference< XPropertyHandler > xPrimary( *m_aSlaveHandlers.begin() ); + Any aPrimaryValue = xPrimary->getPropertyValue( _rPropertyName ); + eState = xPrimary->getPropertyState( _rPropertyName ); + + // loop through the secondary sets + PropertyState eSecondaryState = PropertyState_DIRECT_VALUE; + for ( HandlerArray::const_iterator loop = m_aSlaveHandlers.begin() + 1; + loop != m_aSlaveHandlers.end(); + ++loop + ) + { + // the secondary state + eSecondaryState = (*loop)->getPropertyState( _rPropertyName ); + + // the secondary value + Any aSecondaryValue( (*loop)->getPropertyValue( _rPropertyName ) ); + + if ( ( PropertyState_AMBIGUOUS_VALUE == eSecondaryState ) // secondary is ambiguous + || ( aPrimaryValue != aSecondaryValue ) // unequal values + ) + { + eState = PropertyState_AMBIGUOUS_VALUE; + break; + } + } + + return eState; + } + + + void SAL_CALL PropertyComposer::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + MethodGuard aGuard( *this ); + m_aPropertyListeners.addInterface( _rxListener ); + } + + + void SAL_CALL PropertyComposer::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + MethodGuard aGuard( *this ); + m_aPropertyListeners.removeInterface( _rxListener ); + } + + + Sequence< Property > SAL_CALL PropertyComposer::getSupportedProperties() + { + MethodGuard aGuard( *this ); + + if ( !m_bSupportedPropertiesAreKnown ) + { + // we support a property if and only if all of our slaves support it + + // initially, use all the properties of an arbitrary handler (we take the first one) + putIntoBag( (*m_aSlaveHandlers.begin())->getSupportedProperties(), m_aSupportedProperties ); + + // now intersect with the properties of *all* other handlers + for ( HandlerArray::const_iterator loop = m_aSlaveHandlers.begin() + 1; + loop != m_aSlaveHandlers.end(); + ++loop + ) + { + // the properties supported by the current handler + PropertyBag aThisRound; + putIntoBag( (*loop)->getSupportedProperties(), aThisRound ); + + // the intersection of those properties with all we already have + PropertyBag aIntersection; + std::set_intersection( aThisRound.begin(), aThisRound.end(), m_aSupportedProperties.begin(), m_aSupportedProperties.end(), + std::insert_iterator< PropertyBag >( aIntersection, aIntersection.begin() ), PropertyLessByName() ); + + m_aSupportedProperties.swap( aIntersection ); + if ( m_aSupportedProperties.empty() ) + break; + } + + // remove those properties which are not composable + for ( PropertyBag::iterator check = m_aSupportedProperties.begin(); + check != m_aSupportedProperties.end(); + ) + { + bool bIsComposable = isComposable( check->Name ); + if ( !bIsComposable ) + { + check = m_aSupportedProperties.erase( check ); + } + else + ++check; + } + + m_bSupportedPropertiesAreKnown = true; + } + + return comphelper::containerToSequence( m_aSupportedProperties ); + } + + + static void uniteStringArrays( const PropertyComposer::HandlerArray& _rHandlers, Sequence< OUString > (SAL_CALL XPropertyHandler::*pGetter)( ), + Sequence< OUString >& /* [out] */ _rUnion ) + { + std::set< OUString > aUnitedBag; + + Sequence< OUString > aThisRound; + for (auto const& handler : _rHandlers) + { + aThisRound = (handler.get()->*pGetter)(); + putIntoBag( aThisRound, aUnitedBag ); + } + + copyBagToArray( aUnitedBag, _rUnion ); + } + + + Sequence< OUString > SAL_CALL PropertyComposer::getSupersededProperties( ) + { + MethodGuard aGuard( *this ); + + // we supersede those properties which are superseded by at least one of our slaves + Sequence< OUString > aSuperseded; + uniteStringArrays( m_aSlaveHandlers, &XPropertyHandler::getSupersededProperties, aSuperseded ); + return aSuperseded; + } + + + Sequence< OUString > SAL_CALL PropertyComposer::getActuatingProperties( ) + { + MethodGuard aGuard( *this ); + + // we're interested in those properties which at least one handler wants to have + Sequence< OUString > aActuating; + uniteStringArrays( m_aSlaveHandlers, &XPropertyHandler::getActuatingProperties, aActuating ); + return aActuating; + } + + + LineDescriptor SAL_CALL PropertyComposer::describePropertyLine( const OUString& _rPropertyName, + const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + MethodGuard aGuard( *this ); + return m_aSlaveHandlers[0]->describePropertyLine( _rPropertyName, _rxControlFactory ); + } + + + sal_Bool SAL_CALL PropertyComposer::isComposable( const OUString& _rPropertyName ) + { + MethodGuard aGuard( *this ); + return m_aSlaveHandlers[0]->isComposable( _rPropertyName ); + } + + + InteractiveSelectionResult SAL_CALL PropertyComposer::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, Any& _rData, const Reference< XObjectInspectorUI >& _rxInspectorUI ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + MethodGuard aGuard( *this ); + + impl_ensureUIRequestComposer( _rxInspectorUI ); + ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer ); + + // ask the first of the handlers + InteractiveSelectionResult eResult = (*m_aSlaveHandlers.begin())->onInteractivePropertySelection( + _rPropertyName, + _bPrimary, + _rData, + m_pUIRequestComposer->getUIForPropertyHandler( *m_aSlaveHandlers.begin() ) + ); + + switch ( eResult ) + { + case InteractiveSelectionResult_Cancelled: + // fine + break; + + case InteractiveSelectionResult_Success: + case InteractiveSelectionResult_Pending: + OSL_FAIL( "PropertyComposer::onInteractivePropertySelection: no chance to forward the new value to the other handlers!" ); + // This means that we cannot know the new property value, which either has already been set + // at the first component ("Success"), or will be set later on once the asynchronous input + // is finished ("Pending"). So, we also cannot forward this new property value to the other + // handlers. + // We would need to be a listener at the property at the first component, but even this wouldn't + // be sufficient, since the property handler is free to change *any* property during a dedicated + // property UI. + eResult = InteractiveSelectionResult_Cancelled; + break; + + case InteractiveSelectionResult_ObtainedValue: + // OK. Our own caller will pass this as setPropertyValue, and we will then pass it to + // all slave handlers + break; + + default: + OSL_FAIL( "OPropertyBrowserController::onInteractivePropertySelection: unknown result value!" ); + break; + } + + return eResult; + } + + + void PropertyComposer::impl_ensureUIRequestComposer( const Reference< XObjectInspectorUI >& _rxInspectorUI ) + { + OSL_ENSURE(!m_pUIRequestComposer + || m_pUIRequestComposer->getDelegatorUI().get() == _rxInspectorUI.get(), + "PropertyComposer::impl_ensureUIRequestComposer: somebody's changing the horse " + "in the mid of the race!"); + + if (!m_pUIRequestComposer) + m_pUIRequestComposer.reset( new ComposedPropertyUIUpdate( _rxInspectorUI, this ) ); + } + + + void SAL_CALL PropertyComposer::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& _rOldValue, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + MethodGuard aGuard( *this ); + + impl_ensureUIRequestComposer( _rxInspectorUI ); + ComposedUIAutoFireGuard aAutoFireGuard( *m_pUIRequestComposer ); + + // ask all handlers which expressed interest in this particular property, and "compose" their + // commands for the UIUpdater + for (auto const& slaveHandler : m_aSlaveHandlers) + { + // TODO: make this cheaper (cache it?) + const StlSyntaxSequence< OUString > aThisHandlersActuatingProps( slaveHandler->getActuatingProperties() ); + for (const auto & aThisHandlersActuatingProp : aThisHandlersActuatingProps) + { + if ( aThisHandlersActuatingProp == _rActuatingPropertyName ) + { + slaveHandler->actuatingPropertyChanged( _rActuatingPropertyName, _rNewValue, _rOldValue, + m_pUIRequestComposer->getUIForPropertyHandler(slaveHandler), + _bFirstTimeInit ); + break; + } + } + } + } + + + IMPLEMENT_FORWARD_XCOMPONENT( PropertyComposer, PropertyComposer_Base ) + + + void SAL_CALL PropertyComposer::disposing() + { + MethodGuard aGuard( *this ); + + // dispose our slave handlers + for (auto const& slaveHandler : m_aSlaveHandlers) + { + slaveHandler->removePropertyChangeListener( this ); + slaveHandler->dispose(); + } + + clearContainer( m_aSlaveHandlers ); + + if (m_pUIRequestComposer) + m_pUIRequestComposer->dispose(); + m_pUIRequestComposer.reset(); + } + + + void SAL_CALL PropertyComposer::propertyChange( const PropertyChangeEvent& evt ) + { + if ( !impl_isSupportedProperty_nothrow( evt.PropertyName ) ) + // A slave handler might fire events for more properties than we support. Ignore those. + return; + + PropertyChangeEvent aTranslatedEvent( evt ); + try + { + aTranslatedEvent.NewValue = getPropertyValue( evt.PropertyName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + m_aPropertyListeners.notifyEach( &XPropertyChangeListener::propertyChange, aTranslatedEvent ); + } + + + void SAL_CALL PropertyComposer::disposing( const EventObject& Source ) + { + MethodGuard aGuard( *this ); + m_aPropertyListeners.disposeAndClear( Source ); + } + + + sal_Bool SAL_CALL PropertyComposer::suspend( sal_Bool _bSuspend ) + { + MethodGuard aGuard( *this ); + for ( PropertyComposer::HandlerArray::const_iterator loop = m_aSlaveHandlers.begin(); + loop != m_aSlaveHandlers.end(); + ++loop + ) + { + if ( !(*loop)->suspend( _bSuspend ) ) + { + if ( _bSuspend && ( loop != m_aSlaveHandlers.begin() ) ) + { + // if we tried to suspend, but one of the slave handlers vetoed, + // re-activate the handlers which actually did *not* veto + // the suspension + do + { + --loop; + (*loop)->suspend( false ); + } + while ( loop != m_aSlaveHandlers.begin() ); + } + return false; + } + } + return true; + } + + + bool PropertyComposer::hasPropertyByName( const OUString& _rName ) + { + return impl_isSupportedProperty_nothrow( _rName ); + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propertycomposer.hxx b/extensions/source/propctrlr/propertycomposer.hxx new file mode 100644 index 000000000..5bcc58e23 --- /dev/null +++ b/extensions/source/propctrlr/propertycomposer.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 . + */ + +#pragma once + +#include "pcrcommon.hxx" +#include "composeduiupdate.hxx" +#include "formbrowsertools.hxx" + +#include +#include +#include +#include + +#include +#include +#include + + +namespace pcr +{ + + + //= PropertyComposer + + typedef ::cppu::WeakComponentImplHelper < css::inspection::XPropertyHandler + , css::beans::XPropertyChangeListener + > PropertyComposer_Base; + /** implements an XPropertyHandler which composes its information + from a set of other property handlers + */ + class PropertyComposer :public ::cppu::BaseMutex + ,public PropertyComposer_Base + ,public IPropertyExistenceCheck + { + public: + typedef std::vector< css::uno::Reference< css::inspection::XPropertyHandler > > + HandlerArray; + + private: + HandlerArray m_aSlaveHandlers; + std::unique_ptr< ComposedPropertyUIUpdate > m_pUIRequestComposer; + PropertyChangeListeners m_aPropertyListeners; + bool m_bSupportedPropertiesAreKnown; + PropertyBag m_aSupportedProperties; + + public: + /** constructs an XPropertyHandler which composes its information from a set + of other property handlers + + @param _rSlaveHandlers + the set of slave handlers to invoke. Must not be + */ + explicit PropertyComposer( std::vector< css::uno::Reference< css::inspection::XPropertyHandler > >&& _rSlaveHandlers ); + + public: + // XPropertyHandler overridables + virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override; + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override; + virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override; + virtual css::beans::PropertyState + SAL_CALL getPropertyState( const OUString& _rPropertyName ) override; + virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual css::uno::Sequence< css::beans::Property > + SAL_CALL getSupportedProperties() override; + virtual css::uno::Sequence< OUString > + SAL_CALL getSupersededProperties( ) override; + virtual css::uno::Sequence< OUString > + SAL_CALL getActuatingProperties( ) override; + virtual css::inspection::LineDescriptor + SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + virtual sal_Bool SAL_CALL isComposable( const OUString& _rPropertyName ) override; + virtual css::inspection::InteractiveSelectionResult + SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override; + virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override; + + // XComponent + DECLARE_XCOMPONENT() + virtual void SAL_CALL disposing() override; + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + // IPropertyExistenceCheck + virtual bool hasPropertyByName( const OUString& _rName ) override; + + private: + /** ensures that m_pUIRequestComposer exists + */ + void impl_ensureUIRequestComposer( const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ); + + /** checks whether a given property exists in m_aSupportedProperties + */ + bool impl_isSupportedProperty_nothrow( const OUString& _rPropertyName ) + { + css::beans::Property aDummy; aDummy.Name = _rPropertyName; + return m_aSupportedProperties.find( aDummy ) != m_aSupportedProperties.end(); + } + + private: + class MethodGuard; + friend class MethodGuard; + class MethodGuard : public ::osl::MutexGuard + { + public: + explicit MethodGuard( PropertyComposer& _rInstance ) + : ::osl::MutexGuard( _rInstance.m_aMutex ) + { + if ( _rInstance.m_aSlaveHandlers.empty() ) + throw css::lang::DisposedException( OUString(), _rInstance ); + } + }; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propertycontrolextender.cxx b/extensions/source/propctrlr/propertycontrolextender.cxx new file mode 100644 index 000000000..142e288dd --- /dev/null +++ b/extensions/source/propctrlr/propertycontrolextender.cxx @@ -0,0 +1,125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "propertycontrolextender.hxx" + +#include + +#include + + +namespace pcr +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Any; + using ::com::sun::star::awt::XWindow; + using ::com::sun::star::awt::KeyEvent; + using ::com::sun::star::inspection::XPropertyControl; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::inspection::XPropertyControlContext; + + namespace KeyFunction = ::com::sun::star::awt::KeyFunction; + + + //= PropertyControlExtender_Data + + struct PropertyControlExtender_Data + { + Reference< XPropertyControl > xControl; + Reference< XWindow > xControlWindow; + }; + + + //= PropertyControlExtender + + + PropertyControlExtender::PropertyControlExtender( const Reference< XPropertyControl >& _rxObservedControl ) + :m_pData( new PropertyControlExtender_Data ) + { + try + { + m_pData->xControl.set( _rxObservedControl, UNO_SET_THROW ); + m_pData->xControlWindow.set( m_pData->xControl->getControlWindow(), UNO_SET_THROW ); + m_pData->xControlWindow->addKeyListener( this ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + PropertyControlExtender::~PropertyControlExtender() + { + } + + + void SAL_CALL PropertyControlExtender::keyPressed( const KeyEvent& _event ) + { + OSL_ENSURE( _event.Source == m_pData->xControlWindow, "PropertyControlExtender::keyPressed: where does this come from?" ); + if ( ( _event.KeyFunc != KeyFunction::DELETE ) + || ( _event.Modifiers != 0 ) + ) + return; + + try + { + Reference< XPropertyControl > xControl( m_pData->xControl, UNO_SET_THROW ); + + // reset the value + xControl->setValue( Any() ); + + // and notify the change + // don't use XPropertyControl::notifyModifiedValue. It only notifies when the control content + // is recognized as being modified by the user, which is not the case, since we just modified + // it programmatically. + Reference< XPropertyControlContext > xControlContext( xControl->getControlContext(), UNO_SET_THROW ); + xControlContext->valueChanged( xControl ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + void SAL_CALL PropertyControlExtender::keyReleased( const KeyEvent& /*_event*/ ) + { + // not interested in + } + + + void SAL_CALL PropertyControlExtender::disposing( const EventObject& Source ) + { + OSL_ENSURE( Source.Source == m_pData->xControlWindow, "PropertyControlExtender::disposing: where does this come from?" ); + (void)Source.Source; + m_pData->xControlWindow.clear(); + m_pData->xControl.clear(); + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propertycontrolextender.hxx b/extensions/source/propctrlr/propertycontrolextender.hxx new file mode 100644 index 000000000..ed7c4a06c --- /dev/null +++ b/extensions/source/propctrlr/propertycontrolextender.hxx @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +#include + +#include + + +namespace pcr +{ + + + //= PropertyControlExtender + + struct PropertyControlExtender_Data; + typedef ::cppu::WeakImplHelper < css::awt::XKeyListener + > PropertyControlExtender_Base; + class PropertyControlExtender : public PropertyControlExtender_Base + { + public: + explicit PropertyControlExtender( + const css::uno::Reference< css::inspection::XPropertyControl >& _rxObservedControl + ); + + // XKeyListener + virtual void SAL_CALL keyPressed( const css::awt::KeyEvent& e ) override; + virtual void SAL_CALL keyReleased( const css::awt::KeyEvent& e ) override; + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + protected: + virtual ~PropertyControlExtender() override; + + private: + std::unique_ptr< PropertyControlExtender_Data > m_pData; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propertyeditor.cxx b/extensions/source/propctrlr/propertyeditor.cxx new file mode 100644 index 000000000..2fcf55649 --- /dev/null +++ b/extensions/source/propctrlr/propertyeditor.cxx @@ -0,0 +1,380 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "handlerhelper.hxx" +#include "propertyeditor.hxx" +#include "browserpage.hxx" +#include "linedescriptor.hxx" + +#include +#include + +namespace pcr +{ + using ::com::sun::star::uno::Any; + using ::com::sun::star::inspection::XPropertyControl; + using ::com::sun::star::uno::Reference; + + OPropertyEditor::OPropertyEditor(const css::uno::Reference& rContext, weld::Builder& rBuilder) + : m_xContainer(rBuilder.weld_container("box")) + , m_xTabControl(rBuilder.weld_notebook("tabcontrol")) + , m_xControlHoldingParent(rBuilder.weld_container("controlparent")) // controls initially have this parent before they are moved + , m_xContext(rContext) + , m_pListener(nullptr) + , m_pObserver(nullptr) + , m_nNextId(1) + , m_bHasHelpSection(false) + { + PropertyHandlerHelper::setBuilderParent(rContext, m_xControlHoldingParent.get()); + + m_xTabControl->connect_leave_page(LINK(this, OPropertyEditor, OnPageDeactivate)); + m_xTabControl->connect_enter_page(LINK(this, OPropertyEditor, OnPageActivate)); + } + + OPropertyEditor::~OPropertyEditor() + { + PropertyHandlerHelper::clearBuilderParent(m_xContext); + ClearAll(); + } + + void OPropertyEditor::ClearAll() + { + m_nNextId=1; + + m_aPropertyPageIds.clear(); + m_aShownPages.clear(); + m_aHiddenPages.clear(); + + int nCount = m_xTabControl->get_n_pages(); + for (int i = nCount - 1; i >= 0; --i) + { + OString sID = m_xTabControl->get_page_ident(i); + m_xTabControl->remove_page(sID); + } + + assert(m_xTabControl->get_n_pages() == 0); + } + + Size OPropertyEditor::get_preferred_size() const + { + return m_xTabControl->get_preferred_size(); + } + + void OPropertyEditor::CommitModified() + { + // commit all of my pages, if necessary + for (const auto& page : m_aShownPages) + { + OBrowserPage* pPage = page.second.xPage.get(); + if (pPage && pPage->getListBox().IsModified() ) + pPage->getListBox().CommitModified(); + } + } + + OBrowserPage* OPropertyEditor::getPage(const OUString& rPropertyName) + { + OBrowserPage* pPage = nullptr; + MapStringToPageId::const_iterator aPropertyPageIdPos = m_aPropertyPageIds.find(rPropertyName); + if (aPropertyPageIdPos != m_aPropertyPageIds.end()) + pPage = getPage(aPropertyPageIdPos->second); + return pPage; + } + + const OBrowserPage* OPropertyEditor::getPage( const OUString& _rPropertyName ) const + { + return const_cast< OPropertyEditor* >( this )->getPage( _rPropertyName ); + } + + OBrowserPage* OPropertyEditor::getPage(sal_uInt16 rPageId) + { + OBrowserPage* pPage = nullptr; + auto aPagePos = m_aShownPages.find(rPageId); + if (aPagePos != m_aShownPages.end()) + pPage = aPagePos->second.xPage.get(); + return pPage; + } + + const OBrowserPage* OPropertyEditor::getPage(sal_uInt16 rPageId) const + { + return const_cast(this)->getPage(rPageId); + } + + sal_uInt16 OPropertyEditor::AppendPage(const OUString& rText, const OString& rHelpId) + { + // obtain a new id + sal_uInt16 nId = m_nNextId++; + // insert the id + OString sIdent = OString::number(nId); + m_xTabControl->append_page(sIdent, rText); + + // create a new page + auto xPage = std::make_unique(m_xTabControl->get_page(sIdent), m_xControlHoldingParent.get()); + // some knittings + xPage->getListBox().SetListener(m_pListener); + xPage->getListBox().SetObserver(m_pObserver); + xPage->getListBox().EnableHelpSection(m_bHasHelpSection); + xPage->SetHelpId(rHelpId); + + m_aShownPages[nId] = PropertyPage(m_xTabControl->get_n_pages() - 1, rText, std::move(xPage)); + + // immediately activate the page + m_xTabControl->set_current_page(sIdent); + + return nId; + } + + void OPropertyEditor::SetHelpId( const OString& rHelpId ) + { + m_xTabControl->set_help_id(rHelpId); + } + + void OPropertyEditor::RemovePage(sal_uInt16 nID) + { + auto aPagePos = m_aShownPages.find(nID); + if (aPagePos == m_aShownPages.end()) + return; + + m_aShownPages.erase(aPagePos); + OString sIdent(OString::number(nID)); + m_xTabControl->remove_page(sIdent); + } + + void OPropertyEditor::SetPage(sal_uInt16 nId) + { + m_xTabControl->set_current_page(OString::number(nId)); + } + + sal_uInt16 OPropertyEditor::GetCurPage() const + { + return m_xTabControl->get_current_page_ident().toUInt32(); + } + + void OPropertyEditor::forEachPage( PageOperation _pOperation ) + { + int nCount = m_xTabControl->get_n_pages(); + for (int i = 0; i < nCount; ++i) + { + sal_uInt16 nID = m_xTabControl->get_page_ident(i).toUInt32(); + OBrowserPage* pPage = getPage(nID); + if (!pPage) + continue; + (this->*_pOperation)( *pPage, nullptr ); + } + } + + void OPropertyEditor::setPageLineListener( OBrowserPage& rPage, const void* ) + { + rPage.getListBox().SetListener( m_pListener ); + } + + void OPropertyEditor::SetLineListener(IPropertyLineListener* pListener) + { + m_pListener = pListener; + forEachPage( &OPropertyEditor::setPageLineListener ); + } + + void OPropertyEditor::setPageControlObserver( OBrowserPage& rPage, const void* ) + { + rPage.getListBox().SetObserver( m_pObserver ); + } + + void OPropertyEditor::SetControlObserver( IPropertyControlObserver* _pObserver ) + { + m_pObserver = _pObserver; + forEachPage( &OPropertyEditor::setPageControlObserver ); + } + + void OPropertyEditor::EnableHelpSection( bool bEnable ) + { + m_bHasHelpSection = bEnable; + forEachPage( &OPropertyEditor::enableHelpSection ); + } + + void OPropertyEditor::SetHelpText( const OUString& rHelpText ) + { + int nCount = m_xTabControl->get_n_pages(); + for (int i = 0; i < nCount; ++i) + { + sal_uInt16 nID = m_xTabControl->get_page_ident(i).toUInt32(); + OBrowserPage* pPage = getPage(nID); + if (!pPage) + continue; + setHelpSectionText( *pPage, &rHelpText ); + } + } + + void OPropertyEditor::enableHelpSection( OBrowserPage& rPage, const void* ) + { + rPage.getListBox().EnableHelpSection( m_bHasHelpSection ); + } + + void OPropertyEditor::setHelpSectionText( OBrowserPage& rPage, const void* pPointerToOUString ) + { + OSL_ENSURE( pPointerToOUString, "OPropertyEditor::setHelpSectionText: invalid argument!" ); + if ( !pPointerToOUString ) + return; + + const OUString& rText( *static_cast(pPointerToOUString) ); + rPage.getListBox().SetHelpText( rText ); + } + + void OPropertyEditor::InsertEntry( const OLineDescriptor& rData, sal_uInt16 nPageId, sal_uInt16 nPos ) + { + // let the current page handle this + OBrowserPage* pPage = getPage(nPageId); + DBG_ASSERT( pPage, "OPropertyEditor::InsertEntry: don't have such a page!" ); + if ( !pPage ) + return; + + pPage->getListBox().InsertEntry( rData, nPos ); + + OSL_ENSURE( m_aPropertyPageIds.find( rData.sName ) == m_aPropertyPageIds.end(), + "OPropertyEditor::InsertEntry: property already present in the map!" ); + m_aPropertyPageIds.emplace( rData.sName, nPageId ); + } + + void OPropertyEditor::RemoveEntry( const OUString& rName ) + { + OBrowserPage* pPage = getPage( rName ); + if ( pPage ) + { + OSL_VERIFY( pPage->getListBox().RemoveEntry( rName ) ); + + OSL_ENSURE( m_aPropertyPageIds.find( rName ) != m_aPropertyPageIds.end(), + "OPropertyEditor::RemoveEntry: property not present in the map!" ); + m_aPropertyPageIds.erase( rName ); + } + } + + void OPropertyEditor::ChangeEntry( const OLineDescriptor& rData ) + { + OBrowserPage* pPage = getPage( rData.sName ); + if ( pPage ) + pPage->getListBox().ChangeEntry( rData, EDITOR_LIST_REPLACE_EXISTING ); + } + + void OPropertyEditor::SetPropertyValue( const OUString& rEntryName, const Any& _rValue, bool _bUnknownValue ) + { + OBrowserPage* pPage = getPage( rEntryName ); + if ( pPage ) + pPage->getListBox().SetPropertyValue( rEntryName, _rValue, _bUnknownValue ); + } + + sal_uInt16 OPropertyEditor::GetPropertyPos( const OUString& rEntryName ) const + { + sal_uInt16 nVal=EDITOR_LIST_ENTRY_NOTFOUND; + const OBrowserPage* pPage = getPage( rEntryName ); + if ( pPage ) + nVal = pPage->getListBox().GetPropertyPos( rEntryName ); + return nVal; + } + + void OPropertyEditor::ShowPropertyPage(sal_uInt16 nPageId, bool bShow) + { + assert((m_aHiddenPages.find(nPageId) != m_aHiddenPages.end() || + m_aShownPages.find(nPageId) != m_aShownPages.end()) && "page doesn't exist"); + OString sIdent(OString::number(nPageId)); + if (!bShow) + { + auto aPagePos = m_aShownPages.find(nPageId); + if (aPagePos != m_aShownPages.end()) + { + aPagePos->second.xPage->detach(); + m_xTabControl->remove_page(sIdent); + + m_aHiddenPages[nPageId] = std::move(aPagePos->second); + m_aShownPages.erase(aPagePos); + } + } + else + { + auto aPagePos = m_aHiddenPages.find(nPageId); + if (aPagePos != m_aHiddenPages.end()) + { + m_xTabControl->insert_page(sIdent, aPagePos->second.sLabel, aPagePos->second.nPos); + aPagePos->second.xPage->reattach(m_xTabControl->get_page(sIdent)); + + m_aShownPages[nPageId] = std::move(aPagePos->second); + m_aHiddenPages.erase(aPagePos); + } + } + } + + void OPropertyEditor::EnablePropertyControls( const OUString& rEntryName, sal_Int16 nControls, bool bEnable ) + { + for (const auto& rPage : m_aShownPages) + { + OBrowserPage* pPage = rPage.second.xPage.get(); + if (pPage) + pPage->getListBox().EnablePropertyControls( rEntryName, nControls, bEnable ); + } + } + + void OPropertyEditor::EnablePropertyLine( const OUString& rEntryName, bool bEnable ) + { + for (const auto& rPage : m_aShownPages) + { + OBrowserPage* pPage = rPage.second.xPage.get(); + if (pPage) + pPage->getListBox().EnablePropertyLine( rEntryName, bEnable ); + } + } + + Reference< XPropertyControl > OPropertyEditor::GetPropertyControl(const OUString& rEntryName) + { + Reference< XPropertyControl > xControl; + // let the current page handle this + OBrowserPage* pPage = getPage(m_xTabControl->get_current_page_ident().toUInt32()); + if (pPage) + xControl = pPage->getListBox().GetPropertyControl(rEntryName); + return xControl; + } + + IMPL_LINK(OPropertyEditor, OnPageActivate, const OString&, rNewPage, void) + { + m_aPageActivationHandler.Call(rNewPage); + } + + IMPL_LINK(OPropertyEditor, OnPageDeactivate, const OString&, rIdent, bool) + { + // commit the data on the current (to-be-deactivated) tab page + // (79404) + OBrowserPage* pCurrentPage = getPage(rIdent.toUInt32()); + if (!pCurrentPage) + return true; + + if (pCurrentPage->getListBox().IsModified()) + pCurrentPage->getListBox().CommitModified(); + + return true; + } + + OPropertyEditor::PropertyPage::PropertyPage() + : nPos(0) + { + } + + OPropertyEditor::PropertyPage::PropertyPage(sal_uInt16 nPagePos, const OUString& rLabel, std::unique_ptr pPage) + : nPos(nPagePos), sLabel(rLabel), xPage(std::move(pPage)) + { + } + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propertyeditor.hxx b/extensions/source/propctrlr/propertyeditor.hxx new file mode 100644 index 000000000..1f28510ab --- /dev/null +++ b/extensions/source/propctrlr/propertyeditor.hxx @@ -0,0 +1,134 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "browserpage.hxx" +#include "pcrcommon.hxx" + +#include +#include +#include +#include + +namespace pcr +{ + class IPropertyLineListener; + class IPropertyControlObserver; + class OBrowserPage; + struct OLineDescriptor; + class OBrowserListBox; + + //= OPropertyEditor + class OPropertyEditor final + { + private: + typedef std::map< OUString, sal_uInt16 > MapStringToPageId; + struct PropertyPage + { + sal_uInt16 nPos; + OUString sLabel; + std::unique_ptr xPage; + PropertyPage(); + PropertyPage(sal_uInt16 nPagePos, const OUString& rLabel, std::unique_ptr pPage); + }; + + std::unique_ptr m_xContainer; + std::unique_ptr m_xTabControl; + // controls initially have this parent before they are moved + std::unique_ptr m_xControlHoldingParent; + css::uno::Reference m_xContext; + IPropertyLineListener* m_pListener; + IPropertyControlObserver* m_pObserver; + sal_uInt16 m_nNextId; + Link m_aPageActivationHandler; + bool m_bHasHelpSection; + + MapStringToPageId m_aPropertyPageIds; + std::map m_aShownPages; + std::map m_aHiddenPages; + + public: + explicit OPropertyEditor(const css::uno::Reference& rContext, weld::Builder& rBuilder); + ~OPropertyEditor(); + + void SetLineListener( IPropertyLineListener* ); + void SetControlObserver( IPropertyControlObserver* ); + + void EnableHelpSection( bool _bEnable ); + bool HasHelpSection() const { return m_bHasHelpSection; } + void SetHelpText( const OUString& _rHelpText ); + + void SetHelpId( const OString& sHelpId ); + sal_uInt16 AppendPage( const OUString& r, const OString& _rHelpId ); + void SetPage( sal_uInt16 ); + void RemovePage(sal_uInt16 nID); + sal_uInt16 GetCurPage() const; + void ClearAll(); + + void SetPropertyValue(const OUString& _rEntryName, const css::uno::Any& _rValue, bool _bUnknownValue ); + sal_uInt16 GetPropertyPos(const OUString& rEntryName ) const; + css::uno::Reference< css::inspection::XPropertyControl > + GetPropertyControl( const OUString& rEntryName ); + void EnablePropertyLine( const OUString& _rEntryName, bool _bEnable ); + void EnablePropertyControls( const OUString& _rEntryName, sal_Int16 _nControls, bool _bEnable ); + + void ShowPropertyPage( sal_uInt16 _nPageId, bool _bShow ); + + void InsertEntry( const OLineDescriptor&, sal_uInt16 _nPageId, sal_uInt16 nPos = EDITOR_LIST_APPEND ); + void RemoveEntry( const OUString& _rName ); + void ChangeEntry( const OLineDescriptor& ); + + void setPageActivationHandler(const Link& _rHdl) { m_aPageActivationHandler = _rHdl; } + + Size get_preferred_size() const; + + weld::Widget* getWidget() const { return m_xTabControl.get(); } + + void Show() { m_xTabControl->show(); } + void Hide() { m_xTabControl->hide(); } + void GrabFocus() { m_xTabControl->grab_focus(); } + + void CommitModified(); + + private: + OBrowserPage* getPage( sal_uInt16 _rPageId ); + const OBrowserPage* getPage( sal_uInt16 _rPageId ) const; + + OBrowserPage* getPage( const OUString& _rPropertyName ); + const OBrowserPage* getPage( const OUString& _rPropertyName ) const; + + typedef void (OPropertyEditor::*PageOperation)( OBrowserPage&, const void* ); + void forEachPage( PageOperation _pOperation ); + + void setPageLineListener( OBrowserPage& _rPage, const void* ); + void setPageControlObserver( OBrowserPage& _rPage, const void* ); + void enableHelpSection( OBrowserPage& _rPage, const void* ); + static void setHelpSectionText( OBrowserPage& _rPage, const void* _pPointerToOUString ); + + DECL_LINK(OnPageDeactivate, const OString&, bool); + DECL_LINK(OnPageActivate, const OString&, void); + }; + + +} // namespace pcr + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propertyhandler.cxx b/extensions/source/propctrlr/propertyhandler.cxx new file mode 100644 index 000000000..53cf29fc6 --- /dev/null +++ b/extensions/source/propctrlr/propertyhandler.cxx @@ -0,0 +1,421 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include "propertyhandler.hxx" +#include "formmetadata.hxx" +#include "formbrowsertools.hxx" +#include "handlerhelper.hxx" +#include "formstrings.hxx" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace pcr +{ + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::frame; + using namespace ::com::sun::star::inspection; + using namespace ::comphelper; + + + PropertyHandler::PropertyHandler( const Reference< XComponentContext >& _rxContext ) + :PropertyHandler_Base( m_aMutex ) + ,m_bSupportedPropertiesAreKnown( false ) + ,m_aPropertyListeners( m_aMutex ) + ,m_xContext( _rxContext ) + ,m_pInfoService ( new OPropertyInfoService ) + { + + m_xTypeConverter = Converter::create(_rxContext); + } + + PropertyHandler::~PropertyHandler() + { + } + + void SAL_CALL PropertyHandler::inspect( const Reference< XInterface >& _rxIntrospectee ) + { + if ( !_rxIntrospectee.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XPropertySet > xNewComponent( _rxIntrospectee, UNO_QUERY ); + if ( xNewComponent == m_xComponent ) + return; + + // remove all old property change listeners + ::comphelper::OInterfaceIteratorHelper3 removeListener(m_aPropertyListeners); + ::comphelper::OInterfaceIteratorHelper3 readdListener(m_aPropertyListeners); // will copy the container as needed + while ( removeListener.hasMoreElements() ) + removePropertyChangeListener( removeListener.next() ); + OSL_ENSURE( m_aPropertyListeners.getLength() == 0, "PropertyHandler::inspect: derived classes are expected to forward the removePropertyChangeListener call to their base class (me)!" ); + + // remember the new component, and give derived classes the chance to react on it + m_xComponent = xNewComponent; + onNewComponent(); + + // add the listeners, again + while ( readdListener.hasMoreElements() ) + addPropertyChangeListener( readdListener.next() ); + } + + void PropertyHandler::onNewComponent() + { + if ( m_xComponent.is() ) + m_xComponentPropertyInfo = m_xComponent->getPropertySetInfo(); + else + m_xComponentPropertyInfo.clear(); + + m_bSupportedPropertiesAreKnown = false; + m_aSupportedProperties.realloc( 0 ); + } + + Sequence< Property > SAL_CALL PropertyHandler::getSupportedProperties() + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !m_bSupportedPropertiesAreKnown ) + { + m_aSupportedProperties = StlSyntaxSequence(doDescribeSupportedProperties()); + m_bSupportedPropertiesAreKnown = true; + } + return m_aSupportedProperties; + } + + Sequence< OUString > SAL_CALL PropertyHandler::getSupersededProperties( ) + { + return Sequence< OUString >(); + } + + Sequence< OUString > SAL_CALL PropertyHandler::getActuatingProperties( ) + { + return Sequence< OUString >(); + } + + Any SAL_CALL PropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId = m_pInfoService->getPropertyId( _rPropertyName ); + Property aProperty( impl_getPropertyFromName_throw( _rPropertyName ) ); + + Any aPropertyValue; + if ( !_rControlValue.hasValue() ) + // NULL is converted to NULL + return aPropertyValue; + + if ( ( m_pInfoService->getPropertyUIFlags( nPropId ) & PROP_FLAG_ENUM ) != 0 ) + { + OUString sControlValue; + OSL_VERIFY( _rControlValue >>= sControlValue ); + ::rtl::Reference< IPropertyEnumRepresentation > aEnumConversion( + new DefaultEnumRepresentation( *m_pInfoService, aProperty.Type, nPropId ) ); + // TODO/UNOize: cache those converters? + aEnumConversion->getValueFromDescription( sControlValue, aPropertyValue ); + } + else + aPropertyValue = PropertyHandlerHelper::convertToPropertyValue( + m_xContext, m_xTypeConverter, aProperty, _rControlValue ); + return aPropertyValue; + } + + Any SAL_CALL PropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId = m_pInfoService->getPropertyId( _rPropertyName ); + + if ( ( m_pInfoService->getPropertyUIFlags( nPropId ) & PROP_FLAG_ENUM ) != 0 ) + { + DBG_ASSERT( _rControlValueType.getTypeClass() == TypeClass_STRING, "PropertyHandler::convertToControlValue: ENUM, but not STRING?" ); + + ::rtl::Reference< IPropertyEnumRepresentation > aEnumConversion( + new DefaultEnumRepresentation( *m_pInfoService, _rPropertyValue.getValueType(), nPropId ) ); + // TODO/UNOize: cache those converters? + return Any( aEnumConversion->getDescriptionForValue( _rPropertyValue ) ); + } + + return PropertyHandlerHelper::convertToControlValue( + m_xContext, m_xTypeConverter, _rPropertyValue, _rControlValueType ); + } + + PropertyState SAL_CALL PropertyHandler::getPropertyState( const OUString& /*_rPropertyName*/ ) + { + return PropertyState_DIRECT_VALUE; + } + + LineDescriptor SAL_CALL PropertyHandler::describePropertyLine( const OUString& _rPropertyName, + const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + if ( !_rxControlFactory.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + const Property& rProperty( impl_getPropertyFromId_throw( nPropId ) ); + + LineDescriptor aDescriptor; + if ( ( m_pInfoService->getPropertyUIFlags( nPropId ) & PROP_FLAG_ENUM ) != 0 ) + { + aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( + _rxControlFactory, m_pInfoService->getPropertyEnumRepresentations( nPropId ), + PropertyHandlerHelper::requiresReadOnlyControl( rProperty.Attributes ), false ); + } + else + PropertyHandlerHelper::describePropertyLine( rProperty, aDescriptor, _rxControlFactory ); + + aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) ); + aDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( nPropId ); + + if ( ( m_pInfoService->getPropertyUIFlags( nPropId ) & PROP_FLAG_DATA_PROPERTY ) != 0 ) + aDescriptor.Category = "Data"; + else + aDescriptor.Category = "General"; + return aDescriptor; + } + + sal_Bool SAL_CALL PropertyHandler::isComposable( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + return m_pInfoService->isComposeable( _rPropertyName ); + } + + InteractiveSelectionResult SAL_CALL PropertyHandler::onInteractivePropertySelection( const OUString& /*_rPropertyName*/, sal_Bool /*_bPrimary*/, Any& /*_rData*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/ ) + { + OSL_FAIL( "PropertyHandler::onInteractivePropertySelection: not implemented!" ); + return InteractiveSelectionResult_Cancelled; + } + + void SAL_CALL PropertyHandler::actuatingPropertyChanged( const OUString& /*_rActuatingPropertyName*/, const Any& /*_rNewValue*/, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& /*_rxInspectorUI*/, sal_Bool /*_bFirstTimeInit*/ ) + { + OSL_FAIL( "PropertyHandler::actuatingPropertyChanged: not implemented!" ); + } + + void SAL_CALL PropertyHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !_rxListener.is() ) + throw NullPointerException(); + m_aPropertyListeners.addInterface( _rxListener ); + } + + void SAL_CALL PropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + m_aPropertyListeners.removeInterface( _rxListener ); + } + + sal_Bool SAL_CALL PropertyHandler::suspend( sal_Bool /*_bSuspend*/ ) + { + return true; + } + + IMPLEMENT_FORWARD_XCOMPONENT( PropertyHandler, PropertyHandler_Base ) + + void SAL_CALL PropertyHandler::disposing() + { + m_xComponent.clear(); + m_aPropertyListeners.clear(); + m_xTypeConverter.clear(); + m_aSupportedProperties.realloc( 0 ); + } + + void PropertyHandler::firePropertyChange( const OUString& _rPropName, PropertyId _nPropId, const Any& _rOldValue, const Any& _rNewValue ) + { + PropertyChangeEvent aEvent; + aEvent.Source = m_xComponent; + aEvent.PropertyHandle = _nPropId; + aEvent.PropertyName = _rPropName; + aEvent.OldValue = _rOldValue; + aEvent.NewValue = _rNewValue; + m_aPropertyListeners.notifyEach( &XPropertyChangeListener::propertyChange, aEvent ); + } + + const Property* PropertyHandler::impl_getPropertyFromId_nothrow( PropertyId _nPropId ) const + { + const_cast< PropertyHandler* >( this )->getSupportedProperties(); + const Property* pFound = std::find_if( m_aSupportedProperties.begin(), m_aSupportedProperties.end(), + FindPropertyByHandle( _nPropId ) + ); + if ( pFound != m_aSupportedProperties.end() ) + return pFound; + return nullptr; + } + + const Property& PropertyHandler::impl_getPropertyFromId_throw( PropertyId _nPropId ) const + { + const Property* pProperty = impl_getPropertyFromId_nothrow( _nPropId ); + if ( !pProperty ) + throw UnknownPropertyException(); + + return *pProperty; + } + + const Property& PropertyHandler::impl_getPropertyFromName_throw( const OUString& _rPropertyName ) const + { + const_cast< PropertyHandler* >( this )->getSupportedProperties(); + StlSyntaxSequence< Property >::const_iterator pFound = std::find_if( m_aSupportedProperties.begin(), m_aSupportedProperties.end(), + FindPropertyByName( _rPropertyName ) + ); + if ( pFound == m_aSupportedProperties.end() ) + throw UnknownPropertyException(_rPropertyName); + + return *pFound; + } + + void PropertyHandler::implAddPropertyDescription( std::vector< Property >& _rProperties, const OUString& _rPropertyName, const Type& _rType, sal_Int16 _nAttribs ) const + { + _rProperties.push_back( Property( + _rPropertyName, + m_pInfoService->getPropertyId( _rPropertyName ), + _rType, + _nAttribs + ) ); + } + + weld::Window* PropertyHandler::impl_getDefaultDialogFrame_nothrow() const + { + return PropertyHandlerHelper::getDialogParentFrame(m_xContext); + } + + PropertyId PropertyHandler::impl_getPropertyId_throwUnknownProperty( const OUString& _rPropertyName ) const + { + PropertyId nPropId = m_pInfoService->getPropertyId( _rPropertyName ); + if ( nPropId == -1 ) + throw UnknownPropertyException(_rPropertyName); + return nPropId; + } + + PropertyId PropertyHandler::impl_getPropertyId_throwRuntime( const OUString& _rPropertyName ) const + { + PropertyId nPropId = m_pInfoService->getPropertyId( _rPropertyName ); + if ( nPropId == -1 ) + throw RuntimeException(); + return nPropId; + } + + PropertyId PropertyHandler::impl_getPropertyId_nothrow( const OUString& _rPropertyName ) const + { + return m_pInfoService->getPropertyId( _rPropertyName ); + } + + void PropertyHandler::impl_setContextDocumentModified_nothrow() const + { + Reference< XModifiable > xModifiable( impl_getContextDocument_nothrow(), UNO_QUERY ); + if ( xModifiable.is() ) + xModifiable->setModified( true ); + } + + bool PropertyHandler::impl_componentHasProperty_throw( const OUString& _rPropName ) const + { + return m_xComponentPropertyInfo.is() && m_xComponentPropertyInfo->hasPropertyByName( _rPropName ); + } + + sal_Int16 PropertyHandler::impl_getDocumentMeasurementUnit_throw() const + { + FieldUnit eUnit = FieldUnit::NONE; + + Reference< XServiceInfo > xDocumentSI( impl_getContextDocument_nothrow(), UNO_QUERY ); + OSL_ENSURE( xDocumentSI.is(), "PropertyHandlerHelper::impl_getDocumentMeasurementUnit_throw: No context document - where do I live?" ); + if ( xDocumentSI.is() ) + { + // determine the application type we live in + OUString sConfigurationLocation; + OUString sConfigurationProperty; + if ( xDocumentSI->supportsService( SERVICE_WEB_DOCUMENT ) ) + { // writer + sConfigurationLocation = "/org.openoffice.Office.WriterWeb/Layout/Other"; + sConfigurationProperty = "MeasureUnit"; + } + else if ( xDocumentSI->supportsService( SERVICE_TEXT_DOCUMENT ) ) + { // writer + sConfigurationLocation = "/org.openoffice.Office.Writer/Layout/Other"; + sConfigurationProperty = "MeasureUnit"; + } + else if ( xDocumentSI->supportsService( SERVICE_SPREADSHEET_DOCUMENT ) ) + { // calc + sConfigurationLocation = "/org.openoffice.Office.Calc/Layout/Other/MeasureUnit"; + sConfigurationProperty = "Metric"; + } + else if ( xDocumentSI->supportsService( SERVICE_DRAWING_DOCUMENT ) ) + { + sConfigurationLocation = "/org.openoffice.Office.Draw/Layout/Other/MeasureUnit"; + sConfigurationProperty = "Metric"; + } + else if ( xDocumentSI->supportsService( SERVICE_PRESENTATION_DOCUMENT ) ) + { + sConfigurationLocation = "/org.openoffice.Office.Impress/Layout/Other/MeasureUnit"; + sConfigurationProperty = "Metric"; + } + + // read the measurement unit from the configuration + if ( !(sConfigurationLocation.isEmpty() || sConfigurationProperty.isEmpty()) ) + { + ::utl::OConfigurationTreeRoot aConfigTree( ::utl::OConfigurationTreeRoot::createWithComponentContext( + m_xContext, sConfigurationLocation, -1, ::utl::OConfigurationTreeRoot::CM_READONLY ) ); + sal_Int32 nUnitAsInt = sal_Int32(FieldUnit::NONE); + aConfigTree.getNodeValue( sConfigurationProperty ) >>= nUnitAsInt; + + // if this denotes a valid (and accepted) unit, then use it + if ( ( nUnitAsInt > sal_Int32(FieldUnit::NONE) ) && ( nUnitAsInt <= sal_Int32(FieldUnit::MM_100TH) ) ) + eUnit = static_cast< FieldUnit >( nUnitAsInt ); + } + } + + if ( FieldUnit::NONE == eUnit ) + { + MeasurementSystem eSystem = SvtSysLocale().GetLocaleData().getMeasurementSystemEnum(); + eUnit = MeasurementSystem::Metric == eSystem ? FieldUnit::CM : FieldUnit::INCH; + } + + return VCLUnoHelper::ConvertToMeasurementUnit( eUnit, 1 ); + } + + PropertyHandlerComponent::PropertyHandlerComponent( const Reference< XComponentContext >& _rxContext ) + :PropertyHandler( _rxContext ) + { + } + + IMPLEMENT_FORWARD_XINTERFACE2( PropertyHandlerComponent, PropertyHandler, PropertyHandlerComponent_Base ) + IMPLEMENT_FORWARD_XTYPEPROVIDER2( PropertyHandlerComponent, PropertyHandler, PropertyHandlerComponent_Base ) + + sal_Bool SAL_CALL PropertyHandlerComponent::supportsService( const OUString& ServiceName ) + { + return cppu::supportsService(this, ServiceName); + } + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propertyhandler.hxx b/extensions/source/propctrlr/propertyhandler.hxx new file mode 100644 index 000000000..3491a89be --- /dev/null +++ b/extensions/source/propctrlr/propertyhandler.hxx @@ -0,0 +1,369 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "pcrcommon.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace com::sun::star { + namespace inspection { + struct LineDescriptor; + class XPropertyControlFactory; + } +} + +namespace weld { class Window; } + +namespace pcr +{ + + + typedef sal_Int32 PropertyId; + + + //= PropertyHandler + + class OPropertyInfoService; + typedef ::cppu::WeakComponentImplHelper < css::inspection::XPropertyHandler + > PropertyHandler_Base; + /** the base class for property handlers + */ + class PropertyHandler : public ::cppu::BaseMutex + , public PropertyHandler_Base + { + private: + /// cache for getSupportedProperties + mutable StlSyntaxSequence< css::beans::Property > + m_aSupportedProperties; + mutable bool m_bSupportedPropertiesAreKnown; + + private: + /// the property listener which has been registered + PropertyChangeListeners m_aPropertyListeners; + + protected: + /// the context in which the instance was created + css::uno::Reference< css::uno::XComponentContext > m_xContext; + /// the component we're inspecting + css::uno::Reference< css::beans::XPropertySet > m_xComponent; + /// info about our component's properties + css::uno::Reference< css::beans::XPropertySetInfo > m_xComponentPropertyInfo; + /// type converter, needed on various occasions + css::uno::Reference< css::script::XTypeConverter > m_xTypeConverter; + /// access to property meta data + std::unique_ptr< OPropertyInfoService > m_pInfoService; + + protected: + explicit PropertyHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + virtual ~PropertyHandler() override; + + // default implementations for XPropertyHandler + virtual void SAL_CALL inspect( const css::uno::Reference< css::uno::XInterface >& _rxIntrospectee ) override; + virtual css::uno::Sequence< css::beans::Property > SAL_CALL getSupportedProperties() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupersededProperties( ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getActuatingProperties( ) override; + virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override; + virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override; + virtual css::beans::PropertyState SAL_CALL getPropertyState( const OUString& _rPropertyName ) override; + virtual css::inspection::LineDescriptor SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + virtual sal_Bool SAL_CALL isComposable( const OUString& _rPropertyName ) override; + virtual css::inspection::InteractiveSelectionResult SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) override; + virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual sal_Bool SAL_CALL suspend( sal_Bool _bSuspend ) override; + + // XComponent + DECLARE_XCOMPONENT() + virtual void SAL_CALL disposing() override; + + // own overridables + virtual css::uno::Sequence< css::beans::Property > + doDescribeSupportedProperties() const = 0; + + /// called when XPropertyHandler::inspect has been called, and we thus have a new component to inspect + virtual void onNewComponent(); + + protected: + /** fires the change in a property value to our listener (if any) + @see addPropertyChangeListener + */ + void firePropertyChange( const OUString& _rPropName, PropertyId _nPropId, + const css::uno::Any& _rOldValue, const css::uno::Any& _rNewValue ); + + /** retrieves a window which can be used as parent for dialogs + */ + weld::Window* impl_getDefaultDialogFrame_nothrow() const; + + /** retrieves the property id for a given property name + @throw css::beans::UnknownPropertyException + if the property name is not known to our ->m_pInfoService + */ + PropertyId impl_getPropertyId_throwUnknownProperty( const OUString& _rPropertyName ) const; + + /** retrieves the property id for a given property name + @throw css::uno::RuntimeException + if the property name is not known to our ->m_pInfoService + */ + PropertyId impl_getPropertyId_throwRuntime( const OUString& _rPropertyName ) const; + + + /** retrieves the property id for a given property name + @returns -1 + if the property name is not known to our ->m_pInfoService + */ + PropertyId impl_getPropertyId_nothrow( const OUString& _rPropertyName ) const; + + // helper for implementing doDescribeSupportedProperties + /** adds a description for the given string property to the given property vector + Most probably to be called from within getSupportedProperties + */ + inline void addStringPropertyDescription( + std::vector< css::beans::Property >& _rProperties, + const OUString& _rPropertyName + ) const; + + /** adds a description for the given int32 property to the given property vector + */ + inline void addInt32PropertyDescription( + std::vector< css::beans::Property >& _rProperties, + const OUString& _rPropertyName, + sal_Int16 _nAttribs = 0 + ) const; + + /** adds a description for the given int16 property to the given property vector + */ + inline void addInt16PropertyDescription( + std::vector< css::beans::Property >& _rProperties, + const OUString& _rPropertyName, + sal_Int16 _nAttribs = 0 + ) const; + + /** adds a description for the given double property to the given property vector + */ + inline void addDoublePropertyDescription( + std::vector< css::beans::Property >& _rProperties, + const OUString& _rPropertyName, + sal_Int16 _nAttribs + ) const; + + /** adds a description for the given date property to the given property vector + */ + inline void addDatePropertyDescription( + std::vector< css::beans::Property >& _rProperties, + const OUString& _rPropertyName, + sal_Int16 _nAttribs + ) const; + + /** adds a description for the given time property to the given property vector + */ + inline void addTimePropertyDescription( + std::vector< css::beans::Property >& _rProperties, + const OUString& _rPropertyName, + sal_Int16 _nAttribs + ) const; + + /** adds a description for the given DateTime property to the given property vector + */ + inline void addDateTimePropertyDescription( + std::vector< css::beans::Property >& _rProperties, + const OUString& _rPropertyName, + sal_Int16 _nAttribs + ) const; + + /// adds a Property, given by name only, to a given vector of Properties + void implAddPropertyDescription( + std::vector< css::beans::Property >& _rProperties, + const OUString& _rPropertyName, + const css::uno::Type& _rType, + sal_Int16 _nAttribs = 0 + ) const; + + + // helper for accessing and maintaining meta data about our supported properties + + /** retrieves a property given by handle + + @return + a pointer to the descriptor for the given properties, if it is one of our + supported properties, else. + + @see doDescribeSupportedProperties + @see impl_getPropertyFromId_throw + */ + const css::beans::Property* + impl_getPropertyFromId_nothrow( PropertyId _nPropId ) const; + + /** retrieves a property given by handle + + @throws UnknownPropertyException + if the handler does not support a property with the given handle + + @seealso doDescribeSupportedProperties + @see impl_getPropertyFromId_nothrow + */ + const css::beans::Property& + impl_getPropertyFromId_throw( PropertyId _nPropId ) const; + + /** determines whether a given property id is part of our supported properties + @see getSupportedProperties + @see doDescribeSupportedProperties + */ + bool impl_isSupportedProperty_nothrow( PropertyId _nPropId ) const + { + return impl_getPropertyFromId_nothrow( _nPropId ) != nullptr; + } + + /** retrieves a property given by name + + @throws UnknownPropertyException + if the handler does not support a property with the given name + + @seealso doDescribeSupportedProperties + */ + const css::beans::Property& + impl_getPropertyFromName_throw( const OUString& _rPropertyName ) const; + + /** get the name of a property given by handle + */ + inline OUString + impl_getPropertyNameFromId_nothrow( PropertyId _nPropId ) const; + + /** returns the value of the ContextDocument property in the ComponentContext which was used to create + this handler. + */ + css::uno::Reference< css::frame::XModel > + impl_getContextDocument_nothrow() const + { + return css::uno::Reference< css::frame::XModel >( + m_xContext->getValueByName( "ContextDocument" ), css::uno::UNO_QUERY ); + } + + /** marks the context document as modified + + @see impl_getContextDocument_nothrow + */ + void impl_setContextDocumentModified_nothrow() const; + + /// determines whether our component has a given property + bool impl_componentHasProperty_throw( const OUString& _rPropName ) const; + + /** determines the default measure unit for the document in which our component lives + */ + sal_Int16 impl_getDocumentMeasurementUnit_throw() const; + + private: + PropertyHandler( const PropertyHandler& ) = delete; + PropertyHandler& operator=( const PropertyHandler& ) = delete; + }; + + + inline void PropertyHandler::addStringPropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName ) const + { + implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType::get() ); + } + + inline void PropertyHandler::addInt32PropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const + { + implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType::get(), _nAttribs ); + } + + inline void PropertyHandler::addInt16PropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const + { + implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType::get(), _nAttribs ); + } + + inline void PropertyHandler::addDoublePropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const + { + implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType::get(), _nAttribs ); + } + + inline void PropertyHandler::addDatePropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const + { + implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType::get(), _nAttribs ); + } + + inline void PropertyHandler::addTimePropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const + { + implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType::get(), _nAttribs ); + } + + inline void PropertyHandler::addDateTimePropertyDescription( std::vector< css::beans::Property >& _rProperties, const OUString& _rPropertyName, sal_Int16 _nAttribs ) const + { + implAddPropertyDescription( _rProperties, _rPropertyName, ::cppu::UnoType::get(), _nAttribs ); + } + + inline OUString PropertyHandler::impl_getPropertyNameFromId_nothrow( PropertyId _nPropId ) const + { + const css::beans::Property* pProp = impl_getPropertyFromId_nothrow( _nPropId ); + return pProp ? pProp->Name : OUString(); + } + + + //= PropertyHandlerComponent + + typedef ::cppu::ImplHelper1 < css::lang::XServiceInfo + > PropertyHandlerComponent_Base; + /** PropertyHandler implementation which additionally supports XServiceInfo + */ + class PropertyHandlerComponent :public PropertyHandler + ,public PropertyHandlerComponent_Base + { + protected: + explicit PropertyHandlerComponent( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + DECLARE_XINTERFACE() + DECLARE_XTYPEPROVIDER() + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName( ) override = 0; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) final override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override = 0; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propertyinfo.hxx b/extensions/source/propctrlr/propertyinfo.hxx new file mode 100644 index 000000000..592557c2a --- /dev/null +++ b/extensions/source/propctrlr/propertyinfo.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + + +namespace pcr +{ + + + //= IPropertyInfoService + + class SAL_NO_VTABLE IPropertyInfoService + { + public: + virtual sal_Int32 getPropertyId(const OUString& _rName) const = 0; + virtual OUString getPropertyTranslation(sal_Int32 _nId) const = 0; + virtual OUString getPropertyHelpId(sal_Int32 _nId) const = 0; + virtual sal_Int16 getPropertyPos(sal_Int32 _nId) const = 0; + virtual sal_uInt32 getPropertyUIFlags(sal_Int32 _nId) const = 0; + virtual std::vector< OUString > getPropertyEnumRepresentations(sal_Int32 _nId) const = 0; + + virtual ~IPropertyInfoService() { } + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propeventtranslation.cxx b/extensions/source/propctrlr/propeventtranslation.cxx new file mode 100644 index 000000000..736c1e06f --- /dev/null +++ b/extensions/source/propctrlr/propeventtranslation.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 "propeventtranslation.hxx" + +#include + + +namespace pcr +{ + + + using ::com::sun::star::beans::PropertyChangeEvent; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::beans::XPropertyChangeListener; + using ::com::sun::star::uno::XInterface; + using ::com::sun::star::lang::DisposedException; + + + //= PropertyEventTranslation + + + PropertyEventTranslation::PropertyEventTranslation( const Reference< XPropertyChangeListener >& _rxDelegator, + const Reference< XInterface >& _rxTranslatedEventSource ) + :m_xDelegator( _rxDelegator ) + ,m_xTranslatedEventSource( _rxTranslatedEventSource ) + { + if ( !m_xDelegator.is() ) + throw RuntimeException(); + } + + + void SAL_CALL PropertyEventTranslation::propertyChange( const PropertyChangeEvent& evt ) + { + if ( !m_xDelegator.is() ) + throw DisposedException(); + + if ( !m_xTranslatedEventSource.is() ) + m_xDelegator->propertyChange( evt ); + else + { + PropertyChangeEvent aTranslatedEvent( evt ); + aTranslatedEvent.Source = m_xTranslatedEventSource; + m_xDelegator->propertyChange( aTranslatedEvent ); + } + } + + + void SAL_CALL PropertyEventTranslation::disposing( const EventObject& Source ) + { + if ( !m_xDelegator.is() ) + throw DisposedException(); + + if ( !m_xTranslatedEventSource.is() ) + m_xDelegator->disposing( Source ); + else + { + EventObject aTranslatedEvent( Source ); + aTranslatedEvent.Source = m_xTranslatedEventSource; + m_xDelegator->disposing( aTranslatedEvent ); + } + + m_xDelegator.clear(); + m_xTranslatedEventSource.clear(); + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/propeventtranslation.hxx b/extensions/source/propctrlr/propeventtranslation.hxx new file mode 100644 index 000000000..43155b8c6 --- /dev/null +++ b/extensions/source/propctrlr/propeventtranslation.hxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + + +namespace pcr +{ + + + //= PropertyEventTranslation + + typedef ::cppu::WeakImplHelper < css::beans::XPropertyChangeListener + > PropertyEventTranslation_Base; + + class PropertyEventTranslation : public PropertyEventTranslation_Base + { + css::uno::Reference< css::beans::XPropertyChangeListener > + m_xDelegator; + css::uno::Reference< css::uno::XInterface > + m_xTranslatedEventSource; + + public: + /** constructs the object + @throws NullPointerException + if _rxDelegator is + */ + PropertyEventTranslation( + const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxDelegator, + const css::uno::Reference< css::uno::XInterface >& _rxTranslatedEventSource + ); + + const css::uno::Reference< css::beans::XPropertyChangeListener >& + getDelegator() const { return m_xDelegator; } + + protected: + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + private: + PropertyEventTranslation( const PropertyEventTranslation& ) = delete; + PropertyEventTranslation& operator=( const PropertyEventTranslation& ) = delete; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/proplinelistener.hxx b/extensions/source/propctrlr/proplinelistener.hxx new file mode 100644 index 000000000..6931a1f33 --- /dev/null +++ b/extensions/source/propctrlr/proplinelistener.hxx @@ -0,0 +1,43 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace pcr +{ + + + class IPropertyLineListener + { + public: + virtual void Clicked( const OUString& _rName, bool _bPrimary ) = 0; + virtual void Commit( const OUString& _rName, const css::uno::Any& _rVal ) = 0; + + protected: + ~IPropertyLineListener() {} + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/pushbuttonnavigation.cxx b/extensions/source/propctrlr/pushbuttonnavigation.cxx new file mode 100644 index 000000000..449ffd583 --- /dev/null +++ b/extensions/source/propctrlr/pushbuttonnavigation.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 "pushbuttonnavigation.hxx" +#include +#include "formstrings.hxx" +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::form; + + + namespace + { + const sal_Int32 s_nFirstVirtualButtonType = 1 + sal_Int32(FormButtonType_URL); + + const char* pNavigationURLs[] = + { + ".uno:FormController/moveToFirst", + ".uno:FormController/moveToPrev", + ".uno:FormController/moveToNext", + ".uno:FormController/moveToLast", + ".uno:FormController/saveRecord", + ".uno:FormController/undoRecord", + ".uno:FormController/moveToNew", + ".uno:FormController/deleteRecord", + ".uno:FormController/refreshForm", + nullptr + }; + + sal_Int32 lcl_getNavigationURLIndex( std::u16string_view _rNavURL ) + { + const char** pLookup = pNavigationURLs; + while ( *pLookup ) + { + if ( o3tl::equalsAscii( _rNavURL, *pLookup ) ) + return pLookup - pNavigationURLs; + ++pLookup; + } + return -1; + } + + const char* lcl_getNavigationURL( sal_Int32 _nButtonTypeIndex ) + { + const char** pLookup = pNavigationURLs; + while ( _nButtonTypeIndex-- && *pLookup++ ) + ; + OSL_ENSURE( *pLookup, "lcl_getNavigationURL: invalid index!" ); + return *pLookup; + } + } + + + //= PushButtonNavigation + + + PushButtonNavigation::PushButtonNavigation( const Reference< XPropertySet >& _rxControlModel ) + :m_xControlModel( _rxControlModel ) + ,m_bIsPushButton( false ) + { + OSL_ENSURE( m_xControlModel.is(), "PushButtonNavigation::PushButtonNavigation: invalid control model!" ); + + try + { + m_bIsPushButton = ::comphelper::hasProperty( PROPERTY_BUTTONTYPE, m_xControlModel ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::PushButtonNavigation" ); + } + } + + + FormButtonType PushButtonNavigation::implGetCurrentButtonType() const + { + sal_Int32 nButtonType = sal_Int32(FormButtonType_PUSH); + if ( !m_xControlModel.is() ) + return static_cast(nButtonType); + OSL_VERIFY( ::cppu::enum2int( nButtonType, m_xControlModel->getPropertyValue( PROPERTY_BUTTONTYPE ) ) ); + + if ( nButtonType == sal_Int32(FormButtonType_URL) ) + { + // there's a chance that this is a "virtual" button type + // (which are realized by special URLs) + OUString sTargetURL; + m_xControlModel->getPropertyValue( PROPERTY_TARGET_URL ) >>= sTargetURL; + + sal_Int32 nNavigationURLIndex = lcl_getNavigationURLIndex( sTargetURL ); + if ( nNavigationURLIndex >= 0) + // it actually *is* a virtual button type + nButtonType = s_nFirstVirtualButtonType + nNavigationURLIndex; + } + return static_cast(nButtonType); + } + + + Any PushButtonNavigation::getCurrentButtonType() const + { + OSL_ENSURE( m_bIsPushButton, "PushButtonNavigation::getCurrentButtonType: not expected to be called for forms!" ); + Any aReturn; + + try + { + aReturn <<= implGetCurrentButtonType(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::getCurrentButtonType" ); + } + return aReturn; + } + + + void PushButtonNavigation::setCurrentButtonType( const Any& _rValue ) const + { + OSL_ENSURE( m_bIsPushButton, "PushButtonNavigation::setCurrentButtonType: not expected to be called for forms!" ); + if ( !m_xControlModel.is() ) + return; + + try + { + sal_Int32 nButtonType = sal_Int32(FormButtonType_PUSH); + OSL_VERIFY( ::cppu::enum2int( nButtonType, _rValue ) ); + OUString sTargetURL; + + bool bIsVirtualButtonType = nButtonType >= s_nFirstVirtualButtonType; + if ( bIsVirtualButtonType ) + { + const char* pURL = lcl_getNavigationURL( nButtonType - s_nFirstVirtualButtonType ); + sTargetURL = OUString::createFromAscii( pURL ); + + nButtonType = sal_Int32(FormButtonType_URL); + } + + m_xControlModel->setPropertyValue( PROPERTY_BUTTONTYPE, Any( static_cast< FormButtonType >( nButtonType ) ) ); + m_xControlModel->setPropertyValue( PROPERTY_TARGET_URL, Any( sTargetURL ) ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::setCurrentButtonType" ); + } + } + + + PropertyState PushButtonNavigation::getCurrentButtonTypeState( ) const + { + OSL_ENSURE( m_bIsPushButton, "PushButtonNavigation::getCurrentButtonTypeState: not expected to be called for forms!" ); + PropertyState eState = PropertyState_DIRECT_VALUE; + + try + { + Reference< XPropertyState > xStateAccess( m_xControlModel, UNO_QUERY ); + if ( xStateAccess.is() ) + { + // let's see what the model says about the ButtonType property + eState = xStateAccess->getPropertyState( PROPERTY_BUTTONTYPE ); + if ( eState == PropertyState_DIRECT_VALUE ) + { + sal_Int32 nRealButtonType = sal_Int32(FormButtonType_PUSH); + OSL_VERIFY( ::cppu::enum2int( nRealButtonType, m_xControlModel->getPropertyValue( PROPERTY_BUTTONTYPE ) ) ); + // perhaps it's one of the virtual button types? + if ( sal_Int32(FormButtonType_URL) == nRealButtonType ) + { + // yes, it is -> rely on the state of the URL property + eState = xStateAccess->getPropertyState( PROPERTY_TARGET_URL ); + } + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::getCurrentButtonTypeState" ); + } + + return eState; + } + + + Any PushButtonNavigation::getCurrentTargetURL() const + { + Any aReturn; + if ( !m_xControlModel.is() ) + return aReturn; + + try + { + aReturn = m_xControlModel->getPropertyValue( PROPERTY_TARGET_URL ); + if ( m_bIsPushButton ) + { + FormButtonType nCurrentButtonType = implGetCurrentButtonType(); + bool bIsVirtualButtonType = nCurrentButtonType >= FormButtonType(s_nFirstVirtualButtonType); + if ( bIsVirtualButtonType ) + { + // pretend (to the user) that there's no URL set - since + // virtual button types imply a special (technical) URL which + // the user should not see + aReturn <<= OUString(); + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::getCurrentTargetURL" ); + } + return aReturn; + } + + + void PushButtonNavigation::setCurrentTargetURL( const Any& _rValue ) const + { + if ( !m_xControlModel.is() ) + return; + + try + { + m_xControlModel->setPropertyValue( PROPERTY_TARGET_URL, _rValue ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::setCurrentTargetURL" ); + } + } + + + PropertyState PushButtonNavigation::getCurrentTargetURLState( ) const + { + PropertyState eState = PropertyState_DIRECT_VALUE; + + try + { + Reference< XPropertyState > xStateAccess( m_xControlModel, UNO_QUERY ); + if ( xStateAccess.is() ) + { + eState = xStateAccess->getPropertyState( PROPERTY_TARGET_URL ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "PushButtonNavigation::setCurrentTargetURL" ); + } + + return eState; + } + + + bool PushButtonNavigation::currentButtonTypeIsOpenURL() const + { + FormButtonType nButtonType( FormButtonType_PUSH ); + try + { + nButtonType = implGetCurrentButtonType(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return nButtonType == FormButtonType_URL; + } + + + bool PushButtonNavigation::hasNonEmptyCurrentTargetURL() const + { + OUString sTargetURL; + OSL_VERIFY( getCurrentTargetURL() >>= sTargetURL ); + return !sTargetURL.isEmpty(); + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/pushbuttonnavigation.hxx b/extensions/source/propctrlr/pushbuttonnavigation.hxx new file mode 100644 index 000000000..7248fb27d --- /dev/null +++ b/extensions/source/propctrlr/pushbuttonnavigation.hxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + + +namespace pcr +{ + + + //= PushButtonNavigation + + class PushButtonNavigation final + { + css::uno::Reference< css::beans::XPropertySet > + m_xControlModel; + bool m_bIsPushButton; + + public: + /** ctor + @param _rxControlModel + the control model which is or will be bound + */ + explicit PushButtonNavigation( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel + ); + + /** returns the current value of the "ButtonType" property, taking into account + the "virtual" button types such as "move-to-next-record button". + */ + css::uno::Any + getCurrentButtonType() const; + + /** sets the current value of the "ButtonType" property, taking into account + the "virtual" button types such as "move-to-next-record button". + */ + void setCurrentButtonType( const css::uno::Any& _rValue ) const; + + /** retrieves the current state of the "ButtonType" property, taking into account + the "virtual" button types such as "move-to-next-record button". + */ + css::beans::PropertyState + getCurrentButtonTypeState( ) const; + + /** returns the current value of the "TargetURL" property, taking into account + that some URLs are special values caused by "virtual" ButtonTypes + */ + css::uno::Any + getCurrentTargetURL() const; + + /** sets the current value of the "TargetURL" property, taking into account + that some URLs are special values caused by "virtual" ButtonTypes + */ + void setCurrentTargetURL( const css::uno::Any& _rValue ) const; + + /** retrieves the current state of the "TargetURL" property, taking into account + that some URLs are special values caused by "virtual" ButtonTypes + */ + css::beans::PropertyState + getCurrentTargetURLState( ) const; + + /** determines whether the current button type is FormButtonType_URL + */ + bool currentButtonTypeIsOpenURL() const; + + /** determines whether the TargetURL property does currently denote a non-empty string + */ + bool hasNonEmptyCurrentTargetURL() const; + + private: + css::form::FormButtonType implGetCurrentButtonType() const; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/selectlabeldialog.cxx b/extensions/source/propctrlr/selectlabeldialog.cxx new file mode 100644 index 000000000..c8c0a82a3 --- /dev/null +++ b/extensions/source/propctrlr/selectlabeldialog.cxx @@ -0,0 +1,279 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "selectlabeldialog.hxx" +#include +#include +#include "formbrowsertools.hxx" +#include "formstrings.hxx" +#include "modulepcr.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::sdbc; + using namespace ::com::sun::star::lang; + + + // OSelectLabelDialog + OSelectLabelDialog::OSelectLabelDialog(weld::Window* pParent, Reference< XPropertySet > const & _xControlModel) + : GenericDialogController(pParent, "modules/spropctrlr/ui/labelselectiondialog.ui", "LabelSelectionDialog") + , m_xControlModel(_xControlModel) + , m_bLastSelected(false) + , m_bHaveAssignableControl(false) + , m_xMainDesc(m_xBuilder->weld_label("label")) + , m_xControlTree(m_xBuilder->weld_tree_view("control")) + , m_xScratchIter(m_xControlTree->make_iterator()) + , m_xNoAssignment(m_xBuilder->weld_check_button("noassignment")) + { + m_xControlTree->connect_changed(LINK(this, OSelectLabelDialog, OnEntrySelected)); + m_xControlTree->set_size_request(-1, m_xControlTree->get_height_rows(8)); + + // fill the description + OUString sDescription = m_xMainDesc->get_label(); + sal_Int16 nClassID = FormComponentType::CONTROL; + if (::comphelper::hasProperty(PROPERTY_CLASSID, m_xControlModel)) + nClassID = ::comphelper::getINT16(m_xControlModel->getPropertyValue(PROPERTY_CLASSID)); + + sDescription = sDescription.replaceAll("$controlclass$", + GetUIHeadlineName(nClassID, Any(m_xControlModel))); + OUString sName = ::comphelper::getString(m_xControlModel->getPropertyValue(PROPERTY_NAME)); + sDescription = sDescription.replaceAll("$controlname$", sName); + m_xMainDesc->set_label(sDescription); + + // search for the root of the form hierarchy + Reference< XChild > xCont(m_xControlModel, UNO_QUERY); + Reference< XInterface > xSearch( xCont.is() ? xCont->getParent() : Reference< XInterface > ()); + Reference< XResultSet > xParentAsResultSet(xSearch, UNO_QUERY); + while (xParentAsResultSet.is()) + { + xCont.set(xSearch, UNO_QUERY); + xSearch = xCont.is() ? xCont->getParent() : Reference< XInterface > (); + xParentAsResultSet.set(xSearch, UNO_QUERY); + } + + // and insert all entries below this root into the listbox + if (xSearch.is()) + { + // check which service the allowed components must support + sal_Int16 nClassId = 0; + try { nClassId = ::comphelper::getINT16(m_xControlModel->getPropertyValue(PROPERTY_CLASSID)); } catch(...) { } + m_sRequiredService = (FormComponentType::RADIOBUTTON == nClassId) ? OUString(SERVICE_COMPONENT_GROUPBOX) : OUString(SERVICE_COMPONENT_FIXEDTEXT); + m_aRequiredControlImage = (FormComponentType::RADIOBUTTON == nClassId) ? OUString(RID_EXTBMP_GROUPBOX) : OUString(RID_EXTBMP_FIXEDTEXT); + + // calc the currently set label control (so InsertEntries can calc m_xInitialSelection) + Any aCurrentLabelControl( m_xControlModel->getPropertyValue(PROPERTY_CONTROLLABEL) ); + DBG_ASSERT((aCurrentLabelControl.getValueTypeClass() == TypeClass_INTERFACE) || !aCurrentLabelControl.hasValue(), + + "OSelectLabelDialog::OSelectLabelDialog : invalid ControlLabel property !"); + if (aCurrentLabelControl.hasValue()) + aCurrentLabelControl >>= m_xInitialLabelControl; + + // insert the root + OUString sRootName(PcrRes(RID_STR_FORMS)); + m_xControlTree->insert(nullptr, -1, &sRootName, nullptr, + nullptr, nullptr, false, m_xScratchIter.get()); + m_xControlTree->set_image(*m_xScratchIter, RID_EXTBMP_FORMS); + + // build the tree + m_xInitialSelection.reset(); + m_bHaveAssignableControl = false; + std::unique_ptr xRoot = m_xControlTree->make_iterator(); + m_xControlTree->get_iter_first(*xRoot); + InsertEntries(xSearch, *xRoot); + m_xControlTree->expand_row(*xRoot); + } + + if (m_xInitialSelection) + { + m_xControlTree->scroll_to_row(*m_xInitialSelection); + m_xControlTree->select(*m_xInitialSelection); + } + else + { + m_xControlTree->scroll_to_row(0); + m_xControlTree->unselect_all(); + m_xNoAssignment->set_active(true); + } + + if (!m_bHaveAssignableControl) + { // no controls which can be assigned + m_xNoAssignment->set_active(true); + m_xNoAssignment->set_sensitive(false); + } + + m_xLastSelected = m_xControlTree->make_iterator(nullptr); + + m_xNoAssignment->connect_toggled(LINK(this, OSelectLabelDialog, OnNoAssignmentClicked)); + OnNoAssignmentClicked(*m_xNoAssignment); + } + + OSelectLabelDialog::~OSelectLabelDialog() + { + } + + sal_Int32 OSelectLabelDialog::InsertEntries(const Reference< XInterface > & _xContainer, const weld::TreeIter& rContainerEntry) + { + Reference< XIndexAccess > xContainer(_xContainer, UNO_QUERY); + if (!xContainer.is()) + return 0; + + sal_Int32 nChildren = 0; + OUString sName; + Reference< XPropertySet > xAsSet; + for (sal_Int32 i=0; igetCount(); ++i) + { + xContainer->getByIndex(i) >>= xAsSet; + if (!xAsSet.is()) + { + SAL_INFO("extensions.propctrlr", "OSelectLabelDialog::InsertEntries : strange : a form component which isn't a property set !"); + continue; + } + + if (!::comphelper::hasProperty(PROPERTY_NAME, xAsSet)) + // we need at least a name for displaying ... + continue; + sName = ::comphelper::getString(xAsSet->getPropertyValue(PROPERTY_NAME)); + + // we need to check if the control model supports the required service + Reference< XServiceInfo > xInfo(xAsSet, UNO_QUERY); + if (!xInfo.is()) + continue; + + if (!xInfo->supportsService(m_sRequiredService)) + { // perhaps it is a container + Reference< XIndexAccess > xCont(xAsSet, UNO_QUERY); + if (xCont.is() && xCont->getCount()) + { // yes -> step down + m_xControlTree->insert(&rContainerEntry, -1, &sName, nullptr, + nullptr, nullptr, false, m_xScratchIter.get()); + m_xControlTree->set_image(*m_xScratchIter, RID_EXTBMP_FORM); + auto xIter = m_xControlTree->make_iterator(&rContainerEntry); + m_xControlTree->iter_nth_child(*xIter, nChildren); + sal_Int32 nContChildren = InsertEntries(xCont, *xIter); + if (nContChildren) + { + m_xControlTree->expand_row(*xIter); + ++nChildren; + } + else + { // oops, no valid children -> remove the entry + m_xControlTree->remove(*xIter); + } + } + continue; + } + + // get the label + if (!::comphelper::hasProperty(PROPERTY_LABEL, xAsSet)) + continue; + + OUString sDisplayName = + ::comphelper::getString(xAsSet->getPropertyValue(PROPERTY_LABEL)) + + " (" + sName + ")"; + + // all requirements met -> insert + m_xUserData.emplace_back(new Reference(xAsSet)); + OUString sId(weld::toId(m_xUserData.back().get())); + m_xControlTree->insert(&rContainerEntry, -1, &sDisplayName, &sId, nullptr, nullptr, false, m_xScratchIter.get()); + m_xControlTree->set_image(*m_xScratchIter, m_aRequiredControlImage); + + if (m_xInitialLabelControl == xAsSet) + { + m_xInitialSelection = m_xControlTree->make_iterator(&rContainerEntry); + m_xControlTree->iter_nth_child(*m_xInitialSelection, nChildren); + } + + ++nChildren; + m_bHaveAssignableControl = true; + } + + return nChildren; + } + + IMPL_LINK(OSelectLabelDialog, OnEntrySelected, weld::TreeView&, rLB, void) + { + DBG_ASSERT(&rLB == m_xControlTree.get(), "OSelectLabelDialog::OnEntrySelected : where did this come from ?"); + std::unique_ptr xIter = m_xControlTree->make_iterator(); + bool bSelected = m_xControlTree->get_selected(xIter.get()); + OUString sData = bSelected ? m_xControlTree->get_id(*xIter) : OUString(); + if (!sData.isEmpty()) + m_xSelectedControl.set(*weld::fromId*>(sData)); + m_xNoAssignment->set_active(sData.isEmpty()); + } + + IMPL_LINK(OSelectLabelDialog, OnNoAssignmentClicked, weld::Toggleable&, rButton, void) + { + DBG_ASSERT(&rButton == m_xNoAssignment.get(), "OSelectLabelDialog::OnNoAssignmentClicked : where did this come from ?"); + + if (m_xNoAssignment->get_active()) + { + m_bLastSelected = m_xControlTree->get_selected(m_xLastSelected.get()); + } + else + { + DBG_ASSERT(m_bHaveAssignableControl, "OSelectLabelDialog::OnNoAssignmentClicked"); + // search the first assignable entry + auto xSearch = m_xControlTree->make_iterator(nullptr); + bool bSearch = m_xControlTree->get_iter_first(*xSearch); + while (bSearch) + { + if (m_xControlTree->get_id(*xSearch).toInt64()) + break; + bSearch = m_xControlTree->iter_next(*xSearch); + } + // and select it + if (bSearch) + { + m_xControlTree->copy_iterator(*xSearch, *m_xLastSelected); + m_xControlTree->select(*m_xLastSelected); + m_bLastSelected = true; + } + } + + if (m_bLastSelected) + { + if (!m_xNoAssignment->get_active()) + m_xControlTree->select(*m_xLastSelected); + else + m_xControlTree->unselect(*m_xLastSelected); + } + } +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/selectlabeldialog.hxx b/extensions/source/propctrlr/selectlabeldialog.hxx new file mode 100644 index 000000000..9affa3512 --- /dev/null +++ b/extensions/source/propctrlr/selectlabeldialog.hxx @@ -0,0 +1,62 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +namespace pcr +{ + // OSelectLabelDialog + class OSelectLabelDialog final : public weld::GenericDialogController + { + css::uno::Reference< css::beans::XPropertySet > m_xControlModel; + OUString m_sRequiredService; + OUString m_aRequiredControlImage; + std::unique_ptr m_xInitialSelection; + // the entry data of the listbox entries + std::vector>> m_xUserData; + css::uno::Reference< css::beans::XPropertySet > m_xInitialLabelControl; + + css::uno::Reference< css::beans::XPropertySet > m_xSelectedControl; + std::unique_ptr m_xLastSelected; + bool m_bLastSelected; + bool m_bHaveAssignableControl; + + std::unique_ptr m_xMainDesc; + std::unique_ptr m_xControlTree; + std::unique_ptr m_xScratchIter; + std::unique_ptr m_xNoAssignment; + + public: + OSelectLabelDialog(weld::Window* pParent, css::uno::Reference< css::beans::XPropertySet > const & _xControlModel); + virtual ~OSelectLabelDialog() override; + + css::uno::Reference< css::beans::XPropertySet > GetSelected() const { return m_xNoAssignment->get_active() ? css::uno::Reference< css::beans::XPropertySet > () : m_xSelectedControl; } + + private: + sal_Int32 InsertEntries(const css::uno::Reference< css::uno::XInterface >& _xContainer, const weld::TreeIter& rContainerEntry); + + DECL_LINK(OnEntrySelected, weld::TreeView&, void); + DECL_LINK(OnNoAssignmentClicked, weld::Toggleable&, void); + }; +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/sqlcommanddesign.cxx b/extensions/source/propctrlr/sqlcommanddesign.cxx new file mode 100644 index 000000000..73e205be4 --- /dev/null +++ b/extensions/source/propctrlr/sqlcommanddesign.cxx @@ -0,0 +1,355 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "sqlcommanddesign.hxx" +#include "formstrings.hxx" +#include +#include "modulepcr.hxx" +#include "unourl.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +namespace pcr +{ + + + using ::com::sun::star::uno::Reference; + using ::com::sun::star::beans::PropertyChangeEvent; + using ::com::sun::star::uno::RuntimeException; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::awt::XTopWindow; + using ::com::sun::star::awt::XWindow; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::lang::XComponent; + using ::com::sun::star::frame::XComponentLoader; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::frame::XTitle; + using ::com::sun::star::lang::EventObject; + using ::com::sun::star::lang::NullPointerException; + using ::com::sun::star::lang::DisposedException; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::frame::XFrames; + using ::com::sun::star::util::XCloseable; + using ::com::sun::star::lang::XMultiServiceFactory; + using ::com::sun::star::frame::XDispatchProvider; + using ::com::sun::star::frame::XDispatch; + using ::com::sun::star::frame::Desktop; + using ::com::sun::star::frame::XDesktop2; + + namespace FrameSearchFlag = ::com::sun::star::frame::FrameSearchFlag; + namespace CommandType = ::com::sun::star::sdb::CommandType; + + + //= ISQLCommandAdapter + + + ISQLCommandAdapter::~ISQLCommandAdapter() + { + } + + + //= SQLCommandDesigner + + + SQLCommandDesigner::SQLCommandDesigner( const Reference< XComponentContext >& _rxContext, + const ::rtl::Reference< ISQLCommandAdapter >& _rxPropertyAdapter, + const ::dbtools::SharedConnection& _rConnection, const Link& _rCloseLink ) + :m_xContext( _rxContext ) + ,m_xConnection( _rConnection ) + ,m_xObjectAdapter( _rxPropertyAdapter ) + ,m_aCloseLink( _rCloseLink ) + { + if ( m_xContext.is() ) + m_xORB = m_xContext->getServiceManager(); + if ( !m_xORB.is() || !_rxPropertyAdapter.is() || !m_xConnection.is() ) + throw NullPointerException(); + + impl_doOpenDesignerFrame_nothrow(); + } + + + SQLCommandDesigner::~SQLCommandDesigner() + { + } + + + void SAL_CALL SQLCommandDesigner::propertyChange( const PropertyChangeEvent& Event ) + { + OSL_ENSURE( m_xDesigner.is() && ( Event.Source == m_xDesigner ), "SQLCommandDesigner::propertyChange: where did this come from?" ); + + if ( !(m_xDesigner.is() && ( Event.Source == m_xDesigner )) ) + return; + + try + { + if ( PROPERTY_ACTIVECOMMAND == Event.PropertyName ) + { + OUString sCommand; + OSL_VERIFY( Event.NewValue >>= sCommand ); + m_xObjectAdapter->setSQLCommand( sCommand ); + } + else if ( PROPERTY_ESCAPE_PROCESSING == Event.PropertyName ) + { + bool bEscapeProcessing( false ); + OSL_VERIFY( Event.NewValue >>= bEscapeProcessing ); + m_xObjectAdapter->setEscapeProcessing( bEscapeProcessing ); + } + } + catch( const RuntimeException& ) { throw; } + catch( const Exception& ) + { + // not allowed to leave, so silence it + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + void SAL_CALL SQLCommandDesigner::disposing( const EventObject& Source ) + { + if ( m_xDesigner.is() && ( Source.Source == m_xDesigner ) ) + { + m_aCloseLink.Call( *this ); + m_xDesigner.clear(); + } + } + + + void SQLCommandDesigner::dispose() + { + if ( impl_isDisposed() ) + return; + + if ( isActive() ) + impl_closeDesigner_nothrow(); + + m_xConnection.clear(); + m_xContext.clear(); + m_xORB.clear(); + } + + + void SQLCommandDesigner::impl_checkDisposed_throw() const + { + if ( impl_isDisposed() ) + throw DisposedException(); + } + + + void SQLCommandDesigner::raise() const + { + impl_checkDisposed_throw(); + impl_raise_nothrow(); + } + + + bool SQLCommandDesigner::suspend() const + { + impl_checkDisposed_throw(); + return impl_trySuspendDesigner_nothrow(); + } + + + void SQLCommandDesigner::impl_raise_nothrow() const + { + OSL_PRECOND( isActive(), "SQLCommandDesigner::impl_raise_nothrow: not active!" ); + if ( !isActive() ) + return; + + try + { + // activate the frame for this component + Reference< XFrame > xFrame( m_xDesigner->getFrame(), css::uno::UNO_SET_THROW ); + Reference< XWindow > xWindow( xFrame->getContainerWindow(), css::uno::UNO_SET_THROW ); + Reference< XTopWindow > xTopWindow( xWindow, UNO_QUERY_THROW ); + + xTopWindow->toFront(); + xWindow->setFocus(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + void SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow() + { + OSL_PRECOND( !isActive(), + "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: already active!" ); + OSL_PRECOND( m_xConnection.is(), "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: this will crash!" ); + osl_atomic_increment(&m_refCount); + + try + { + // for various reasons, we don't want the new frame to appear in the desktop's frame list + // thus, we create a blank frame at the desktop, remove it from the desktop's frame list + // immediately, and then load the component into this blank (and now parent-less) frame + Reference< XComponentLoader > xLoader( impl_createEmptyParentlessTask_nothrow(), UNO_QUERY_THROW ); + const bool bEscapeProcessing = m_xObjectAdapter->getEscapeProcessing(); + Sequence< PropertyValue > aArgs{ + comphelper::makePropertyValue(PROPERTY_ACTIVE_CONNECTION, m_xConnection.getTyped()), + comphelper::makePropertyValue(PROPERTY_COMMAND, m_xObjectAdapter->getSQLCommand()), + comphelper::makePropertyValue(PROPERTY_COMMANDTYPE, CommandType::COMMAND), + comphelper::makePropertyValue(PROPERTY_ESCAPE_PROCESSING, bEscapeProcessing), + comphelper::makePropertyValue("GraphicalDesign", bEscapeProcessing) + }; + + Reference< XComponent > xQueryDesign = xLoader->loadComponentFromURL( + ".component:DB/QueryDesign", + "_self", + FrameSearchFlag::TASKS | FrameSearchFlag::CREATE, + aArgs + ); + + // remember this newly loaded component - we need to care for it e.g. when we're suspended + m_xDesigner.set(xQueryDesign, css::uno::UNO_QUERY); + OSL_ENSURE( m_xDesigner.is() || !xQueryDesign.is(), "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: the component is expected to be a controller!" ); + if ( m_xDesigner.is() ) + { + Reference< XPropertySet > xQueryDesignProps( m_xDesigner, UNO_QUERY ); + OSL_ENSURE( xQueryDesignProps.is(), "SQLCommandDesigner::impl_doOpenDesignerFrame_nothrow: the controller should have properties!" ); + if ( xQueryDesignProps.is() ) + { + xQueryDesignProps->addPropertyChangeListener( PROPERTY_ACTIVECOMMAND, this ); + xQueryDesignProps->addPropertyChangeListener( PROPERTY_ESCAPE_PROCESSING, this ); + } + } + + // get the frame which we just opened and set its title + Reference< XTitle> xTitle(xQueryDesign,UNO_QUERY); + if ( xTitle.is() ) + { + OUString sDisplayName = PcrRes(RID_RSC_ENUM_COMMAND_TYPE[CommandType::COMMAND]); + xTitle->setTitle(sDisplayName); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + m_xDesigner.clear(); + } + osl_atomic_decrement(&m_refCount); + } + + + Reference< XFrame > SQLCommandDesigner::impl_createEmptyParentlessTask_nothrow( ) const + { + OSL_PRECOND( m_xORB.is(), "SQLCommandDesigner::impl_createEmptyParentlessTask_nothrow: this will crash!" ); + + Reference< XFrame > xFrame; + try + { + Reference< XDesktop2 > xDesktop = Desktop::create(m_xContext); + + Reference< XFrames > xDesktopFramesCollection( xDesktop->getFrames(), css::uno::UNO_SET_THROW ); + xFrame = xDesktop->findFrame( "_blank", FrameSearchFlag::CREATE ); + OSL_ENSURE( xFrame.is(), "SQLCommandDesigner::impl_createEmptyParentlessTask_nothrow: could not create an empty frame!" ); + xDesktopFramesCollection->remove( xFrame ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return xFrame; + } + + + void SQLCommandDesigner::impl_closeDesigner_nothrow() + { + OSL_PRECOND( isActive(), "SQLCommandDesigner::impl_closeDesigner_nothrow: invalid call!" ); + // close it + try + { + // do not listen anymore... + Reference< XPropertySet > xProps( m_xDesigner, UNO_QUERY ); + if ( xProps.is() ) + xProps->removePropertyChangeListener( PROPERTY_ACTIVECOMMAND, this ); + + // we need to close the frame via the "user interface", by dispatching a close command, + // instead of calling XCloseable::close directly. The latter method would also close + // the frame, but not care for things like shutting down the office when the last + // frame is gone ... + const UnoURL aCloseURL( ".uno:CloseDoc", + Reference< XMultiServiceFactory >( m_xORB, UNO_QUERY ) ); + + Reference< XDispatchProvider > xProvider( m_xDesigner->getFrame(), UNO_QUERY_THROW ); + Reference< XDispatch > xDispatch( xProvider->queryDispatch( aCloseURL, "_top", FrameSearchFlag::SELF ) ); + OSL_ENSURE( xDispatch.is(), "SQLCommandDesigner::impl_closeDesigner_nothrow: no dispatcher for the CloseDoc command!" ); + if ( xDispatch.is() ) + { + xDispatch->dispatch( aCloseURL, Sequence< PropertyValue >( ) ); + } + else + { + // fallback: use the XCloseable::close (with all possible disadvantages) + Reference< XCloseable > xClose( m_xDesigner->getFrame(), UNO_QUERY ); + if ( xClose.is() ) + xClose->close( true ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + + m_xDesigner.clear(); + } + + + bool SQLCommandDesigner::impl_trySuspendDesigner_nothrow() const + { + OSL_PRECOND( isActive(), "SQLCommandDesigner::impl_trySuspendDesigner_nothrow: no active designer, this will crash!" ); + bool bAllow = true; + try + { + bAllow = m_xDesigner->suspend( true ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + return bAllow; + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/sqlcommanddesign.hxx b/extensions/source/propctrlr/sqlcommanddesign.hxx new file mode 100644 index 000000000..a72ba11b0 --- /dev/null +++ b/extensions/source/propctrlr/sqlcommanddesign.hxx @@ -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 . + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + class ISQLCommandAdapter; + + //= SQLCommandDesigner + + typedef ::cppu::WeakImplHelper < css::beans::XPropertyChangeListener + > SQLCommandDesigner_Base; + /** encapsulates the code for calling and managing a query design frame, used + for interactively designing the Command property of a ->RowSet + */ + class SQLCommandDesigner final : public SQLCommandDesigner_Base + { + private: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + css::uno::Reference< css::lang::XMultiComponentFactory > m_xORB; + ::dbtools::SharedConnection m_xConnection; + css::uno::Reference< css::frame::XController > m_xDesigner; + ::rtl::Reference< ISQLCommandAdapter > m_xObjectAdapter; + Link m_aCloseLink; + + public: + /** creates the instance, and immediately opens the SQL command design frame + + @param _rxContext + our component context. Must not be , and must provide a non- XMultiComponentFactory + @param _rxPropertyAdapter + an adapter to the object's SQL command related properties + @param _rConnection + the current connection of ->_rxRowSet. Must not be . + @param _rCloseLink + link to call when the component has been closed + @throws css::lang::NullPointerException + if any of the arguments (except ->_rCloseLink) is , or if the component context + does not provide a valid component factory. + */ + SQLCommandDesigner( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext, + const ::rtl::Reference< ISQLCommandAdapter >& _rxPropertyAdapter, + const ::dbtools::SharedConnection& _rConnection, + const Link& _rCloseLink + ); + + /** determines whether the SQL Command designer is currently active, i.e. + if there currently exists a frame which allows the user entering the SQL command + */ + bool isActive() const { return m_xDesigner.is(); } + + /** returns the property adapter used by the instance + */ + const ::rtl::Reference< ISQLCommandAdapter >& getPropertyAdapter() const { return m_xObjectAdapter; } + + /** raises the designer window to top + @precond + the designer is active (->isActive) + @precond + the instance is not disposed + */ + void raise() const; + + /** suspends the designer + @precond + the designer is active (->isActive) + @precond + the instance is not disposed + */ + bool suspend() const; + + /** disposes the instance so that it becomes non-functional + */ + void dispose(); + + private: + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override; + + virtual ~SQLCommandDesigner() override; + + /** opens a new frame for interactively designing an SQL command + @precond + the designer is not currently active (see ->isActive) + @precond + ->m_xConnection is not + */ + void impl_doOpenDesignerFrame_nothrow(); + + /** impl-version of ->raise + */ + void impl_raise_nothrow() const; + + /** determines whether we are already disposed + */ + bool impl_isDisposed() const + { + return !m_xContext.is(); + } + /** checks whether we are already disposed + @throws css::lang::DisposedException + if we in fact are disposed + */ + void impl_checkDisposed_throw() const; + + /** create an empty top-level frame, which does not belong to the desktop's frame list + @precond + ->m_xORB is not + */ + css::uno::Reference< css::frame::XFrame > + impl_createEmptyParentlessTask_nothrow() const; + + /** closes the component denoted by m_xDesigner + @precond + our designer component is actually active (->isActive) + @precond + we're not disposed already + */ + void impl_closeDesigner_nothrow(); + + /** suspends our designer component + @precond + the designer component is actually active (->isActive) + @return + if the suspension was successful, if it was vetoed + */ + bool impl_trySuspendDesigner_nothrow() const; + + SQLCommandDesigner( const SQLCommandDesigner& ) = delete; + SQLCommandDesigner& operator=( const SQLCommandDesigner& ) = delete; + }; + + + //= ISQLCommandAdapter + + /** an adapter to forward changed SQL command property values to a component + */ + class ISQLCommandAdapter : public salhelper::SimpleReferenceObject + { + public: + /// retrieves the current SQL command of the component + virtual OUString getSQLCommand() const = 0; + /// retrieves the current value of the EscapeProcessing property of the component + virtual bool getEscapeProcessing() const = 0; + + /// sets a new SQL command + virtual void setSQLCommand( const OUString& _rCommand ) const = 0; + /// sets a new EscapeProcessing property value + virtual void setEscapeProcessing( const bool _bEscapeProcessing ) const = 0; + + virtual ~ISQLCommandAdapter() override; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/standardcontrol.cxx b/extensions/source/propctrlr/standardcontrol.cxx new file mode 100644 index 000000000..95b4143c7 --- /dev/null +++ b/extensions/source/propctrlr/standardcontrol.cxx @@ -0,0 +1,865 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "standardcontrol.hxx" +#include "pcrcommon.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +// ugly dependencies for the OColorControl +#include + +#include +#include +#include + +#include +#include + +namespace pcr +{ + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::inspection; + + //= OTimeControl + OTimeControl::OTimeControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : OTimeControl_Base(PropertyControlType::TimeField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_xFormatter(new weld::TimeFormatter(*getTypedControlWindow())) + { + m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration); + } + + void SAL_CALL OTimeControl::setValue( const Any& _rValue ) + { + util::Time aUNOTime; + if ( !( _rValue >>= aUNOTime ) ) + { + getTypedControlWindow()->set_text(""); + m_xFormatter->SetTime(tools::Time(tools::Time::EMPTY)); + } + else + { + m_xFormatter->SetTime(::tools::Time(aUNOTime)); + } + } + + Any SAL_CALL OTimeControl::getValue() + { + Any aPropValue; + if ( !getTypedControlWindow()->get_text().isEmpty() ) + { + aPropValue <<= m_xFormatter->GetTime().GetUNOTime(); + } + return aPropValue; + } + + Type SAL_CALL OTimeControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + //= ODateControl + ODateControl::ODateControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : ODateControl_Base(PropertyControlType::DateField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_xEntry(m_xBuilder->weld_entry("entry")) + , m_xCalendarBox(std::make_unique(m_xBuilder->weld_menu_button("button"), false)) + { + m_xEntryFormatter.reset(new weld::DateFormatter(*m_xEntry)); + + m_xEntryFormatter->SetStrictFormat(true); + m_xEntryFormatter->SetMin(::Date(1, 1, 1600)); + m_xEntryFormatter->SetMax(::Date(1, 1, 9999)); + + m_xEntryFormatter->SetExtDateFormat(ExtDateFieldFormat::SystemShortYYYY); + m_xEntryFormatter->EnableEmptyField(true); + + m_xCalendarBox->connect_activated(LINK(this, ODateControl, ActivateHdl)); + + m_xCalendarBox->get_button().connect_toggled(LINK(this, ODateControl, ToggleHdl)); + } + + void SAL_CALL ODateControl::disposing() + { + m_xEntryFormatter.reset(); + m_xEntry.reset(); + m_xCalendarBox.reset(); + ODateControl_Base::disposing(); + } + + void SAL_CALL ODateControl::setValue( const Any& _rValue ) + { + util::Date aUNODate; + if ( !( _rValue >>= aUNODate ) ) + { + m_xEntry->set_text(OUString()); + } + else + { + ::Date aDate( aUNODate.Day, aUNODate.Month, aUNODate.Year ); + m_xEntryFormatter->SetDate(aDate); + } + } + + IMPL_LINK_NOARG(ODateControl, ActivateHdl, SvtCalendarBox&, void) + { + m_xEntryFormatter->SetDate(m_xCalendarBox->get_date()); + setModified(); + m_xEntry->grab_focus(); + } + + IMPL_LINK(ODateControl, ToggleHdl, weld::Toggleable&, rToggle, void) + { + if (!rToggle.get_active()) + return; + ::Date aDate = m_xEntryFormatter->GetDate(); + if (aDate.IsEmpty()) + { + // with an empty date preselect today in the calendar + aDate = ::Date(::Date::SYSTEM); + } + m_xCalendarBox->set_date(aDate); + } + + Any SAL_CALL ODateControl::getValue() + { + Any aPropValue; + if (!m_xEntry->get_text().isEmpty()) + { + ::Date aDate(m_xEntryFormatter->GetDate()); + aPropValue <<= aDate.GetUNODate(); + } + return aPropValue; + } + + Type SAL_CALL ODateControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + //= OEditControl + OEditControl::OEditControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bPW, bool bReadOnly) + : OEditControl_Base( bPW ? PropertyControlType::CharacterField : PropertyControlType::TextField, std::move(xBuilder), std::move(xWidget), bReadOnly ) + { + m_bIsPassword = bPW; + + auto pWidget = getTypedControlWindow(); + pWidget->set_sensitive(true); + pWidget->set_editable(!bReadOnly); + + if (m_bIsPassword) + pWidget->set_max_length( 1 ); + } + + void SAL_CALL OEditControl::setValue( const Any& _rValue ) + { + OUString sText; + if ( m_bIsPassword ) + { + sal_Int16 nValue = 0; + _rValue >>= nValue; + if ( nValue ) + { + sText = OUString(static_cast(nValue)); + } + } + else + _rValue >>= sText; + + getTypedControlWindow()->set_text( sText ); + } + + Any SAL_CALL OEditControl::getValue() + { + Any aPropValue; + + OUString sText( getTypedControlWindow()->get_text() ); + if ( m_bIsPassword ) + { + if ( !sText.isEmpty() ) + aPropValue <<= static_cast(sText[0]); + } + else + aPropValue <<= sText; + + return aPropValue; + } + + Type SAL_CALL OEditControl::getValueType() + { + return m_bIsPassword ? ::cppu::UnoType::get() : ::cppu::UnoType::get(); + } + + void OEditControl::setModified() + { + OEditControl_Base::setModified(); + + // for password controls, we fire a commit for every single change + if ( m_bIsPassword ) + notifyModifiedValue(); + } + + static sal_Int64 ImplCalcLongValue( double nValue, sal_uInt16 nDigits ) + { + double n = nValue; + for ( sal_uInt16 d = 0; d < nDigits; ++d ) + n *= 10; + + return o3tl::saturating_cast(n); + } + + static double ImplCalcDoubleValue(sal_Int64 nValue, sal_uInt16 nDigits ) + { + double n = nValue; + for ( sal_uInt16 d = 0; d < nDigits; ++d ) + n /= 10; + return n; + } + + ODateTimeControl::ODateTimeControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : ODateTimeControl_Base(PropertyControlType::DateTimeField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_xDate(std::make_unique(m_xBuilder->weld_menu_button("datefield"))) + , m_xTime(m_xBuilder->weld_formatted_spin_button("timefield")) + , m_xFormatter(new weld::TimeFormatter(*m_xTime)) + { + m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration); + } + + void SAL_CALL ODateTimeControl::setValue( const Any& _rValue ) + { + if ( !_rValue.hasValue() ) + { + m_xDate->set_date(::Date(::Date::SYSTEM)); + m_xTime->set_text(""); + m_xFormatter->SetTime(tools::Time(tools::Time::EMPTY)); + } + else + { + util::DateTime aUNODateTime; + OSL_VERIFY( _rValue >>= aUNODateTime ); + + ::DateTime aDateTime( ::DateTime::EMPTY ); + ::utl::typeConvert( aUNODateTime, aDateTime ); + + m_xDate->set_date(aDateTime); + m_xFormatter->SetTime(aDateTime); + } + } + + Any SAL_CALL ODateTimeControl::getValue() + { + Any aPropValue; + if (!m_xTime->get_text().isEmpty()) + { + ::DateTime aDateTime(m_xDate->get_date(), m_xFormatter->GetTime()); + + util::DateTime aUNODateTime; + ::utl::typeConvert( aDateTime, aUNODateTime ); + + aPropValue <<= aUNODateTime; + } + return aPropValue; + } + + Type SAL_CALL ODateTimeControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + //= OHyperlinkControl + OHyperlinkControl::OHyperlinkControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : OHyperlinkControl_Base(PropertyControlType::HyperlinkField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_xEntry(m_xBuilder->weld_entry("entry")) + , m_xButton(m_xBuilder->weld_button("button")) + , m_aActionListeners(m_aMutex) + { + auto pWidget = getTypedControlWindow(); + pWidget->set_sensitive(true); + m_xEntry->set_editable(!bReadOnly); + + m_xButton->connect_clicked(LINK(this, OHyperlinkControl, OnHyperlinkClicked)); + } + + Any SAL_CALL OHyperlinkControl::getValue() + { + OUString sText = m_xEntry->get_text(); + return Any( sText ); + } + + void SAL_CALL OHyperlinkControl::setValue( const Any& _value ) + { + OUString sText; + _value >>= sText; + m_xEntry->set_text( sText ); + } + + Type SAL_CALL OHyperlinkControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + void SAL_CALL OHyperlinkControl::addActionListener( const Reference< XActionListener >& listener ) + { + if ( listener.is() ) + m_aActionListeners.addInterface( listener ); + } + + void SAL_CALL OHyperlinkControl::removeActionListener( const Reference< XActionListener >& listener ) + { + m_aActionListeners.removeInterface( listener ); + } + + void SAL_CALL OHyperlinkControl::disposing() + { + m_xButton.reset(); + m_xEntry.reset(); + OHyperlinkControl_Base::disposing(); + + EventObject aEvent( *this ); + m_aActionListeners.disposeAndClear( aEvent ); + } + + IMPL_LINK_NOARG( OHyperlinkControl, OnHyperlinkClicked, weld::Button&, void ) + { + ActionEvent aEvent( *this, "clicked" ); + m_aActionListeners.forEach< XActionListener >( + [&aEvent] (uno::Reference const& xListener) + { return xListener->actionPerformed(aEvent); }); + } + + //= ONumericControl + ONumericControl::ONumericControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : ONumericControl_Base(PropertyControlType::NumericField, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_eValueUnit( FieldUnit::NONE ) + , m_nFieldToUNOValueFactor( 1 ) + { + Optional< double > value( getMaxValue() ); + value.Value = -value.Value; + setMinValue( value ); + } + + ::sal_Int16 SAL_CALL ONumericControl::getDecimalDigits() + { + return getTypedControlWindow()->get_digits(); + } + + void SAL_CALL ONumericControl::setDecimalDigits( ::sal_Int16 decimaldigits ) + { + weld::MetricSpinButton* pControlWindow = getTypedControlWindow(); + sal_Int64 min, max; + pControlWindow->get_range(min, max, FieldUnit::NONE); + pControlWindow->set_digits(decimaldigits); + pControlWindow->set_range(min, max, FieldUnit::NONE); + } + + Optional< double > SAL_CALL ONumericControl::getMinValue() + { + Optional< double > aReturn( true, 0 ); + + sal_Int64 minValue = getTypedControlWindow()->get_min(FieldUnit::NONE); + if ( minValue == std::numeric_limits::min() ) + aReturn.IsPresent = false; + else + aReturn.Value = static_cast(minValue); + + return aReturn; + } + + void SAL_CALL ONumericControl::setMinValue( const Optional< double >& _minvalue ) + { + if ( !_minvalue.IsPresent ) + getTypedControlWindow()->set_min( std::numeric_limits::min(), FieldUnit::NONE ); + else + getTypedControlWindow()->set_min( impl_apiValueToFieldValue_nothrow( _minvalue.Value ) , m_eValueUnit); + } + + Optional< double > SAL_CALL ONumericControl::getMaxValue() + { + Optional< double > aReturn( true, 0 ); + + sal_Int64 maxValue = getTypedControlWindow()->get_max(FieldUnit::NONE); + if ( maxValue == std::numeric_limits::max() ) + aReturn.IsPresent = false; + else + aReturn.Value = static_cast(maxValue); + + return aReturn; + } + + void SAL_CALL ONumericControl::setMaxValue( const Optional< double >& _maxvalue ) + { + if ( !_maxvalue.IsPresent ) + getTypedControlWindow()->set_max( std::numeric_limits::max(), FieldUnit::NONE ); + else + getTypedControlWindow()->set_max( impl_apiValueToFieldValue_nothrow( _maxvalue.Value ), m_eValueUnit ); + } + + ::sal_Int16 SAL_CALL ONumericControl::getDisplayUnit() + { + return VCLUnoHelper::ConvertToMeasurementUnit( getTypedControlWindow()->get_unit(), 1 ); + } + + void SAL_CALL ONumericControl::setDisplayUnit( ::sal_Int16 _displayunit ) + { + if ( ( _displayunit < MeasureUnit::MM_100TH ) || ( _displayunit > MeasureUnit::PERCENT ) ) + throw IllegalArgumentException(); + if ( ( _displayunit == MeasureUnit::MM_100TH ) + || ( _displayunit == MeasureUnit::MM_10TH ) + || ( _displayunit == MeasureUnit::INCH_1000TH ) + || ( _displayunit == MeasureUnit::INCH_100TH ) + || ( _displayunit == MeasureUnit::INCH_10TH ) + || ( _displayunit == MeasureUnit::PERCENT ) + ) + throw IllegalArgumentException(); + + sal_Int16 nDummyFactor = 1; + FieldUnit eFieldUnit = VCLUnoHelper::ConvertToFieldUnit( _displayunit, nDummyFactor ); + if ( nDummyFactor != 1 ) + // everything which survived the checks above should result in a factor of 1, i.e., + // it should have a direct counterpart as FieldUnit + throw RuntimeException(); + getTypedControlWindow()->set_unit(eFieldUnit); + } + + ::sal_Int16 SAL_CALL ONumericControl::getValueUnit() + { + return VCLUnoHelper::ConvertToMeasurementUnit( m_eValueUnit, m_nFieldToUNOValueFactor ); + } + + void SAL_CALL ONumericControl::setValueUnit( ::sal_Int16 _valueunit ) + { + if ( ( _valueunit < MeasureUnit::MM_100TH ) || ( _valueunit > MeasureUnit::PERCENT ) ) + throw IllegalArgumentException(); + m_eValueUnit = VCLUnoHelper::ConvertToFieldUnit( _valueunit, m_nFieldToUNOValueFactor ); + } + + void SAL_CALL ONumericControl::setValue( const Any& _rValue ) + { + if ( !_rValue.hasValue() ) + { + getTypedControlWindow()->set_text( "" ); + } + else + { + double nValue( 0 ); + OSL_VERIFY( _rValue >>= nValue ); + auto nControlValue = impl_apiValueToFieldValue_nothrow( nValue ); + getTypedControlWindow()->set_value( nControlValue, m_eValueUnit ); + } + } + + sal_Int64 ONumericControl::impl_apiValueToFieldValue_nothrow( double _nApiValue ) const + { + sal_Int64 nControlValue = ImplCalcLongValue( _nApiValue, getTypedControlWindow()->get_digits() ); + nControlValue /= m_nFieldToUNOValueFactor; + return nControlValue; + } + + double ONumericControl::impl_fieldValueToApiValue_nothrow(sal_Int64 nFieldValue) const + { + double nApiValue = ImplCalcDoubleValue( nFieldValue, getTypedControlWindow()->get_digits() ); + nApiValue *= m_nFieldToUNOValueFactor; + return nApiValue; + } + + Any SAL_CALL ONumericControl::getValue() + { + Any aPropValue; + if ( !getTypedControlWindow()->get_text().isEmpty() ) + { + double nValue = impl_fieldValueToApiValue_nothrow( getTypedControlWindow()->get_value( m_eValueUnit ) ); + aPropValue <<= nValue; + } + return aPropValue; + } + + Type SAL_CALL ONumericControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + //= OColorControl + OColorControl::OColorControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : OColorControl_Base(PropertyControlType::ColorListBox, std::move(xBuilder), std::move(xWidget), bReadOnly) + { + getTypedControlWindow()->SetSlotId(SID_FM_CTL_PROPERTIES); + } + + void SAL_CALL OColorControl::setValue( const Any& _rValue ) + { + css::util::Color nColor = sal_uInt32(COL_TRANSPARENT); + if (_rValue.hasValue()) + _rValue >>= nColor; + getTypedControlWindow()->SelectEntry(::Color(ColorTransparency, nColor)); + } + + Any SAL_CALL OColorControl::getValue() + { + Any aPropValue; + ::Color aRgbCol = getTypedControlWindow()->GetSelectEntryColor(); + if (aRgbCol == COL_TRANSPARENT) + return aPropValue; + aPropValue <<= aRgbCol; + return aPropValue; + } + + Type SAL_CALL OColorControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + void OColorControl::setModified() + { + OColorControl_Base::setModified(); + + // fire a commit + notifyModifiedValue(); + } + + //= OListboxControl + OListboxControl::OListboxControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : OListboxControl_Base(PropertyControlType::ListBox, std::move(xBuilder), std::move(xWidget), bReadOnly) + { + } + + Any SAL_CALL OListboxControl::getValue() + { + OUString sControlValue( getTypedControlWindow()->get_active_text() ); + + Any aPropValue; + if ( !sControlValue.isEmpty() ) + aPropValue <<= sControlValue; + return aPropValue; + } + + Type SAL_CALL OListboxControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + void SAL_CALL OListboxControl::setValue( const Any& _rValue ) + { + if ( !_rValue.hasValue() ) + getTypedControlWindow()->set_active(-1); + else + { + OUString sSelection; + _rValue >>= sSelection; + + if (getTypedControlWindow()->find_text(sSelection) == -1) + getTypedControlWindow()->insert_text(0, sSelection); + + if (sSelection != getTypedControlWindow()->get_active_text()) + getTypedControlWindow()->set_active_text(sSelection); + } + } + + void SAL_CALL OListboxControl::clearList() + { + getTypedControlWindow()->clear(); + } + + void SAL_CALL OListboxControl::prependListEntry( const OUString& NewEntry ) + { + getTypedControlWindow()->insert_text(0, NewEntry); + } + + void SAL_CALL OListboxControl::appendListEntry( const OUString& NewEntry ) + { + getTypedControlWindow()->append_text(NewEntry); + } + + Sequence< OUString > SAL_CALL OListboxControl::getListEntries() + { + const sal_Int32 nCount = getTypedControlWindow()->get_count(); + Sequence< OUString > aRet(nCount); + OUString* pIter = aRet.getArray(); + for (sal_Int32 i = 0; i < nCount ; ++i,++pIter) + *pIter = getTypedControlWindow()->get_text(i); + + return aRet; + } + + void OListboxControl::setModified() + { + OListboxControl_Base::setModified(); + + // fire a commit + notifyModifiedValue(); + } + + //= OComboboxControl + OComboboxControl::OComboboxControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : OComboboxControl_Base(PropertyControlType::ComboBox, std::move(xBuilder), std::move(xWidget), bReadOnly) + { + getTypedControlWindow()->connect_changed( LINK( this, OComboboxControl, OnEntrySelected ) ); + } + + void SAL_CALL OComboboxControl::setValue( const Any& _rValue ) + { + OUString sText; + _rValue >>= sText; + weld::ComboBox* pControlWindow = getTypedControlWindow(); + // tdf#138701 leave current cursor valid if the contents won't change + if (pControlWindow->get_active_text() != sText) + pControlWindow->set_entry_text(sText); + } + + Any SAL_CALL OComboboxControl::getValue() + { + return Any( getTypedControlWindow()->get_active_text() ); + } + + Type SAL_CALL OComboboxControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + void SAL_CALL OComboboxControl::clearList() + { + getTypedControlWindow()->clear(); + } + + void SAL_CALL OComboboxControl::prependListEntry( const OUString& NewEntry ) + { + getTypedControlWindow()->insert_text(0, NewEntry); + } + + void SAL_CALL OComboboxControl::appendListEntry( const OUString& NewEntry ) + { + getTypedControlWindow()->append_text( NewEntry ); + } + + Sequence< OUString > SAL_CALL OComboboxControl::getListEntries( ) + { + const sal_Int32 nCount = getTypedControlWindow()->get_count(); + Sequence< OUString > aRet(nCount); + OUString* pIter = aRet.getArray(); + for (sal_Int32 i = 0; i < nCount ; ++i,++pIter) + *pIter = getTypedControlWindow()->get_text(i); + + return aRet; + } + + IMPL_LINK_NOARG( OComboboxControl, OnEntrySelected, weld::ComboBox&, void ) + { + // fire a commit + notifyModifiedValue(); + } + + namespace + { + + StlSyntaxSequence< OUString > lcl_convertMultiLineToList( std::u16string_view _rCompsedTextWithLineBreaks ) + { + sal_Int32 nLines = comphelper::string::getTokenCount(_rCompsedTextWithLineBreaks, '\n'); + StlSyntaxSequence< OUString > aStrings( nLines ); + if (nLines) + { + StlSyntaxSequence< OUString >::iterator stringItem = aStrings.begin(); + sal_Int32 nIdx {0}; + do + { + *stringItem = o3tl::getToken(_rCompsedTextWithLineBreaks, 0, '\n', nIdx ); + ++stringItem; + } + while (nIdx>0); + } + return aStrings; + } + + OUString lcl_convertListToMultiLine( const StlSyntaxSequence< OUString >& _rStrings ) + { + OUStringBuffer sMultiLineText; + for ( StlSyntaxSequence< OUString >::const_iterator item = _rStrings.begin(); + item != _rStrings.end(); + ) + { + sMultiLineText.append(*item); + if ( ++item != _rStrings.end() ) + sMultiLineText.append("\n"); + } + return sMultiLineText.makeStringAndClear(); + } + + + OUString lcl_convertListToDisplayText( const StlSyntaxSequence< OUString >& _rStrings ) + { + OUStringBuffer aComposed; + for ( StlSyntaxSequence< OUString >::const_iterator strings = _rStrings.begin(); + strings != _rStrings.end(); + ++strings + ) + { + if ( strings != _rStrings.begin() ) + aComposed.append( ';' ); + aComposed.append( '\"' ); + aComposed.append( *strings ); + aComposed.append( '\"' ); + } + return aComposed.makeStringAndClear(); + } + } + + void OMultilineEditControl::CheckEntryTextViewMisMatch() + { + // if there are newlines or something else which the entry cannot show, then make + // just the multiline dropdown editable as the canonical source for text + m_xEntry->set_sensitive(m_xEntry->get_text() == m_xTextView->get_text()); + } + + void OMultilineEditControl::SetStringListValue(const StlSyntaxSequence& rStrings) + { + m_xEntry->set_text(lcl_convertListToDisplayText(rStrings)); + m_xTextView->set_text(lcl_convertListToMultiLine(rStrings)); + CheckEntryTextViewMisMatch(); + } + + StlSyntaxSequence OMultilineEditControl::GetStringListValue() const + { + return lcl_convertMultiLineToList(m_xTextView->get_text()); + } + + void OMultilineEditControl::SetTextValue(const OUString& rText) + { + OSL_PRECOND( m_nOperationMode == eMultiLineText, "OMultilineEditControl::SetTextValue: illegal call!" ); + + m_xTextView->set_text(rText); + m_xEntry->set_text(rText); + CheckEntryTextViewMisMatch(); + } + + OUString OMultilineEditControl::GetTextValue() const + { + OSL_PRECOND( m_nOperationMode == eMultiLineText, "OMultilineEditControl::GetTextValue: illegal call!" ); + return m_xTextView->get_text(); + } + + //= OMultilineEditControl + OMultilineEditControl::OMultilineEditControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, MultiLineOperationMode eMode, bool bReadOnly) + : OMultilineEditControl_Base(eMode == eMultiLineText ? PropertyControlType::MultiLineTextField : PropertyControlType::StringListField, + std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_nOperationMode(eMode) + , m_xEntry(m_xBuilder->weld_entry("entry")) + , m_xButton(m_xBuilder->weld_menu_button("button")) + , m_xPopover(m_xBuilder->weld_widget("popover")) + , m_xTextView(m_xBuilder->weld_text_view("textview")) + , m_xOk(m_xBuilder->weld_button("ok")) + { + m_xButton->set_popover(m_xPopover.get()); + m_xTextView->set_size_request(m_xTextView->get_approximate_digit_width() * 30, m_xTextView->get_height_rows(8)); + m_xOk->connect_clicked(LINK(this, OMultilineEditControl, ButtonHandler)); + } + + IMPL_LINK_NOARG(OMultilineEditControl, TextViewModifiedHdl, weld::TextView&, void) + { + // tdf#139070 during editing update the entry to look like how it will + // look once editing is finished so that the default behaviour of vcl + // to strip newlines and the default behaviour of gtk to show a newline + // symbol is suppressed + OUString sText = m_xTextView->get_text(); + auto aSeq = lcl_convertMultiLineToList(sText); + if (aSeq.getLength() > 1) + m_xEntry->set_text(lcl_convertListToDisplayText(aSeq)); + else + m_xEntry->set_text(sText); + CheckEntryTextViewMisMatch(); + setModified(); + } + + void OMultilineEditControl::editChanged() + { + m_xTextView->set_text(m_xEntry->get_text()); + CheckEntryTextViewMisMatch(); + setModified(); + } + + IMPL_LINK_NOARG(OMultilineEditControl, ButtonHandler, weld::Button&, void) + { + m_xButton->set_active(false); + notifyModifiedValue(); + } + + void SAL_CALL OMultilineEditControl::setValue( const Any& _rValue ) + { + impl_checkDisposed_throw(); + + switch (m_nOperationMode) + { + case eMultiLineText: + { + OUString sText; + if ( !( _rValue >>= sText ) && _rValue.hasValue() ) + throw IllegalTypeException(); + SetTextValue(sText); + break; + } + case eStringList: + { + Sequence< OUString > aStringLines; + if ( !( _rValue >>= aStringLines ) && _rValue.hasValue() ) + throw IllegalTypeException(); + SetStringListValue( StlSyntaxSequence(aStringLines) ); + break; + } + } + } + + Any SAL_CALL OMultilineEditControl::getValue() + { + impl_checkDisposed_throw(); + + Any aValue; + switch (m_nOperationMode) + { + case eMultiLineText: + aValue <<= GetTextValue(); + break; + case eStringList: + aValue <<= GetStringListValue(); + break; + } + return aValue; + } + + Type SAL_CALL OMultilineEditControl::getValueType() + { + if (m_nOperationMode == eMultiLineText) + return ::cppu::UnoType::get(); + return cppu::UnoType>::get(); + } + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/standardcontrol.hxx b/extensions/source/propctrlr/standardcontrol.hxx new file mode 100644 index 000000000..fcd194886 --- /dev/null +++ b/extensions/source/propctrlr/standardcontrol.hxx @@ -0,0 +1,412 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "commoncontrol.hxx" +#include "pcrcommon.hxx" + +#include +#include +#include +#include +#include +#include +#include + +namespace pcr +{ + //= OTimeControl + typedef CommonBehaviourControl OTimeControl_Base; + class OTimeControl : public OTimeControl_Base + { + std::unique_ptr m_xFormatter; + public: + OTimeControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + virtual void SAL_CALL disposing() override + { + m_xFormatter.reset(); + OTimeControl_Base::disposing(); + } + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + virtual void SetModifyHandler() override + { + OTimeControl_Base::SetModifyHandler(); + getTypedControlWindow()->connect_value_changed( LINK( this, CommonBehaviourControlHelper, TimeModifiedHdl ) ); + } + + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + }; + + //= ODateControl + typedef CommonBehaviourControl ODateControl_Base; + class ODateControl : public ODateControl_Base + { + std::unique_ptr m_xEntry; + std::unique_ptr m_xCalendarBox; + std::unique_ptr m_xEntryFormatter; + + DECL_LINK(ActivateHdl, SvtCalendarBox&, void); + DECL_LINK(ToggleHdl, weld::Toggleable&, void); + + public: + ODateControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + virtual void SetModifyHandler() override + { + ODateControl_Base::SetModifyHandler(); + + m_xEntry->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xEntryFormatter->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + m_xCalendarBox->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xCalendarBox->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + + m_xEntryFormatter->connect_changed(LINK(this, CommonBehaviourControlHelper, EditModifiedHdl)); + } + + virtual void SAL_CALL disposing() override; + + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + }; + + //= OEditControl + typedef CommonBehaviourControl OEditControl_Base; + class OEditControl final : public OEditControl_Base + { + bool m_bIsPassword : 1; + + public: + OEditControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bPassWord, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + virtual void SetModifyHandler() override + { + OEditControl_Base::SetModifyHandler(); + getTypedControlWindow()->connect_changed( LINK( this, CommonBehaviourControlHelper, EditModifiedHdl ) ); + } + + private: + // CommonBehaviourControlHelper::modified + virtual void setModified() override; + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + }; + + //= ODateTimeControl + typedef CommonBehaviourControl ODateTimeControl_Base; + class ODateTimeControl : public ODateTimeControl_Base + { + private: + std::unique_ptr m_xDate; + std::unique_ptr m_xTime; + std::unique_ptr m_xFormatter; + + public: + ODateTimeControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + virtual void SetModifyHandler() override + { + m_xDate->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xDate->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + m_xTime->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xTime->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + + m_xDate->connect_selected( LINK( this, CommonBehaviourControlHelper, DateModifiedHdl ) ); + m_xTime->connect_value_changed( LINK( this, CommonBehaviourControlHelper, TimeModifiedHdl ) ); + } + + virtual void SAL_CALL disposing() override + { + m_xFormatter.reset(); + m_xTime.reset(); + m_xDate.reset(); + ODateTimeControl_Base::disposing(); + } + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + }; + + //= OHyperlinkControl + typedef CommonBehaviourControl OHyperlinkControl_Base; + class OHyperlinkControl final : public OHyperlinkControl_Base + { + private: + std::unique_ptr m_xEntry; + std::unique_ptr m_xButton; + + ::comphelper::OInterfaceContainerHelper2 m_aActionListeners; + + public: + OHyperlinkControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + virtual void SetModifyHandler() override + { + m_xEntry->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xEntry->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + m_xButton->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xButton->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + + m_xEntry->connect_changed( LINK( this, CommonBehaviourControlHelper, EditModifiedHdl ) ); + } + + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + + // XHyperlinkControl + virtual void SAL_CALL addActionListener( const css::uno::Reference< css::awt::XActionListener >& listener ) override; + virtual void SAL_CALL removeActionListener( const css::uno::Reference< css::awt::XActionListener >& listener ) override; + + private: + // XComponent + virtual void SAL_CALL disposing() override; + + DECL_LINK(OnHyperlinkClicked, weld::Button&, void); + }; + + //= ONumericControl + typedef CommonBehaviourControl ONumericControl_Base; + class ONumericControl : public ONumericControl_Base + { + private: + FieldUnit m_eValueUnit; + sal_Int16 m_nFieldToUNOValueFactor; + + public: + ONumericControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + // XNumericControl + virtual ::sal_Int16 SAL_CALL getDecimalDigits() override; + virtual void SAL_CALL setDecimalDigits( ::sal_Int16 _decimaldigits ) override; + virtual css::beans::Optional< double > SAL_CALL getMinValue() override; + virtual void SAL_CALL setMinValue( const css::beans::Optional< double >& _minvalue ) override; + virtual css::beans::Optional< double > SAL_CALL getMaxValue() override; + virtual void SAL_CALL setMaxValue( const css::beans::Optional< double >& _maxvalue ) override; + virtual ::sal_Int16 SAL_CALL getDisplayUnit() override; + virtual void SAL_CALL setDisplayUnit( ::sal_Int16 _displayunit ) override; + virtual ::sal_Int16 SAL_CALL getValueUnit() override; + virtual void SAL_CALL setValueUnit( ::sal_Int16 _valueunit ) override; + + virtual void SetModifyHandler() override + { + ONumericControl_Base::SetModifyHandler(); + weld::MetricSpinButton* pSpinButton = getTypedControlWindow(); + pSpinButton->connect_value_changed( LINK( this, CommonBehaviourControlHelper, MetricModifiedHdl ) ); + pSpinButton->get_widget().connect_changed( LINK( this, CommonBehaviourControlHelper, EditModifiedHdl ) ); + } + + private: + virtual weld::Widget* getWidget() override { return &getTypedControlWindow()->get_widget(); } + + /** converts an API value (double, as passed into set[Max|Min|]Value) into + a int value which can be passed to our NumericField. + + The conversion respects our decimal digits as well as our value factor (m_nFieldToUNOValueFactor). + */ + sal_Int64 impl_apiValueToFieldValue_nothrow( double nApiValue ) const; + + /** converts a control value, as obtained from our Numeric field, into a value which can passed + to outer callers via our UNO API. + */ + double impl_fieldValueToApiValue_nothrow(sal_Int64 nFieldValue) const; + }; + + //= OColorControl + typedef CommonBehaviourControl OColorControl_Base; + class OColorControl : public OColorControl_Base + { + public: + OColorControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + virtual void SetModifyHandler() override + { + OColorControl_Base::SetModifyHandler(); + getTypedControlWindow()->SetSelectHdl(LINK(this, CommonBehaviourControlHelper, ColorModifiedHdl)); + } + + protected: + // CommonBehaviourControlHelper::setModified + virtual void setModified() override; + + private: + virtual weld::Widget* getWidget() override { return &getTypedControlWindow()->get_widget(); } + }; + + //= OListboxControl + typedef CommonBehaviourControl OListboxControl_Base; + class OListboxControl : public OListboxControl_Base + { + public: + OListboxControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + // XStringListControl + virtual void SAL_CALL clearList( ) override; + virtual void SAL_CALL prependListEntry( const OUString& NewEntry ) override; + virtual void SAL_CALL appendListEntry( const OUString& NewEntry ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getListEntries( ) override; + + virtual void SetModifyHandler() override + { + OListboxControl_Base::SetModifyHandler(); + getTypedControlWindow()->connect_changed(LINK(this, CommonBehaviourControlHelper, ModifiedHdl)); + } + + protected: + // CommonBehaviourControlHelper::setModified + virtual void setModified() override; + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + }; + + //= OComboboxControl + typedef CommonBehaviourControl< css::inspection::XStringListControl, weld::ComboBox > OComboboxControl_Base; + class OComboboxControl final : public OComboboxControl_Base + { + public: + OComboboxControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + // XStringListControl + virtual void SAL_CALL clearList( ) override; + virtual void SAL_CALL prependListEntry( const OUString& NewEntry ) override; + virtual void SAL_CALL appendListEntry( const OUString& NewEntry ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getListEntries( ) override; + + virtual void SetModifyHandler() override + { + OComboboxControl_Base::SetModifyHandler(); + getTypedControlWindow()->connect_changed(LINK(this, CommonBehaviourControlHelper, ModifiedHdl)); + } + + // CommonBehaviourControlHelper::setModified + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + + private: + DECL_LINK( OnEntrySelected, weld::ComboBox&, void ); + }; + + + //= DropDownEditControl + + enum MultiLineOperationMode + { + eStringList, + eMultiLineText + }; + + //= OMultilineEditControl + typedef CommonBehaviourControl OMultilineEditControl_Base; + class OMultilineEditControl : public OMultilineEditControl_Base + { + private: + MultiLineOperationMode m_nOperationMode; + std::unique_ptr m_xEntry; + std::unique_ptr m_xButton; + std::unique_ptr m_xPopover; + std::unique_ptr m_xTextView; + std::unique_ptr m_xOk; + + void SetTextValue(const OUString& rText); + OUString GetTextValue() const; + + void SetStringListValue( const StlSyntaxSequence< OUString >& _rStrings ); + StlSyntaxSequence< OUString > + GetStringListValue() const; + + DECL_LINK(ButtonHandler, weld::Button&, void); + DECL_LINK(TextViewModifiedHdl, weld::TextView&, void); + + void CheckEntryTextViewMisMatch(); + + public: + OMultilineEditControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, MultiLineOperationMode eMode, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + + virtual void editChanged() override; + + virtual void SetModifyHandler() override + { + m_xEntry->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xEntry->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + m_xButton->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xButton->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + + m_xEntry->connect_changed( LINK( this, CommonBehaviourControlHelper, EditModifiedHdl ) ); + m_xTextView->connect_changed( LINK( this, OMultilineEditControl, TextViewModifiedHdl ) ); + } + + virtual void SAL_CALL disposing() override + { + m_xOk.reset(); + m_xTextView.reset(); + m_xButton.reset(); + m_xEntry.reset(); + OMultilineEditControl_Base::disposing(); + } + + }; + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/stringrepresentation.cxx b/extensions/source/propctrlr/stringrepresentation.cxx new file mode 100644 index 000000000..143ab1363 --- /dev/null +++ b/extensions/source/propctrlr/stringrepresentation.cxx @@ -0,0 +1,604 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "modulepcr.hxx" + +#include + +namespace pcr{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace { + +class StringRepresentation: + public ::cppu::WeakImplHelper< + lang::XServiceInfo, + inspection::XStringRepresentation, + lang::XInitialization> +{ +public: + explicit StringRepresentation(uno::Reference< uno::XComponentContext > const & context); + StringRepresentation (const StringRepresentation&) = delete; + StringRepresentation& operator=(const StringRepresentation&) = delete; + + // lang::XServiceInfo: + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString & ServiceName) override; + virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // inspection::XStringRepresentation: + virtual OUString SAL_CALL convertToControlValue(const uno::Any & PropertyValue) override; + virtual uno::Any SAL_CALL convertToPropertyValue(const OUString & ControlValue, const uno::Type & ControlValueType) override; + + // lang::XInitialization: + virtual void SAL_CALL initialize(const uno::Sequence< uno::Any > & aArguments) override; + +private: + virtual ~StringRepresentation() override {} + + /** converts a generic value into a string representation + + If you want to convert values whose string representation does not depend + on a concrete property, use this version + + @return + if and only if the value could be converted + */ + static bool convertGenericValueToString( + const uno::Any& _rValue, + OUString& _rStringRep + ); + + /** converts string representation into generic value + + If you want to convert values whose string representation does not depend + on a concrete property, use this version + + @return + if and only if the value could be converted + */ + static bool convertStringToGenericValue( + const OUString& _rStringRep, + uno::Any& _rValue, + const uno::Type& _rTargetType + ); + + /** uses the simple convert method from the type converter + * + * \param _rValue the value to be converted + * \return the converted string. + */ + OUString convertSimpleToString( const uno::Any& _rValue ); + + /** converts a string into his constant value if it exists, otherwise the type converter is used. + * \param _rValue the value to be converted + * \param _ePropertyType the type of the property to be converted into + * \return the converted value + */ + uno::Any convertStringToSimple( const OUString& _rValue,const uno::TypeClass& _ePropertyType ); + + uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< script::XTypeConverter > m_xTypeConverter; + uno::Reference< reflection::XConstantsTypeDescription > m_xTypeDescription; + uno::Sequence< OUString > m_aValues; + uno::Sequence< uno::Reference< reflection::XConstantTypeDescription> > m_aConstants; + +}; + +} + +StringRepresentation::StringRepresentation(uno::Reference< uno::XComponentContext > const & context) : + m_xContext(context) +{} + +// com.sun.star.uno.XServiceInfo: +OUString SAL_CALL StringRepresentation::getImplementationName() +{ + return "StringRepresentation"; +} + +sal_Bool SAL_CALL StringRepresentation::supportsService(OUString const & serviceName) +{ + return cppu::supportsService(this, serviceName); +} + +uno::Sequence< OUString > SAL_CALL StringRepresentation::getSupportedServiceNames() +{ + return { "com.sun.star.inspection.StringRepresentation" }; +} + +// inspection::XStringRepresentation: +OUString SAL_CALL StringRepresentation::convertToControlValue(const uno::Any & PropertyValue) +{ + OUString sReturn; + if ( !convertGenericValueToString( PropertyValue, sReturn ) ) + { + sReturn = convertSimpleToString( PropertyValue ); +#ifdef DBG_UTIL + if ( sReturn.isEmpty() && PropertyValue.hasValue() ) + { + SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertPropertyValueToStringRepresentation: cannot convert values of type '" + << PropertyValue.getValueType().getTypeName() + << "'!" ); + } +#endif + } + + return sReturn; +} + +uno::Any SAL_CALL StringRepresentation::convertToPropertyValue(const OUString & ControlValue, const uno::Type & ControlValueType) +{ + uno::Any aReturn; + + uno::TypeClass ePropertyType = ControlValueType.getTypeClass(); + switch ( ePropertyType ) + { + case uno::TypeClass_FLOAT: + case uno::TypeClass_DOUBLE: + case uno::TypeClass_BYTE: + case uno::TypeClass_SHORT: + case uno::TypeClass_LONG: + case uno::TypeClass_HYPER: + case uno::TypeClass_UNSIGNED_SHORT: + case uno::TypeClass_UNSIGNED_LONG: + case uno::TypeClass_UNSIGNED_HYPER: + try + { + aReturn = convertStringToSimple(ControlValue, ePropertyType); + } + catch( const script::CannotConvertException& ) { } + catch( const lang::IllegalArgumentException& ) { } + break; + + default: + #if OSL_DEBUG_LEVEL > 0 + bool bCanConvert = + #endif + convertStringToGenericValue( ControlValue, aReturn, ControlValueType ); + + #if OSL_DEBUG_LEVEL > 0 + // could not convert ... + if ( !bCanConvert && !ControlValue.isEmpty() ) + { + SAL_WARN( "extensions.propctrlr", "StringRepresentation::convertStringRepresentationToPropertyValue: cannot convert into values of type '" + << ControlValueType.getTypeName() << "'!" ); + } + #endif + } + + return aReturn; +} + +namespace { + +// This comparison functor assumes an underlying set of constants with pairwise +// unequal values that are all of UNO SHORT or LONG type: +struct CompareConstants { + bool operator ()( + css::uno::Reference< css::reflection::XConstantTypeDescription > const & + c1, + css::uno::Reference< css::reflection::XConstantTypeDescription > const & + c2) const + { + return c1->getConstantValue().get() + < c2->getConstantValue().get(); + } +}; + +} + +// lang::XInitialization: +void SAL_CALL StringRepresentation::initialize(const uno::Sequence< uno::Any > & aArguments) +{ + sal_Int32 nLength = aArguments.getLength(); + if ( !nLength ) + return; + + const uno::Any* pIter = aArguments.getConstArray(); + m_xTypeConverter.set(*pIter++,uno::UNO_QUERY); + if ( nLength != 3 ) + return; + + OUString sConstantName; + *pIter++ >>= sConstantName; + *pIter >>= m_aValues; + + if ( !m_xContext.is() ) + return; + + uno::Reference< container::XHierarchicalNameAccess > xTypeDescProv( + m_xContext->getValueByName("/singletons/com.sun.star.reflection.theTypeDescriptionManager"), + uno::UNO_QUERY_THROW ); + + m_xTypeDescription.set( xTypeDescProv->getByHierarchicalName( sConstantName ), uno::UNO_QUERY_THROW ); + uno::Sequence< + uno::Reference< reflection::XConstantTypeDescription > > + cs(m_xTypeDescription->getConstants()); + auto [begin, end] = asNonConstRange(cs); + std::sort(begin, end, CompareConstants()); + m_aConstants = cs; +} + +OUString StringRepresentation::convertSimpleToString( const uno::Any& _rValue ) +{ + OUString sReturn; + if ( m_xTypeConverter.is() && _rValue.hasValue() ) + { + try + { + if ( m_aConstants.hasElements() ) + { + sal_Int16 nConstantValue = 0; + if ( _rValue >>= nConstantValue ) + { + const uno::Reference< reflection::XConstantTypeDescription>* pIter = m_aConstants.getConstArray(); + const uno::Reference< reflection::XConstantTypeDescription>* pEnd = pIter + m_aConstants.getLength(); + for(sal_Int32 i = 0;pIter != pEnd;++pIter,++i) + { + if ( (*pIter)->getConstantValue() == _rValue ) + { + OSL_ENSURE(i < m_aValues.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues"); + sReturn = m_aValues[i]; + break; + } + } + } + } + + if ( sReturn.isEmpty() ) + m_xTypeConverter->convertToSimpleType( _rValue, uno::TypeClass_STRING ) >>= sReturn; + } + catch( const script::CannotConvertException& ) { } + catch( const lang::IllegalArgumentException& ) { } + } + return sReturn; +} + + +namespace +{ + struct ConvertIntegerFromAndToString + { + OUString operator()( sal_Int32 _rIntValue ) const + { + return OUString::number( _rIntValue ); + } + sal_Int32 operator()( std::u16string_view _rStringValue ) const + { + return o3tl::toInt32(_rStringValue); + } + }; + + struct StringIdentity + { + OUString operator()( const OUString& _rValue ) const + { + return _rValue; + } + }; + + template < class ElementType, class Transformer > + OUString composeSequenceElements( const Sequence< ElementType >& _rElements, const Transformer& _rTransformer ) + { + OUStringBuffer sCompose; + + // loop through the elements and concatenate the string representations of the integers + // (separated by a line break) + for (const auto& rElement : _rElements) + { + sCompose.append(OUString(_rTransformer(rElement))); + sCompose.append("\n"); + } + sCompose.stripEnd('\n'); + + return sCompose.makeStringAndClear(); + } + + template < class ElementType, class Transformer > + void splitComposedStringToSequence( std::u16string_view _rComposed, Sequence< ElementType >& _out_SplitUp, const Transformer& _rTransformer ) + { + _out_SplitUp.realloc( 0 ); + if ( _rComposed.empty() ) + return; + sal_Int32 tokenPos = 0; + do + { + _out_SplitUp.realloc( _out_SplitUp.getLength() + 1 ); + _out_SplitUp.getArray()[ _out_SplitUp.getLength() - 1 ] = static_cast(_rTransformer( OUString(o3tl::getToken(_rComposed, 0, '\n', tokenPos )) )); + } + while ( tokenPos != -1 ); + } +} + + +bool StringRepresentation::convertGenericValueToString( const uno::Any& _rValue, OUString& _rStringRep ) +{ + bool bCanConvert = true; + + switch ( _rValue.getValueTypeClass() ) + { + case uno::TypeClass_STRING: + _rValue >>= _rStringRep; + break; + + case uno::TypeClass_BOOLEAN: + { + bool bValue = false; + _rValue >>= bValue; + _rStringRep = bValue ? PcrRes(RID_RSC_ENUM_YESNO[1]) + : PcrRes(RID_RSC_ENUM_YESNO[0]); + } + break; + + // some sequence types + case uno::TypeClass_SEQUENCE: + { + Sequence< OUString > aStringValues; + Sequence< sal_Int8 > aInt8Values; + Sequence< sal_uInt16 > aUInt16Values; + Sequence< sal_Int16 > aInt16Values; + Sequence< sal_uInt32 > aUInt32Values; + Sequence< sal_Int32 > aInt32Values; + + // string sequences + if ( _rValue >>= aStringValues ) + { + _rStringRep = composeSequenceElements( aStringValues, StringIdentity() ); + } + // byte sequences + else if ( _rValue >>= aInt8Values ) + { + _rStringRep = composeSequenceElements( aInt8Values, ConvertIntegerFromAndToString() ); + } + // uInt16 sequences + else if ( _rValue >>= aUInt16Values ) + { + _rStringRep = composeSequenceElements( aUInt16Values, ConvertIntegerFromAndToString() ); + } + // Int16 sequences + else if ( _rValue >>= aInt16Values ) + { + _rStringRep = composeSequenceElements( aInt16Values, ConvertIntegerFromAndToString() ); + } + // uInt32 sequences + else if ( _rValue >>= aUInt32Values ) + { + _rStringRep = composeSequenceElements( aUInt32Values, ConvertIntegerFromAndToString() ); + } + // Int32 sequences + else if ( _rValue >>= aInt32Values ) + { + _rStringRep = composeSequenceElements( aInt32Values, ConvertIntegerFromAndToString() ); + } + else + bCanConvert = false; + } + break; + case uno::TypeClass_CONSTANT: + break; + + // some structs + case uno::TypeClass_STRUCT: + OSL_FAIL( "StringRepresentation::convertGenericValueToString(STRUCT): this is dead code - isn't it?" ); + if ( _rValue.getValueType().equals( cppu::UnoType< util::Date >::get() )) + { + // weird enough, the string representation of dates, as used + // by the control displaying dates, and thus as passed through the layers, + // is YYYYMMDD. + util::Date aUnoDate; + _rValue >>= aUnoDate; + _rStringRep = ::dbtools::DBTypeConversion::toDateString(aUnoDate); + } + else if ( _rValue.getValueType().equals( cppu::UnoType< util::Time >::get() )) + { + // similar for time (HHMMSSHH) + util::Time aUnoTime; + _rValue >>= aUnoTime; + _rStringRep = ::dbtools::DBTypeConversion::toTimeString(aUnoTime); + } + else if ( _rValue.getValueType().equals( cppu::UnoType< util::DateTime >::get() )) + { + util::DateTime aUnoDateTime; + _rValue >>= aUnoDateTime; + _rStringRep = ::dbtools::DBTypeConversion::toDateTimeString(aUnoDateTime); + } + else + bCanConvert = false; + break; + + default: + bCanConvert = false; + break; + } + + return bCanConvert; +} + +uno::Any StringRepresentation::convertStringToSimple( const OUString& _rValue,const uno::TypeClass& _ePropertyType ) +{ + uno::Any aReturn; + if ( m_xTypeConverter.is() && !_rValue.isEmpty() ) + { + try + { + if ( m_aConstants.hasElements() && m_aValues.hasElements() ) + { + const OUString* pIter = m_aValues.getConstArray(); + const OUString* pEnd = pIter + m_aValues.getLength(); + for(sal_Int32 i = 0;pIter != pEnd;++pIter,++i) + { + if ( *pIter == _rValue ) + { + OSL_ENSURE(i < m_aConstants.getLength() ,"StringRepresentation::convertSimpleToString: Index is not in range of m_aValues"); + aReturn = m_aConstants[i]->getConstantValue(); + break; + } + } + } + + if ( !aReturn.hasValue() ) + aReturn = m_xTypeConverter->convertToSimpleType( Any( _rValue ), _ePropertyType ); + } + catch( const script::CannotConvertException& ) { } + catch( const lang::IllegalArgumentException& ) { } + } + return aReturn; +} + +bool StringRepresentation::convertStringToGenericValue( const OUString& _rStringRep, uno::Any& _rValue, const uno::Type& _rTargetType ) +{ + bool bCanConvert = true; + + switch ( _rTargetType.getTypeClass() ) + { + case uno::TypeClass_STRING: + _rValue <<= _rStringRep; + break; + + case uno::TypeClass_BOOLEAN: + { + _rValue <<= PcrRes(RID_RSC_ENUM_YESNO[0]) != _rStringRep; + } + break; + + case uno::TypeClass_SEQUENCE: + { + uno::Type aElementType = ::comphelper::getSequenceElementType( _rTargetType ); + + switch ( aElementType.getTypeClass() ) + { + case uno::TypeClass_STRING: + { + Sequence< OUString > aElements; + splitComposedStringToSequence( _rStringRep, aElements, StringIdentity() ); + _rValue <<= aElements; + } + break; + case uno::TypeClass_SHORT: + { + Sequence< sal_Int16 > aElements; + splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() ); + _rValue <<= aElements; + } + break; + case uno::TypeClass_UNSIGNED_SHORT: + { + Sequence< sal_uInt16 > aElements; + splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() ); + _rValue <<= aElements; + } + break; + case uno::TypeClass_LONG: + { + Sequence< sal_Int32 > aElements; + splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() ); + _rValue <<= aElements; + } + break; + case uno::TypeClass_UNSIGNED_LONG: + { + Sequence< sal_uInt32 > aElements; + splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() ); + _rValue <<= aElements; + } + break; + case uno::TypeClass_BYTE: + { + Sequence< sal_Int8 > aElements; + splitComposedStringToSequence( _rStringRep, aElements, ConvertIntegerFromAndToString() ); + _rValue <<= aElements; + } + break; + default: + bCanConvert = false; + break; + } + } + break; + + case uno::TypeClass_STRUCT: + OSL_FAIL( "StringRepresentation::convertStringToGenericValue(STRUCT): this is dead code - isn't it?" ); + if ( _rTargetType.equals( cppu::UnoType< util::Date >::get() )) + { + // weird enough, the string representation of dates, as used + // by the control displaying dates, and thus as passed through the layers, + // is YYYYMMDD. + + _rValue <<= ::dbtools::DBTypeConversion::toDate(_rStringRep); + } + else if ( _rTargetType.equals( cppu::UnoType< util::Time >::get() )) + { + // similar for time (HHMMSSHH) + _rValue <<= ::dbtools::DBTypeConversion::toTime(_rStringRep); + } + else if ( _rTargetType.equals( cppu::UnoType< util::DateTime >::get() )) + { + _rValue <<= ::dbtools::DBTypeConversion::toDateTime(_rStringRep); + } + else + bCanConvert = false; + break; + + default: + bCanConvert = false; + break; + } + + return bCanConvert; +} + + +} // pcr + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_StringRepresentation_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::StringRepresentation(context)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/submissionhandler.cxx b/extensions/source/propctrlr/submissionhandler.cxx new file mode 100644 index 000000000..87609e905 --- /dev/null +++ b/extensions/source/propctrlr/submissionhandler.cxx @@ -0,0 +1,431 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "submissionhandler.hxx" +#include "formmetadata.hxx" +#include "formstrings.hxx" +#include "handlerhelper.hxx" + +#include +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::comphelper; + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::xforms; + using namespace ::com::sun::star::container; + using namespace ::com::sun::star::inspection; + + + //= SubmissionHelper + + + SubmissionHelper::SubmissionHelper( ::osl::Mutex& _rMutex, const Reference< XPropertySet >& _rxIntrospectee, const Reference< frame::XModel >& _rxContextDocument ) + :EFormsHelper( _rMutex, _rxIntrospectee, _rxContextDocument ) + { + OSL_ENSURE( canTriggerSubmissions( _rxIntrospectee, _rxContextDocument ), + "SubmissionHelper::SubmissionHelper: you should not have instantiated me!" ); + } + + + bool SubmissionHelper::canTriggerSubmissions( const Reference< XPropertySet >& _rxControlModel, + const Reference< frame::XModel >& _rxContextDocument ) + { + if ( !EFormsHelper::isEForm( _rxContextDocument ) ) + return false; + + try + { + Reference< submission::XSubmissionSupplier > xSubmissionSupp( _rxControlModel, UNO_QUERY ); + if ( xSubmissionSupp.is() ) + return true; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "SubmissionHelper::canTriggerSubmissions" ); + } + return false; + } + + + //= SubmissionPropertyHandler + + + SubmissionPropertyHandler::SubmissionPropertyHandler( const Reference< XComponentContext >& _rxContext ) + :PropertyHandlerComponent( _rxContext ) + ,OPropertyChangeListener( m_aMutex ) + { + } + + + SubmissionPropertyHandler::~SubmissionPropertyHandler( ) + { + disposeAdapter(); + } + + + OUString SubmissionPropertyHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.SubmissionPropertyHandler"; + } + + + Sequence< OUString > SubmissionPropertyHandler::getSupportedServiceNames( ) + { + return { "com.sun.star.form.inspection.SubmissionPropertyHandler" }; + } + + + Any SAL_CALL SubmissionPropertyHandler::getPropertyValue( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + OSL_ENSURE(m_pHelper, "SubmissionPropertyHandler::getPropertyValue: inconsistency!"); + // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties + + Any aReturn; + try + { + switch ( nPropId ) + { + case PROPERTY_ID_SUBMISSION_ID: + { + Reference< submission::XSubmissionSupplier > xSubmissionSupp( m_xComponent, UNO_QUERY ); + OSL_ENSURE( xSubmissionSupp.is(), "SubmissionPropertyHandler::getPropertyValue: this should never happen ..." ); + // this handler is not intended for components which are no XSubmissionSupplier + Reference< submission::XSubmission > xSubmission; + if ( xSubmissionSupp.is() ) + xSubmission = xSubmissionSupp->getSubmission( ); + aReturn <<= xSubmission; + } + break; + + case PROPERTY_ID_XFORMS_BUTTONTYPE: + { + FormButtonType eType = FormButtonType_PUSH; + OSL_VERIFY( m_xComponent->getPropertyValue( PROPERTY_BUTTONTYPE ) >>= eType ); + if ( ( eType != FormButtonType_PUSH ) && ( eType != FormButtonType_SUBMIT ) ) + eType = FormButtonType_PUSH; + aReturn <<= eType; + } + break; + + default: + OSL_FAIL( "SubmissionPropertyHandler::getPropertyValue: cannot handle this property!" ); + break; + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "SubmissionPropertyHandler::getPropertyValue" ); + } + + return aReturn; + } + + + void SAL_CALL SubmissionPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + OSL_ENSURE(m_pHelper, "SubmissionPropertyHandler::setPropertyValue: inconsistency!"); + // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties + + try + { + switch ( nPropId ) + { + case PROPERTY_ID_SUBMISSION_ID: + { + Reference< submission::XSubmission > xSubmission; + OSL_VERIFY( _rValue >>= xSubmission ); + + Reference< submission::XSubmissionSupplier > xSubmissionSupp( m_xComponent, UNO_QUERY ); + OSL_ENSURE( xSubmissionSupp.is(), "SubmissionPropertyHandler::setPropertyValue: this should never happen ..." ); + // this handler is not intended for components which are no XSubmissionSupplier + if ( xSubmissionSupp.is() ) + { + xSubmissionSupp->setSubmission( xSubmission ); + impl_setContextDocumentModified_nothrow(); + } + } + break; + + case PROPERTY_ID_XFORMS_BUTTONTYPE: + m_xComponent->setPropertyValue( PROPERTY_BUTTONTYPE, _rValue ); + break; + + default: + OSL_FAIL( "SubmissionPropertyHandler::setPropertyValue: cannot handle this id!" ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "SubmissionPropertyHandler::setPropertyValue" ); + } + } + + + Sequence< OUString > SAL_CALL SubmissionPropertyHandler::getActuatingProperties( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_pHelper) + return Sequence< OUString >(); + + Sequence aReturn { PROPERTY_XFORMS_BUTTONTYPE }; + return aReturn; + } + + + Sequence< OUString > SAL_CALL SubmissionPropertyHandler::getSupersededProperties( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (!m_pHelper) + return Sequence< OUString >(); + + Sequence< OUString > aReturn{ PROPERTY_TARGET_URL, + PROPERTY_TARGET_FRAME, + PROPERTY_BUTTONTYPE }; + return aReturn; + } + + + void SubmissionPropertyHandler::onNewComponent() + { + if ( m_xPropChangeMultiplexer.is() ) + { + m_xPropChangeMultiplexer->dispose(); + m_xPropChangeMultiplexer.clear(); + } + + PropertyHandlerComponent::onNewComponent(); + + Reference< frame::XModel > xDocument( impl_getContextDocument_nothrow() ); + DBG_ASSERT( xDocument.is(), "SubmissionPropertyHandler::onNewComponent: no document!" ); + + m_pHelper.reset(); + + if ( SubmissionHelper::canTriggerSubmissions( m_xComponent, xDocument ) ) + { + m_pHelper.reset( new SubmissionHelper( m_aMutex, m_xComponent, xDocument ) ); + + m_xPropChangeMultiplexer = new OPropertyChangeMultiplexer( this, m_xComponent ); + m_xPropChangeMultiplexer->addProperty( PROPERTY_BUTTONTYPE ); + } + } + + + Sequence< Property > SubmissionPropertyHandler::doDescribeSupportedProperties() const + { + std::vector< Property > aProperties; + if (m_pHelper) + { + implAddPropertyDescription( aProperties, PROPERTY_SUBMISSION_ID, cppu::UnoType::get() ); + implAddPropertyDescription( aProperties, PROPERTY_XFORMS_BUTTONTYPE, ::cppu::UnoType::get() ); + } + if ( aProperties.empty() ) + return Sequence< Property >(); + return comphelper::containerToSequence(aProperties); + } + + + LineDescriptor SAL_CALL SubmissionPropertyHandler::describePropertyLine( const OUString& _rPropertyName, + const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !_rxControlFactory.is() ) + throw NullPointerException(); + if (!m_pHelper) + throw RuntimeException(); + + std::vector< OUString > aListEntries; + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + switch ( nPropId ) + { + case PROPERTY_ID_SUBMISSION_ID: + m_pHelper->getAllElementUINames(EFormsHelper::Submission, aListEntries, false); + break; + + case PROPERTY_ID_XFORMS_BUTTONTYPE: + { + // available options are nearly the same as for the "normal" button type, but only the + // first two options + aListEntries = m_pInfoService->getPropertyEnumRepresentations( PROPERTY_ID_BUTTONTYPE ); + aListEntries.resize( 2 ); + } + break; + + default: + OSL_FAIL( "SubmissionPropertyHandler::describePropertyLine: cannot handle this id!" ); + return LineDescriptor(); + } + + LineDescriptor aDescriptor; + aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory, std::move(aListEntries), false, true ); + aDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( nPropId ); + aDescriptor.Category = "General"; + aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) ); + return aDescriptor; + } + + + void SAL_CALL SubmissionPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& /*_rOldValue*/, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) ); + OSL_PRECOND(m_pHelper, + "SubmissionPropertyHandler::actuatingPropertyChanged: inconsistency!"); + // if we survived impl_getPropertyId_throwRuntime, we should have a helper, since no helper implies no properties + + switch ( nActuatingPropId ) + { + case PROPERTY_ID_XFORMS_BUTTONTYPE: + { + FormButtonType eType = FormButtonType_PUSH; + OSL_VERIFY( _rNewValue >>= eType ); + _rxInspectorUI->enablePropertyUI( PROPERTY_SUBMISSION_ID, eType == FormButtonType_SUBMIT ); + } + break; + + default: + OSL_FAIL( "SubmissionPropertyHandler::actuatingPropertyChanged: cannot handle this id!" ); + } + } + + + Any SAL_CALL SubmissionPropertyHandler::convertToPropertyValue( const OUString& _rPropertyName, const Any& _rControlValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Any aPropertyValue; + + OSL_ENSURE( + m_pHelper, + "SubmissionPropertyHandler::convertToPropertyValue: we have no SupportedProperties!"); + if (!m_pHelper) + return aPropertyValue; + + OUString sControlValue; + OSL_VERIFY( _rControlValue >>= sControlValue ); + + PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) ); + switch ( nPropId ) + { + case PROPERTY_ID_SUBMISSION_ID: + { + Reference< XSubmission > xSubmission( m_pHelper->getModelElementFromUIName( EFormsHelper::Submission, sControlValue ), UNO_QUERY ); + aPropertyValue <<= xSubmission; + } + break; + + case PROPERTY_ID_XFORMS_BUTTONTYPE: + { + ::rtl::Reference< IPropertyEnumRepresentation > aEnumConversion( + new DefaultEnumRepresentation( *m_pInfoService, ::cppu::UnoType::get(), PROPERTY_ID_BUTTONTYPE ) ); + // TODO/UNOize: make aEnumConversion a member? + aEnumConversion->getValueFromDescription( sControlValue, aPropertyValue ); + } + break; + + default: + OSL_FAIL( "SubmissionPropertyHandler::convertToPropertyValue: cannot handle this id!" ); + } + + return aPropertyValue; + } + + + Any SAL_CALL SubmissionPropertyHandler::convertToControlValue( const OUString& _rPropertyName, const Any& _rPropertyValue, const Type& _rControlValueType ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + Any aControlValue; + + OSL_ENSURE( + m_pHelper, + "SubmissionPropertyHandler::convertToControlValue: we have no SupportedProperties!"); + if (!m_pHelper) + return aControlValue; + + OSL_ENSURE( _rControlValueType.getTypeClass() == TypeClass_STRING, + "SubmissionPropertyHandler::convertToControlValue: all our controls should use strings for value exchange!" ); + + PropertyId nPropId( m_pInfoService->getPropertyId( _rPropertyName ) ); + switch ( nPropId ) + { + case PROPERTY_ID_SUBMISSION_ID: + { + Reference< XPropertySet > xSubmission( _rPropertyValue, UNO_QUERY ); + if ( xSubmission.is() ) + aControlValue <<= EFormsHelper::getModelElementUIName( EFormsHelper::Submission, xSubmission ); + } + break; + + case PROPERTY_ID_XFORMS_BUTTONTYPE: + { + ::rtl::Reference< IPropertyEnumRepresentation > aEnumConversion( + new DefaultEnumRepresentation( *m_pInfoService, _rPropertyValue.getValueType(), PROPERTY_ID_BUTTONTYPE ) ); + // TODO/UNOize: make aEnumConversion a member? + aControlValue <<= aEnumConversion->getDescriptionForValue( _rPropertyValue ); + } + break; + + default: + OSL_FAIL( "SubmissionPropertyHandler::convertToControlValue: cannot handle this id!" ); + } + + return aControlValue; + } + + + void SubmissionPropertyHandler::_propertyChanged( const PropertyChangeEvent& _rEvent ) + { + if ( _rEvent.PropertyName == PROPERTY_BUTTONTYPE ) + firePropertyChange( PROPERTY_XFORMS_BUTTONTYPE, PROPERTY_ID_XFORMS_BUTTONTYPE, _rEvent.OldValue, _rEvent.NewValue ); + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_SubmissionPropertyHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::SubmissionPropertyHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/submissionhandler.hxx b/extensions/source/propctrlr/submissionhandler.hxx new file mode 100644 index 000000000..f263041b2 --- /dev/null +++ b/extensions/source/propctrlr/submissionhandler.hxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include "propertyhandler.hxx" +#include "eformshelper.hxx" + +#include +#include + +namespace comphelper +{ + class OPropertyChangeMultiplexer; +} + + +namespace pcr +{ + + + //= SubmissionHelper + + class SubmissionHelper : public EFormsHelper + { + public: + SubmissionHelper( + osl::Mutex& _rMutex, + const css::uno::Reference< css::beans::XPropertySet >& _rxIntrospectee, + const css::uno::Reference< css::frame::XModel >& _rxContextDocument + ); + + /** determines whether the given control model is able to trigger submissions + + Instances of the SubmissionHelper class should not be instantiated + for components where this method returned + */ + static bool canTriggerSubmissions( + const css::uno::Reference< css::beans::XPropertySet >& _rxControlModel, + const css::uno::Reference< css::frame::XModel >& _rxContextDocument + ); + }; + + + //= SubmissionPropertyHandler + + /** a property handler for any virtual string properties + */ + class SubmissionPropertyHandler : public PropertyHandlerComponent, public ::comphelper::OPropertyChangeListener + { + private: + std::unique_ptr< SubmissionHelper > m_pHelper; + rtl::Reference<::comphelper::OPropertyChangeMultiplexer> m_xPropChangeMultiplexer; + + public: + explicit SubmissionPropertyHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + virtual ~SubmissionPropertyHandler() override; + protected: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override; + + // XPropertyHandler overriables + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::uno::Sequence< OUString > + SAL_CALL getActuatingProperties( ) override; + virtual css::uno::Sequence< OUString > + SAL_CALL getSupersededProperties( ) override; + virtual css::inspection::LineDescriptor + SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) override; + virtual css::uno::Any SAL_CALL convertToPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rControlValue ) override; + virtual css::uno::Any SAL_CALL convertToControlValue( const OUString& _rPropertyName, const css::uno::Any& _rPropertyValue, const css::uno::Type& _rControlValueType ) override; + + // PropertyHandler overridables + virtual css::uno::Sequence< css::beans::Property > + doDescribeSupportedProperties() const override; + virtual void onNewComponent() override; + + private: + // OPropertyChangeListener + virtual void _propertyChanged(const css::beans::PropertyChangeEvent& _rEvent) override; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/taborder.cxx b/extensions/source/propctrlr/taborder.cxx new file mode 100644 index 000000000..6ada66b5a --- /dev/null +++ b/extensions/source/propctrlr/taborder.cxx @@ -0,0 +1,320 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "taborder.hxx" + +#include +#include "formstrings.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace pcr +{ + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::awt; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::form; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::datatransfer; + + namespace { + + OUString GetImage( const Reference< XPropertySet >& _rxSet ) + { + OUString sImageId = RID_EXTBMP_CONTROL; + // TODO: classify controls also in Basic propbrw + if ( _rxSet.is() && ::comphelper::hasProperty( PROPERTY_CLASSID, _rxSet ) ) + { + switch( ::comphelper::getINT16( _rxSet->getPropertyValue( PROPERTY_CLASSID ) ) ) + { + case FormComponentType::COMMANDBUTTON: sImageId = RID_EXTBMP_BUTTON; break; + case FormComponentType::FIXEDTEXT: sImageId = RID_EXTBMP_FIXEDTEXT; break; + case FormComponentType::TEXTFIELD: sImageId = RID_EXTBMP_EDITBOX; break; + case FormComponentType::RADIOBUTTON: sImageId = RID_EXTBMP_RADIOBUTTON; break; + case FormComponentType::CHECKBOX: sImageId = RID_EXTBMP_CHECKBOX; break; + case FormComponentType::LISTBOX: sImageId = RID_EXTBMP_LISTBOX; break; + case FormComponentType::COMBOBOX: sImageId = RID_EXTBMP_COMBOBOX; break; + case FormComponentType::GROUPBOX: sImageId = RID_EXTBMP_GROUPBOX; break; + case FormComponentType::IMAGEBUTTON: sImageId = RID_EXTBMP_IMAGEBUTTON; break; + case FormComponentType::FILECONTROL: sImageId = RID_EXTBMP_FILECONTROL; break; + case FormComponentType::HIDDENCONTROL: sImageId = RID_EXTBMP_HIDDEN; break; + case FormComponentType::DATEFIELD: sImageId = RID_EXTBMP_DATEFIELD; break; + case FormComponentType::TIMEFIELD: sImageId = RID_EXTBMP_TIMEFIELD; break; + case FormComponentType::NUMERICFIELD: sImageId = RID_EXTBMP_NUMERICFIELD; break; + case FormComponentType::CURRENCYFIELD: sImageId = RID_EXTBMP_CURRENCYFIELD; break; + case FormComponentType::PATTERNFIELD: sImageId = RID_EXTBMP_PATTERNFIELD; break; + case FormComponentType::IMAGECONTROL: sImageId = RID_EXTBMP_IMAGECONTROL; break; + case FormComponentType::GRIDCONTROL: sImageId = RID_EXTBMP_GRID; break; + case FormComponentType::SCROLLBAR: sImageId = RID_EXTBMP_SCROLLBAR; break; + case FormComponentType::SPINBUTTON: sImageId = RID_EXTBMP_SPINBUTTON; break; + case FormComponentType::NAVIGATIONBAR: sImageId = RID_EXTBMP_NAVIGATIONBAR; break; + default: + OSL_FAIL( "TabOrderDialog::GetImage: unknown control type" ); + } + } + + return sImageId; + } + + //= OSimpleTabModel + + class OSimpleTabModel : public ::cppu::WeakImplHelper< XTabControllerModel> + { + Sequence< Reference< XControlModel > > m_aModels; + + public: + explicit OSimpleTabModel( const Sequence< Reference< XControlModel > >& _rModels ) + :m_aModels( _rModels ) + { + } + + // XTabControllerModel + virtual void SAL_CALL setControlModels(const Sequence< Reference< XControlModel > >& rModels) override {m_aModels = rModels;} + virtual Sequence< Reference< XControlModel > > SAL_CALL getControlModels() override {return m_aModels;} + virtual void SAL_CALL setGroup(const Sequence< Reference< XControlModel > >& /*Group*/, const OUString& /*GroupName*/) override {} + virtual sal_Int32 SAL_CALL getGroupCount() override {return 0;} + virtual void SAL_CALL getGroup(sal_Int32 /*nGroup*/, Sequence< Reference< XControlModel > >& /*Group*/, OUString& /*Name*/) override {} + virtual void SAL_CALL getGroupByName(const OUString& /*Name*/, Sequence< Reference< XControlModel > >& /*Group*/) override {} + virtual sal_Bool SAL_CALL getGroupControl() override {return false;} ; + virtual void SAL_CALL setGroupControl(sal_Bool /*GroupControl*/) override {}; + }; + + } + + //= TabOrderDialog + TabOrderDialog::TabOrderDialog(weld::Window* _pParent, const Reference< XTabControllerModel >& _rxTabModel, + const Reference< XControlContainer >& _rxControlCont, const Reference< XComponentContext >& _rxORB) + : GenericDialogController( _pParent, "modules/spropctrlr/ui/taborder.ui", "TabOrderDialog") + , m_xModel( _rxTabModel ) + , m_xControlContainer( _rxControlCont ) + , m_xORB( _rxORB ) + , m_xLB_Controls(m_xBuilder->weld_tree_view("CTRLtree")) + , m_xPB_OK(m_xBuilder->weld_button("ok")) + , m_xPB_MoveUp(m_xBuilder->weld_button("upB")) + , m_xPB_MoveDown(m_xBuilder->weld_button("downB")) + , m_xPB_AutoOrder(m_xBuilder->weld_button("autoB")) + { + m_xLB_Controls->set_size_request(m_xLB_Controls->get_approximate_digit_width() * 60, + m_xLB_Controls->get_height_rows(10)); + m_xLB_Controls->set_selection_mode(SelectionMode::Multiple); + + m_xLB_Controls->connect_model_changed(LINK(this, TabOrderDialog, ModelHasMoved)); + m_xPB_MoveUp->connect_clicked( LINK( this, TabOrderDialog, MoveUpClickHdl ) ); + m_xPB_MoveDown->connect_clicked( LINK( this, TabOrderDialog, MoveDownClickHdl ) ); + m_xPB_AutoOrder->connect_clicked( LINK( this, TabOrderDialog, AutoOrderClickHdl ) ); + m_xPB_OK->connect_clicked( LINK( this, TabOrderDialog, OKClickHdl ) ); + m_xPB_OK->set_sensitive(false); + + if ( m_xModel.is() ) + m_xTempModel = new OSimpleTabModel( m_xModel->getControlModels() ); + + if ( m_xTempModel.is() && m_xControlContainer.is() ) + FillList(); + + if (m_xLB_Controls->n_children() < 2) + { + m_xPB_MoveUp->set_sensitive(false); + m_xPB_MoveDown->set_sensitive(false); + m_xPB_AutoOrder->set_sensitive(false); + } + + } + + void TabOrderDialog::SetModified() + { + m_xPB_OK->set_sensitive(true); + } + + TabOrderDialog::~TabOrderDialog() + { + } + + void TabOrderDialog::FillList() + { + DBG_ASSERT( m_xTempModel.is() && m_xControlContainer.is(), "TabOrderDialog::FillList: invalid call!" ); + if ( !m_xTempModel.is() || !m_xControlContainer.is() ) + return; + + m_xLB_Controls->clear(); + + try + { + OUString aName; + OUString aImage; + + const Sequence> aControlModels = m_xTempModel->getControlModels(); + for ( auto const& rControlModel : aControlModels ) + { + Reference< XPropertySet > xControl( rControlModel, UNO_QUERY ); + Reference< XPropertySetInfo > xPI; + if ( xControl.is() ) + xPI = xControl->getPropertySetInfo(); + + if ( xPI.is() ) + { + if ( xPI->hasPropertyByName( PROPERTY_TABSTOP ) ) + { + aName = ::comphelper::getString( xControl->getPropertyValue( PROPERTY_NAME ) ); + // TODO: do Basic controls have a name? + aImage = GetImage( xControl ); + OUString sId(weld::toId(xControl.get())); + m_xLB_Controls->append(sId, aName, aImage); + } + } + else + { + // no property set -> no tab order + OSL_FAIL( "TabOrderDialog::FillList: invalid control encountered!" ); + m_xLB_Controls->clear(); + break; + } + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "TabOrderDialog::FillList" ); + } + + // select first entry + if (m_xLB_Controls->n_children()) + m_xLB_Controls->select(0); + } + + IMPL_LINK_NOARG( TabOrderDialog, MoveUpClickHdl, weld::Button&, void ) + { + MoveSelection(-1); + } + + IMPL_LINK_NOARG( TabOrderDialog, MoveDownClickHdl, weld::Button&, void ) + { + MoveSelection(1); + } + + IMPL_LINK_NOARG( TabOrderDialog, AutoOrderClickHdl, weld::Button&, void ) + { + try + { + Reference< css::form::runtime::XFormController > xTabController = css::form::runtime::FormController::create( m_xORB ); + + xTabController->setModel( m_xTempModel ); + xTabController->setContainer( m_xControlContainer ); + xTabController->autoTabOrder(); + + SetModified(); + FillList(); + + ::comphelper::disposeComponent( xTabController ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "TabOrderDialog::AutoOrderClickHdl" ); + } + } + + IMPL_LINK_NOARG( TabOrderDialog, OKClickHdl, weld::Button&, void ) + { + int nEntryCount = m_xLB_Controls->n_children(); + Sequence< Reference< XControlModel > > aSortedControlModelSeq( nEntryCount ); + const Sequence< Reference< XControlModel > > aControlModels( m_xTempModel->getControlModels()); + Reference< XControlModel > * pSortedControlModels = aSortedControlModelSeq.getArray(); + + for (int i = 0; i < nEntryCount; ++i) + { + XPropertySet* pEntry = weld::fromId(m_xLB_Controls->get_id(i)); + for( auto const& rControlModel : aControlModels ) + { + Reference< XPropertySet > xSet(rControlModel, UNO_QUERY); + if (xSet.get() == pEntry) + { + pSortedControlModels[i] = rControlModel; + break; + } + } + } + + // TODO: UNO action (to bracket all the single actions which are being created) + m_xModel->setControlModels( aSortedControlModelSeq ); + + m_xDialog->response(RET_OK); + } + + IMPL_LINK_NOARG(TabOrderDialog, ModelHasMoved, weld::TreeView&, void) + { + SetModified(); + } + + void TabOrderDialog::MoveSelection(int nRelPos) + { + std::vector aRows(m_xLB_Controls->get_selected_rows()); + if (aRows.empty()) + return; + + m_xLB_Controls->unselect_all(); + for (int i = 0; i < abs(nRelPos); ++i) + { + SetModified(); + + // move entries + if (nRelPos < 0) + { + std::sort(aRows.begin(), aRows.end()); + + int nFirstSelPos = aRows[0]; + if (nFirstSelPos == 0) return; + + for (auto row : aRows) + { + int nInsertPos = row - 1; + m_xLB_Controls->swap(nInsertPos, row); + } + + for (auto row : aRows) + m_xLB_Controls->select(row - 1); + } + else if (nRelPos > 0) + { + std::sort(aRows.rbegin(), aRows.rend()); + + int nLastSelPos = aRows[0]; + if( (nLastSelPos + nRelPos - i) > (m_xLB_Controls->n_children()-1) ) return; + + for (auto row : aRows) + { + int nInsertPos = row + 1; + m_xLB_Controls->swap(nInsertPos, row); + } + + for (auto row : aRows) + m_xLB_Controls->select(row + 1); + } + } + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/taborder.hxx b/extensions/source/propctrlr/taborder.hxx new file mode 100644 index 000000000..e43f010e8 --- /dev/null +++ b/extensions/source/propctrlr/taborder.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 pcr +{ + //= TabOrderDialog + class TabOrderDialog : public weld::GenericDialogController + { + css::uno::Reference< css::awt::XTabControllerModel > + m_xTempModel; + css::uno::Reference< css::awt::XTabControllerModel > + m_xModel; + css::uno::Reference< css::awt::XControlContainer > + m_xControlContainer; + css::uno::Reference< css::uno::XComponentContext > + m_xORB; + + std::unique_ptr m_xLB_Controls; + std::unique_ptr m_xPB_OK; + std::unique_ptr m_xPB_MoveUp; + std::unique_ptr m_xPB_MoveDown; + std::unique_ptr m_xPB_AutoOrder; + + DECL_LINK( ModelHasMoved, weld::TreeView&, void ); + DECL_LINK( MoveUpClickHdl, weld::Button&, void ); + DECL_LINK( MoveDownClickHdl, weld::Button&, void ); + DECL_LINK( AutoOrderClickHdl, weld::Button&, void ); + DECL_LINK( OKClickHdl, weld::Button&, void ); + + void FillList(); + void MoveSelection(int nRelPos); + + public: + TabOrderDialog( + weld::Window* pParent, + const css::uno::Reference< css::awt::XTabControllerModel >& _rxTabModel, + const css::uno::Reference< css::awt::XControlContainer >& _rxControlCont, + const css::uno::Reference< css::uno::XComponentContext >& _rxORB + ); + + virtual ~TabOrderDialog() override; + + void SetModified(); + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/unourl.cxx b/extensions/source/propctrlr/unourl.cxx new file mode 100644 index 000000000..88c963012 --- /dev/null +++ b/extensions/source/propctrlr/unourl.cxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "unourl.hxx" +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::util; + + + //= UnoURL + + UnoURL::UnoURL( const OUString& _rCompleteURL, const Reference< XMultiServiceFactory >& _rxORB ) + { + m_aURL.Complete = _rCompleteURL; + + OSL_ENSURE( _rxORB.is(), "UnoURL::UnoURL: invalid ORB!" ); + Reference< XURLTransformer > xTransform; + try + { + if ( _rxORB.is() ) + { + xTransform.set( URLTransformer::create(comphelper::getComponentContext(_rxORB)) ); + OSL_ENSURE( xTransform.is(), "UnoURL::UnoURL: could not create a URL transformer!" ); + if ( xTransform.is() ) + xTransform->parseStrict( m_aURL ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "UnoURL::UnoURL" ); + } + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/unourl.hxx b/extensions/source/propctrlr/unourl.hxx new file mode 100644 index 000000000..824c865ea --- /dev/null +++ b/extensions/source/propctrlr/unourl.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include +#include + + +namespace pcr +{ + + + //= UnoURL + + class UnoURL + { + private: + css::util::URL m_aURL; + + public: + UnoURL( + const OUString& _rCompleteURL, + const css::uno::Reference< css::lang::XMultiServiceFactory >& _rxORB + ); + + operator const css::util::URL& () const { return m_aURL; } + }; + + +} // namespacepcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/usercontrol.cxx b/extensions/source/propctrlr/usercontrol.cxx new file mode 100644 index 000000000..8cccb48e8 --- /dev/null +++ b/extensions/source/propctrlr/usercontrol.cxx @@ -0,0 +1,276 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "usercontrol.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include "modulepcr.hxx" +#include + + +namespace pcr +{ + + + using ::com::sun::star::uno::Any; + using ::com::sun::star::uno::Type; + + namespace PropertyControlType = ::com::sun::star::inspection::PropertyControlType; + + IMPL_LINK(OFormatSampleControl, KeyInputHdl, const KeyEvent&, rKeyEvent, bool) + { + // want to handle two keys myself : Del/Backspace should empty the window (setting my prop to "standard" this way) + sal_uInt16 nKey = rKeyEvent.GetKeyCode().GetCode(); + if ((KEY_DELETE == nKey) || (KEY_BACKSPACE == nKey)) + { + m_xSpinButton->set_text(""); + m_xEntry->set_text(""); + setModified(); + } + + return true; + } + + void OFormatSampleControl::SetFormatSupplier( const SvNumberFormatsSupplierObj* pSupplier ) + { + Formatter& rFieldFormatter = m_xSpinButton->GetFormatter(); + if (pSupplier) + { + rFieldFormatter.TreatAsNumber(true); + + SvNumberFormatter* pFormatter = pSupplier->GetNumberFormatter(); + rFieldFormatter.SetFormatter(pFormatter); + rFieldFormatter.SetValue( 1234.56789 ); + } + else + { + rFieldFormatter.TreatAsNumber(false); + rFieldFormatter.SetFormatter(nullptr); + m_xSpinButton->set_text( "" ); + } + + m_xEntry->set_text(m_xSpinButton->get_text()); + } + + OFormatSampleControl::OFormatSampleControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : OFormatSampleControl_Base(PropertyControlType::Unknown, std::move(xBuilder), std::move(xWidget), bReadOnly) + , m_xSpinButton(m_xBuilder->weld_formatted_spin_button("sample")) + , m_xEntry(m_xBuilder->weld_entry("entry")) + { + Formatter& rFieldFormatter = m_xSpinButton->GetFormatter(); + rFieldFormatter.TreatAsNumber(true); + rFieldFormatter.ClearMinValue(); + rFieldFormatter.ClearMaxValue(); + m_xEntry->connect_key_press(LINK(this, OFormatSampleControl, KeyInputHdl)); + } + + void SAL_CALL OFormatSampleControl::setValue( const Any& _rValue ) + { + sal_Int32 nFormatKey = 0; + if ( _rValue >>= nFormatKey ) + { + // else set the new format key, the text will be reformatted + Formatter& rFieldFormatter = m_xSpinButton->GetFormatter(); + rFieldFormatter.SetFormatKey(nFormatKey); + + SvNumberFormatter* pNF = rFieldFormatter.GetFormatter(); + const SvNumberformat* pEntry = pNF->GetEntry( nFormatKey ); + OSL_ENSURE( pEntry, "OFormatSampleControl::setValue: invalid format entry!" ); + + const bool bIsTextFormat = ( pEntry && pEntry->IsTextFormat() ); + if ( bIsTextFormat ) + m_xSpinButton->set_text( PcrRes( RID_STR_TEXT_FORMAT ) ); + else + rFieldFormatter.SetValue( pEntry ? getPreviewValue( *pEntry ) : 1234.56789 ); + } + else + m_xSpinButton->set_text( "" ); + + m_xEntry->set_text(m_xSpinButton->get_text()); + } + + double OFormatSampleControl::getPreviewValue( const SvNumberformat& i_rEntry ) + { + double nValue = 1234.56789; + switch ( i_rEntry.GetType() & ~SvNumFormatType::DEFINED ) + { + case SvNumFormatType::DATE: + { + Date aCurrentDate( Date::SYSTEM ); + static css::util::Date STANDARD_DB_DATE(30,12,1899); + nValue = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(aCurrentDate.GetDate()),STANDARD_DB_DATE); + } + break; + case SvNumFormatType::TIME: + case SvNumFormatType::DATETIME: + { + tools::Time aCurrentTime( tools::Time::SYSTEM ); + nValue = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(aCurrentTime.GetTime())); + } + break; + default: + break; + } + return nValue; + } + + + double OFormatSampleControl::getPreviewValue(SvNumberFormatter const * _pNF, sal_Int32 _nFormatKey) + { + const SvNumberformat* pEntry = _pNF->GetEntry(_nFormatKey); + DBG_ASSERT( pEntry, "OFormattedNumericControl::SetFormatDescription: invalid format key!" ); + double nValue = 1234.56789; + if ( pEntry ) + nValue = getPreviewValue( *pEntry ); + return nValue; + } + + Any SAL_CALL OFormatSampleControl::getValue() + { + Any aPropValue; + if ( !m_xSpinButton->get_text().isEmpty() ) + { + Formatter& rFieldFormatter = m_xSpinButton->GetFormatter(); + aPropValue <<= rFieldFormatter.GetValue(); + } + return aPropValue; + } + + Type SAL_CALL OFormatSampleControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + OFormattedNumericControl::OFormattedNumericControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : OFormattedNumericControl_Base(PropertyControlType::Unknown, std::move(xBuilder), std::move(xWidget), bReadOnly) + { + Formatter& rFormatter = getTypedControlWindow()->GetFormatter(); + rFormatter.TreatAsNumber(true); + rFormatter.ClearMinValue(); + rFormatter.ClearMaxValue(); + } + + OFormattedNumericControl::~OFormattedNumericControl() + { + } + + void SAL_CALL OFormattedNumericControl::setValue( const Any& _rValue ) + { + double nValue( 0 ); + if ( _rValue >>= nValue ) + getTypedControlWindow()->GetFormatter().SetValue(nValue); + else + getTypedControlWindow()->set_text(""); + } + + Any SAL_CALL OFormattedNumericControl::getValue() + { + Any aPropValue; + if ( !getTypedControlWindow()->get_text().isEmpty() ) + aPropValue <<= getTypedControlWindow()->GetFormatter().GetValue(); + return aPropValue; + } + + Type SAL_CALL OFormattedNumericControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + void OFormattedNumericControl::SetFormatDescription(const FormatDescription& rDesc) + { + bool bFallback = true; + + Formatter& rFieldFormatter = getTypedControlWindow()->GetFormatter(); + if (rDesc.pSupplier) + { + rFieldFormatter.TreatAsNumber(true); + + SvNumberFormatter* pFormatter = rDesc.pSupplier->GetNumberFormatter(); + if (pFormatter != rFieldFormatter.GetFormatter()) + rFieldFormatter.SetFormatter(pFormatter); + rFieldFormatter.SetFormatKey(rDesc.nKey); + + const SvNumberformat* pEntry = rFieldFormatter.GetFormatter()->GetEntry(rFieldFormatter.GetFormatKey()); + DBG_ASSERT( pEntry, "OFormattedNumericControl::SetFormatDescription: invalid format key!" ); + if ( pEntry ) + { + bFallback = false; + } + + } + + if ( bFallback ) + { + rFieldFormatter.TreatAsNumber(false); + rFieldFormatter.SetFormatter(nullptr); + getTypedControlWindow()->set_text(""); + } + } + + //= OFileUrlControl + OFileUrlControl::OFileUrlControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly) + : OFileUrlControl_Base(PropertyControlType::Unknown, std::move(xBuilder), std::move(xWidget), bReadOnly) + { + getTypedControlWindow()->DisableHistory(); + getTypedControlWindow()->SetPlaceHolder( PcrRes( RID_EMBED_IMAGE_PLACEHOLDER ) ) ; + } + + OFileUrlControl::~OFileUrlControl() + { + } + + void SAL_CALL OFileUrlControl::setValue(const Any& rValue) + { + OUString sURL; + SvtURLBox* pControlWindow = getTypedControlWindow(); + bool bSuccess = rValue >>= sURL; + if (bSuccess && GraphicObject::isGraphicObjectUniqueIdURL(sURL)) + sURL = pControlWindow->GetPlaceHolder(); + pControlWindow->set_entry_text(sURL); + } + + Any SAL_CALL OFileUrlControl::getValue() + { + Any aPropValue; + if (!getTypedControlWindow()->get_active_text().isEmpty()) + aPropValue <<= getTypedControlWindow()->GetURL(); + return aPropValue; + } + + Type SAL_CALL OFileUrlControl::getValueType() + { + return ::cppu::UnoType::get(); + } + + IMPL_LINK_NOARG(OFileUrlControl, URLModifiedHdl, weld::ComboBox&, void) + { + editChanged(); + } + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/usercontrol.hxx b/extensions/source/propctrlr/usercontrol.hxx new file mode 100644 index 000000000..86b53e7f1 --- /dev/null +++ b/extensions/source/propctrlr/usercontrol.hxx @@ -0,0 +1,148 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "commoncontrol.hxx" +#include +#include + +class SvNumberFormatsSupplierObj; + +namespace pcr +{ + //= OFormatSampleControl + typedef CommonBehaviourControl OFormatSampleControl_Base; + class OFormatSampleControl : public OFormatSampleControl_Base + { + private: + std::unique_ptr m_xSpinButton; + std::unique_ptr m_xEntry; + + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + + public: + OFormatSampleControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + virtual void SAL_CALL disposing() override + { + m_xEntry.reset(); + m_xSpinButton.reset(); + OFormatSampleControl_Base::disposing(); + } + + virtual void SetModifyHandler() override + { + m_xEntry->connect_focus_in( LINK( this, CommonBehaviourControlHelper, GetFocusHdl ) ); + m_xEntry->connect_focus_out( LINK( this, CommonBehaviourControlHelper, LoseFocusHdl ) ); + m_xSpinButton->connect_value_changed(LINK(this, CommonBehaviourControlHelper, FormattedModifiedHdl)); + m_xSpinButton->connect_changed(LINK(this, CommonBehaviourControlHelper, EditModifiedHdl)); + } + + void SetFormatSupplier(const SvNumberFormatsSupplierObj* pSupplier); + + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + + /** returns the default preview value for the given format key + * + * \param _pNF the number formatter + * \param _nFormatKey the format key + * \return current date or time or the value 1234.56789 + */ + static double getPreviewValue(SvNumberFormatter const * pNF, sal_Int32 nFormatKey); + + private: + static double getPreviewValue( const SvNumberformat& i_rEntry ); + }; + + //= FormatDescription + struct FormatDescription + { + SvNumberFormatsSupplierObj* pSupplier; + sal_Int32 nKey; + }; + + //= OFormattedNumericControl + typedef CommonBehaviourControl OFormattedNumericControl_Base; + class OFormattedNumericControl : public OFormattedNumericControl_Base + { + public: + OFormattedNumericControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + void SetFormatDescription( const FormatDescription& rDesc ); + + // make some FormattedField methods available + void SetDecimalDigits(sal_uInt16 nPrecision) { getTypedControlWindow()->GetFormatter().SetDecimalDigits(nPrecision); } + void SetDefaultValue(double dDef) { getTypedControlWindow()->GetFormatter().SetDefaultValue(dDef); } + + virtual void SetModifyHandler() override + { + OFormattedNumericControl_Base::SetModifyHandler(); + getTypedControlWindow()->connect_value_changed(LINK(this, CommonBehaviourControlHelper, FormattedModifiedHdl)); + getTypedControlWindow()->connect_changed(LINK(this, CommonBehaviourControlHelper, EditModifiedHdl)); + } + + virtual weld::Widget* getWidget() override { return getTypedControlWindow(); } + + protected: + virtual ~OFormattedNumericControl() override; + }; + + //= OFileUrlControl + typedef CommonBehaviourControl OFileUrlControl_Base; + class OFileUrlControl : public OFileUrlControl_Base + { + private: + DECL_LINK(URLModifiedHdl, weld::ComboBox&, void); + public: + OFileUrlControl(std::unique_ptr xWidget, std::unique_ptr xBuilder, bool bReadOnly); + + // XPropertyControl + virtual css::uno::Any SAL_CALL getValue() override; + virtual void SAL_CALL setValue( const css::uno::Any& _value ) override; + virtual css::uno::Type SAL_CALL getValueType() override; + + virtual void SetModifyHandler() override + { + OFileUrlControl_Base::SetModifyHandler(); + SvtURLBox* pControlWindow = getTypedControlWindow(); + // tdf#140239 and tdf#141084 don't notify that the control has changed content until focus-out + pControlWindow->connect_focus_out(LINK(this, CommonBehaviourControlHelper, LoseFocusHdl)); + pControlWindow->connect_changed(LINK(this, OFileUrlControl, URLModifiedHdl)); + } + + virtual weld::Widget* getWidget() override { return getTypedControlWindow()->getWidget(); } + + protected: + virtual ~OFileUrlControl() override; + }; + +} // namespace pcr + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/xsddatatypes.cxx b/extensions/source/propctrlr/xsddatatypes.cxx new file mode 100644 index 000000000..fdaea8e21 --- /dev/null +++ b/extensions/source/propctrlr/xsddatatypes.cxx @@ -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 . + */ + +#include "xsddatatypes.hxx" + +#include +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::xsd; + using namespace ::com::sun::star::beans; + + template< typename INTERFACE, typename ARGUMENT > + static ARGUMENT getSave( INTERFACE* pObject, ARGUMENT ( SAL_CALL INTERFACE::*pGetter )( ) ) + { + ARGUMENT aReturn = ARGUMENT(); + try + { + aReturn = (pObject->*pGetter)( ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType: getSave" ); + } + return aReturn; + } + + XSDDataType::XSDDataType( const Reference< XDataType >& _rxDataType ) + :m_xDataType( _rxDataType ) + { + DBG_ASSERT( m_xDataType.is(), "XSDDataType::XSDDataType: invalid UNO object!" ); + if ( m_xDataType.is() ) + m_xFacetInfo = m_xDataType->getPropertySetInfo(); + } + + + XSDDataType::~XSDDataType() + { + } + + + sal_Int16 XSDDataType::classify() const + { + sal_Int16 nTypeClass = DataTypeClass::STRING; + try + { + if ( m_xDataType.is() ) + nTypeClass = m_xDataType->getTypeClass(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::classify" ); + } + return nTypeClass; + } + + + bool XSDDataType::isBasicType() const + { + return getSave( m_xDataType.get(), &XDataType::getIsBasic ); + } + + + OUString XSDDataType::getName() const + { + return getSave( m_xDataType.get(), &XDataType::getName ); + } + + + void XSDDataType::setFacet( const OUString& _rFacetName, const Any& _rValue ) + { + try + { + m_xDataType->setPropertyValue( _rFacetName, _rValue ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::setFacet: caught an exception - sure this is the right data type class for this property?" ); + } + } + + + bool XSDDataType::hasFacet( const OUString& _rFacetName ) const + { + bool bReturn = false; + try + { + bReturn = m_xFacetInfo.is() && m_xFacetInfo->hasPropertyByName( _rFacetName ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::hasFacet" ); + } + return bReturn; + } + + Any XSDDataType::getFacet( const OUString& _rFacetName ) + { + Any aReturn; + try + { + aReturn = m_xDataType->getPropertyValue( _rFacetName ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::getFacet: caught an exception - sure this is the right data type class for this property?" ); + } + return aReturn; + } + + + namespace + { + void lcl_copyProperties( const Reference< XPropertySet >& _rxSource, const Reference< XPropertySet >& _rxDest ) + { + Reference< XPropertySetInfo > xSourceInfo; + if ( _rxSource.is() ) + xSourceInfo = _rxSource->getPropertySetInfo(); + Reference< XPropertySetInfo > xDestInfo; + if ( _rxDest.is() ) + xDestInfo = _rxDest->getPropertySetInfo(); + OSL_ENSURE( xSourceInfo.is() && xDestInfo.is(), "lcl_copyProperties: invalid property set( info)s!" ); + if ( !xSourceInfo.is() || !xDestInfo.is() ) + return; + + Sequence< Property > aProperties( xSourceInfo->getProperties() ); + const Property* pProperties = aProperties.getConstArray(); + const Property* pPropertiesEnd = pProperties + aProperties.getLength(); + for ( ; pProperties != pPropertiesEnd; ++pProperties ) + { + if ( xDestInfo->hasPropertyByName( pProperties->Name ) ) + _rxDest->setPropertyValue( pProperties->Name, _rxSource->getPropertyValue( pProperties->Name ) ); + } + } + } + + + void XSDDataType::copyFacetsFrom( const ::rtl::Reference< XSDDataType >& _pSourceType ) + { + OSL_ENSURE( _pSourceType.is(), "XSDDataType::copyFacetsFrom: invalid source type!" ); + if ( !_pSourceType.is() ) + return; + + try + { + Reference< XPropertySet > xSource = _pSourceType->getUnoDataType(); + Reference< XPropertySet > xDest = getUnoDataType(); + lcl_copyProperties( xSource, xDest ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDDataType::copyFacetsFrom" ); + } + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/xsddatatypes.hxx b/extensions/source/propctrlr/xsddatatypes.hxx new file mode 100644 index 000000000..0413d0250 --- /dev/null +++ b/extensions/source/propctrlr/xsddatatypes.hxx @@ -0,0 +1,89 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include +#include + +namespace com::sun::star { + namespace xsd { + class XDataType; + } + namespace beans { + class XPropertySetInfo; + } +} + + +namespace pcr +{ + + + //= XSDDataType + + class XSDDataType : public salhelper::SimpleReferenceObject + { + private: + css::uno::Reference< css::xsd::XDataType > + m_xDataType; + css::uno::Reference< css::beans::XPropertySetInfo > + m_xFacetInfo; + + public: + explicit XSDDataType( + const css::uno::Reference< css::xsd::XDataType >& _rxDataType + ); + + /// retrieves the underlying UNO component + const css::uno::Reference< css::xsd::XDataType >& + getUnoDataType() const { return m_xDataType; } + + /// classifies the data typ + sal_Int16 classify() const; + + // attribute access + OUString getName() const; + bool isBasicType() const; + + /// determines whether a given facet exists at the type + bool hasFacet( const OUString& _rFacetName ) const; + /// retrieves a facet value + css::uno::Any getFacet( const OUString& _rFacetName ); + /// sets a facet value + void setFacet( const OUString& _rFacetName, const css::uno::Any& _rFacetValue ); + + /** copies as much facets (values, respectively) from a give data type instance + */ + void copyFacetsFrom( const ::rtl::Reference< XSDDataType >& _pSourceType ); + + protected: + virtual ~XSDDataType() override; + + private: + XSDDataType( const XSDDataType& ) = delete; + XSDDataType& operator=( const XSDDataType& ) = delete; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/xsdvalidationhelper.cxx b/extensions/source/propctrlr/xsdvalidationhelper.cxx new file mode 100644 index 000000000..b5b96cc28 --- /dev/null +++ b/extensions/source/propctrlr/xsdvalidationhelper.cxx @@ -0,0 +1,406 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "xsdvalidationhelper.hxx" +#include "xsddatatypes.hxx" +#include "formstrings.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::xsd; + using namespace ::com::sun::star::util; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::xforms; + + namespace NumberFormat = ::com::sun::star::util::NumberFormat; + + + //= XSDValidationHelper + + + XSDValidationHelper::XSDValidationHelper( ::osl::Mutex& _rMutex, const Reference< XPropertySet >& _rxIntrospectee, const Reference< frame::XModel >& _rxContextDocument ) + :EFormsHelper( _rMutex, _rxIntrospectee, _rxContextDocument ) + ,m_bInspectingFormattedField( false ) + { + try + { + Reference< XPropertySetInfo > xPSI; + Reference< XServiceInfo > xSI( _rxIntrospectee, UNO_QUERY ); + if ( m_xControlModel.is() ) + xPSI = m_xControlModel->getPropertySetInfo(); + if ( xPSI.is() + && xPSI->hasPropertyByName( PROPERTY_FORMATKEY ) + && xPSI->hasPropertyByName( PROPERTY_FORMATSSUPPLIER ) + && xSI.is() + && xSI->supportsService( SERVICE_COMPONENT_FORMATTEDFIELD ) + ) + m_bInspectingFormattedField = true; + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION("extensions.propctrlr", + "caught an exception while examining the introspectee!"); + } + } + + + void XSDValidationHelper::getAvailableDataTypeNames( std::vector< OUString >& /* [out] */ _rNames ) const + { + _rNames.resize( 0 ); + + try + { + Reference< XDataTypeRepository > xRepository = getDataTypeRepository(); + if ( xRepository.is() ) + { + const Sequence aElements = xRepository->getElementNames(); + + _rNames.resize( aElements.getLength() ); + std::copy( aElements.begin(), aElements.end(), _rNames.begin() ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::getAvailableDataTypeNames" ); + } + } + + + Reference< XDataTypeRepository > XSDValidationHelper::getDataTypeRepository() const + { + Reference< XDataTypeRepository > xRepository; + + Reference< xforms::XModel > xModel( getCurrentFormModel( ) ); + if ( xModel.is() ) + xRepository = xModel->getDataTypeRepository(); + + return xRepository; + } + + + Reference< XDataTypeRepository > XSDValidationHelper::getDataTypeRepository( const OUString& _rModelName ) const + { + Reference< XDataTypeRepository > xRepository; + + Reference< xforms::XModel > xModel( getFormModelByName( _rModelName ) ); + if ( xModel.is() ) + xRepository = xModel->getDataTypeRepository(); + + return xRepository; + } + + + Reference< XDataType > XSDValidationHelper::getDataType( const OUString& _rName ) const + { + Reference< XDataType > xDataType; + + if ( !_rName.isEmpty() ) + { + Reference< XDataTypeRepository > xRepository = getDataTypeRepository(); + if ( xRepository.is() ) + xDataType = xRepository->getDataType( _rName ); + } + return xDataType; + } + + + OUString XSDValidationHelper::getValidatingDataTypeName( ) const + { + OUString sDataTypeName; + try + { + Reference< XPropertySet > xBinding( getCurrentBinding() ); + // it's allowed here to not (yet) have a binding + if ( xBinding.is() ) + { + OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_XSD_DATA_TYPE ) >>= sDataTypeName ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::getValidatingDataTypeName" ); + } + return sDataTypeName; + } + + + ::rtl::Reference< XSDDataType > XSDValidationHelper::getDataTypeByName( const OUString& _rName ) const + { + ::rtl::Reference< XSDDataType > pReturn; + + try + { + Reference< XDataType > xValidatedAgainst; + + if ( !_rName.isEmpty() ) + xValidatedAgainst = getDataType( _rName ); + + if ( xValidatedAgainst.is() ) + pReturn = new XSDDataType( xValidatedAgainst ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::getDataTypeByName" ); + } + + return pReturn; + } + + + ::rtl::Reference< XSDDataType > XSDValidationHelper::getValidatingDataType( ) const + { + return getDataTypeByName( getValidatingDataTypeName() ); + } + + + bool XSDValidationHelper::cloneDataType( const ::rtl::Reference< XSDDataType >& _pDataType, const OUString& _rNewName ) const + { + OSL_ENSURE( _pDataType.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type!" ); + if ( !_pDataType.is() ) + return false; + + try + { + Reference< XDataTypeRepository > xRepository( getDataTypeRepository() ); + OSL_ENSURE( xRepository.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type repository!" ); + if ( !xRepository.is() ) + return false; + + Reference< XDataType > xDataType( _pDataType->getUnoDataType() ); + OSL_ENSURE( xDataType.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type (II)!" ); + if ( !xDataType.is() ) + return false; + + xRepository->cloneDataType( xDataType->getName(), _rNewName ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::cloneDataType" ); + } + return true; + } + + + bool XSDValidationHelper::removeDataTypeFromRepository( const OUString& _rName ) const + { + try + { + Reference< XDataTypeRepository > xRepository( getDataTypeRepository() ); + OSL_ENSURE( xRepository.is(), "XSDValidationHelper::removeDataTypeFromRepository: invalid data type repository!" ); + if ( !xRepository.is() ) + return false; + + if ( !xRepository->hasByName( _rName ) ) + { + OSL_FAIL( "XSDValidationHelper::removeDataTypeFromRepository: invalid repository and/or data type!" ); + return false; + } + + xRepository->revokeDataType( _rName ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::removeDataTypeFromRepository" ); + return false; + } + return true; + } + + + void XSDValidationHelper::setValidatingDataTypeByName( const OUString& _rName ) const + { + try + { + Reference< XPropertySet > xBinding( getCurrentBinding() ); + OSL_ENSURE( xBinding.is(), "XSDValidationHelper::setValidatingDataTypeByName: no active binding - how this?" ); + + if ( xBinding.is() ) + { + // get the old data type - this is necessary for notifying property changes + OUString sOldDataTypeName; + OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_XSD_DATA_TYPE ) >>= sOldDataTypeName ); + Reference< XPropertySet > xOldType; + try { + xOldType = getDataType( sOldDataTypeName ); + } catch( const Exception& ) { } + + // set the new data type name + xBinding->setPropertyValue( PROPERTY_XSD_DATA_TYPE, Any( _rName ) ); + + // retrieve the new data type object + Reference< XPropertySet > xNewType = getDataType( _rName ); + + // fire any changes in the properties which result from this new type + std::set< OUString > aFilter; aFilter.insert( PROPERTY_NAME ); + firePropertyChanges( xOldType, xNewType, aFilter ); + + // fire the change in the Data Type property + OUString sNewDataTypeName; + OSL_VERIFY( xBinding->getPropertyValue( PROPERTY_XSD_DATA_TYPE ) >>= sNewDataTypeName ); + firePropertyChange( PROPERTY_XSD_DATA_TYPE, Any( sOldDataTypeName ), Any( sNewDataTypeName ) ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("extensions.propctrlr"); + } + } + + + void XSDValidationHelper::copyDataType( const OUString& _rFromModel, const OUString& _rToModel, + const OUString& _rDataTypeName ) const + { + if ( _rFromModel == _rToModel ) + // nothing to do (me thinks) + return; + + try + { + Reference< XDataTypeRepository > xFromRepository, xToRepository; + if ( !_rFromModel.isEmpty() ) + xFromRepository = getDataTypeRepository( _rFromModel ); + if ( !_rToModel.isEmpty() ) + xToRepository = getDataTypeRepository( _rToModel ); + + if ( !xFromRepository.is() || !xToRepository.is() ) + return; + + if ( !xFromRepository->hasByName( _rDataTypeName ) || xToRepository->hasByName( _rDataTypeName ) ) + // not existent in the source, or already existent (by name) in the destination + return; + + // determine the built-in type belonging to the source type + ::rtl::Reference< XSDDataType > pSourceType = new XSDDataType( xFromRepository->getDataType( _rDataTypeName ) ); + OUString sTargetBaseType = getBasicTypeNameForClass( pSourceType->classify(), xToRepository ); + + // create the target type + Reference< XDataType > xTargetType = xToRepository->cloneDataType( sTargetBaseType, _rDataTypeName ); + ::rtl::Reference< XSDDataType > pTargetType = new XSDDataType( xTargetType ); + + // copy the facets + pTargetType->copyFacetsFrom( pSourceType ); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::copyDataType" ); + } + } + + + void XSDValidationHelper::findDefaultFormatForIntrospectee() + { + try + { + ::rtl::Reference< XSDDataType > xDataType = getValidatingDataType(); + if ( xDataType.is() ) + { + // find a NumberFormat type corresponding to the DataTypeClass + sal_Int16 nNumberFormatType = NumberFormat::NUMBER; + switch ( xDataType->classify() ) + { + case DataTypeClass::DATETIME: + nNumberFormatType = NumberFormat::DATETIME; + break; + case DataTypeClass::DATE: + nNumberFormatType = NumberFormat::DATE; + break; + case DataTypeClass::TIME: + nNumberFormatType = NumberFormat::TIME; + break; + case DataTypeClass::STRING: + case DataTypeClass::anyURI: + case DataTypeClass::QName: + case DataTypeClass::NOTATION: + nNumberFormatType = NumberFormat::TEXT; + break; + } + + // get the number formatter from the introspectee + Reference< XNumberFormatsSupplier > xSupplier; + Reference< XNumberFormatTypes > xFormatTypes; + OSL_VERIFY( m_xControlModel->getPropertyValue( PROPERTY_FORMATSSUPPLIER ) >>= xSupplier ); + if ( xSupplier.is() ) + xFormatTypes.set(xSupplier->getNumberFormats(), css::uno::UNO_QUERY); + OSL_ENSURE( xFormatTypes.is(), "XSDValidationHelper::findDefaultFormatForIntrospectee: no number formats for the introspectee!" ); + if ( !xFormatTypes.is() ) + return; + + // and the standard format for the given NumberFormat type + sal_Int32 nDesiredFormat = xFormatTypes->getStandardFormat( nNumberFormatType, SvtSysLocale().GetLanguageTag().getLocale() ); + + // set this at the introspectee + m_xControlModel->setPropertyValue( PROPERTY_FORMATKEY, Any( nDesiredFormat ) ); + } + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::findDefaultFormatForIntrospectee" ); + } + } + + + OUString XSDValidationHelper::getBasicTypeNameForClass( sal_Int16 _nClass ) const + { + return getBasicTypeNameForClass( _nClass, getDataTypeRepository() ); + } + + + OUString XSDValidationHelper::getBasicTypeNameForClass( sal_Int16 _nClass, const Reference< XDataTypeRepository >& _rxRepository ) + { + OUString sReturn; + OSL_ENSURE( _rxRepository.is(), "XSDValidationHelper::getBasicTypeNameForClass: invalid repository!" ); + if ( !_rxRepository.is() ) + return sReturn; + + try + { + Reference< XDataType > xDataType = _rxRepository->getBasicDataType( _nClass ); + OSL_ENSURE( xDataType.is(), "XSDValidationHelper::getBasicTypeNameForClass: invalid data type returned!" ); + if ( xDataType.is() ) + sReturn = xDataType->getName(); + } + catch( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "extensions.propctrlr", "XSDValidationHelper::getBasicTypeNameForClass" ); + } + + return sReturn; + } + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/xsdvalidationhelper.hxx b/extensions/source/propctrlr/xsdvalidationhelper.hxx new file mode 100644 index 000000000..2a77ff584 --- /dev/null +++ b/extensions/source/propctrlr/xsdvalidationhelper.hxx @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "eformshelper.hxx" +#include "xsddatatypes.hxx" + +#include +#include +#include + + +namespace pcr +{ + + + class XSDDataType; + + //= XSDValidationHelper + + class XSDValidationHelper : public EFormsHelper + { + private: + bool m_bInspectingFormattedField; + public: + bool isInspectingFormattedField() const { return m_bInspectingFormattedField; } + + public: + XSDValidationHelper( + ::osl::Mutex& _rMutex, + const css::uno::Reference< css::beans::XPropertySet >& _rxIntrospectee, + const css::uno::Reference< css::frame::XModel >& _rxContextDocument + ); + + /** retrieves the names of all XForms models in the document the control lives in + */ + void getAvailableDataTypeNames( std::vector< OUString >& /* [out] */ _rNames ) const; + + /** retrieves a particular data type given by name + */ + ::rtl::Reference< XSDDataType > + getDataTypeByName( const OUString& _rName ) const; + + /** retrieves the DataType instance which the control model is currently validated against + + If there is a binding set at our control model, which at the same time acts as validator, + and if this validator is bound to an XDataType, then this data type is retrieved here. + */ + ::rtl::Reference< XSDDataType > + getValidatingDataType( ) const; + + /** retrieves the name of the data type which the control model is currently validated against + + @seealso getValidatingDataType + */ + OUString + getValidatingDataTypeName( ) const; + + /** binds the validator to a new data type + + To be called with an active binding only. + */ + void setValidatingDataTypeByName( const OUString& _rName ) const; + + /** removes the data type given by name from the data type repository + */ + bool removeDataTypeFromRepository( const OUString& _rName ) const; + + /** creates a new data type, which is a clone of an existing data type + */ + bool cloneDataType( const ::rtl::Reference< XSDDataType >& _pDataType, const OUString& _rNewName ) const; + + /** retrieves the name of the basic data type which has the given class + */ + OUString + getBasicTypeNameForClass( sal_Int16 _eClass ) const; + + /** copy a data type from one model to another + + If a data type with the given name already exists in the target model, then nothing + happens. In particular, the facets of the data type are not copied. + */ + void copyDataType( const OUString& _rFromModel, const OUString& _rToModel, + const OUString& _rDataTypeName ) const; + + /** finds (and sets) a default format for the formatted field we're inspecting, + according to the current data type the control value is evaluated against + */ + void findDefaultFormatForIntrospectee(); + + private: + /** retrieves the data type repository associated with the current model + */ + css::uno::Reference< css::xforms::XDataTypeRepository > + getDataTypeRepository() const; + + /** retrieves the data type repository associated with any model + */ + css::uno::Reference< css::xforms::XDataTypeRepository > + getDataTypeRepository( const OUString& _rModelName ) const; + + /** retrieves the data type object for the given name + */ + css::uno::Reference< css::xsd::XDataType > + getDataType( const OUString& _rName ) const; + + /** retrieves the name of the basic data type which has the given class, in the given repository + */ + static OUString + getBasicTypeNameForClass( + sal_Int16 _nClass, + const css::uno::Reference< css::xforms::XDataTypeRepository >& _rxRepository + ); + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/xsdvalidationpropertyhandler.cxx b/extensions/source/propctrlr/xsdvalidationpropertyhandler.cxx new file mode 100644 index 000000000..1f8351cdb --- /dev/null +++ b/extensions/source/propctrlr/xsdvalidationpropertyhandler.cxx @@ -0,0 +1,673 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "xsdvalidationpropertyhandler.hxx" +#include "formstrings.hxx" +#include "formmetadata.hxx" +#include "xsddatatypes.hxx" +#include "modulepcr.hxx" +#include +#include +#include "newdatatype.hxx" +#include "xsdvalidationhelper.hxx" +#include "pcrcommon.hxx" +#include "handlerhelper.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace pcr +{ + + + using namespace ::com::sun::star; + using namespace ::com::sun::star::uno; + using namespace ::com::sun::star::lang; + using namespace ::com::sun::star::beans; + using namespace ::com::sun::star::xforms; + using namespace ::com::sun::star::xsd; + using namespace ::com::sun::star::script; + using namespace ::com::sun::star::inspection; + + using ::com::sun::star::beans::PropertyAttribute::MAYBEVOID; + + + //= XSDValidationPropertyHandler + + XSDValidationPropertyHandler::XSDValidationPropertyHandler( const Reference< XComponentContext >& _rxContext ) + :PropertyHandlerComponent( _rxContext ) + { + } + + + XSDValidationPropertyHandler::~XSDValidationPropertyHandler() + { + } + + + OUString XSDValidationPropertyHandler::getImplementationName( ) + { + return "com.sun.star.comp.extensions.XSDValidationPropertyHandler"; + } + + + Sequence< OUString > XSDValidationPropertyHandler::getSupportedServiceNames( ) + { + return{ "com.sun.star.form.inspection.XSDValidationPropertyHandler" }; + } + + + Any SAL_CALL XSDValidationPropertyHandler::getPropertyValue( const OUString& _rPropertyName ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + OSL_ENSURE(m_pHelper, "XSDValidationPropertyHandler::getPropertyValue: inconsistency!"); + // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties + + Any aReturn; + ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType(); + switch ( nPropId ) + { + // common facets + case PROPERTY_ID_XSD_DATA_TYPE: aReturn = pType.is() ? pType->getFacet( PROPERTY_NAME ) : Any( OUString() ); break; + case PROPERTY_ID_XSD_WHITESPACES:aReturn = pType.is() ? pType->getFacet( PROPERTY_XSD_WHITESPACES ) : Any( WhiteSpaceTreatment::Preserve ); break; + case PROPERTY_ID_XSD_PATTERN: aReturn = pType.is() ? pType->getFacet( PROPERTY_XSD_PATTERN ) : Any( OUString() ); break; + + // all other properties are simply forwarded, if they exist at the given type + default: + { + if ( pType.is() && pType->hasFacet( _rPropertyName ) ) + aReturn = pType->getFacet( _rPropertyName ); + } + break; + } + + return aReturn; + } + + + void SAL_CALL XSDValidationPropertyHandler::setPropertyValue( const OUString& _rPropertyName, const Any& _rValue ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + OSL_ENSURE(m_pHelper, "XSDValidationPropertyHandler::getPropertyValue: inconsistency!"); + // if we survived impl_getPropertyId_throwUnknownProperty, we should have a helper, since no helper implies no properties + + if ( PROPERTY_ID_XSD_DATA_TYPE == nPropId ) + { + OUString sTypeName; + OSL_VERIFY( _rValue >>= sTypeName ); + m_pHelper->setValidatingDataTypeByName( sTypeName ); + impl_setContextDocumentModified_nothrow(); + return; + } + + ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType(); + if ( !pType.is() ) + { + OSL_FAIL( "XSDValidationPropertyHandler::setPropertyValue: you're trying to set a type facet, without a current type!" ); + return; + } + + pType->setFacet( _rPropertyName, _rValue ); + impl_setContextDocumentModified_nothrow(); + } + + + void XSDValidationPropertyHandler::onNewComponent() + { + PropertyHandlerComponent::onNewComponent(); + + Reference< frame::XModel > xDocument( impl_getContextDocument_nothrow() ); + DBG_ASSERT( xDocument.is(), "XSDValidationPropertyHandler::onNewComponent: no document!" ); + if ( EFormsHelper::isEForm( xDocument ) ) + m_pHelper.reset( new XSDValidationHelper( m_aMutex, m_xComponent, xDocument ) ); + else + m_pHelper.reset(); + } + + + Sequence< Property > XSDValidationPropertyHandler::doDescribeSupportedProperties() const + { + std::vector< Property > aProperties; + + if (m_pHelper) + { + bool bAllowBinding = m_pHelper->canBindToAnyDataType(); + + if ( bAllowBinding ) + { + aProperties.reserve( 12 ); + + addStringPropertyDescription( aProperties, PROPERTY_XSD_DATA_TYPE ); + addInt16PropertyDescription ( aProperties, PROPERTY_XSD_WHITESPACES ); + addStringPropertyDescription( aProperties, PROPERTY_XSD_PATTERN ); + + // string facets + addInt32PropertyDescription( aProperties, PROPERTY_XSD_LENGTH, MAYBEVOID ); + addInt32PropertyDescription( aProperties, PROPERTY_XSD_MIN_LENGTH, MAYBEVOID ); + addInt32PropertyDescription( aProperties, PROPERTY_XSD_MAX_LENGTH, MAYBEVOID ); + + // decimal facets + addInt32PropertyDescription( aProperties, PROPERTY_XSD_TOTAL_DIGITS, MAYBEVOID ); + addInt32PropertyDescription( aProperties, PROPERTY_XSD_FRACTION_DIGITS, MAYBEVOID ); + + // facets for different types + addInt16PropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_INT, MAYBEVOID ); + addInt16PropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_INT, MAYBEVOID ); + addInt16PropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_INT, MAYBEVOID ); + addInt16PropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_INT, MAYBEVOID ); + addDoublePropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_DOUBLE, MAYBEVOID ); + addDoublePropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_DOUBLE, MAYBEVOID ); + addDoublePropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_DOUBLE, MAYBEVOID ); + addDoublePropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_DOUBLE, MAYBEVOID ); + addDatePropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_DATE, MAYBEVOID ); + addDatePropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_DATE, MAYBEVOID ); + addDatePropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_DATE, MAYBEVOID ); + addDatePropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_DATE, MAYBEVOID ); + addTimePropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_TIME, MAYBEVOID ); + addTimePropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_TIME, MAYBEVOID ); + addTimePropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_TIME, MAYBEVOID ); + addTimePropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_TIME, MAYBEVOID ); + addDateTimePropertyDescription( aProperties, PROPERTY_XSD_MAX_INCLUSIVE_DATE_TIME, MAYBEVOID ); + addDateTimePropertyDescription( aProperties, PROPERTY_XSD_MAX_EXCLUSIVE_DATE_TIME, MAYBEVOID ); + addDateTimePropertyDescription( aProperties, PROPERTY_XSD_MIN_INCLUSIVE_DATE_TIME, MAYBEVOID ); + addDateTimePropertyDescription( aProperties, PROPERTY_XSD_MIN_EXCLUSIVE_DATE_TIME, MAYBEVOID ); + } + } + + return comphelper::containerToSequence( aProperties ); + } + + + Sequence< OUString > SAL_CALL XSDValidationPropertyHandler::getSupersededProperties( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + + std::vector< OUString > aSuperfluous; + if (m_pHelper) + { + aSuperfluous.push_back( OUString(PROPERTY_CONTROLSOURCE) ); + aSuperfluous.push_back( OUString(PROPERTY_EMPTY_IS_NULL) ); + aSuperfluous.push_back( OUString(PROPERTY_FILTERPROPOSAL) ); + aSuperfluous.push_back( OUString(PROPERTY_LISTSOURCETYPE) ); + aSuperfluous.push_back( OUString(PROPERTY_LISTSOURCE) ); + aSuperfluous.push_back( OUString(PROPERTY_BOUNDCOLUMN) ); + + bool bAllowBinding = m_pHelper->canBindToAnyDataType(); + + if ( bAllowBinding ) + { + aSuperfluous.push_back( OUString(PROPERTY_MAXTEXTLEN) ); + aSuperfluous.push_back( OUString(PROPERTY_VALUEMIN) ); + aSuperfluous.push_back( OUString(PROPERTY_VALUEMAX) ); + aSuperfluous.push_back( OUString(PROPERTY_DECIMAL_ACCURACY) ); + aSuperfluous.push_back( OUString(PROPERTY_TIMEMIN) ); + aSuperfluous.push_back( OUString(PROPERTY_TIMEMAX) ); + aSuperfluous.push_back( OUString(PROPERTY_DATEMIN) ); + aSuperfluous.push_back( OUString(PROPERTY_DATEMAX) ); + aSuperfluous.push_back( OUString(PROPERTY_EFFECTIVE_MIN) ); + aSuperfluous.push_back( OUString(PROPERTY_EFFECTIVE_MAX) ); + } + } + + return comphelper::containerToSequence( aSuperfluous ); + } + + + Sequence< OUString > SAL_CALL XSDValidationPropertyHandler::getActuatingProperties( ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + std::vector< OUString > aInterestedInActuations; + if (m_pHelper) + { + aInterestedInActuations.push_back( OUString(PROPERTY_XSD_DATA_TYPE) ); + aInterestedInActuations.push_back( OUString(PROPERTY_XML_DATA_MODEL) ); + } + return comphelper::containerToSequence( aInterestedInActuations ); + } + + + namespace + { + void showPropertyUI( const Reference< XObjectInspectorUI >& _rxInspectorUI, const OUString& _rPropertyName, bool _bShow ) + { + if ( _bShow ) + _rxInspectorUI->showPropertyUI( _rPropertyName ); + else + _rxInspectorUI->hidePropertyUI( _rPropertyName ); + } + } + + + LineDescriptor SAL_CALL XSDValidationPropertyHandler::describePropertyLine( const OUString& _rPropertyName, + const Reference< XPropertyControlFactory >& _rxControlFactory ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if ( !_rxControlFactory.is() ) + throw NullPointerException(); + if (!m_pHelper) + throw RuntimeException(); + + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + LineDescriptor aDescriptor; + if ( nPropId != PROPERTY_ID_XSD_DATA_TYPE ) + aDescriptor.IndentLevel = 1; + + // collect some information about the to-be-created control + sal_Int16 nControlType = PropertyControlType::TextField; + std::vector< OUString > aListEntries; + Optional< double > aMinValue( false, 0 ); + Optional< double > aMaxValue( false, 0 ); + + switch ( nPropId ) + { + case PROPERTY_ID_XSD_DATA_TYPE: + nControlType = PropertyControlType::ListBox; + + implGetAvailableDataTypeNames( aListEntries ); + + aDescriptor.PrimaryButtonId = UID_PROP_ADD_DATA_TYPE; + aDescriptor.SecondaryButtonId = UID_PROP_REMOVE_DATA_TYPE; + aDescriptor.HasPrimaryButton = aDescriptor.HasSecondaryButton = true; + aDescriptor.PrimaryButtonImageURL = "private:graphicrepository/extensions/res/buttonplus.png"; + aDescriptor.SecondaryButtonImageURL = "private:graphicrepository/extensions/res/buttonminus.png"; + break; + + case PROPERTY_ID_XSD_WHITESPACES: + { + nControlType = PropertyControlType::ListBox; + aListEntries = m_pInfoService->getPropertyEnumRepresentations( PROPERTY_ID_XSD_WHITESPACES ); + } + break; + + case PROPERTY_ID_XSD_PATTERN: + nControlType = PropertyControlType::TextField; + break; + + case PROPERTY_ID_XSD_LENGTH: + case PROPERTY_ID_XSD_MIN_LENGTH: + case PROPERTY_ID_XSD_MAX_LENGTH: + nControlType = PropertyControlType::NumericField; + break; + + case PROPERTY_ID_XSD_TOTAL_DIGITS: + case PROPERTY_ID_XSD_FRACTION_DIGITS: + nControlType = PropertyControlType::NumericField; + break; + + case PROPERTY_ID_XSD_MAX_INCLUSIVE_INT: + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_INT: + case PROPERTY_ID_XSD_MIN_INCLUSIVE_INT: + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_INT: + { + nControlType = PropertyControlType::NumericField; + + // handle limits for various 'INT' types according to + // their actual semantics (year, month, day) + + ::rtl::Reference< XSDDataType > xDataType( m_pHelper->getValidatingDataType() ); + sal_Int16 nTypeClass = xDataType.is() ? xDataType->classify() : DataTypeClass::STRING; + + aMinValue.IsPresent = aMaxValue.IsPresent = true; + aMinValue.Value = DataTypeClass::gYear == nTypeClass ? 0 : 1; + aMaxValue.Value = std::numeric_limits< sal_Int32 >::max(); + if ( DataTypeClass::gMonth == nTypeClass ) + aMaxValue.Value = 12; + else if ( DataTypeClass::gDay == nTypeClass ) + aMaxValue.Value = 31; + } + break; + + case PROPERTY_ID_XSD_MAX_INCLUSIVE_DOUBLE: + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DOUBLE: + case PROPERTY_ID_XSD_MIN_INCLUSIVE_DOUBLE: + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DOUBLE: + nControlType = PropertyControlType::NumericField; + // TODO/eForms: do we have "auto-digits"? + break; + + case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE: + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE: + case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE: + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE: + nControlType = PropertyControlType::DateField; + break; + + case PROPERTY_ID_XSD_MAX_INCLUSIVE_TIME: + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_TIME: + case PROPERTY_ID_XSD_MIN_INCLUSIVE_TIME: + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_TIME: + nControlType = PropertyControlType::TimeField; + break; + + case PROPERTY_ID_XSD_MAX_INCLUSIVE_DATE_TIME: + case PROPERTY_ID_XSD_MAX_EXCLUSIVE_DATE_TIME: + case PROPERTY_ID_XSD_MIN_INCLUSIVE_DATE_TIME: + case PROPERTY_ID_XSD_MIN_EXCLUSIVE_DATE_TIME: + nControlType = PropertyControlType::DateTimeField; + break; + + default: + OSL_FAIL( "XSDValidationPropertyHandler::describePropertyLine: cannot handle this property!" ); + break; + } + + switch ( nControlType ) + { + case PropertyControlType::ListBox: + aDescriptor.Control = PropertyHandlerHelper::createListBoxControl( _rxControlFactory, std::move(aListEntries), false, false ); + break; + case PropertyControlType::NumericField: + aDescriptor.Control = PropertyHandlerHelper::createNumericControl( _rxControlFactory, 0, aMinValue, aMaxValue ); + break; + default: + aDescriptor.Control = _rxControlFactory->createPropertyControl( nControlType, false ); + break; + } + + aDescriptor.Category = "Data"; + aDescriptor.DisplayName = m_pInfoService->getPropertyTranslation( nPropId ); + aDescriptor.HelpURL = HelpIdUrl::getHelpURL( m_pInfoService->getPropertyHelpId( nPropId ) ); + + return aDescriptor; + } + + + InteractiveSelectionResult SAL_CALL XSDValidationPropertyHandler::onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, Any& /*_rData*/, const Reference< XObjectInspectorUI >& _rxInspectorUI ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + OSL_ENSURE(m_pHelper, "XSDValidationPropertyHandler::onInteractivePropertySelection: we " + "don't have any SupportedProperties!"); + if (!m_pHelper) + return InteractiveSelectionResult_Cancelled; + + PropertyId nPropId( impl_getPropertyId_throwUnknownProperty( _rPropertyName ) ); + + switch ( nPropId ) + { + case PROPERTY_ID_XSD_DATA_TYPE: + { + if ( _bPrimary ) + { + OUString sNewDataTypeName; + if ( implPrepareCloneDataCurrentType( sNewDataTypeName ) ) + { + implDoCloneCurrentDataType( sNewDataTypeName ); + return InteractiveSelectionResult_Success; + } + } + else + return implPrepareRemoveCurrentDataType() && implDoRemoveCurrentDataType() ? InteractiveSelectionResult_Success : InteractiveSelectionResult_Cancelled; + } + break; + + default: + OSL_FAIL( "XSDValidationPropertyHandler::onInteractivePropertySelection: unexpected property to build a dedicated UI!" ); + break; + } + return InteractiveSelectionResult_Cancelled; + } + + + void SAL_CALL XSDValidationPropertyHandler::addPropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyHandlerComponent::addPropertyChangeListener( _rxListener ); + if (m_pHelper) + m_pHelper->registerBindingListener( _rxListener ); + } + + + void SAL_CALL XSDValidationPropertyHandler::removePropertyChangeListener( const Reference< XPropertyChangeListener >& _rxListener ) + { + ::osl::MutexGuard aGuard( m_aMutex ); + if (m_pHelper) + m_pHelper->revokeBindingListener( _rxListener ); + PropertyHandlerComponent::removePropertyChangeListener( _rxListener ); + } + + + bool XSDValidationPropertyHandler::implPrepareCloneDataCurrentType( OUString& _rNewName ) + { + OSL_PRECOND( + m_pHelper, + "XSDValidationPropertyHandler::implPrepareCloneDataCurrentType: this will crash!"); + + ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType(); + if ( !pType.is() ) + { + OSL_FAIL( "XSDValidationPropertyHandler::implPrepareCloneDataCurrentType: invalid current data type!" ); + return false; + } + + std::vector< OUString > aExistentNames; + m_pHelper->getAvailableDataTypeNames( aExistentNames ); + + NewDataTypeDialog aDialog( nullptr, pType->getName(), aExistentNames ); // TODO/eForms: proper parent + if (aDialog.run() != RET_OK) + return false; + + _rNewName = aDialog.GetName(); + return true; + } + + + void XSDValidationPropertyHandler::implDoCloneCurrentDataType( const OUString& _rNewName ) + { + OSL_PRECOND(m_pHelper, + "XSDValidationPropertyHandler::implDoCloneCurrentDataType: this will crash!"); + + ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType(); + if ( !pType.is() ) + return; + + if ( !m_pHelper->cloneDataType( pType, _rNewName ) ) + return; + + m_pHelper->setValidatingDataTypeByName( _rNewName ); + } + + bool XSDValidationPropertyHandler::implPrepareRemoveCurrentDataType() + { + OSL_PRECOND( + m_pHelper, + "XSDValidationPropertyHandler::implPrepareRemoveCurrentDataType: this will crash!"); + + ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType(); + if ( !pType.is() ) + { + OSL_FAIL( "XSDValidationPropertyHandler::implPrepareRemoveCurrentDataType: invalid current data type!" ); + return false; + } + + // confirmation message + OUString sConfirmation( PcrRes( RID_STR_CONFIRM_DELETE_DATA_TYPE ) ); + sConfirmation = sConfirmation.replaceFirst( "#type#", pType->getName() ); + + std::unique_ptr xQueryBox(Application::CreateMessageDialog(nullptr, // TODO/eForms: proper parent + VclMessageType::Question, VclButtonsType::YesNo, + sConfirmation)); + return xQueryBox->run() == RET_YES; + } + + bool XSDValidationPropertyHandler::implDoRemoveCurrentDataType() + { + OSL_PRECOND(m_pHelper, + "XSDValidationPropertyHandler::implDoRemoveCurrentDataType: this will crash!"); + + ::rtl::Reference< XSDDataType > pType = m_pHelper->getValidatingDataType(); + if ( !pType.is() ) + return false; + + // set a new data type at the binding, which is the "basic" type for the one + // we are going to delete + // (do this before the actual deletion, so the old type is still valid for property change + // notifications) + m_pHelper->setValidatingDataTypeByName( m_pHelper->getBasicTypeNameForClass( pType->classify() ) ); + // now remove the type + m_pHelper->removeDataTypeFromRepository( pType->getName() ); + + return true; + } + + + void SAL_CALL XSDValidationPropertyHandler::actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const Any& _rNewValue, const Any& _rOldValue, const Reference< XObjectInspectorUI >& _rxInspectorUI, sal_Bool _bFirstTimeInit ) + { + if ( !_rxInspectorUI.is() ) + throw NullPointerException(); + + ::osl::MutexGuard aGuard( m_aMutex ); + PropertyId nActuatingPropId( impl_getPropertyId_throwRuntime( _rActuatingPropertyName ) ); + if (!m_pHelper) + throw RuntimeException(); + // if we survived impl_getPropertyId_throwRuntime, we should have a helper, since no helper implies no properties + + switch ( nActuatingPropId ) + { + case PROPERTY_ID_XSD_DATA_TYPE: + { + ::rtl::Reference< XSDDataType > xDataType( m_pHelper->getValidatingDataType() ); + + // is removal of this type possible? + bool bIsBasicType = xDataType.is() && xDataType->isBasicType(); + _rxInspectorUI->enablePropertyUIElements( PROPERTY_XSD_DATA_TYPE, PropertyLineElement::PrimaryButton, xDataType.is() ); + _rxInspectorUI->enablePropertyUIElements( PROPERTY_XSD_DATA_TYPE, PropertyLineElement::SecondaryButton, xDataType.is() && !bIsBasicType ); + + + // show the facets which are available at the data type + OUString aFacets[] = { + OUString(PROPERTY_XSD_WHITESPACES), OUString(PROPERTY_XSD_PATTERN), + OUString(PROPERTY_XSD_LENGTH), OUString(PROPERTY_XSD_MIN_LENGTH), OUString(PROPERTY_XSD_MAX_LENGTH), OUString(PROPERTY_XSD_TOTAL_DIGITS), + OUString(PROPERTY_XSD_FRACTION_DIGITS), + OUString(PROPERTY_XSD_MAX_INCLUSIVE_INT), + OUString(PROPERTY_XSD_MAX_EXCLUSIVE_INT), + OUString(PROPERTY_XSD_MIN_INCLUSIVE_INT), + OUString(PROPERTY_XSD_MIN_EXCLUSIVE_INT), + OUString(PROPERTY_XSD_MAX_INCLUSIVE_DOUBLE), + OUString(PROPERTY_XSD_MAX_EXCLUSIVE_DOUBLE), + OUString(PROPERTY_XSD_MIN_INCLUSIVE_DOUBLE), + OUString(PROPERTY_XSD_MIN_EXCLUSIVE_DOUBLE), + OUString(PROPERTY_XSD_MAX_INCLUSIVE_DATE), + OUString(PROPERTY_XSD_MAX_EXCLUSIVE_DATE), + OUString(PROPERTY_XSD_MIN_INCLUSIVE_DATE), + OUString(PROPERTY_XSD_MIN_EXCLUSIVE_DATE), + OUString(PROPERTY_XSD_MAX_INCLUSIVE_TIME), + OUString(PROPERTY_XSD_MAX_EXCLUSIVE_TIME), + OUString(PROPERTY_XSD_MIN_INCLUSIVE_TIME), + OUString(PROPERTY_XSD_MIN_EXCLUSIVE_TIME), + OUString(PROPERTY_XSD_MAX_INCLUSIVE_DATE_TIME), + OUString(PROPERTY_XSD_MAX_EXCLUSIVE_DATE_TIME), + OUString(PROPERTY_XSD_MIN_INCLUSIVE_DATE_TIME), + OUString(PROPERTY_XSD_MIN_EXCLUSIVE_DATE_TIME) + }; + + size_t i=0; + const OUString* pLoop = nullptr; + for ( i = 0, pLoop = aFacets; + i < SAL_N_ELEMENTS( aFacets ); + ++i, ++pLoop + ) + { + showPropertyUI( _rxInspectorUI, *pLoop, xDataType.is() && xDataType->hasFacet( *pLoop ) ); + _rxInspectorUI->enablePropertyUI( *pLoop, !bIsBasicType ); + } + } + break; + + case PROPERTY_ID_XML_DATA_MODEL: + { + // The data type which the current binding works with may not be present in the + // new model. Thus, transfer it. + OUString sOldModelName; _rOldValue >>= sOldModelName; + OUString sNewModelName; _rNewValue >>= sNewModelName; + OUString sDataType = m_pHelper->getValidatingDataTypeName(); + m_pHelper->copyDataType( sOldModelName, sNewModelName, sDataType ); + + // the list of available data types depends on the chosen model, so update this + if ( !_bFirstTimeInit ) + _rxInspectorUI->rebuildPropertyUI( PROPERTY_XSD_DATA_TYPE ); + } + break; + + default: + OSL_FAIL( "XSDValidationPropertyHandler::actuatingPropertyChanged: cannot handle this property!" ); + return; + } + + // in both cases, we need to care for the current value of the XSD_DATA_TYPE property, + // and update the FormatKey of the formatted field we're inspecting (if any) + if ( !_bFirstTimeInit && m_pHelper->isInspectingFormattedField() ) + m_pHelper->findDefaultFormatForIntrospectee(); + } + + + void XSDValidationPropertyHandler::implGetAvailableDataTypeNames( std::vector< OUString >& /* [out] */ _rNames ) const + { + OSL_PRECOND( + m_pHelper, + "XSDValidationPropertyHandler::implGetAvailableDataTypeNames: this will crash!"); + // start with *all* types which are available at the model + std::vector< OUString > aAllTypes; + m_pHelper->getAvailableDataTypeNames( aAllTypes ); + _rNames.clear(); + _rNames.reserve( aAllTypes.size() ); + + // then allow only those which are "compatible" with our control + for (auto const& dataType : aAllTypes) + { + ::rtl::Reference< XSDDataType > pType = m_pHelper->getDataTypeByName(dataType); + if ( pType.is() && m_pHelper->canBindToDataType( pType->classify() ) ) + _rNames.push_back(dataType); + } + } + + +} // namespace pcr + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_propctrlr_XSDValidationPropertyHandler_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(new pcr::XSDValidationPropertyHandler(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/propctrlr/xsdvalidationpropertyhandler.hxx b/extensions/source/propctrlr/xsdvalidationpropertyhandler.hxx new file mode 100644 index 000000000..32803b215 --- /dev/null +++ b/extensions/source/propctrlr/xsdvalidationpropertyhandler.hxx @@ -0,0 +1,88 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "propertyhandler.hxx" + +#include + + +namespace pcr +{ + + + class XSDValidationHelper; + + //= XSDValidationPropertyHandler + + class XSDValidationPropertyHandler : public PropertyHandlerComponent + { + private: + std::unique_ptr< XSDValidationHelper > m_pHelper; + + public: + explicit XSDValidationPropertyHandler( + const css::uno::Reference< css::uno::XComponentContext >& _rxContext + ); + + protected: + virtual ~XSDValidationPropertyHandler() override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override; + + // XPropertyHandler overriables + virtual css::uno::Any SAL_CALL getPropertyValue( const OUString& _rPropertyName ) override; + virtual void SAL_CALL setPropertyValue( const OUString& _rPropertyName, const css::uno::Any& _rValue ) override; + virtual css::uno::Sequence< OUString > + SAL_CALL getSupersededProperties( ) override; + virtual css::uno::Sequence< OUString > + SAL_CALL getActuatingProperties( ) override; + virtual css::inspection::LineDescriptor + SAL_CALL describePropertyLine( const OUString& _rPropertyName, const css::uno::Reference< css::inspection::XPropertyControlFactory >& _rxControlFactory ) override; + virtual css::inspection::InteractiveSelectionResult + SAL_CALL onInteractivePropertySelection( const OUString& _rPropertyName, sal_Bool _bPrimary, css::uno::Any& _rData, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI ) override; + virtual void SAL_CALL actuatingPropertyChanged( const OUString& _rActuatingPropertyName, const css::uno::Any& _rNewValue, const css::uno::Any& _rOldValue, const css::uno::Reference< css::inspection::XObjectInspectorUI >& _rxInspectorUI, sal_Bool ) override; + virtual void SAL_CALL addPropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + virtual void SAL_CALL removePropertyChangeListener( const css::uno::Reference< css::beans::XPropertyChangeListener >& _rxListener ) override; + + // PropertyHandler overridables + virtual css::uno::Sequence< css::beans::Property > + doDescribeSupportedProperties() const override; + virtual void onNewComponent() override; + + private: + bool implPrepareRemoveCurrentDataType(); + bool implDoRemoveCurrentDataType(); + + bool implPrepareCloneDataCurrentType( OUString& _rNewName ); + void implDoCloneCurrentDataType( const OUString& _rNewName ); + + /** retrieves the names of the data types which our introspectee can be validated against + */ + void implGetAvailableDataTypeNames( std::vector< OUString >& /* [out] */ _rNames ) const; + }; + + +} // namespace pcr + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/grid.cxx b/extensions/source/scanner/grid.cxx new file mode 100644 index 000000000..110779c55 --- /dev/null +++ b/extensions/source/scanner/grid.cxx @@ -0,0 +1,700 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + +#include +#include + +#include "grid.hxx" +#include +#include +#include +#include +#include + +#include +#include +#include + +class GridWindow : public weld::CustomWidgetController +{ + // helper class for handles + struct impHandle + { + Point maPos; + sal_uInt16 mnOffX; + sal_uInt16 mnOffY; + + impHandle(const Point& rPos, sal_uInt16 nX, sal_uInt16 nY) + : maPos(rPos), mnOffX(nX), mnOffY(nY) + { + } + + bool operator<(const impHandle& rComp) const + { + return (maPos.X() < rComp.maPos.X()); + } + + void draw(vcl::RenderContext& rRenderContext, const BitmapEx& rBitmapEx) + { + const Point aOffset(rRenderContext.PixelToLogic(Point(mnOffX, mnOffY))); + rRenderContext.DrawBitmapEx(maPos - aOffset, rBitmapEx); + } + + bool isHit(OutputDevice const & rWin, const Point& rPos) + { + const Point aOffset(rWin.PixelToLogic(Point(mnOffX, mnOffY))); + const tools::Rectangle aTarget(maPos - aOffset, maPos + aOffset); + return aTarget.Contains(rPos); + } + }; + + tools::Rectangle m_aGridArea; + + double m_fMinX; + double m_fMinY; + double m_fMaxX; + double m_fMaxY; + + double m_fChunkX; + double m_fMinChunkX; + double m_fChunkY; + double m_fMinChunkY; + + double* m_pXValues; + double* m_pOrigYValues; + int m_nValues; + std::unique_ptr m_pNewYValues; + + sal_uInt16 m_BmOffX; + sal_uInt16 m_BmOffY; + + bool m_bCutValues; + + // stuff for handles + using Handles = std::vector; + static constexpr auto npos = std::numeric_limits::max(); + Handles m_aHandles; + Handles::size_type m_nDragIndex; + + BitmapEx m_aMarkerBitmap; + + Point transform( double x, double y ); + void transform( const Point& rOriginal, double& x, double& y ); + + double findMinX(); + double findMinY(); + double findMaxX(); + double findMaxY(); + + void drawGrid(vcl::RenderContext& rRenderContext); + void drawOriginal(vcl::RenderContext& rRenderContext); + void drawNew(vcl::RenderContext& rRenderContext); + void drawHandles(vcl::RenderContext& rRenderContext); + + void computeExtremes(); + static void computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut ); + void computeNew(); + static double interpolate( double x, double const * pNodeX, double const * pNodeY, int nNodes ); + + virtual bool MouseMove( const MouseEvent& ) override; + virtual bool MouseButtonDown( const MouseEvent& ) override; + virtual bool MouseButtonUp( const MouseEvent& ) override; + void onResize(); + virtual void Resize() override; + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override; + void drawLine(vcl::RenderContext& rRenderContext, double x1, double y1, double x2, double y2); +public: + GridWindow(); + void Init(double* pXValues, double* pYValues, int nValues, bool bCutValues, const BitmapEx &rMarkerBitmap); + virtual ~GridWindow() override; + + void setBoundings( double fMinX, double fMinY, double fMaxX, double fMaxY ); + + double* getNewYValues() { return m_pNewYValues.get(); } + + void ChangeMode(ResetType nType); + + virtual void Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect ) override; +}; + +GridWindow::GridWindow() + : m_aGridArea(50, 15, 100, 100) + , m_fMinX(0.0) + , m_fMinY(0.0) + , m_fMaxX(0.0) + , m_fMaxY(0.0) + , m_fChunkX(0.0) + , m_fMinChunkX(0.0) + , m_fChunkY(0.0) + , m_fMinChunkY(0.0) + , m_pXValues(nullptr) + , m_pOrigYValues(nullptr) + , m_nValues(0) + , m_BmOffX(0) + , m_BmOffY(0) + , m_bCutValues(false) + , m_nDragIndex(npos) +{ +} + +void GridWindow::Init(double* pXValues, double* pYValues, int nValues, bool bCutValues, const BitmapEx &rMarkerBitmap) +{ + m_aMarkerBitmap = rMarkerBitmap; + m_pXValues = pXValues; + m_pOrigYValues = pYValues; + m_nValues = nValues; + m_bCutValues = bCutValues; + + onResize(); + + if (m_pOrigYValues && m_nValues) + { + m_pNewYValues.reset(new double[ m_nValues ]); + memcpy( m_pNewYValues.get(), m_pOrigYValues, sizeof( double ) * m_nValues ); + } + + setBoundings( 0, 0, 1023, 1023 ); + computeExtremes(); + + // create left and right marker as first and last entry + m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1); + m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1); + m_aHandles.push_back(impHandle(transform(findMinX(), findMinY()), m_BmOffX, m_BmOffY)); + m_aHandles.push_back(impHandle(transform(findMaxX(), findMaxY()), m_BmOffX, m_BmOffY)); +} + +void GridWindow::Resize() +{ + onResize(); +} + +void GridWindow::onResize() +{ + Size aSize = GetOutputSizePixel(); + m_aGridArea.setWidth( aSize.Width() - 80 ); + m_aGridArea.setHeight( aSize.Height() - 40 ); +} + +void GridWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea) +{ + Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(240, 200), MapMode(MapUnit::MapAppFont))); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); + CustomWidgetController::SetDrawingArea(pDrawingArea); + SetOutputSizePixel(aSize); +} + +GridDialog::GridDialog(weld::Window* pParent, double* pXValues, double* pYValues, int nValues) + : GenericDialogController(pParent, "modules/scanner/ui/griddialog.ui", "GridDialog") + , m_xOKButton(m_xBuilder->weld_button("ok")) + , m_xResetTypeBox(m_xBuilder->weld_combo_box("resetTypeCombobox")) + , m_xResetButton(m_xBuilder->weld_button("resetButton")) + , m_xGridWindow(new GridWindow) + , m_xGridWindowWND(new weld::CustomWeld(*m_xBuilder, "gridwindow", *m_xGridWindow)) +{ + m_xGridWindow->Init(pXValues, pYValues, nValues, true/*bCutValues*/, BitmapEx(RID_SCANNER_HANDLE)); + m_xResetTypeBox->set_active(0); + m_xResetButton->connect_clicked( LINK( this, GridDialog, ClickButtonHdl ) ); +} + +GridDialog::~GridDialog() +{ +} + +GridWindow::~GridWindow() +{ + m_pNewYValues.reset(); +} + +double GridWindow::findMinX() +{ + if( ! m_pXValues ) + return 0.0; + double fMin = m_pXValues[0]; + for( int i = 1; i < m_nValues; i++ ) + if( m_pXValues[ i ] < fMin ) + fMin = m_pXValues[ i ]; + return fMin; +} + +double GridWindow::findMinY() +{ + if( ! m_pNewYValues ) + return 0.0; + double fMin = m_pNewYValues[0]; + for( int i = 1; i < m_nValues; i++ ) + if( m_pNewYValues[ i ] < fMin ) + fMin = m_pNewYValues[ i ]; + return fMin; +} + + +double GridWindow::findMaxX() +{ + if( ! m_pXValues ) + return 0.0; + double fMax = m_pXValues[0]; + for( int i = 1; i < m_nValues; i++ ) + if( m_pXValues[ i ] > fMax ) + fMax = m_pXValues[ i ]; + return fMax; +} + + +double GridWindow::findMaxY() +{ + if( ! m_pNewYValues ) + return 0.0; + double fMax = m_pNewYValues[0]; + for( int i = 1; i < m_nValues; i++ ) + if( m_pNewYValues[ i ] > fMax ) + fMax = m_pNewYValues[ i ]; + return fMax; +} + + +void GridWindow::computeExtremes() +{ + if( !(m_nValues && m_pXValues && m_pOrigYValues) ) + return; + + m_fMaxX = m_fMinX = m_pXValues[0]; + m_fMaxY = m_fMinY = m_pOrigYValues[0]; + for( int i = 1; i < m_nValues; i++ ) + { + if( m_pXValues[ i ] > m_fMaxX ) + m_fMaxX = m_pXValues[ i ]; + else if( m_pXValues[ i ] < m_fMinX ) + m_fMinX = m_pXValues[ i ]; + if( m_pOrigYValues[ i ] > m_fMaxY ) + m_fMaxY = m_pOrigYValues[ i ]; + else if( m_pOrigYValues[ i ] < m_fMinY ) + m_fMinY = m_pOrigYValues[ i ]; + } + setBoundings( m_fMinX, m_fMinY, m_fMaxX, m_fMaxY ); +} + + +Point GridWindow::transform( double x, double y ) +{ + Point aRet; + + aRet.setX( static_cast( ( x - m_fMinX ) * + static_cast(m_aGridArea.GetWidth()) / ( m_fMaxX - m_fMinX ) + + m_aGridArea.Left() ) ); + aRet.setY( static_cast( + m_aGridArea.Bottom() - + ( y - m_fMinY ) * + static_cast(m_aGridArea.GetHeight()) / ( m_fMaxY - m_fMinY ) ) ); + return aRet; +} + +void GridWindow::transform( const Point& rOriginal, double& x, double& y ) +{ + const tools::Long nWidth = m_aGridArea.GetWidth(); + const tools::Long nHeight = m_aGridArea.GetHeight(); + if (!nWidth || !nHeight) + return; + x = ( rOriginal.X() - m_aGridArea.Left() ) * (m_fMaxX - m_fMinX) / static_cast(nWidth) + m_fMinX; + y = ( m_aGridArea.Bottom() - rOriginal.Y() ) * (m_fMaxY - m_fMinY) / static_cast(nHeight) + m_fMinY; +} + +void GridWindow::drawLine(vcl::RenderContext& rRenderContext, double x1, double y1, double x2, double y2 ) +{ + rRenderContext.DrawLine(transform(x1, y1), transform(x2, y2)); +} + +void GridWindow::computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut ) +{ + // get a nice chunk size like 10, 100, 25 or such + fChunkOut = ( fMax - fMin ) / 6.0; + int logchunk = static_cast(std::log10( fChunkOut )); + int nChunk = static_cast( fChunkOut / std::exp( static_cast(logchunk-1) * M_LN10 ) ); + if( nChunk >= 75 ) + nChunk = 100; + else if( nChunk >= 35 ) + nChunk = 50; + else if ( nChunk > 20 ) + nChunk = 25; + else if ( nChunk >= 13 ) + nChunk = 20; + else if( nChunk > 5 ) + nChunk = 10; + else + nChunk = 5; + fChunkOut = static_cast(nChunk) * exp( static_cast(logchunk-1) * M_LN10 ); + // compute whole chunks fitting into fMin + nChunk = static_cast( fMin / fChunkOut ); + fMinChunkOut = static_cast(nChunk) * fChunkOut; + while( fMinChunkOut < fMin ) + fMinChunkOut += fChunkOut; +} + + +void GridWindow::computeNew() +{ + if(2 == m_aHandles.size()) + { + // special case: only left and right markers + double xleft, yleft; + double xright, yright; + transform(m_aHandles[0].maPos, xleft, yleft); + transform(m_aHandles[1].maPos, xright, yright ); + double factor = (yright-yleft)/(xright-xleft); + for( int i = 0; i < m_nValues; i++ ) + { + m_pNewYValues[ i ] = yleft + ( m_pXValues[ i ] - xleft )*factor; + } + } + else + { + // sort markers + std::sort(m_aHandles.begin(), m_aHandles.end()); + const int nSorted = m_aHandles.size(); + int i; + + // get node arrays + std::unique_ptr nodex(new double[ nSorted ]); + std::unique_ptr nodey(new double[ nSorted ]); + + for( i = 0; i < nSorted; i++ ) + transform( m_aHandles[i].maPos, nodex[ i ], nodey[ i ] ); + + for( i = 0; i < m_nValues; i++ ) + { + double x = m_pXValues[ i ]; + m_pNewYValues[ i ] = interpolate( x, nodex.get(), nodey.get(), nSorted ); + if( m_bCutValues ) + { + if( m_pNewYValues[ i ] > m_fMaxY ) + m_pNewYValues[ i ] = m_fMaxY; + else if( m_pNewYValues[ i ] < m_fMinY ) + m_pNewYValues[ i ] = m_fMinY; + } + } + } +} + + +double GridWindow::interpolate( + double x, + double const * pNodeX, + double const * pNodeY, + int nNodes ) +{ + // compute Lagrange interpolation + double ret = 0; + for( int i = 0; i < nNodes; i++ ) + { + double sum = pNodeY[ i ]; + for( int n = 0; n < nNodes; n++ ) + { + if( n != i ) + { + sum *= x - pNodeX[ n ]; + sum /= pNodeX[ i ] - pNodeX[ n ]; + } + } + ret += sum; + } + return ret; +} + +void GridDialog::setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY) +{ + m_xGridWindow->setBoundings(fMinX, fMinY, fMaxX, fMaxY); +} + +void GridWindow::setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY) +{ + m_fMinX = fMinX; + m_fMinY = fMinY; + m_fMaxX = fMaxX; + m_fMaxY = fMaxY; + + computeChunk( m_fMinX, m_fMaxX, m_fChunkX, m_fMinChunkX ); + computeChunk( m_fMinY, m_fMaxY, m_fChunkY, m_fMinChunkY ); +} + +void GridWindow::drawGrid(vcl::RenderContext& rRenderContext) +{ + char pBuf[256]; + rRenderContext.SetLineColor(COL_BLACK); + // draw vertical lines + for (double fX = m_fMinChunkX; fX < m_fMaxX; fX += m_fChunkX) + { + drawLine(rRenderContext, fX, m_fMinY, fX, m_fMaxY); + // draw tickmarks + Point aPt = transform(fX, m_fMinY); + std::sprintf(pBuf, "%g", fX); + OUString aMark(pBuf, strlen(pBuf), osl_getThreadTextEncoding()); + Size aTextSize(rRenderContext.GetTextWidth(aMark), rRenderContext.GetTextHeight()); + aPt.AdjustX( -(aTextSize.Width() / 2) ); + aPt.AdjustY(aTextSize.Height() / 2 ); + rRenderContext.DrawText(aPt, aMark); + } + // draw horizontal lines + for (double fY = m_fMinChunkY; fY < m_fMaxY; fY += m_fChunkY) + { + drawLine(rRenderContext, m_fMinX, fY, m_fMaxX, fY); + // draw tickmarks + Point aPt = transform(m_fMinX, fY); + std::sprintf(pBuf, "%g", fY); + OUString aMark(pBuf, strlen(pBuf), osl_getThreadTextEncoding()); + Size aTextSize(rRenderContext.GetTextWidth(aMark), rRenderContext.GetTextHeight()); + aPt.AdjustX( -(aTextSize.Width() + 2) ); + aPt.AdjustY( -(aTextSize.Height() / 2) ); + rRenderContext.DrawText(aPt, aMark); + } + + // draw boundings + drawLine(rRenderContext, m_fMinX, m_fMinY, m_fMaxX, m_fMinY); + drawLine(rRenderContext, m_fMinX, m_fMaxY, m_fMaxX, m_fMaxY); + drawLine(rRenderContext, m_fMinX, m_fMinY, m_fMinX, m_fMaxY); + drawLine(rRenderContext, m_fMaxX, m_fMinY, m_fMaxX, m_fMaxY); +} + +void GridWindow::drawOriginal(vcl::RenderContext& rRenderContext) +{ + if (m_nValues && m_pXValues && m_pOrigYValues) + { + rRenderContext.SetLineColor(COL_RED); + for (int i = 0; i < m_nValues - 1; i++) + { + drawLine(rRenderContext, + m_pXValues[i], m_pOrigYValues[i], + m_pXValues[i + 1], m_pOrigYValues[i + 1]); + } + } +} + +void GridWindow::drawNew(vcl::RenderContext& rRenderContext) +{ + if (m_nValues && m_pXValues && m_pNewYValues) + { + rRenderContext.SetClipRegion(vcl::Region(m_aGridArea)); + rRenderContext.SetLineColor(COL_YELLOW); + for (int i = 0; i < m_nValues - 1; i++) + { + drawLine(rRenderContext, + m_pXValues[i], m_pNewYValues[i], + m_pXValues[i + 1], m_pNewYValues[i + 1]); + } + rRenderContext.SetClipRegion(); + } +} + +void GridWindow::drawHandles(vcl::RenderContext& rRenderContext) +{ + for(impHandle & rHandle : m_aHandles) + { + rHandle.draw(rRenderContext, m_aMarkerBitmap); + } +} + +void GridWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + rRenderContext.SetBackground(Wallpaper(Application::GetSettings().GetStyleSettings().GetDialogColor())); + drawGrid(rRenderContext); + drawOriginal(rRenderContext); + drawNew(rRenderContext); + drawHandles(rRenderContext); +} + +bool GridWindow::MouseMove( const MouseEvent& rEvt ) +{ + if( rEvt.GetButtons() != MOUSE_LEFT || m_nDragIndex == npos ) + return false; + + Point aPoint( rEvt.GetPosPixel() ); + + if( m_nDragIndex == 0 || m_nDragIndex == m_aHandles.size() - 1) + { + aPoint.setX( m_aHandles[m_nDragIndex].maPos.X() ); + } + else + { + if(aPoint.X() < m_aGridArea.Left()) + aPoint.setX( m_aGridArea.Left() ); + else if(aPoint.X() > m_aGridArea.Right()) + aPoint.setX( m_aGridArea.Right() ); + } + + if( aPoint.Y() < m_aGridArea.Top() ) + aPoint.setY( m_aGridArea.Top() ); + else if( aPoint.Y() > m_aGridArea.Bottom() ) + aPoint.setY( m_aGridArea.Bottom() ); + + if( aPoint != m_aHandles[m_nDragIndex].maPos ) + { + m_aHandles[m_nDragIndex].maPos = aPoint; + Invalidate( m_aGridArea ); + } + + return false; +} + +bool GridWindow::MouseButtonUp( const MouseEvent& rEvt ) +{ + if( rEvt.GetButtons() == MOUSE_LEFT ) + { + if( m_nDragIndex != npos ) + { + m_nDragIndex = npos; + computeNew(); + Invalidate(m_aGridArea); + } + } + + return false; +} + +bool GridWindow::MouseButtonDown( const MouseEvent& rEvt ) +{ + Point aPoint( rEvt.GetPosPixel() ); + Handles::size_type nMarkerIndex = npos; + + for(Handles::size_type a(0); nMarkerIndex == npos && a < m_aHandles.size(); a++) + { + if(m_aHandles[a].isHit(GetDrawingArea()->get_ref_device(), aPoint)) + { + nMarkerIndex = a; + } + } + + if( rEvt.GetButtons() == MOUSE_LEFT ) + { + // user wants to drag a button + if( nMarkerIndex != npos ) + { + m_nDragIndex = nMarkerIndex; + } + } + else if( rEvt.GetButtons() == MOUSE_RIGHT ) + { + // user wants to add/delete a button + if( nMarkerIndex != npos ) + { + if( nMarkerIndex != 0 && nMarkerIndex != m_aHandles.size() - 1) + { + // delete marker under mouse + if( m_nDragIndex == nMarkerIndex ) + m_nDragIndex = npos; + + m_aHandles.erase(m_aHandles.begin() + nMarkerIndex); + } + } + else + { + m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1); + m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1); + m_aHandles.push_back(impHandle(aPoint, m_BmOffX, m_BmOffY)); + } + + computeNew(); + Invalidate(m_aGridArea); + } + + return false; +} + +void GridWindow::ChangeMode(ResetType nType) +{ + switch( nType ) + { + case ResetType::LINEAR_ASCENDING: + { + for( int i = 0; i < m_nValues; i++ ) + { + m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX); + } + } + break; + case ResetType::LINEAR_DESCENDING: + { + for( int i = 0; i < m_nValues; i++ ) + { + m_pNewYValues[ i ] = m_fMaxY - (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX); + } + } + break; + case ResetType::RESET: + { + if( m_pOrigYValues && m_pNewYValues && m_nValues ) + memcpy( m_pNewYValues.get(), m_pOrigYValues, m_nValues*sizeof(double) ); + } + break; + case ResetType::EXPONENTIAL: + { + for( int i = 0; i < m_nValues; i++ ) + { + m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)*(rtl::math::expm1((m_pXValues[i]-m_fMinX)/(m_fMaxX-m_fMinX)))/(M_E-1.0); + } + } + break; + + default: + break; + } + + if (m_pNewYValues) + { + for(size_t i(0); i < m_aHandles.size(); i++) + { + // find nearest xvalue + double x, y; + transform( m_aHandles[i].maPos, x, y ); + int nIndex = 0; + double delta = std::fabs( x-m_pXValues[0] ); + for( int n = 1; n < m_nValues; n++ ) + { + if( delta > std::fabs( x - m_pXValues[ n ] ) ) + { + delta = std::fabs( x - m_pXValues[ n ] ); + nIndex = n; + } + } + if( 0 == i ) + m_aHandles[i].maPos = transform( m_fMinX, m_pNewYValues[ nIndex ] ); + else if( m_aHandles.size() - 1 == i ) + m_aHandles[i].maPos = transform( m_fMaxX, m_pNewYValues[ nIndex ] ); + else + m_aHandles[i].maPos = transform( m_pXValues[ nIndex ], m_pNewYValues[ nIndex ] ); + } + } + + Invalidate(); +} + +IMPL_LINK_NOARG(GridDialog, ClickButtonHdl, weld::Button&, void) +{ + int nType = m_xResetTypeBox->get_active(); + m_xGridWindow->ChangeMode(static_cast(nType)); +} + +double* GridDialog::getNewYValues() +{ + return m_xGridWindow->getNewYValues(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/grid.hxx b/extensions/source/scanner/grid.hxx new file mode 100644 index 000000000..86f1a521c --- /dev/null +++ b/extensions/source/scanner/grid.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +class GridWindow; + +enum class ResetType +{ + LINEAR_ASCENDING = 0, + LINEAR_DESCENDING = 1, + RESET = 2, + EXPONENTIAL = 3 +}; + +class GridDialog : public weld::GenericDialogController +{ + std::unique_ptr m_xOKButton; + std::unique_ptr m_xResetTypeBox; + std::unique_ptr m_xResetButton; + std::unique_ptr m_xGridWindow; + std::unique_ptr m_xGridWindowWND; + + DECL_LINK(ClickButtonHdl, weld::Button&, void); + +public: + GridDialog(weld::Window* pParent, double* pXValues, double* pYValues, int nValues); + virtual ~GridDialog() override; + void setBoundings(double fMinX, double fMinY, double fMaxX, double fMaxY); + double* getNewYValues(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/sane.cxx b/extensions/source/scanner/sane.cxx new file mode 100644 index 000000000..de03e1158 --- /dev/null +++ b/extensions/source/scanner/sane.cxx @@ -0,0 +1,996 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 "sane.hxx" +#include +#include +#include +#include +#include +#include + +#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL +#include +#define dump_state( a, b, c, d ) fprintf( stderr, a, b, c, d ); +#else +#define dump_state( a, b, c, d ) ; +#endif +static void dbg_msg( const char* pString, ... ) +{ +#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL + va_list ap; + va_start( ap, pString ); + vfprintf( stderr, pString, ap ); + va_end( ap ); +#else + (void)pString; +#endif +} + +#define FAIL_SHUTDOWN_STATE( x, y, z ) \ + if( x != SANE_STATUS_GOOD ) \ + { \ + dump_state( "%s returned error %d (%s)\n", \ + y, x, p_strstatus( x ) ); \ + DeInit(); \ + return z; \ + } + +#define FAIL_STATE( x, y, z ) \ + if( x != SANE_STATUS_GOOD ) \ + { \ + dump_state( "%s returned error %d (%s)\n", \ + y, x, p_strstatus( x ) ); \ + return z; \ + } + +#define DUMP_STATE( x, y ) \ + if( x != SANE_STATUS_GOOD ) \ + { \ + dump_state( "%s returned error %d (%s)\n", \ + y, x, p_strstatus( x ) ); \ + } + +int Sane::nRefCount = 0; +oslModule Sane::pSaneLib = nullptr; +SANE_Int Sane::nVersion = 0; +SANE_Device** Sane::ppDevices = nullptr; +int Sane::nDevices = 0; + +SANE_Status (*Sane::p_init)( SANE_Int*, + SANE_Auth_Callback ) = nullptr; +void (*Sane::p_exit)() = nullptr; +SANE_Status (*Sane::p_get_devices)( const SANE_Device***, + SANE_Bool ) = nullptr; +SANE_Status (*Sane::p_open)( SANE_String_Const, SANE_Handle ) = nullptr; +void (*Sane::p_close)( SANE_Handle ) = nullptr; +const SANE_Option_Descriptor* (*Sane::p_get_option_descriptor)( + SANE_Handle, SANE_Int ) = nullptr; +SANE_Status (*Sane::p_control_option)( SANE_Handle, SANE_Int, + SANE_Action, void*, + SANE_Int* ) = nullptr; +SANE_Status (*Sane::p_get_parameters)( SANE_Handle, + SANE_Parameters* ) = nullptr; +SANE_Status (*Sane::p_start)( SANE_Handle ) = nullptr; +SANE_Status (*Sane::p_read)( SANE_Handle, SANE_Byte*, SANE_Int, + SANE_Int* ) = nullptr; +void (*Sane::p_cancel)( SANE_Handle ) = nullptr; +SANE_Status (*Sane::p_set_io_mode)( SANE_Handle, SANE_Bool ) = nullptr; +SANE_Status (*Sane::p_get_select_fd)( SANE_Handle, SANE_Int* ) = nullptr; +SANE_String_Const (*Sane::p_strstatus)( SANE_Status ) = nullptr; + +static bool bSaneSymbolLoadFailed = false; + +inline oslGenericFunction Sane::LoadSymbol( const char* pSymbolname ) +{ + oslGenericFunction pFunction = osl_getAsciiFunctionSymbol( pSaneLib, pSymbolname ); + if( ! pFunction ) + { + fprintf( stderr, "Could not load symbol %s\n", + pSymbolname ); + bSaneSymbolLoadFailed = true; + } + return pFunction; +} + +SANE_Status Sane::ControlOption( int nOption, SANE_Action nAction, + void* pData ) +{ + SANE_Int nInfo = 0; + + SANE_Status nStatus = p_control_option( maHandle, static_cast(nOption), + nAction, pData, &nInfo ); + DUMP_STATE( nStatus, "sane_control_option" ); +#if OSL_DEBUG_LEVEL > 0 + if( nStatus != SANE_STATUS_GOOD ) + { + const char* pAction = "Unknown"; + switch( nAction ) + { + case SANE_ACTION_GET_VALUE: + pAction = "SANE_ACTION_GET_VALUE";break; + case SANE_ACTION_SET_VALUE: + pAction = "SANE_ACTION_SET_VALUE";break; + case SANE_ACTION_SET_AUTO: + pAction = "SANE_ACTION_SET_AUTO";break; + } + dbg_msg( "Option: \"%s\" action: %s\n", + OUStringToOString(GetOptionName(nOption), osl_getThreadTextEncoding()).getStr(), + pAction ); + } +#endif + if( nInfo & SANE_INFO_RELOAD_OPTIONS ) + ReloadOptions(); + return nStatus; +} + +Sane::Sane() : + mnOptions( 0 ), + mnDevice( -1 ), + maHandle( nullptr ) +{ + if( ! nRefCount || ! pSaneLib ) + Init(); + nRefCount++; +}; + +Sane::~Sane() +{ + if( IsOpen() ) + Close(); + nRefCount--; + if( ! nRefCount && pSaneLib ) + DeInit(); +} + +void Sane::Init() +{ +#ifndef DISABLE_DYNLOADING + OUString sSaneLibName( "libsane" SAL_DLLEXTENSION ); + pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY ); + if( ! pSaneLib ) + { + sSaneLibName = "libsane" SAL_DLLEXTENSION ".1"; + pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY ); + } + // try reasonable places that might not be in the library search path + if( ! pSaneLib ) + { + OUString sSaneLibSystemPath( "/usr/local/lib/libsane" SAL_DLLEXTENSION ); + osl_getFileURLFromSystemPath( sSaneLibSystemPath.pData, &sSaneLibName.pData ); + pSaneLib = osl_loadModule( sSaneLibName.pData, SAL_LOADMODULE_LAZY ); + } +#endif + if( pSaneLib ) + { + bSaneSymbolLoadFailed = false; + p_init = reinterpret_cast( + LoadSymbol( "sane_init" )); + p_exit = reinterpret_cast( + LoadSymbol( "sane_exit" )); + p_get_devices = reinterpret_cast( + LoadSymbol( "sane_get_devices" )); + p_open = reinterpret_cast( + LoadSymbol( "sane_open" )); + p_close = reinterpret_cast( + LoadSymbol( "sane_close" )); + p_get_option_descriptor = reinterpret_cast( + LoadSymbol( "sane_get_option_descriptor" )); + p_control_option = reinterpret_cast( + LoadSymbol( "sane_control_option" )); + p_get_parameters = reinterpret_cast( + LoadSymbol( "sane_get_parameters" )); + p_start = reinterpret_cast( + LoadSymbol( "sane_start" )); + p_read = reinterpret_cast( + LoadSymbol( "sane_read" )); + p_cancel = reinterpret_cast( + LoadSymbol( "sane_cancel" )); + p_set_io_mode = reinterpret_cast( + LoadSymbol( "sane_set_io_mode" )); + p_get_select_fd = reinterpret_cast( + LoadSymbol( "sane_get_select_fd" )); + p_strstatus = reinterpret_cast( + LoadSymbol( "sane_strstatus" )); + if( bSaneSymbolLoadFailed ) + DeInit(); + else + { + SANE_Status nStatus = p_init( &nVersion, nullptr ); + FAIL_SHUTDOWN_STATE( nStatus, "sane_init", ); + nStatus = p_get_devices( const_cast(&ppDevices), + SANE_FALSE ); + FAIL_SHUTDOWN_STATE( nStatus, "sane_get_devices", ); + for( nDevices = 0 ; ppDevices[ nDevices ]; nDevices++ ) ; + } + } +#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL + else + fprintf( stderr, "libsane%s could not be opened: %s\n", SAL_DLLEXTENSION, + dlerror() ); +#endif +} + +void Sane::DeInit() +{ + if( pSaneLib ) + { + p_exit(); +#ifndef DISABLE_DYNLOADING + osl_unloadModule( pSaneLib ); +#endif + pSaneLib = nullptr; + } +} + +void Sane::ReloadDevices() +{ + if( IsOpen() ) + Close(); + DeInit(); + Init(); +} + +void Sane::ReloadOptions() +{ + if( ! IsOpen() ) + return; + + const SANE_Option_Descriptor* pZero = p_get_option_descriptor( maHandle, 0 ); + SANE_Word pOptions[2]; + SANE_Status nStatus = p_control_option( maHandle, 0, SANE_ACTION_GET_VALUE, + static_cast(pOptions), nullptr ); + if( nStatus != SANE_STATUS_GOOD ) + fprintf( stderr, "Error: sane driver returned %s while reading number of options !\n", p_strstatus( nStatus ) ); + + mnOptions = pOptions[ 0 ]; + if( o3tl::make_unsigned(pZero->size) > sizeof( SANE_Word ) ) + fprintf( stderr, "driver returned number of options with larger size than SANE_Word!!!\n" ); + mppOptions.reset(new const SANE_Option_Descriptor*[ mnOptions ]); + mppOptions[ 0 ] = pZero; + for( int i = 1; i < mnOptions; i++ ) + mppOptions[ i ] = p_get_option_descriptor( maHandle, i ); + + CheckConsistency( nullptr, true ); + + maReloadOptionsLink.Call( *this ); +} + +bool Sane::Open( const char* name ) +{ + SANE_Status nStatus = p_open( reinterpret_cast(name), &maHandle ); + FAIL_STATE( nStatus, "sane_open", false ); + + ReloadOptions(); + + if( mnDevice == -1 ) + { + OString aDevice( name ); + for( int i = 0; i < nDevices; i++ ) + { + if( aDevice == ppDevices[i]->name ) + { + mnDevice = i; + break; + } + } + } + + return true; +} + +bool Sane::Open( int n ) +{ + if( n >= 0 && n < nDevices ) + { + mnDevice = n; + return Open( ppDevices[n]->name ); + } + return false; +} + +void Sane::Close() +{ + if( maHandle ) + { + p_close( maHandle ); + mppOptions.reset(); + maHandle = nullptr; + mnDevice = -1; + } +} + +int Sane::GetOptionByName( const char* rName ) +{ + int i; + OString aOption( rName ); + for( i = 0; i < mnOptions; i++ ) + { + if( mppOptions[i]->name && aOption == mppOptions[i]->name ) + return i; + } + return -1; +} + +bool Sane::GetOptionValue( int n, bool& rRet ) +{ + if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL ) + return false; + SANE_Word nRet; + SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, &nRet ); + if( nStatus != SANE_STATUS_GOOD ) + return false; + + rRet = nRet; + return true; +} + +bool Sane::GetOptionValue( int n, OString& rRet ) +{ + bool bSuccess = false; + if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING ) + return false; + std::unique_ptr pRet(new char[mppOptions[n]->size+1]); + SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet.get() ); + if( nStatus == SANE_STATUS_GOOD ) + { + bSuccess = true; + rRet = pRet.get(); + } + return bSuccess; +} + +bool Sane::GetOptionValue( int n, double& rRet, int nElement ) +{ + bool bSuccess = false; + + if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT && + mppOptions[n]->type != SANE_TYPE_FIXED ) ) + return false; + + std::unique_ptr pRet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]); + SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pRet.get() ); + if( nStatus == SANE_STATUS_GOOD ) + { + bSuccess = true; + if( mppOptions[n]->type == SANE_TYPE_INT ) + rRet = static_cast(pRet[ nElement ]); + else + rRet = SANE_UNFIX( pRet[nElement] ); + } + return bSuccess; +} + +bool Sane::GetOptionValue( int n, double* pSet ) +{ + if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_FIXED && + mppOptions[n]->type != SANE_TYPE_INT ) ) + return false; + + std::unique_ptr pFixedSet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]); + SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pFixedSet.get() ); + if( nStatus != SANE_STATUS_GOOD ) + return false; + for( size_t i = 0; i size/sizeof(SANE_Word); i++ ) + { + if( mppOptions[n]->type == SANE_TYPE_FIXED ) + pSet[i] = SANE_UNFIX( pFixedSet[i] ); + else + pSet[i] = static_cast(pFixedSet[i]); + } + return true; +} + +void Sane::SetOptionValue( int n, bool bSet ) +{ + if( ! maHandle || mppOptions[n]->type != SANE_TYPE_BOOL ) + return; + SANE_Word nRet = bSet ? SANE_TRUE : SANE_FALSE; + ControlOption( n, SANE_ACTION_SET_VALUE, &nRet ); +} + +void Sane::SetOptionValue( int n, std::u16string_view rSet ) +{ + if( ! maHandle || mppOptions[n]->type != SANE_TYPE_STRING ) + return; + OString aSet(OUStringToOString(rSet, osl_getThreadTextEncoding())); + ControlOption( n, SANE_ACTION_SET_VALUE, const_cast(aSet.getStr()) ); +} + +void Sane::SetOptionValue( int n, double fSet, int nElement ) +{ + if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT && + mppOptions[n]->type != SANE_TYPE_FIXED ) ) + return; + + if( mppOptions[n]->size/sizeof(SANE_Word) > 1 ) + { + std::unique_ptr pSet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]); + SANE_Status nStatus = ControlOption( n, SANE_ACTION_GET_VALUE, pSet.get() ); + if( nStatus == SANE_STATUS_GOOD ) + { + pSet[nElement] = mppOptions[n]->type == SANE_TYPE_INT ? + static_cast(fSet) : SANE_FIX( fSet ); + ControlOption( n, SANE_ACTION_SET_VALUE, pSet.get() ); + } + } + else + { + SANE_Word nSetTo = + mppOptions[n]->type == SANE_TYPE_INT ? + static_cast(fSet) : SANE_FIX( fSet ); + + ControlOption( n, SANE_ACTION_SET_VALUE, &nSetTo ); + } +} + +void Sane::SetOptionValue( int n, double const * pSet ) +{ + if( ! maHandle || ( mppOptions[n]->type != SANE_TYPE_INT && + mppOptions[n]->type != SANE_TYPE_FIXED ) ) + return; + std::unique_ptr pFixedSet(new SANE_Word[mppOptions[n]->size/sizeof(SANE_Word)]); + for( size_t i = 0; i < mppOptions[n]->size/sizeof(SANE_Word); i++ ) + { + if( mppOptions[n]->type == SANE_TYPE_FIXED ) + pFixedSet[i] = SANE_FIX( pSet[i] ); + else + pFixedSet[i] = static_cast(pSet[i]); + } + ControlOption( n, SANE_ACTION_SET_VALUE, pFixedSet.get() ); +} + +namespace { + +enum FrameStyleType { + FrameStyle_BW, FrameStyle_Gray, FrameStyle_RGB, FrameStyle_Separated +}; + +} + +#define BYTE_BUFFER_SIZE 32768 + +static sal_uInt8 ReadValue( FILE* fp, int depth ) +{ + if( depth == 16 ) + { + sal_uInt16 nWord; + // data always come in native byte order ! + // 16 bits is not really supported by backends as of now + // e.g. UMAX Astra 1200S delivers 16 bit but in BIGENDIAN + // against SANE documentation (xscanimage gets the same result + // as we do + size_t items_read = fread( &nWord, 1, 2, fp ); + + if (items_read != 2) + { + SAL_WARN( "extensions.scanner", "short read, abandoning" ); + return 0; + } + + return static_cast( nWord / 256 ); + } + sal_uInt8 nByte; + size_t items_read = fread( &nByte, 1, 1, fp ); + if (items_read != 1) + { + SAL_WARN( "extensions.scanner", "short read, abandoning" ); + return 0; + } + return nByte; +} + +bool Sane::CheckConsistency( const char* pMes, bool bInit ) +{ + static const SANE_Option_Descriptor** pDescArray = nullptr; + static const SANE_Option_Descriptor* pZero = nullptr; + + if( bInit ) + { + pDescArray = mppOptions.get(); + if( mppOptions ) + pZero = mppOptions[0]; + return true; + } + + bool bConsistent = true; + + if( pDescArray != mppOptions.get() ) + bConsistent = false; + if( pZero != mppOptions[0] ) + bConsistent = false; + + if( ! bConsistent ) + dbg_msg( "Sane is not consistent. (%s)\n", pMes ); + + return bConsistent; +} + +bool Sane::Start( BitmapTransporter& rBitmap ) +{ + int nStream = 0, nLine = 0, i = 0; + SANE_Parameters aParams; + FrameStyleType eType = FrameStyle_Gray; + bool bSuccess = true; + bool bWidthSet = false; + + if( ! maHandle ) + return false; + + int nWidthMM = 0; + int nHeightMM = 0; + double fTLx, fTLy, fResl = 0.0; + int nOption; + nOption = GetOptionByName( "tl-x" ); + if( nOption != -1 && + GetOptionValue( nOption, fTLx ) && + GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + double fBRx; + nOption = GetOptionByName( "br-x" ); + if( nOption != -1 && + GetOptionValue( nOption, fBRx ) && + GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + nWidthMM = static_cast(fabs(fBRx - fTLx)); + } + } + nOption = GetOptionByName( "tl-y" ); + if( nOption != -1 && + GetOptionValue( nOption, fTLy ) && + GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + double fBRy; + nOption = GetOptionByName( "br-y" ); + if( nOption != -1 && + GetOptionValue( nOption, fBRy ) && + GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + nHeightMM = static_cast(fabs(fBRy - fTLy)); + } + } + if( ( nOption = GetOptionByName( "resolution" ) ) != -1 ) + (void)GetOptionValue( nOption, fResl ); + + std::unique_ptr pBuffer; + + SANE_Status nStatus = SANE_STATUS_GOOD; + + rBitmap.lock(); + SvMemoryStream& aConverter = rBitmap.getStream(); + aConverter.Seek( 0 ); + aConverter.SetEndian( SvStreamEndian::LITTLE ); + + // write bitmap stream header + aConverter.WriteChar( 'B' ).WriteChar( 'M' ); + aConverter.WriteUInt32( 0 ); + aConverter.WriteUInt32( 0 ); + aConverter.WriteUInt32( 60 ); + + // write BITMAPINFOHEADER + aConverter.WriteUInt32( 40 ); + aConverter.WriteUInt32( 0 ); // fill in width later + aConverter.WriteUInt32( 0 ); // fill in height later + aConverter.WriteUInt16( 1 ); + // create header for 24 bits + // correct later if necessary + aConverter.WriteUInt16( 24 ); + aConverter.WriteUInt32( 0 ); + aConverter.WriteUInt32( 0 ); + aConverter.WriteUInt32( 0 ); + aConverter.WriteUInt32( 0 ); + aConverter.WriteUInt32( 0 ); + aConverter.WriteUInt32( 0 ); + + for( nStream=0; nStream < 3 && bSuccess ; nStream++ ) + { + nStatus = p_start( maHandle ); + DUMP_STATE( nStatus, "sane_start" ); + CheckConsistency( "sane_start" ); + if( nStatus == SANE_STATUS_GOOD ) + { + nStatus = p_get_parameters( maHandle, &aParams ); + DUMP_STATE( nStatus, "sane_get_parameters" ); + CheckConsistency( "sane_get_parameters" ); + if (nStatus != SANE_STATUS_GOOD || aParams.bytes_per_line == 0) + { + bSuccess = false; + break; + } +#if (OSL_DEBUG_LEVEL > 0) || defined DBG_UTIL + const char* const ppFormats[] = { "SANE_FRAME_GRAY", "SANE_FRAME_RGB", + "SANE_FRAME_RED", "SANE_FRAME_GREEN", + "SANE_FRAME_BLUE", "Unknown !!!" }; + fprintf( stderr, "Parameters for frame %d:\n", nStream ); + if( static_cast< + typename std::make_unsigned< + typename std::underlying_type::type>::type>( + aParams.format) + > 4 ) + { + aParams.format = SANE_Frame(5); + } + fprintf( stderr, "format: %s\n", ppFormats[ static_cast(aParams.format) ] ); + fprintf( stderr, "last_frame: %s\n", aParams.last_frame ? "TRUE" : "FALSE" ); + fprintf( stderr, "depth: %d\n", static_cast(aParams.depth) ); + fprintf( stderr, "pixels_per_line: %d\n", static_cast(aParams.pixels_per_line) ); + fprintf( stderr, "bytes_per_line: %d\n", static_cast(aParams.bytes_per_line) ); +#endif + if( ! pBuffer ) + { + pBuffer.reset(new sal_uInt8[ BYTE_BUFFER_SIZE < 4*aParams.bytes_per_line ? 4*aParams.bytes_per_line : BYTE_BUFFER_SIZE ]); + } + + if( aParams.last_frame ) + nStream=3; + + switch( aParams.format ) + { + case SANE_FRAME_GRAY: + eType = FrameStyle_Gray; + if( aParams.depth == 1 ) + eType = FrameStyle_BW; + break; + case SANE_FRAME_RGB: + eType = FrameStyle_RGB; + break; + case SANE_FRAME_RED: + case SANE_FRAME_GREEN: + case SANE_FRAME_BLUE: + eType = FrameStyle_Separated; + break; + default: + fprintf( stderr, "Warning: unknown frame style !!!\n" ); + } + + bool bSynchronousRead = true; + + // should be fail safe, but ... ?? + nStatus = p_set_io_mode( maHandle, SANE_FALSE ); + CheckConsistency( "sane_set_io_mode" ); + if( nStatus != SANE_STATUS_GOOD ) + { + bSynchronousRead = false; + nStatus = p_set_io_mode(maHandle, SANE_TRUE); + CheckConsistency( "sane_set_io_mode" ); + if (nStatus != SANE_STATUS_GOOD) + { + SAL_WARN("extensions.scanner", "SANE driver status is: " << nStatus); + } + } + + SANE_Int nLen=0; + SANE_Int fd = 0; + + if( ! bSynchronousRead ) + { + nStatus = p_get_select_fd( maHandle, &fd ); + DUMP_STATE( nStatus, "sane_get_select_fd" ); + CheckConsistency( "sane_get_select_fd" ); + if( nStatus != SANE_STATUS_GOOD ) + bSynchronousRead = true; + } + utl::TempFile aFrame; + aFrame.EnableKillingFile(); + FILE* pFrame = fopen(OUStringToOString(aFrame.GetFileName(), osl_getThreadTextEncoding()).getStr(), "w+b"); + if( ! pFrame ) + { + bSuccess = false; + break; + } + do { + if( ! bSynchronousRead ) + { + fd_set fdset; + struct timeval tv; + + FD_ZERO( &fdset ); + FD_SET( static_cast(fd), &fdset ); + tv.tv_sec = 5; + tv.tv_usec = 0; + if( select( fd+1, &fdset, nullptr, nullptr, &tv ) == 0 ) + fprintf( stderr, "Timeout on sane_read descriptor\n" ); + } + nLen = 0; + nStatus = p_read( maHandle, pBuffer.get(), BYTE_BUFFER_SIZE, &nLen ); + CheckConsistency( "sane_read" ); + if( nLen && ( nStatus == SANE_STATUS_GOOD || + nStatus == SANE_STATUS_EOF ) ) + { + bSuccess = (static_cast(nLen) == fwrite( pBuffer.get(), 1, nLen, pFrame )); + if (!bSuccess) + break; + } + else + DUMP_STATE( nStatus, "sane_read" ); + } while( nStatus == SANE_STATUS_GOOD ); + if (nStatus != SANE_STATUS_EOF || !bSuccess) + { + fclose( pFrame ); + bSuccess = false; + break; + } + + int nFrameLength = ftell( pFrame ); + fseek( pFrame, 0, SEEK_SET ); + sal_uInt32 nWidth = static_cast(aParams.pixels_per_line); + sal_uInt32 nHeight = static_cast(nFrameLength / aParams.bytes_per_line); + if( ! bWidthSet ) + { + if( ! fResl ) + fResl = 300; // if all else fails that's a good guess + if( ! nWidthMM ) + nWidthMM = static_cast((static_cast(nWidth) / fResl) * 25.4); + if( ! nHeightMM ) + nHeightMM = static_cast((static_cast(nHeight) / fResl) * 25.4); + SAL_INFO("extensions.scanner", "set dimensions to(" << nWidth << ", " << nHeight << ") Pixel, (" << nWidthMM << ", " << nHeightMM << + ") mm, resolution is " << fResl); + + aConverter.Seek( 18 ); + aConverter.WriteUInt32( nWidth ); + aConverter.WriteUInt32( nHeight ); + aConverter.Seek( 38 ); + aConverter.WriteUInt32( 1000*nWidth/nWidthMM ); + aConverter.WriteUInt32( 1000*nHeight/nHeightMM ); + bWidthSet = true; + } + aConverter.Seek(60); + + if( eType == FrameStyle_BW ) + { + aConverter.Seek( 10 ); + aConverter.WriteUInt32( 64 ); + aConverter.Seek( 28 ); + aConverter.WriteUInt16( 1 ); + aConverter.Seek( 54 ); + // write color table + aConverter.WriteUInt16( 0xffff ); + aConverter.WriteUChar( 0xff ); + aConverter.WriteUChar( 0 ); + aConverter.WriteUInt32( 0 ); + aConverter.Seek( 64 ); + } + else if( eType == FrameStyle_Gray ) + { + aConverter.Seek( 10 ); + aConverter.WriteUInt32( 1084 ); + aConverter.Seek( 28 ); + aConverter.WriteUInt16( 8 ); + aConverter.Seek( 54 ); + // write color table + for( nLine = 0; nLine < 256; nLine++ ) + { + aConverter.WriteUChar( nLine ); + aConverter.WriteUChar( nLine ); + aConverter.WriteUChar( nLine ); + aConverter.WriteUChar( 0 ); + } + aConverter.Seek( 1084 ); + } + + for (nLine = nHeight-1; nLine >= 0; --nLine) + { + if (fseek(pFrame, nLine * aParams.bytes_per_line, SEEK_SET) == -1) + { + bSuccess = false; + break; + } + if( eType == FrameStyle_BW || + ( eType == FrameStyle_Gray && aParams.depth == 8 ) + ) + { + SANE_Int items_read = fread( pBuffer.get(), 1, aParams.bytes_per_line, pFrame ); + if (items_read != aParams.bytes_per_line) + { + SAL_WARN( "extensions.scanner", "short read, padding with zeros" ); + memset(pBuffer.get() + items_read, 0, aParams.bytes_per_line - items_read); + } + aConverter.WriteBytes(pBuffer.get(), aParams.bytes_per_line); + } + else if( eType == FrameStyle_Gray ) + { + for( i = 0; i < (aParams.pixels_per_line); i++ ) + { + sal_uInt8 nGray = ReadValue( pFrame, aParams.depth ); + aConverter.WriteUChar( nGray ); + } + } + else if( eType == FrameStyle_RGB ) + { + for( i = 0; i < (aParams.pixels_per_line); i++ ) + { + sal_uInt8 nRed, nGreen, nBlue; + nRed = ReadValue( pFrame, aParams.depth ); + nGreen = ReadValue( pFrame, aParams.depth ); + nBlue = ReadValue( pFrame, aParams.depth ); + aConverter.WriteUChar( nBlue ); + aConverter.WriteUChar( nGreen ); + aConverter.WriteUChar( nRed ); + } + } + else if( eType == FrameStyle_Separated ) + { + for( i = 0; i < (aParams.pixels_per_line); i++ ) + { + sal_uInt8 nValue = ReadValue( pFrame, aParams.depth ); + switch( aParams.format ) + { + case SANE_FRAME_RED: + aConverter.SeekRel( 2 ); + aConverter.WriteUChar( nValue ); + break; + case SANE_FRAME_GREEN: + aConverter.SeekRel( 1 ); + aConverter.WriteUChar( nValue ); + aConverter.SeekRel( 1 ); + break; + case SANE_FRAME_BLUE: + aConverter.WriteUChar( nValue ); + aConverter.SeekRel( 2 ); + break; + case SANE_FRAME_GRAY: + case SANE_FRAME_RGB: + break; + } + } + } + int nGap = aConverter.Tell() & 3; + if (nGap) + aConverter.SeekRel( 4-nGap ); + } + fclose( pFrame ); // deletes tmpfile + if( eType != FrameStyle_Separated ) + break; + } + else + bSuccess = false; + } + // get stream length + int nPos = aConverter.TellEnd(); + + aConverter.Seek( 2 ); + aConverter.WriteUInt32( nPos+1 ); + aConverter.Seek( 0 ); + + rBitmap.unlock(); + + if( bSuccess ) + { + // only cancel a successful operation + // sane disrupts memory else + p_cancel( maHandle ); + CheckConsistency( "sane_cancel" ); + } + pBuffer.reset(); + + ReloadOptions(); + + + dbg_msg( "Sane::Start returns with %s\n", bSuccess ? "TRUE" : "FALSE" ); + + return bSuccess; +} + +int Sane::GetRange( int n, std::unique_ptr& rpDouble ) +{ + if( mppOptions[n]->constraint_type != SANE_CONSTRAINT_RANGE && + mppOptions[n]->constraint_type != SANE_CONSTRAINT_WORD_LIST ) + { + return -1; + } + + rpDouble = nullptr; + int nItems, i; + bool bIsFixed = mppOptions[n]->type == SANE_TYPE_FIXED; + + dbg_msg( "Sane::GetRange of option %s ", mppOptions[n]->name ); + if(mppOptions[n]->constraint_type == SANE_CONSTRAINT_RANGE ) + { + double fMin, fMax, fQuant; + if( bIsFixed ) + { + fMin = SANE_UNFIX( mppOptions[n]->constraint.range->min ); + fMax = SANE_UNFIX( mppOptions[n]->constraint.range->max ); + fQuant = SANE_UNFIX( mppOptions[n]->constraint.range->quant ); + } + else + { + fMin = static_cast(mppOptions[n]->constraint.range->min); + fMax = static_cast(mppOptions[n]->constraint.range->max); + fQuant = static_cast(mppOptions[n]->constraint.range->quant); + } + if( fQuant != 0.0 ) + { + dbg_msg( "quantum range [ %lg ; %lg ; %lg ]\n", + fMin, fQuant, fMax ); + nItems = static_cast((fMax - fMin)/fQuant)+1; + rpDouble.reset(new double[ nItems ]); + double fValue = fMin; + for( i = 0; i < nItems; i++, fValue += fQuant ) + rpDouble[i] = fValue; + rpDouble[ nItems-1 ] = fMax; + return nItems; + } + else + { + dbg_msg( "normal range [ %lg %lg ]\n", + fMin, fMax ); + rpDouble.reset(new double[2]); + rpDouble[0] = fMin; + rpDouble[1] = fMax; + return 0; + } + } + else + { + nItems = mppOptions[n]->constraint.word_list[0]; + rpDouble.reset(new double[nItems]); + for( i=0; iconstraint.word_list[i+1] ) : + static_cast(mppOptions[n]->constraint.word_list[i+1]); + } + dbg_msg( "wordlist [ %lg ... %lg ]\n", + rpDouble[ 0 ], rpDouble[ nItems-1 ] ); + return nItems; + } +} + +static const char *ppUnits[] = { + "", + "[Pixel]", + "[Bit]", + "[mm]", + "[DPI]", + "[%]", + "[usec]" +}; + +OUString Sane::GetOptionUnitName( int n ) +{ + OUString aText; + SANE_Unit nUnit = mppOptions[n]->unit; + size_t nUnitAsSize = static_cast(nUnit); + if (nUnitAsSize >= SAL_N_ELEMENTS( ppUnits )) + aText = "[unknown units]"; + else + aText = OUString( ppUnits[ nUnit ], strlen(ppUnits[ nUnit ]), osl_getThreadTextEncoding() ); + return aText; +} + +bool Sane::ActivateButtonOption( int n ) +{ + SANE_Status nStatus = ControlOption( n, SANE_ACTION_SET_VALUE, nullptr ); + return nStatus == SANE_STATUS_GOOD; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/sane.hxx b/extensions/source/scanner/sane.hxx new file mode 100644 index 000000000..a0e631942 --- /dev/null +++ b/extensions/source/scanner/sane.hxx @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace com::sun::star::uno; + + +class BitmapTransporter: public cppu::WeakImplHelper +{ + SvMemoryStream m_aStream; + osl::Mutex m_aProtector; + +public: + + BitmapTransporter(); + virtual ~BitmapTransporter() override; + + virtual css::awt::Size SAL_CALL getSize() override; + virtual Sequence< sal_Int8 > SAL_CALL getDIB() override; + virtual Sequence< sal_Int8 > SAL_CALL getMaskDIB() override { return Sequence< sal_Int8 >(); } + + // Misc + void lock() { m_aProtector.acquire(); } + void unlock() { m_aProtector.release(); } + SvMemoryStream& getStream() { return m_aStream; } +}; + + +class Sane +{ +private: + static int nRefCount; + static oslModule pSaneLib; + + static SANE_Status (*p_init)( SANE_Int*, + SANE_Auth_Callback ); + static void (*p_exit)(); + static SANE_Status (*p_get_devices)( const SANE_Device***, + SANE_Bool ); + static SANE_Status (*p_open)( SANE_String_Const, SANE_Handle ); + static void (*p_close)( SANE_Handle ); + static const SANE_Option_Descriptor* (*p_get_option_descriptor)( + SANE_Handle, SANE_Int ); + static SANE_Status (*p_control_option)( SANE_Handle, SANE_Int, + SANE_Action, void*, + SANE_Int* ); + static SANE_Status (*p_get_parameters)( SANE_Handle, + SANE_Parameters* ); + static SANE_Status (*p_start)( SANE_Handle ); + static SANE_Status (*p_read)( SANE_Handle, SANE_Byte*, SANE_Int, + SANE_Int* ); + static void (*p_cancel)( SANE_Handle ); + static SANE_Status (*p_set_io_mode)( SANE_Handle, SANE_Bool ); + static SANE_Status (*p_get_select_fd)( SANE_Handle, SANE_Int* ); + static SANE_String_Const (*p_strstatus)( SANE_Status ); + + static SANE_Int nVersion; + static SANE_Device** ppDevices; + static int nDevices; + + std::unique_ptr mppOptions; + int mnOptions; + int mnDevice; + SANE_Handle maHandle; + + Link maReloadOptionsLink; + + static inline oslGenericFunction + LoadSymbol( const char* ); + static void Init(); + static void DeInit(); + + SANE_Status ControlOption( int, SANE_Action, void* ); + + bool CheckConsistency( const char*, bool bInit = false ); + +public: + Sane(); + ~Sane(); + + static bool IsSane() + { return pSaneLib != nullptr; } + bool IsOpen() const + { return maHandle != nullptr; } + static int CountDevices() + { return nDevices; } + static OUString GetName( int n ) + { return ppDevices[n]->name ? OUString( ppDevices[n]->name, strlen(ppDevices[n]->name), osl_getThreadTextEncoding() ) : OUString(); } + static OUString GetVendor( int n ) + { return ppDevices[n]->vendor ? OUString( ppDevices[n]->vendor, strlen(ppDevices[n]->vendor), osl_getThreadTextEncoding() ) : OUString(); } + static OUString GetModel( int n ) + { return ppDevices[n]->model ? OUString( ppDevices[n]->model, strlen(ppDevices[n]->model), osl_getThreadTextEncoding() ) : OUString(); } + static OUString GetType( int n ) + { return ppDevices[n]->type ? OUString( ppDevices[n]->type, strlen(ppDevices[n]->type), osl_getThreadTextEncoding() ) : OUString(); } + + OUString GetOptionName( int n ) + { return mppOptions[n]->name ? OUString( mppOptions[n]->name, strlen(mppOptions[n]->name), osl_getThreadTextEncoding() ) : OUString(); } + OUString GetOptionTitle( int n ) + { return mppOptions[n]->title ? OUString( mppOptions[n]->title, strlen(mppOptions[n]->title), osl_getThreadTextEncoding() ) : OUString(); } + SANE_Value_Type GetOptionType( int n ) + { return mppOptions[n]->type; } + SANE_Unit GetOptionUnit( int n ) + { return mppOptions[n]->unit; } + OUString GetOptionUnitName( int n ); + SANE_Int GetOptionCap( int n ) + { return mppOptions[n]->cap; } + SANE_Constraint_Type GetOptionConstraintType( int n ) + { return mppOptions[n]->constraint_type; } + const char** GetStringConstraint( int n ) + { return const_cast(mppOptions[n]->constraint.string_list); } + int GetRange( int, std::unique_ptr& ); + + inline int GetOptionElements( int n ); + int GetOptionByName( const char* ); + bool GetOptionValue( int, bool& ); + bool GetOptionValue( int, OString& ); + bool GetOptionValue( int, double&, int nElement = 0 ); + bool GetOptionValue( int, double* ); + + void SetOptionValue( int, bool ); + void SetOptionValue( int, std::u16string_view ); + void SetOptionValue( int, double, int nElement = 0 ); + void SetOptionValue( int, double const * ); + + bool ActivateButtonOption( int ); + + int CountOptions() { return mnOptions; } + int GetDeviceNumber() const { return mnDevice; } + + bool Open( const char* ); + bool Open( int ); + void Close(); + void ReloadDevices(); + void ReloadOptions(); + + bool Start( BitmapTransporter& ); + + inline Link SetReloadOptionsHdl( const Link& rLink ); +}; + + +inline int Sane::GetOptionElements( int n ) +{ + if( mppOptions[n]->type == SANE_TYPE_FIXED || + mppOptions[n]->type == SANE_TYPE_INT ) + { + return mppOptions[n]->size/sizeof( SANE_Word ); + } + return 1; +} + + +inline Link Sane::SetReloadOptionsHdl( const Link& rLink ) +{ + Link aRet = maReloadOptionsLink; + maReloadOptionsLink = rLink; + return aRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/sanedlg.cxx b/extensions/source/scanner/sanedlg.cxx new file mode 100644 index 000000000..8486195c9 --- /dev/null +++ b/extensions/source/scanner/sanedlg.cxx @@ -0,0 +1,1467 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "sanedlg.hxx" +#include "grid.hxx" +#include +#include +#include +#include +#include +#include + +#define PREVIEW_WIDTH 113 +#define PREVIEW_HEIGHT 160 + +#define RECT_SIZE_PIX 7 + +namespace { + +void DrawRectangles(vcl::RenderContext& rRenderContext, Point const & rUL, Point const & rBR) +{ + int nMiddleX, nMiddleY; + Point aBL, aUR; + + aUR = Point(rBR.X(), rUL.Y()); + aBL = Point(rUL.X(), rBR.Y()); + nMiddleX = (rBR.X() - rUL.X()) / 2 + rUL.X(); + nMiddleY = (rBR.Y() - rUL.Y()) / 2 + rUL.Y(); + + rRenderContext.DrawLine(rUL, aBL); + rRenderContext.DrawLine(aBL, rBR); + rRenderContext.DrawLine(rBR, aUR); + rRenderContext.DrawLine(aUR, rUL); + rRenderContext.DrawRect(tools::Rectangle(rUL, Size(RECT_SIZE_PIX,RECT_SIZE_PIX))); + rRenderContext.DrawRect(tools::Rectangle(aBL, Size(RECT_SIZE_PIX, -RECT_SIZE_PIX))); + rRenderContext.DrawRect(tools::Rectangle(rBR, Size(-RECT_SIZE_PIX, -RECT_SIZE_PIX))); + rRenderContext.DrawRect(tools::Rectangle(aUR, Size(-RECT_SIZE_PIX, RECT_SIZE_PIX ))); + rRenderContext.DrawRect(tools::Rectangle(Point(nMiddleX - RECT_SIZE_PIX / 2, rUL.Y()), Size(RECT_SIZE_PIX, RECT_SIZE_PIX))); + rRenderContext.DrawRect(tools::Rectangle(Point(nMiddleX - RECT_SIZE_PIX / 2, rBR.Y()), Size(RECT_SIZE_PIX, -RECT_SIZE_PIX))); + rRenderContext.DrawRect(tools::Rectangle(Point(rUL.X(), nMiddleY - RECT_SIZE_PIX / 2), Size(RECT_SIZE_PIX, RECT_SIZE_PIX))); + rRenderContext.DrawRect(tools::Rectangle(Point(rBR.X(), nMiddleY - RECT_SIZE_PIX / 2), Size(-RECT_SIZE_PIX, RECT_SIZE_PIX))); +} + +} + +class ScanPreview : public weld::CustomWidgetController +{ +private: + enum DragDirection { TopLeft, Top, TopRight, Right, BottomRight, Bottom, + BottomLeft, Left }; + + BitmapEx maPreviewBitmapEx; + tools::Rectangle maPreviewRect; + Point maLastUL, maLastBR; + Point maTopLeft, maBottomRight; + Point maMinTopLeft, maMaxBottomRight; + SaneDlg* mpParentDialog; + DragDirection meDragDirection; + bool mbDragEnable; + bool mbDragDrawn; + bool mbIsDragging; + +public: + ScanPreview() + : maMaxBottomRight(PREVIEW_WIDTH, PREVIEW_HEIGHT) + , mpParentDialog(nullptr) + , meDragDirection(TopLeft) + , mbDragEnable(false) + , mbDragDrawn(false) + , mbIsDragging(false) + { + } + + void Init(SaneDlg *pParent) + { + mpParentDialog = pParent; + } + + void ResetForNewScanner() + { + maTopLeft = Point(); + maBottomRight = Point(); + maMinTopLeft = Point(); + maMaxBottomRight = Point(PREVIEW_WIDTH, PREVIEW_HEIGHT); + } + + void EnableDrag() + { + mbDragEnable = true; + } + + void DisableDrag() + { + mbDragEnable = false; + } + + bool IsDragEnabled() const + { + return mbDragEnable; + } + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + virtual bool MouseButtonDown(const MouseEvent& rMEvt) override; + virtual bool MouseMove(const MouseEvent& rMEvt) override; + virtual bool MouseButtonUp(const MouseEvent& rMEvt) override; + Point GetPixelPos(const Point& rIn) const; + Point GetLogicPos(const Point& rIn) const; + + void GetPreviewLogicRect(Point& rTopLeft, Point &rBottomRight) const + { + rTopLeft = GetLogicPos(maTopLeft); + rBottomRight = GetLogicPos(maBottomRight); + } + void GetMaxLogicRect(Point& rTopLeft, Point &rBottomRight) const + { + rTopLeft = maMinTopLeft; + rBottomRight = maMaxBottomRight; + + } + void ChangePreviewLogicTopLeftY(tools::Long Y) + { + Point aPoint(0, Y); + aPoint = GetPixelPos(aPoint); + maTopLeft.setY( aPoint.Y() ); + } + void ChangePreviewLogicTopLeftX(tools::Long X) + { + Point aPoint(X, 0); + aPoint = GetPixelPos(aPoint); + maTopLeft.setX( aPoint.X() ); + } + void ChangePreviewLogicBottomRightY(tools::Long Y) + { + Point aPoint(0, Y); + aPoint = GetPixelPos(aPoint); + maBottomRight.setY( aPoint.Y() ); + } + void ChangePreviewLogicBottomRightX(tools::Long X) + { + Point aPoint(X, 0); + aPoint = GetPixelPos(aPoint); + maBottomRight.setX( aPoint.X() ); + } + void SetPreviewLogicRect(const Point& rTopLeft, const Point &rBottomRight) + { + maTopLeft = GetPixelPos(rTopLeft); + maBottomRight = GetPixelPos(rBottomRight); + maPreviewRect = tools::Rectangle(maTopLeft, + Size(maBottomRight.X() - maTopLeft.X(), + maBottomRight.Y() - maTopLeft.Y())); + } + void SetPreviewMaxRect(const Point& rTopLeft, const Point &rBottomRight) + { + maMinTopLeft = rTopLeft; + maMaxBottomRight = rBottomRight; + } + void DrawDrag(vcl::RenderContext& rRenderContext); + void UpdatePreviewBounds(); + void SetBitmap(SvStream &rStream) + { + ReadDIBBitmapEx(maPreviewBitmapEx, rStream, true); + } + virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override + { + Size aSize(pDrawingArea->get_ref_device().LogicToPixel(Size(PREVIEW_WIDTH, PREVIEW_HEIGHT), MapMode(MapUnit::MapAppFont))); + aSize.setWidth(aSize.getWidth()+1); + aSize.setHeight(aSize.getHeight()+1); + pDrawingArea->set_size_request(aSize.Width(), aSize.Height()); + CustomWidgetController::SetDrawingArea(pDrawingArea); + SetOutputSizePixel(aSize); + } +}; + +SaneDlg::SaneDlg(weld::Window* pParent, Sane& rSane, bool bScanEnabled) + : GenericDialogController(pParent, "modules/scanner/ui/sanedialog.ui", "SaneDialog") + , mpParent(pParent) + , mrSane(rSane) + , mbScanEnabled(bScanEnabled) + , mnCurrentOption(0) + , mnCurrentElement(0) + , mfMin(0.0) + , mfMax(0.0) + , doScan(false) + , mxCancelButton(m_xBuilder->weld_button("cancel")) + , mxDeviceInfoButton(m_xBuilder->weld_button("deviceInfoButton")) + , mxPreviewButton(m_xBuilder->weld_button("previewButton")) + , mxScanButton(m_xBuilder->weld_button("ok")) + , mxButtonOption(m_xBuilder->weld_button("optionsButton")) + , mxOptionTitle(m_xBuilder->weld_label("optionTitleLabel")) + , mxOptionDescTxt(m_xBuilder->weld_label("optionsDescLabel")) + , mxVectorTxt(m_xBuilder->weld_label("vectorLabel")) + , mxLeftField(m_xBuilder->weld_metric_spin_button("leftSpinbutton", FieldUnit::PIXEL)) + , mxTopField(m_xBuilder->weld_metric_spin_button("topSpinbutton", FieldUnit::PIXEL)) + , mxRightField(m_xBuilder->weld_metric_spin_button("rightSpinbutton", FieldUnit::PIXEL)) + , mxBottomField(m_xBuilder->weld_metric_spin_button("bottomSpinbutton", FieldUnit::PIXEL)) + , mxDeviceBox(m_xBuilder->weld_combo_box("deviceCombobox")) + , mxReslBox(m_xBuilder->weld_combo_box("reslCombobox")) + , mxAdvancedBox(m_xBuilder->weld_check_button("advancedCheckbutton")) + , mxVectorBox(m_xBuilder->weld_spin_button("vectorSpinbutton")) + , mxQuantumRangeBox(m_xBuilder->weld_combo_box("quantumRangeCombobox")) + , mxStringRangeBox(m_xBuilder->weld_combo_box("stringRangeCombobox")) + , mxBoolCheckBox(m_xBuilder->weld_check_button("boolCheckbutton")) + , mxStringEdit(m_xBuilder->weld_entry("stringEntry")) + , mxNumericEdit(m_xBuilder->weld_entry("numericEntry")) + , mxOptionBox(m_xBuilder->weld_tree_view("optionSvTreeListBox")) + , mxPreview(new ScanPreview) + , mxPreviewWnd(new weld::CustomWeld(*m_xBuilder, "preview", *mxPreview)) +{ + Size aSize(mxOptionBox->get_approximate_digit_width() * 32, mxOptionBox->get_height_rows(8)); + mxOptionTitle->set_size_request(aSize.Width(), aSize.Height() / 2); + mxOptionBox->set_size_request(aSize.Width(), aSize.Height()); + mxPreview->Init(this); + if( Sane::IsSane() ) + { + InitDevices(); // opens first sane device + DisableOption(); + InitFields(); + } + + mxDeviceInfoButton->connect_clicked( LINK( this, SaneDlg, ClickBtnHdl ) ); + mxPreviewButton->connect_clicked( LINK( this, SaneDlg, ClickBtnHdl ) ); + mxScanButton->connect_clicked( LINK( this, SaneDlg, ClickBtnHdl ) ); + mxButtonOption->connect_clicked( LINK( this, SaneDlg, ClickBtnHdl ) ); + mxDeviceBox->connect_changed( LINK( this, SaneDlg, SelectHdl ) ); + mxOptionBox->connect_changed( LINK( this, SaneDlg, OptionsBoxSelectHdl ) ); + mxCancelButton->connect_clicked( LINK( this, SaneDlg, ClickBtnHdl ) ); + mxBoolCheckBox->connect_toggled( LINK( this, SaneDlg, ToggleBtnHdl ) ); + mxStringEdit->connect_changed( LINK( this, SaneDlg, ModifyHdl ) ); + mxNumericEdit->connect_changed( LINK( this, SaneDlg, ModifyHdl ) ); + mxVectorBox->connect_changed( LINK( this, SaneDlg, ModifyHdl ) ); + mxReslBox->connect_changed( LINK( this, SaneDlg, ValueModifyHdl ) ); + mxStringRangeBox->connect_changed( LINK( this, SaneDlg, SelectHdl ) ); + mxQuantumRangeBox->connect_changed( LINK( this, SaneDlg, SelectHdl ) ); + mxLeftField->connect_value_changed( LINK( this, SaneDlg, MetricValueModifyHdl ) ); + mxRightField->connect_value_changed( LINK( this, SaneDlg, MetricValueModifyHdl) ); + mxTopField->connect_value_changed( LINK( this, SaneDlg, MetricValueModifyHdl) ); + mxBottomField->connect_value_changed( LINK( this, SaneDlg, MetricValueModifyHdl) ); + mxAdvancedBox->connect_toggled( LINK( this, SaneDlg, ToggleBtnHdl ) ); + + maOldLink = mrSane.SetReloadOptionsHdl( LINK( this, SaneDlg, ReloadSaneOptionsHdl ) ); +} + +SaneDlg::~SaneDlg() +{ + mrSane.SetReloadOptionsHdl(maOldLink); +} + +namespace { + +OUString SaneResId(TranslateId aID) +{ + return Translate::get(aID, Translate::Create("pcr")); +} + +} + +short SaneDlg::run() +{ + if (!Sane::IsSane()) + { + std::unique_ptr xErrorBox(Application::CreateMessageDialog(mpParent, + VclMessageType::Warning, VclButtonsType::Ok, + SaneResId(STR_COULD_NOT_BE_INIT))); + xErrorBox->run(); + return RET_CANCEL; + } + LoadState(); + return GenericDialogController::run(); +} + +void SaneDlg::InitDevices() +{ + if( ! Sane::IsSane() ) + return; + + if( mrSane.IsOpen() ) + mrSane.Close(); + mrSane.ReloadDevices(); + mxDeviceBox->clear(); + for (int i = 0; i < Sane::CountDevices(); ++i) + mxDeviceBox->append_text(Sane::GetName(i)); + if( Sane::CountDevices() ) + { + mrSane.Open(0); + mxDeviceBox->set_active(0); + } +} + +void SaneDlg::InitFields() +{ + if( ! Sane::IsSane() ) + return; + + int nOption, i, nValue; + double fValue; + const char *ppSpecialOptions[] = { + "resolution", + "tl-x", + "tl-y", + "br-x", + "br-y", + "preview" + }; + + mxPreview->EnableDrag(); + mxReslBox->clear(); + Point aTopLeft, aBottomRight; + mxPreview->GetPreviewLogicRect(aTopLeft, aBottomRight); + Point aMinTopLeft, aMaxBottomRight; + mxPreview->GetMaxLogicRect(aMinTopLeft, aMaxBottomRight); + mxScanButton->set_visible( mbScanEnabled ); + + if( ! mrSane.IsOpen() ) + return; + + // set Resolution + nOption = mrSane.GetOptionByName( "resolution" ); + if( nOption != -1 ) + { + double fRes; + + if( mrSane.GetOptionValue( nOption, fRes ) ) + { + mxReslBox->set_sensitive(true); + + mxReslBox->set_entry_text(OUString::number(static_cast(fRes))); + std::unique_ptr pDouble; + nValue = mrSane.GetRange( nOption, pDouble ); + if( nValue > -1 ) + { + assert(pDouble); + if( nValue ) + { + for( i=0; i(pDouble[i]) % 20) ) + mxReslBox->append_text(OUString::number(static_cast(pDouble[i]))); + } + } + else + { + mxReslBox->append_text(OUString::number(static_cast(pDouble[0]))); + // Can only select 75 and 2400 dpi in Scanner dialogue + // scanner allows random setting of dpi resolution, a slider might be useful + // support that + // workaround: offer at least some more standard dpi resolution between + // min and max value + int bGot300 = 0; + for (sal_uInt32 nRes = static_cast(pDouble[0]) * 2; nRes < static_cast(pDouble[1]); nRes = nRes * 2) + { + if ( !bGot300 && nRes > 300 ) { + nRes = 300; bGot300 = 1; + } + mxReslBox->append_text(OUString::number(nRes)); + } + mxReslBox->append_text(OUString::number(static_cast(pDouble[1]))); + } + } + else + mxReslBox->set_sensitive( false ); + } + } + else + mxReslBox->set_sensitive( false ); + + // set scan area + for( i = 0; i < 4; i++ ) + { + char const *pOptionName = nullptr; + weld::MetricSpinButton* pField = nullptr; + switch( i ) + { + case 0: + pOptionName = "tl-x"; + pField = mxLeftField.get(); + break; + case 1: + pOptionName = "tl-y"; + pField = mxTopField.get(); + break; + case 2: + pOptionName = "br-x"; + pField = mxRightField.get(); + break; + case 3: + pOptionName = "br-y"; + pField = mxBottomField.get(); + } + nOption = pOptionName ? mrSane.GetOptionByName( pOptionName ) : -1; + if( nOption != -1 ) + { + if( mrSane.GetOptionValue( nOption, fValue ) ) + { + if( mrSane.GetOptionUnit( nOption ) == SANE_UNIT_MM ) + { + pField->set_unit( FieldUnit::MM ); + pField->set_value( static_cast(fValue), FieldUnit::MM ); + } + else // SANE_UNIT_PIXEL + { + pField->set_unit( FieldUnit::PIXEL ); + pField->set_value( static_cast(fValue), FieldUnit::PIXEL ); + } + switch( i ) { + case 0: aTopLeft.setX( static_cast(fValue) );break; + case 1: aTopLeft.setY( static_cast(fValue) );break; + case 2: aBottomRight.setX( static_cast(fValue) );break; + case 3: aBottomRight.setY( static_cast(fValue) );break; + } + } + std::unique_ptr pDouble; + nValue = mrSane.GetRange( nOption, pDouble ); + if( nValue > -1 ) + { + if( pDouble ) + { + pField->set_min( static_cast(pDouble[0]), FieldUnit::NONE ); + if( nValue ) + pField->set_max( static_cast(pDouble[ nValue-1 ]), FieldUnit::NONE ); + else + pField->set_max( static_cast(pDouble[ 1 ]), FieldUnit::NONE ); + } + switch( i ) { + case 0: aMinTopLeft.setX( pField->get_min(FieldUnit::NONE) );break; + case 1: aMinTopLeft.setY( pField->get_min(FieldUnit::NONE) );break; + case 2: aMaxBottomRight.setX( pField->get_max(FieldUnit::NONE) );break; + case 3: aMaxBottomRight.setY( pField->get_max(FieldUnit::NONE) );break; + } + } + else + { + switch( i ) { + case 0: aMinTopLeft.setX( static_cast(fValue) );break; + case 1: aMinTopLeft.setY( static_cast(fValue) );break; + case 2: aMaxBottomRight.setX( static_cast(fValue) );break; + case 3: aMaxBottomRight.setY( static_cast(fValue) );break; + } + } + pField->set_sensitive(true); + } + else + { + mxPreview->DisableDrag(); + pField->set_min( 0, FieldUnit::NONE ); + switch( i ) { + case 0: + aMinTopLeft.setX( 0 ); + aTopLeft.setX( 0 ); + pField->set_max( PREVIEW_WIDTH, FieldUnit::NONE ); + pField->set_value( 0, FieldUnit::NONE ); + break; + case 1: + aMinTopLeft.setY( 0 ); + aTopLeft.setY( 0 ); + pField->set_max( PREVIEW_HEIGHT, FieldUnit::NONE ); + pField->set_value( 0, FieldUnit::NONE ); + break; + case 2: + aMaxBottomRight.setX( PREVIEW_WIDTH ); + aBottomRight.setX( PREVIEW_WIDTH ); + pField->set_max( PREVIEW_WIDTH, FieldUnit::NONE ); + pField->set_value( PREVIEW_WIDTH, FieldUnit::NONE ); + break; + case 3: + aMaxBottomRight.setY( PREVIEW_HEIGHT ); + aBottomRight.setY( PREVIEW_HEIGHT ); + pField->set_max( PREVIEW_HEIGHT, FieldUnit::NONE ); + pField->set_value( PREVIEW_HEIGHT, FieldUnit::NONE ); + break; + } + pField->set_sensitive(false); + } + } + + mxPreview->SetPreviewMaxRect(aMinTopLeft, aMaxBottomRight); + mxPreview->SetPreviewLogicRect(aTopLeft, aBottomRight); + mxPreview->Invalidate(); + + // fill OptionBox + mxOptionBox->clear(); + std::unique_ptr xParentEntry(mxOptionBox->make_iterator()); + bool bGroupRejected = false; + for( i = 1; i < mrSane.CountOptions(); i++ ) + { + OUString aOption=mrSane.GetOptionName( i ); + bool bInsertAdvanced = + (mrSane.GetOptionCap( i ) & SANE_CAP_ADVANCED) == 0 || + mxAdvancedBox->get_active(); + if( mrSane.GetOptionType( i ) == SANE_TYPE_GROUP ) + { + if( bInsertAdvanced ) + { + aOption = mrSane.GetOptionTitle( i ); + mxOptionBox->append(xParentEntry.get()); + mxOptionBox->set_text(*xParentEntry, aOption, 0); + bGroupRejected = false; + } + else + bGroupRejected = true; + } + else if( !aOption.isEmpty() && + ! ( mrSane.GetOptionCap( i ) & + ( + SANE_CAP_HARD_SELECT | + SANE_CAP_INACTIVE + ) ) && + bInsertAdvanced && ! bGroupRejected ) + { + bool bIsSpecial = false; + for( size_t n = 0; !bIsSpecial && + n < SAL_N_ELEMENTS(ppSpecialOptions); n++ ) + { + if( aOption == OUString::createFromAscii(ppSpecialOptions[n]) ) + bIsSpecial=true; + } + if( ! bIsSpecial ) + { + if (xParentEntry) + mxOptionBox->append(xParentEntry.get(), aOption); + else + mxOptionBox->append_text(aOption); + } + } + } +} + +IMPL_LINK( SaneDlg, ClickBtnHdl, weld::Button&, rButton, void ) +{ + if( mrSane.IsOpen() ) + { + if( &rButton == mxDeviceInfoButton.get() ) + { + OUString aString(SaneResId(STR_DEVICE_DESC)); + aString = aString.replaceFirst( "%s", Sane::GetName( mrSane.GetDeviceNumber() ) ); + aString = aString.replaceFirst( "%s", Sane::GetVendor( mrSane.GetDeviceNumber() ) ); + aString = aString.replaceFirst( "%s", Sane::GetModel( mrSane.GetDeviceNumber() ) ); + aString = aString.replaceFirst( "%s", Sane::GetType( mrSane.GetDeviceNumber() ) ); + std::unique_ptr xInfoBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Info, VclButtonsType::Ok, + aString)); + xInfoBox->run(); + } + else if( &rButton == mxPreviewButton.get() ) + AcquirePreview(); + else if( &rButton == mxButtonOption.get() ) + { + + SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption ); + switch( nType ) + { + case SANE_TYPE_BUTTON: + mrSane.ActivateButtonOption( mnCurrentOption ); + break; + case SANE_TYPE_FIXED: + case SANE_TYPE_INT: + { + int nElements = mrSane.GetOptionElements( mnCurrentOption ); + std::unique_ptr x(new double[ nElements ]); + std::unique_ptr y(new double[ nElements ]); + for( int i = 0; i < nElements; i++ ) + x[ i ] = static_cast(i); + mrSane.GetOptionValue( mnCurrentOption, y.get() ); + + GridDialog aGrid(m_xDialog.get(), x.get(), y.get(), nElements); + aGrid.set_title( mrSane.GetOptionName( mnCurrentOption ) ); + aGrid.setBoundings( 0, mfMin, nElements, mfMax ); + if (aGrid.run() && aGrid.getNewYValues()) + mrSane.SetOptionValue( mnCurrentOption, aGrid.getNewYValues() ); + } + break; + case SANE_TYPE_BOOL: + case SANE_TYPE_STRING: + case SANE_TYPE_GROUP: + break; + } + } + } + if (&rButton == mxScanButton.get()) + { + double fRes = static_cast(mxReslBox->get_active_text().toUInt32()); + SetAdjustedNumericalValue( "resolution", fRes ); + UpdateScanArea(true); + SaveState(); + m_xDialog->response(mrSane.IsOpen() ? RET_OK : RET_CANCEL); + doScan = mrSane.IsOpen(); + } + else if( &rButton == mxCancelButton.get() ) + { + mrSane.Close(); + m_xDialog->response(RET_CANCEL); + } +} + +IMPL_LINK( SaneDlg, ToggleBtnHdl, weld::Toggleable&, rButton, void ) +{ + if( mrSane.IsOpen() ) + { + if( &rButton == mxBoolCheckBox.get() ) + { + mrSane.SetOptionValue( mnCurrentOption, + mxBoolCheckBox->get_active() ); + } + else if( &rButton == mxAdvancedBox.get() ) + { + ReloadSaneOptionsHdl( mrSane ); + } + } +} + +IMPL_LINK( SaneDlg, SelectHdl, weld::ComboBox&, rListBox, void ) +{ + if( &rListBox == mxDeviceBox.get() && Sane::IsSane() && Sane::CountDevices() ) + { + int nNewNumber = mxDeviceBox->get_active(); + int nOldNumber = mrSane.GetDeviceNumber(); + if (nNewNumber != nOldNumber) + { + mrSane.Close(); + mrSane.Open(nNewNumber); + mxPreview->ResetForNewScanner(); + InitFields(); + } + } + if( mrSane.IsOpen() ) + { + if( &rListBox == mxQuantumRangeBox.get() ) + { + double fValue = mxQuantumRangeBox->get_active_text().toDouble(); + mrSane.SetOptionValue(mnCurrentOption, fValue, mnCurrentElement); + } + else if( &rListBox == mxStringRangeBox.get() ) + { + mrSane.SetOptionValue(mnCurrentOption, mxStringRangeBox->get_active_text()); + } + } +} + +IMPL_LINK_NOARG(SaneDlg, OptionsBoxSelectHdl, weld::TreeView&, void) +{ + if (!Sane::IsSane()) + return; + + OUString aOption = mxOptionBox->get_selected_text(); + int nOption = mrSane.GetOptionByName(OUStringToOString(aOption, + osl_getThreadTextEncoding()).getStr()); + if( nOption == -1 || nOption == mnCurrentOption ) + return; + + DisableOption(); + mnCurrentOption = nOption; + mxOptionTitle->set_label(mrSane.GetOptionTitle(mnCurrentOption)); + SANE_Value_Type nType = mrSane.GetOptionType( mnCurrentOption ); + SANE_Constraint_Type nConstraint; + switch( nType ) + { + case SANE_TYPE_BOOL: EstablishBoolOption();break; + case SANE_TYPE_STRING: + nConstraint = mrSane.GetOptionConstraintType( mnCurrentOption ); + if( nConstraint == SANE_CONSTRAINT_STRING_LIST ) + EstablishStringRange(); + else + EstablishStringOption(); + break; + case SANE_TYPE_FIXED: + case SANE_TYPE_INT: + { + nConstraint = mrSane.GetOptionConstraintType( mnCurrentOption ); + int nElements = mrSane.GetOptionElements( mnCurrentOption ); + mnCurrentElement = 0; + if( nConstraint == SANE_CONSTRAINT_RANGE || + nConstraint == SANE_CONSTRAINT_WORD_LIST ) + EstablishQuantumRange(); + else + { + mfMin = mfMax = 0.0; + EstablishNumericOption(); + } + if( nElements > 1 ) + { + if( nElements <= 10 ) + { + mxVectorBox->set_range(1, mrSane.GetOptionElements(mnCurrentOption)); + mxVectorBox->set_value(1); + mxVectorBox->show(); + mxVectorTxt->show(); + } + else + { + DisableOption(); + // bring up dialog only on button click + EstablishButtonOption(); + } + } + } + break; + case SANE_TYPE_BUTTON: + EstablishButtonOption(); + break; + default: break; + } +} + +IMPL_LINK(SaneDlg, ModifyHdl, weld::Entry&, rEdit, void) +{ + if( !mrSane.IsOpen() ) + return; + + if (&rEdit == mxStringEdit.get()) + { + mrSane.SetOptionValue( mnCurrentOption, mxStringEdit->get_text() ); + } + else if (&rEdit == mxNumericEdit.get()) + { + double fValue = mxNumericEdit->get_text().toDouble(); + if( mfMin != mfMax && ( fValue < mfMin || fValue > mfMax ) ) + { + char pBuf[256]; + if( fValue < mfMin ) + fValue = mfMin; + else if( fValue > mfMax ) + fValue = mfMax; + sprintf( pBuf, "%g", fValue ); + mxNumericEdit->set_text( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) ); + } + mrSane.SetOptionValue( mnCurrentOption, fValue, mnCurrentElement ); + } + else if (&rEdit == mxVectorBox.get()) + { + mnCurrentElement = mxVectorBox->get_value() - 1; + double fValue; + if( mrSane.GetOptionValue( mnCurrentOption, fValue, mnCurrentElement )) + { + char pBuf[256]; + sprintf( pBuf, "%g", fValue ); + OUString aValue( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ); + mxNumericEdit->set_text( aValue ); + mxQuantumRangeBox->set_active_text( aValue ); + } + } +} + +IMPL_LINK(SaneDlg, ValueModifyHdl, weld::ComboBox&, rEdit, void) +{ + if( !mrSane.IsOpen() ) + return; + + if (&rEdit != mxReslBox.get()) + return; + + double fRes = static_cast(mxReslBox->get_active_text().toUInt32()); + int nOption = mrSane.GetOptionByName( "resolution" ); + if( nOption == -1 ) + return; + + std::unique_ptr pDouble; + int nValues = mrSane.GetRange( nOption, pDouble ); + if( nValues > 0 ) + { + int i; + for( i = 0; i < nValues; i++ ) + { + if( fRes == pDouble[i] ) + break; + } + if( i >= nValues ) + fRes = pDouble[0]; + } + else if( nValues == 0 ) + { + if( fRes < pDouble[ 0 ] ) + fRes = pDouble[ 0 ]; + if( fRes > pDouble[ 1 ] ) + fRes = pDouble[ 1 ]; + } + mxReslBox->set_entry_text(OUString::number(static_cast(fRes))); +} + +IMPL_LINK(SaneDlg, MetricValueModifyHdl, weld::MetricSpinButton&, rEdit, void) +{ + if( !mrSane.IsOpen() ) + return; + + if (&rEdit == mxTopField.get()) + { + mxPreview->ChangePreviewLogicTopLeftY(mxTopField->get_value(FieldUnit::NONE)); + mxPreview->Invalidate(); + } + else if (&rEdit == mxLeftField.get()) + { + mxPreview->ChangePreviewLogicTopLeftX(mxLeftField->get_value(FieldUnit::NONE)); + mxPreview->Invalidate(); + } + else if (&rEdit == mxBottomField.get()) + { + mxPreview->ChangePreviewLogicBottomRightY(mxBottomField->get_value(FieldUnit::NONE)); + mxPreview->Invalidate(); + } + else if (&rEdit == mxRightField.get()) + { + mxPreview->ChangePreviewLogicBottomRightX(mxRightField->get_value(FieldUnit::NONE)); + mxPreview->Invalidate(); + } +} + +IMPL_LINK_NOARG( SaneDlg, ReloadSaneOptionsHdl, Sane&, void ) +{ + mnCurrentOption = -1; + mnCurrentElement = 0; + DisableOption(); + InitFields(); + mxPreview->Invalidate(); +} + +void SaneDlg::AcquirePreview() +{ + if( ! mrSane.IsOpen() ) + return; + + UpdateScanArea( true ); + // set small resolution for preview + double fResl = static_cast(mxReslBox->get_active_text().toUInt32()); + SetAdjustedNumericalValue( "resolution", 30.0 ); + + int nOption = mrSane.GetOptionByName( "preview" ); + if( nOption == -1 ) + { + OUString aString(SaneResId(STR_SLOW_PREVIEW)); + std::unique_ptr xBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::OkCancel, + aString)); + if (xBox->run() == RET_CANCEL) + return; + } + else + mrSane.SetOptionValue( nOption, true ); + + rtl::Reference xTransporter(new BitmapTransporter); + if (!mrSane.Start(*xTransporter)) + { + std::unique_ptr xErrorBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, + SaneResId(STR_ERROR_SCAN))); + xErrorBox->run(); + } + else + { +#if OSL_DEBUG_LEVEL > 0 + SAL_INFO("extensions.scanner", "Previewbitmapstream contains " << xTransporter->getStream().TellEnd() << "bytes"); +#endif + xTransporter->getStream().Seek( STREAM_SEEK_TO_BEGIN ); + mxPreview->SetBitmap(xTransporter->getStream()); + } + + SetAdjustedNumericalValue( "resolution", fResl ); + mxReslBox->set_entry_text(OUString::number(static_cast(fResl))); + + mxPreview->UpdatePreviewBounds(); + mxPreview->Invalidate(); +} + +void ScanPreview::UpdatePreviewBounds() +{ + if( mbDragEnable ) + { + maPreviewRect = tools::Rectangle( maTopLeft, + Size( maBottomRight.X() - maTopLeft.X(), + maBottomRight.Y() - maTopLeft.Y() ) + ); + } + else + { + Size aBMSize( maPreviewBitmapEx.GetSizePixel() ); + if( aBMSize.Width() > aBMSize.Height() && aBMSize.Width() ) + { + int nVHeight = (maBottomRight.X() - maTopLeft.X()) * aBMSize.Height() / aBMSize.Width(); + maPreviewRect = tools::Rectangle( Point( maTopLeft.X(), ( maTopLeft.Y() + maBottomRight.Y() )/2 - nVHeight/2 ), + Size( maBottomRight.X() - maTopLeft.X(), + nVHeight ) ); + } + else if (aBMSize.Height()) + { + int nVWidth = (maBottomRight.Y() - maTopLeft.Y()) * aBMSize.Width() / aBMSize.Height(); + maPreviewRect = tools::Rectangle( Point( ( maTopLeft.X() + maBottomRight.X() )/2 - nVWidth/2, maTopLeft.Y() ), + Size( nVWidth, + maBottomRight.Y() - maTopLeft.Y() ) ); + } + } +} + +void ScanPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + rRenderContext.SetMapMode(MapMode(MapUnit::MapAppFont)); + rRenderContext.SetFillColor(COL_WHITE); + rRenderContext.SetLineColor(COL_WHITE); + rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), + Size(PREVIEW_WIDTH, PREVIEW_HEIGHT))); + rRenderContext.SetMapMode(MapMode(MapUnit::MapPixel)); + // check for sane values + rRenderContext.DrawBitmapEx(maPreviewRect.TopLeft(), maPreviewRect.GetSize(), maPreviewBitmapEx); + + mbDragDrawn = false; + DrawDrag(rRenderContext); +} + +void SaneDlg::DisableOption() +{ + mxBoolCheckBox->hide(); + mxStringEdit->hide(); + mxNumericEdit->hide(); + mxQuantumRangeBox->hide(); + mxStringRangeBox->hide(); + mxButtonOption->hide(); + mxVectorBox->hide(); + mxVectorTxt->hide(); + mxOptionDescTxt->hide(); +} + +void SaneDlg::EstablishBoolOption() +{ + bool bSuccess, bValue; + + bSuccess = mrSane.GetOptionValue( mnCurrentOption, bValue ); + if( bSuccess ) + { + mxBoolCheckBox->set_label( mrSane.GetOptionName( mnCurrentOption ) ); + mxBoolCheckBox->set_active( bValue ); + mxBoolCheckBox->show(); + } +} + +void SaneDlg::EstablishStringOption() +{ + bool bSuccess; + OString aValue; + + bSuccess = mrSane.GetOptionValue( mnCurrentOption, aValue ); + if( bSuccess ) + { + mxOptionDescTxt->set_label( mrSane.GetOptionName( mnCurrentOption ) ); + mxOptionDescTxt->show(); + mxStringEdit->set_text(OStringToOUString(aValue, osl_getThreadTextEncoding())); + mxStringEdit->show(); + } +} + +void SaneDlg::EstablishStringRange() +{ + const char** ppStrings = mrSane.GetStringConstraint( mnCurrentOption ); + mxStringRangeBox->clear(); + for( int i = 0; ppStrings[i] != nullptr; i++ ) + mxStringRangeBox->append_text( OUString( ppStrings[i], strlen(ppStrings[i]), osl_getThreadTextEncoding() ) ); + OString aValue; + mrSane.GetOptionValue( mnCurrentOption, aValue ); + mxStringRangeBox->set_active_text(OStringToOUString(aValue, osl_getThreadTextEncoding())); + mxStringRangeBox->show(); + mxOptionDescTxt->set_label( mrSane.GetOptionName( mnCurrentOption ) ); + mxOptionDescTxt->show(); +} + +void SaneDlg::EstablishQuantumRange() +{ + mpRange.reset(); + int nValues = mrSane.GetRange( mnCurrentOption, mpRange ); + if( nValues == 0 ) + { + mfMin = mpRange[ 0 ]; + mfMax = mpRange[ 1 ]; + mpRange.reset(); + EstablishNumericOption(); + } + else if( nValues > 0 ) + { + char pBuf[ 256 ]; + mxQuantumRangeBox->clear(); + mfMin = mpRange[ 0 ]; + mfMax = mpRange[ nValues-1 ]; + for( int i = 0; i < nValues; i++ ) + { + sprintf( pBuf, "%g", mpRange[ i ] ); + mxQuantumRangeBox->append_text( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) ); + } + double fValue; + if( mrSane.GetOptionValue( mnCurrentOption, fValue, mnCurrentElement ) ) + { + sprintf( pBuf, "%g", fValue ); + mxQuantumRangeBox->set_active_text( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) ); + } + mxQuantumRangeBox->show(); + OUString aText( mrSane.GetOptionName( mnCurrentOption ) + " " ); + aText += mrSane.GetOptionUnitName( mnCurrentOption ); + mxOptionDescTxt->set_label(aText); + mxOptionDescTxt->show(); + } +} + +void SaneDlg::EstablishNumericOption() +{ + bool bSuccess; + double fValue; + + bSuccess = mrSane.GetOptionValue( mnCurrentOption, fValue ); + if( ! bSuccess ) + return; + + char pBuf[256]; + OUString aText( mrSane.GetOptionName( mnCurrentOption ) + " " ); + aText += mrSane.GetOptionUnitName( mnCurrentOption ); + if( mfMin != mfMax ) + { + sprintf( pBuf, " < %g ; %g >", mfMin, mfMax ); + aText += OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ); + } + mxOptionDescTxt->set_label( aText ); + mxOptionDescTxt->show(); + sprintf( pBuf, "%g", fValue ); + mxNumericEdit->set_text( OUString( pBuf, strlen(pBuf), osl_getThreadTextEncoding() ) ); + mxNumericEdit->show(); +} + +void SaneDlg::EstablishButtonOption() +{ + mxOptionDescTxt->set_label(mrSane.GetOptionName(mnCurrentOption)); + mxOptionDescTxt->show(); + mxButtonOption->show(); +} + +bool ScanPreview::MouseMove(const MouseEvent& rMEvt) +{ + if( !mbIsDragging ) + return false; + + Point aMousePos = rMEvt.GetPosPixel(); + // move into valid area + Point aLogicPos = GetLogicPos( aMousePos ); + aMousePos = GetPixelPos( aLogicPos ); + switch( meDragDirection ) + { + case TopLeft: maTopLeft = aMousePos; break; + case Top: maTopLeft.setY( aMousePos.Y() ); break; + case TopRight: + maTopLeft.setY( aMousePos.Y() ); + maBottomRight.setX( aMousePos.X() ); + break; + case Right: maBottomRight.setX( aMousePos.X() ); break; + case BottomRight: maBottomRight = aMousePos; break; + case Bottom: maBottomRight.setY( aMousePos.Y() ); break; + case BottomLeft: + maTopLeft.setX( aMousePos.X() ); + maBottomRight.setY( aMousePos.Y() ); + break; + case Left: maTopLeft.setX( aMousePos.X() ); break; + default: break; + } + int nSwap; + if( maTopLeft.X() > maBottomRight.X() ) + { + nSwap = maTopLeft.X(); + maTopLeft.setX( maBottomRight.X() ); + maBottomRight.setX( nSwap ); + } + if( maTopLeft.Y() > maBottomRight.Y() ) + { + nSwap = maTopLeft.Y(); + maTopLeft.setY( maBottomRight.Y() ); + maBottomRight.setY( nSwap ); + } + Invalidate(); + mpParentDialog->UpdateScanArea(false); + return false; +} + +bool ScanPreview::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if (!mbIsDragging && mbDragEnable) + { + Point aMousePixel = rMEvt.GetPosPixel(); + + int nMiddleX = ( maBottomRight.X() - maTopLeft.X() ) / 2 - RECT_SIZE_PIX/2 + maTopLeft.X(); + int nMiddleY = ( maBottomRight.Y() - maTopLeft.Y() ) / 2 - RECT_SIZE_PIX/2 + maTopLeft.Y(); + if( aMousePixel.Y() >= maTopLeft.Y() && + aMousePixel.Y() < maTopLeft.Y() + RECT_SIZE_PIX ) + { + if( aMousePixel.X() >= maTopLeft.X() && + aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX ) + { + meDragDirection = TopLeft; + mbIsDragging = true; + } + else if( aMousePixel.X() >= nMiddleX && + aMousePixel.X() < nMiddleX + RECT_SIZE_PIX ) + { + meDragDirection = Top; + mbIsDragging = true; + } + else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX && + aMousePixel.X() <= maBottomRight.X() ) + { + meDragDirection = TopRight; + mbIsDragging = true; + } + } + else if( aMousePixel.Y() >= nMiddleY && + aMousePixel.Y() < nMiddleY + RECT_SIZE_PIX ) + { + if( aMousePixel.X() >= maTopLeft.X() && + aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX ) + { + meDragDirection = Left; + mbIsDragging = true; + } + else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX && + aMousePixel.X() <= maBottomRight.X() ) + { + meDragDirection = Right; + mbIsDragging = true; + } + } + else if( aMousePixel.Y() <= maBottomRight.Y() && + aMousePixel.Y() > maBottomRight.Y() - RECT_SIZE_PIX ) + { + if( aMousePixel.X() >= maTopLeft.X() && + aMousePixel.X() < maTopLeft.X() + RECT_SIZE_PIX ) + { + meDragDirection = BottomLeft; + mbIsDragging = true; + } + else if( aMousePixel.X() >= nMiddleX && + aMousePixel.X() < nMiddleX + RECT_SIZE_PIX ) + { + meDragDirection = Bottom; + mbIsDragging = true; + } + else if( aMousePixel.X() > maBottomRight.X() - RECT_SIZE_PIX && + aMousePixel.X() <= maBottomRight.X() ) + { + meDragDirection = BottomRight; + mbIsDragging = true; + } + } + } + + if( mbIsDragging ) + Invalidate(); + + return false; +} + +bool ScanPreview::MouseButtonUp(const MouseEvent&) +{ + if( mbIsDragging ) + mpParentDialog->UpdateScanArea(true); + mbIsDragging = false; + + return false; +} + +void ScanPreview::DrawDrag(vcl::RenderContext& rRenderContext) +{ + if (!mbDragEnable) + return; + + RasterOp eROP = rRenderContext.GetRasterOp(); + rRenderContext.SetRasterOp(RasterOp::Invert); + rRenderContext.SetMapMode(MapMode(MapUnit::MapPixel)); + + if (mbDragDrawn) + DrawRectangles(rRenderContext, maLastUL, maLastBR); + + maLastUL = maTopLeft; + maLastBR = maBottomRight; + DrawRectangles(rRenderContext, maTopLeft, maBottomRight); + + mbDragDrawn = true; + rRenderContext.SetRasterOp(eROP); + rRenderContext.SetMapMode(MapMode(MapUnit::MapAppFont)); +} + +Point ScanPreview::GetPixelPos( const Point& rIn) const +{ + Point aConvert( + ( ( rIn.X() * PREVIEW_WIDTH ) / + ( maMaxBottomRight.X() - maMinTopLeft.X() ) ) + , + ( ( rIn.Y() * PREVIEW_HEIGHT ) + / ( maMaxBottomRight.Y() - maMinTopLeft.Y() ) ) + ); + + return GetDrawingArea()->get_ref_device().LogicToPixel(aConvert, MapMode(MapUnit::MapAppFont)); +} + +Point ScanPreview::GetLogicPos(const Point& rIn) const +{ + Point aConvert = GetDrawingArea()->get_ref_device().PixelToLogic(rIn, MapMode(MapUnit::MapAppFont)); + if( aConvert.X() < 0 ) + aConvert.setX( 0 ); + if( aConvert.X() >= PREVIEW_WIDTH ) + aConvert.setX( PREVIEW_WIDTH-1 ); + if( aConvert.Y() < 0 ) + aConvert.setY( 0 ); + if( aConvert.Y() >= PREVIEW_HEIGHT ) + aConvert.setY( PREVIEW_HEIGHT-1 ); + + aConvert.setX( aConvert.X() * ( maMaxBottomRight.X() - maMinTopLeft.X() ) ); + aConvert.setX( aConvert.X() / ( PREVIEW_WIDTH) ); + aConvert.setY( aConvert.Y() * ( maMaxBottomRight.Y() - maMinTopLeft.Y() ) ); + aConvert.setY( aConvert.Y() / ( PREVIEW_HEIGHT) ); + return aConvert; +} + +void SaneDlg::UpdateScanArea(bool bSend) +{ + if (!mxPreview->IsDragEnabled()) + return; + + Point aUL, aBR; + mxPreview->GetPreviewLogicRect(aUL, aBR); + + mxLeftField->set_value(aUL.X(), FieldUnit::NONE); + mxTopField->set_value(aUL.Y(), FieldUnit::NONE); + mxRightField->set_value(aBR.X(), FieldUnit::NONE); + mxBottomField->set_value(aBR.Y(), FieldUnit::NONE); + + if (!bSend) + return; + + if( mrSane.IsOpen() ) + { + SetAdjustedNumericalValue( "tl-x", static_cast(aUL.X()) ); + SetAdjustedNumericalValue( "tl-y", static_cast(aUL.Y()) ); + SetAdjustedNumericalValue( "br-x", static_cast(aBR.X()) ); + SetAdjustedNumericalValue( "br-y", static_cast(aBR.Y()) ); + } +} + +bool SaneDlg::LoadState() +{ + int i; + + if( ! Sane::IsSane() ) + return false; + + const char* pEnv = getenv("HOME"); + OUString aFileName = (pEnv ? OUString(pEnv, strlen(pEnv), osl_getThreadTextEncoding() ) : OUString()) + "/.so_sane_state"; + Config aConfig( aFileName ); + if( ! aConfig.HasGroup( "SANE" ) ) + return false; + + aConfig.SetGroup( "SANE" ); + OString aString = aConfig.ReadKey( "SO_LastSaneDevice" ); + for( i = 0; i < Sane::CountDevices() && aString != OUStringToOString(Sane::GetName(i), osl_getThreadTextEncoding()); i++ ) ; + if( i == Sane::CountDevices() ) + return false; + + mrSane.Close(); + mrSane.Open( aString.getStr() ); + + DisableOption(); + InitFields(); + + if( mrSane.IsOpen() ) + { + int iMax = aConfig.GetKeyCount(); + for (i = 0; i < iMax; ++i) + { + aString = aConfig.GetKeyName( i ); + OString aValue = aConfig.ReadKey( i ); + int nOption = mrSane.GetOptionByName( aString.getStr() ); + if( nOption == -1 ) + continue; + + if (aValue.startsWith("BOOL=")) + { + aValue = aValue.copy(RTL_CONSTASCII_LENGTH("BOOL=")); + bool aBOOL = aValue.toInt32() != 0; + mrSane.SetOptionValue( nOption, aBOOL ); + } + else if (aValue.startsWith("STRING=")) + { + aValue = aValue.copy(RTL_CONSTASCII_LENGTH("STRING=")); + mrSane.SetOptionValue(nOption,OStringToOUString(aValue, osl_getThreadTextEncoding()) ); + } + else if (aValue.startsWith("NUMERIC=")) + { + aValue = aValue.copy(RTL_CONSTASCII_LENGTH("NUMERIC=")); + + sal_Int32 nIndex = 0; + int n = 0; + do + { + OString aSub = aValue.getToken(0, ':', nIndex); + double fValue=0.0; + sscanf(aSub.getStr(), "%lg", &fValue); + SetAdjustedNumericalValue(aString.getStr(), fValue, n++); + } + while ( nIndex >= 0 ); + } + } + } + + DisableOption(); + InitFields(); + + return true; +} + +void SaneDlg::SaveState() +{ + if( ! Sane::IsSane() ) + return; + + const char* pEnv = getenv( "HOME" ); + OUString aFileName; + + if( pEnv ) + aFileName = OUString::createFromAscii(pEnv) + "/.so_sane_state"; + else + aFileName = OStringToOUString("", osl_getThreadTextEncoding()) + "/.so_sane_state"; + + Config aConfig( aFileName ); + aConfig.DeleteGroup( "SANE" ); + aConfig.SetGroup( "SANE" ); + aConfig.WriteKey( "SO_LastSANEDevice", + OUStringToOString(mxDeviceBox->get_active_text(), RTL_TEXTENCODING_UTF8) ); + + static char const* pSaveOptions[] = { + "resolution", + "tl-x", + "tl-y", + "br-x", + "br-y" + }; + for(const char * pSaveOption : pSaveOptions) + { + OString aOption = pSaveOption; + int nOption = mrSane.GetOptionByName( pSaveOption ); + if( nOption > -1 ) + { + SANE_Value_Type nType = mrSane.GetOptionType( nOption ); + switch( nType ) + { + case SANE_TYPE_BOOL: + { + bool bValue; + if( mrSane.GetOptionValue( nOption, bValue ) ) + { + OString aString = "BOOL=" + OString::number(static_cast(bValue)); + aConfig.WriteKey(aOption, aString); + } + } + break; + case SANE_TYPE_STRING: + { + OString aValue; + if( mrSane.GetOptionValue( nOption, aValue ) ) + { + OString aString = "STRING=" + aValue; + aConfig.WriteKey( aOption, aString ); + } + } + break; + case SANE_TYPE_FIXED: + case SANE_TYPE_INT: + { + OStringBuffer aString("NUMERIC="); + double fValue; + char buf[256]; + int n; + + for( n = 0; n < mrSane.GetOptionElements( nOption ); n++ ) + { + if( ! mrSane.GetOptionValue( nOption, fValue, n ) ) + break; + if( n > 0 ) + aString.append(':'); + sprintf( buf, "%lg", fValue ); + aString.append(buf); + } + if( n >= mrSane.GetOptionElements( nOption ) ) + aConfig.WriteKey( aOption, aString.makeStringAndClear() ); + } + break; + default: + break; + } + } + } +} + +bool SaneDlg::SetAdjustedNumericalValue( + const char* pOption, + double fValue, + int nElement ) +{ + if (! Sane::IsSane() || ! mrSane.IsOpen()) + return false; + int const nOption(mrSane.GetOptionByName(pOption)); + if (nOption == -1) + return false; + + if( nElement < 0 || nElement >= mrSane.GetOptionElements( nOption ) ) + return false; + + std::unique_ptr pValues; + int nValues; + if( ( nValues = mrSane.GetRange( nOption, pValues ) ) < 0 ) + { + return false; + } + + SAL_INFO("extensions.scanner", "SaneDlg::SetAdjustedNumericalValue(\"" << pOption << "\", " << fValue << ") "); + + if( nValues ) + { + int nNearest = 0; + double fNearest = 1e6; + for( int i = 0; i < nValues; i++ ) + { + if( fabs( fValue - pValues[ i ] ) < fNearest ) + { + fNearest = fabs( fValue - pValues[ i ] ); + nNearest = i; + } + } + fValue = pValues[ nNearest ]; + } + else + { + if( fValue < pValues[0] ) + fValue = pValues[0]; + if( fValue > pValues[1] ) + fValue = pValues[1]; + } + mrSane.SetOptionValue( nOption, fValue, nElement ); + SAL_INFO("extensions.scanner", "yields " << fValue); + + + return true; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/sanedlg.hxx b/extensions/source/scanner/sanedlg.hxx new file mode 100644 index 000000000..e9ba1540d --- /dev/null +++ b/extensions/source/scanner/sanedlg.hxx @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include +#include + +#include "sane.hxx" + +class ScanPreview; + +class SaneDlg : public weld::GenericDialogController +{ +private: + weld::Window* mpParent; + Sane& mrSane; + bool mbScanEnabled; + + Link maOldLink; + + int mnCurrentOption; + int mnCurrentElement; + std::unique_ptr mpRange; + double mfMin, mfMax; + + bool doScan; + + std::unique_ptr mxCancelButton; + std::unique_ptr mxDeviceInfoButton; + std::unique_ptr mxPreviewButton; + std::unique_ptr mxScanButton; + std::unique_ptr mxButtonOption; + + std::unique_ptr mxOptionTitle; + std::unique_ptr mxOptionDescTxt; + std::unique_ptr mxVectorTxt; + + std::unique_ptr mxLeftField; + std::unique_ptr mxTopField; + std::unique_ptr mxRightField; + std::unique_ptr mxBottomField; + + std::unique_ptr mxDeviceBox; + std::unique_ptr mxReslBox; + std::unique_ptr mxAdvancedBox; + + std::unique_ptr mxVectorBox; + std::unique_ptr mxQuantumRangeBox; + std::unique_ptr mxStringRangeBox; + + std::unique_ptr mxBoolCheckBox; + + std::unique_ptr mxStringEdit; + std::unique_ptr mxNumericEdit; + + std::unique_ptr mxOptionBox; + + std::unique_ptr mxPreview; + std::unique_ptr mxPreviewWnd; + + DECL_LINK( ClickBtnHdl, weld::Button&, void ); + DECL_LINK( ToggleBtnHdl, weld::Toggleable&, void ); + DECL_LINK( SelectHdl, weld::ComboBox&, void ); + DECL_LINK( ModifyHdl, weld::Entry&, void ); + DECL_LINK( MetricValueModifyHdl, weld::MetricSpinButton&, void ); + DECL_LINK( ValueModifyHdl, weld::ComboBox&, void ); + DECL_LINK( ReloadSaneOptionsHdl, Sane&, void ); + DECL_LINK( OptionsBoxSelectHdl, weld::TreeView&, void ); + + void SaveState(); + bool LoadState(); + + void InitDevices(); + void InitFields(); + void AcquirePreview(); + void DisableOption(); + void EstablishBoolOption(); + void EstablishStringOption(); + void EstablishStringRange(); + void EstablishQuantumRange(); + void EstablishNumericOption(); + void EstablishButtonOption(); + + // helper + bool SetAdjustedNumericalValue( const char* pOption, double fValue, int nElement = 0 ); +public: + SaneDlg(weld::Window*, Sane&, bool); + virtual ~SaneDlg() override; + + virtual short run() override; + void UpdateScanArea( bool ); + bool getDoScan() const { return doScan;} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/scanner.cxx b/extensions/source/scanner/scanner.cxx new file mode 100644 index 000000000..b661a4f7e --- /dev/null +++ b/extensions/source/scanner/scanner.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 "scanner.hxx" + +#include +#include +#include + +Reference< XInterface > ScannerManager_CreateInstance( const Reference< css::lang::XMultiServiceFactory >& /*rxFactory*/ ) +{ + return *( new ScannerManager() ); +} + + +ScannerManager::ScannerManager() : + mpData( nullptr ) +{ + AcquireData(); +} + + +ScannerManager::~ScannerManager() +{ + ReleaseData(); +} + + +Sequence< sal_Int8 > SAL_CALL ScannerManager::getMaskDIB() +{ + return Sequence< sal_Int8 >(); +} + + +OUString ScannerManager::getImplementationName() +{ + return "com.sun.star.scanner.ScannerManager"; +} + + +sal_Bool ScannerManager::supportsService(OUString const & ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + + +css::uno::Sequence ScannerManager::getSupportedServiceNames() +{ + return { "com.sun.star.scanner.ScannerManager" }; +} + + +sal_Bool SAL_CALL ScannerManager::configureScanner( ScannerContext& rContext ) +{ + return configureScannerAndScan( rContext, nullptr ); +} + +void SAL_CALL ScannerManager::initialize(const css::uno::Sequence& rArguments) +{ + ::comphelper::NamedValueCollection aProperties(rArguments); + if (aProperties.has("ParentWindow")) + aProperties.get("ParentWindow") >>= mxDialogParent; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_ScannerManager_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence const&) +{ + return cppu::acquire(new ScannerManager()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/scanner.hxx b/extensions/source/scanner/scanner.hxx new file mode 100644 index 000000000..42e03a453 --- /dev/null +++ b/extensions/source/scanner/scanner.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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace cppu; +using namespace com::sun::star::uno; +using namespace com::sun::star::scanner; + +class ScannerManager final : + public cppu::WeakImplHelper< + XScannerManager2, css::awt::XBitmap, css::lang::XServiceInfo, css::lang::XInitialization> +{ + osl::Mutex maProtector; + css::uno::Reference mxDialogParent; + void* mpData; + + static void AcquireData(); + void ReleaseData(); + +public: + + ScannerManager(); + virtual ~ScannerManager() override; + + // XScannerManager + virtual Sequence< ScannerContext > SAL_CALL getAvailableScanners() override; + virtual sal_Bool SAL_CALL configureScanner( ScannerContext& scanner_context ) override; + virtual sal_Bool SAL_CALL configureScannerAndScan( ScannerContext& scanner_context, const Reference< css::lang::XEventListener >& rxListener ) override; + virtual void SAL_CALL startScan( const ScannerContext& scanner_context, const Reference< css::lang::XEventListener >& rxListener ) override; + virtual ScanError SAL_CALL getError( const ScannerContext& scanner_context ) override; + virtual Reference< css::awt::XBitmap > SAL_CALL getBitmap( const ScannerContext& scanner_context ) override; + + // XBitmap + virtual css::awt::Size SAL_CALL getSize() override; + virtual Sequence< sal_Int8 > SAL_CALL getDIB() override; + virtual Sequence< sal_Int8 > SAL_CALL getMaskDIB() override; + + OUString SAL_CALL getImplementationName() override; + + sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override; + + css::uno::Sequence SAL_CALL getSupportedServiceNames() override; + + virtual void SAL_CALL initialize(const css::uno::Sequence& rArguments) override; + +#ifdef _WIN32 + void* GetData() const { return mpData; } +#endif + void SetData( void* pData ) { ReleaseData(); mpData = pData; } + }; + +/// @throws Exception +Reference< XInterface > ScannerManager_CreateInstance( const Reference< css::lang::XMultiServiceFactory >& rxFactory ); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/scanunx.cxx b/extensions/source/scanner/scanunx.cxx new file mode 100644 index 000000000..b06e30a27 --- /dev/null +++ b/extensions/source/scanner/scanunx.cxx @@ -0,0 +1,341 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "scanner.hxx" +#include "sanedlg.hxx" +#include +#include +#include +#include +#include + +#include + +BitmapTransporter::BitmapTransporter() +{ + SAL_INFO("extensions.scanner", "BitmapTransporter"); +} + + +BitmapTransporter::~BitmapTransporter() +{ + SAL_INFO("extensions.scanner", "~BitmapTransporter"); +} + + +css::awt::Size BitmapTransporter::getSize() +{ + osl::MutexGuard aGuard( m_aProtector ); + css::awt::Size aRet; + + // ensure that there is at least a header + int nLen = m_aStream.TellEnd(); + if( nLen > 15 ) + { + int nPreviousPos = m_aStream.Tell(); + m_aStream.Seek( 4 ); + m_aStream.ReadInt32( aRet.Width ).ReadInt32( aRet.Height ); + m_aStream.Seek( nPreviousPos ); + } + else + aRet.Width = aRet.Height = 0; + + + return aRet; +} + + +Sequence< sal_Int8 > BitmapTransporter::getDIB() +{ + osl::MutexGuard aGuard( m_aProtector ); + int nPreviousPos = m_aStream.Tell(); + + // create return value + int nBytes = m_aStream.TellEnd(); + m_aStream.Seek( 0 ); + + Sequence< sal_Int8 > aValue( nBytes ); + m_aStream.ReadBytes( aValue.getArray(), nBytes ); + m_aStream.Seek( nPreviousPos ); + + return aValue; +} + +namespace { + +struct SaneHolder +{ + Sane m_aSane; + Reference< css::awt::XBitmap > m_xBitmap; + osl::Mutex m_aProtector; + ScanError m_nError; + bool m_bBusy; + + SaneHolder() : m_nError(ScanError_ScanErrorNone), m_bBusy(false) {} +}; + + typedef std::vector< std::shared_ptr > sanevec; + class allSanes + { + private: + int mnRefCount; + public: + sanevec m_aSanes; + allSanes() : mnRefCount(0) {} + void acquire(); + void release(); + }; + + void allSanes::acquire() + { + ++mnRefCount; + } + + void allSanes::release() + { + // was unused, now because of i99835: "Scanning interface not SANE API + // compliant" destroy all SaneHolder to get Sane Dtor called + --mnRefCount; + if (!mnRefCount) + m_aSanes.clear(); + } + + struct theSaneProtector : public rtl::Static {}; + struct theSanes : public rtl::Static {}; + +class ScannerThread : public osl::Thread +{ + std::shared_ptr m_pHolder; + Reference< css::lang::XEventListener > m_xListener; + ScannerManager* m_pManager; // just for the disposing call + +public: + virtual void SAL_CALL run() override; + virtual void SAL_CALL onTerminated() override { delete this; } +public: + ScannerThread( const std::shared_ptr& pHolder, + const Reference< css::lang::XEventListener >& listener, + ScannerManager* pManager ); + virtual ~ScannerThread() override; +}; + +} + +ScannerThread::ScannerThread(const std::shared_ptr& pHolder, + const Reference< css::lang::XEventListener >& listener, + ScannerManager* pManager) + : m_pHolder( pHolder ), m_xListener( listener ), m_pManager( pManager ) +{ + SAL_INFO("extensions.scanner", "ScannerThread"); +} + + +ScannerThread::~ScannerThread() +{ + SAL_INFO("extensions.scanner", "~ScannerThread"); +} + + +void ScannerThread::run() +{ + osl_setThreadName("ScannerThread"); + + osl::MutexGuard aGuard( m_pHolder->m_aProtector ); + rtl::Reference pTransporter = new BitmapTransporter; + + m_pHolder->m_xBitmap = pTransporter; + + m_pHolder->m_bBusy = true; + if( m_pHolder->m_aSane.IsOpen() ) + { + int nOption = m_pHolder->m_aSane.GetOptionByName( "preview" ); + if( nOption != -1 ) + m_pHolder->m_aSane.SetOptionValue( nOption, false ); + + m_pHolder->m_nError = + m_pHolder->m_aSane.Start( *pTransporter ) ? + ScanError_ScanErrorNone : ScanError_ScanCanceled; + } + else + m_pHolder->m_nError = ScanError_ScannerNotAvailable; + + + Reference< XInterface > xXInterface( static_cast< OWeakObject* >( m_pManager ) ); + m_xListener->disposing( css::lang::EventObject(xXInterface) ); + m_pHolder->m_bBusy = false; +} + + +void ScannerManager::AcquireData() +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + theSanes::get().acquire(); +} + + +void ScannerManager::ReleaseData() +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + theSanes::get().release(); +} + + +css::awt::Size ScannerManager::getSize() +{ + css::awt::Size aRet; + aRet.Width = aRet.Height = 0; + return aRet; +} + + +Sequence< sal_Int8 > ScannerManager::getDIB() +{ + return Sequence< sal_Int8 >(); +} + + +Sequence< ScannerContext > ScannerManager::getAvailableScanners() +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + if( rSanes.empty() ) + { + auto pSaneHolder = std::make_shared(); + if( Sane::IsSane() ) + rSanes.push_back( pSaneHolder ); + } + + if( Sane::IsSane() ) + { + Sequence< ScannerContext > aRet{ { /* ScannerName */ "SANE", /* InternalData */ 0 } }; + return aRet; + } + + return Sequence< ScannerContext >(); +} + + +sal_Bool ScannerManager::configureScannerAndScan( ScannerContext& scanner_context, + const Reference< css::lang::XEventListener >& listener ) +{ + bool bRet; + bool bScan; + { + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + SAL_INFO("extensions.scanner", "ScannerManager::configureScanner"); + + if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() ) + throw ScannerException( + "Scanner does not exist", + Reference< XScannerManager >( this ), + ScanError_InvalidContext + ); + + std::shared_ptr pHolder = rSanes[scanner_context.InternalData]; + if( pHolder->m_bBusy ) + throw ScannerException( + "Scanner is busy", + Reference< XScannerManager >( this ), + ScanError_ScanInProgress + ); + + pHolder->m_bBusy = true; + SaneDlg aDlg(Application::GetFrameWeld(mxDialogParent), pHolder->m_aSane, listener.is()); + bRet = aDlg.run(); + bScan = aDlg.getDoScan(); + pHolder->m_bBusy = false; + } + if ( bScan ) + startScan( scanner_context, listener ); + + return bRet; +} + + +void ScannerManager::startScan( const ScannerContext& scanner_context, + const Reference< css::lang::XEventListener >& listener ) +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + SAL_INFO("extensions.scanner", "ScannerManager::startScan"); + + if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() ) + throw ScannerException( + "Scanner does not exist", + Reference< XScannerManager >( this ), + ScanError_InvalidContext + ); + std::shared_ptr pHolder = rSanes[scanner_context.InternalData]; + if( pHolder->m_bBusy ) + throw ScannerException( + "Scanner is busy", + Reference< XScannerManager >( this ), + ScanError_ScanInProgress + ); + pHolder->m_bBusy = true; + + ScannerThread* pThread = new ScannerThread( pHolder, listener, this ); + pThread->create(); +} + + +ScanError ScannerManager::getError( const ScannerContext& scanner_context ) +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() ) + throw ScannerException( + "Scanner does not exist", + Reference< XScannerManager >( this ), + ScanError_InvalidContext + ); + + std::shared_ptr pHolder = rSanes[scanner_context.InternalData]; + + return pHolder->m_nError; +} + + +Reference< css::awt::XBitmap > ScannerManager::getBitmap( const ScannerContext& scanner_context ) +{ + osl::MutexGuard aGuard( theSaneProtector::get() ); + sanevec &rSanes = theSanes::get().m_aSanes; + + if( scanner_context.InternalData < 0 || o3tl::make_unsigned(scanner_context.InternalData) >= rSanes.size() ) + throw ScannerException( + "Scanner does not exist", + Reference< XScannerManager >( this ), + ScanError_InvalidContext + ); + std::shared_ptr pHolder = rSanes[scanner_context.InternalData]; + + osl::MutexGuard aProtGuard( pHolder->m_aProtector ); + + Reference< css::awt::XBitmap > xRet( pHolder->m_xBitmap ); + pHolder->m_xBitmap.clear(); + + return xRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/scanwin.cxx b/extensions/source/scanner/scanwin.cxx new file mode 100644 index 000000000..109f2944a --- /dev/null +++ b/extensions/source/scanner/scanwin.cxx @@ -0,0 +1,646 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 "twain32shim.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scanner.hxx" + +namespace +{ +enum TwainState +{ + TWAIN_STATE_NONE = 0, + TWAIN_STATE_SCANNING = 1, + TWAIN_STATE_DONE = 2, + TWAIN_STATE_CANCELED = 3 +}; + +struct HANDLEDeleter +{ + using pointer = HANDLE; + void operator()(HANDLE h) { CloseHandle(h); } +}; + +using ScopedHANDLE = std::unique_ptr; + +class Twain +{ +public: + Twain(); + ~Twain(); + + bool SelectSource(ScannerManager& rMgr, const VclPtr& xTopWindow); + bool PerformTransfer(ScannerManager& rMgr, + const css::uno::Reference& rxListener, + const VclPtr& xTopWindow); + void WaitReadyForNextTask(); + + TwainState GetState() const { return meState; } + +private: + friend class ShimListenerThread; + class ShimListenerThread : public salhelper::Thread + { + public: + ShimListenerThread(const VclPtr& xTopWindow); + ~ShimListenerThread() override; + void execute() override; + const OUString& getError() { return msErrorReported; } + + // These methods are executed outside of own thread + bool WaitInitialization(); + bool WaitRequestResult(); + void DontNotify() { mbDontNotify = true; } + void RequestDestroy(); + bool RequestSelectSource(); + bool RequestInitXfer(); + + private: + VclPtr mxTopWindow; // the window that we made modal + bool mbDontNotify = false; + HWND mhWndShim = nullptr; // shim main window handle + OUString msErrorReported; + osl::Condition mcInitCompleted; // initially not set + bool mbInitSucceeded = false; + osl::Condition mcGotRequestResult; + bool mbRequestResult = false; + + void SendShimRequest(WPARAM nRequest); + bool SendShimRequestWithResult(WPARAM nRequest); + void NotificationHdl(WPARAM nEvent, LPARAM lParam); + void NotifyOwner(WPARAM nEvent); + void NotifyXFerOwner(LPARAM nHandle); + }; + css::uno::Reference mxListener; + css::uno::Reference mxMgr; + ScannerManager* mpCurMgr = nullptr; + TwainState meState = TWAIN_STATE_NONE; + rtl::Reference mpThread; + osl::Mutex maMutex; + + DECL_LINK(ImpNotifyHdl, void*, void); + DECL_LINK(ImpNotifyXferHdl, void*, void); + void Notify(WPARAM nEvent); // called by shim communication thread to notify me + void NotifyXFer(LPARAM nHandle); // called by shim communication thread to notify me + + bool InitializeNewShim(ScannerManager& rMgr, const VclPtr& xTopWindow); + + void Reset(); // cleanup thread and manager +}; + +Twain aTwain; + +Twain::ShimListenerThread::ShimListenerThread(const VclPtr& xTopWindow) + : salhelper::Thread("TWAINShimListenerThread") + , mxTopWindow(xTopWindow) +{ + if (mxTopWindow) + { + mxTopWindow->IncModalCount(); // the operation is modal to the frame + } +} + +Twain::ShimListenerThread::~ShimListenerThread() +{ + if (mxTopWindow) + { + mxTopWindow->DecModalCount(); // unblock the frame + } +} + +bool Twain::ShimListenerThread::WaitInitialization() +{ + mcInitCompleted.wait(); + return mbInitSucceeded; +} + +bool Twain::ShimListenerThread::WaitRequestResult() +{ + mcGotRequestResult.wait(); + return mbRequestResult; +} + +void Twain::ShimListenerThread::SendShimRequest(WPARAM nRequest) +{ + if (mhWndShim) + PostMessageW(mhWndShim, WM_TWAIN_REQUEST, nRequest, 0); +} + +bool Twain::ShimListenerThread::SendShimRequestWithResult(WPARAM nRequest) +{ + mcGotRequestResult.reset(); + mbRequestResult = false; + SendShimRequest(nRequest); + return WaitRequestResult(); +} + +void Twain::ShimListenerThread::RequestDestroy() { SendShimRequest(TWAIN_REQUEST_QUIT); } + +bool Twain::ShimListenerThread::RequestSelectSource() +{ + assert(mbInitSucceeded); + return SendShimRequestWithResult(TWAIN_REQUEST_SELECTSOURCE); +} + +bool Twain::ShimListenerThread::RequestInitXfer() +{ + assert(mbInitSucceeded); + return SendShimRequestWithResult(TWAIN_REQUEST_INITXFER); +} + +void Twain::ShimListenerThread::NotifyOwner(WPARAM nEvent) +{ + if (!mbDontNotify) + aTwain.Notify(nEvent); +} + +void Twain::ShimListenerThread::NotifyXFerOwner(LPARAM nHandle) +{ + if (!mbDontNotify) + aTwain.NotifyXFer(nHandle); +} + +// May only be called from the own thread, so no threading issues modifying self +void Twain::ShimListenerThread::NotificationHdl(WPARAM nEvent, LPARAM lParam) +{ + switch (nEvent) + { + case TWAIN_EVENT_NOTIFYHWND: // shim reported its main HWND for communications + if (!mcInitCompleted.check()) // only if not yet initialized! + { + // Owner is still waiting mcInitCompleted in its Twain::InitializeNewShim, + // holding its access mutex + mhWndShim = reinterpret_cast(lParam); + + mbInitSucceeded = lParam != 0; + mcInitCompleted.set(); + } + break; + case TWAIN_EVENT_SCANNING: + NotifyOwner(nEvent); + break; + case TWAIN_EVENT_XFER: + NotifyXFerOwner(lParam); + break; + case TWAIN_EVENT_REQUESTRESULT: + mbRequestResult = lParam; + mcGotRequestResult.set(); + break; + // We don't handle TWAIN_EVENT_QUIT notification from shim, because we send it ourselves + // in the end of execute() + } +} + +// Spawn a separate 32-bit process to use TWAIN on Windows, and listen for its notifications +void Twain::ShimListenerThread::execute() +{ + MSG msg; + // Initialize thread message queue before launching shim process + PeekMessageW(&msg, nullptr, 0, 0, PM_NOREMOVE); + + try + { + ScopedHANDLE hShimProcess; + { + // Determine twain32shim executable URL: + OUString shimURL("$BRAND_BASE_DIR/" LIBO_BIN_FOLDER "/twain32shim.exe"); + rtl::Bootstrap::expandMacros(shimURL); + + OUString sCmdLine; + if (osl::FileBase::getSystemPathFromFileURL(shimURL, sCmdLine) != osl::FileBase::E_None) + throw std::exception("getSystemPathFromFileURL failed!"); + + HANDLE hDup; + if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), + &hDup, SYNCHRONIZE | THREAD_QUERY_LIMITED_INFORMATION, TRUE, 0)) + ThrowLastError("DuplicateHandle"); + // we will not need our copy as soon as shim has its own inherited one + ScopedHANDLE hScopedDup(hDup); + DWORD nDup = static_cast(reinterpret_cast(hDup)); + if (reinterpret_cast(nDup) != hDup) + throw std::exception("HANDLE does not fit to 32 bit - cannot pass to shim!"); + + // Send this thread handle as the first parameter + sCmdLine = "\"" + sCmdLine + "\" " + OUString::number(nDup); + + // We need a WinAPI HANDLE of the process to be able to wait on it and detect the process + // termination; so use WinAPI to start the process, not osl_executeProcess. + + STARTUPINFOW si{}; + si.cb = sizeof(si); + PROCESS_INFORMATION pi; + + if (!CreateProcessW(nullptr, const_cast(o3tl::toW(sCmdLine.getStr())), nullptr, + nullptr, TRUE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi)) + ThrowLastError("CreateProcessW"); + + CloseHandle(pi.hThread); + hShimProcess.reset(pi.hProcess); + } + HANDLE h = hShimProcess.get(); + while (true) + { + DWORD nWaitResult = MsgWaitForMultipleObjects(1, &h, FALSE, INFINITE, QS_POSTMESSAGE); + // Process any messages in queue before checking if we need to break, to not loose + // possible pending notifications + while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) + { + // process it here + if (msg.message == WM_TWAIN_EVENT) + { + NotificationHdl(msg.wParam, msg.lParam); + } + } + if (nWaitResult == WAIT_OBJECT_0) + { + // shim process exited - return + break; + } + if (nWaitResult == WAIT_FAILED) + { + // Some Win32 error - report and return + ThrowLastError("MsgWaitForMultipleObjects"); + } + } + } + catch (const std::exception& e) + { + msErrorReported = OUString(e.what(), strlen(e.what()), RTL_TEXTENCODING_UTF8); + // allow owner to resume (in case the condition isn't set yet) + mcInitCompleted.set(); // let mbInitSucceeded keep its (maybe false) value! + } + // allow owner to resume (in case the conditions isn't set yet) + mcGotRequestResult.set(); + NotifyOwner(TWAIN_EVENT_QUIT); +} + +Twain::Twain() {} + +Twain::~Twain() +{ + osl::MutexGuard aGuard(maMutex); + if (mpThread) + { + mpThread->DontNotify(); + mpThread->RequestDestroy(); + mpThread->join(); + mpThread.clear(); + } +} + +void Twain::Reset() +{ + mpThread->join(); + if (!mpThread->getError().isEmpty()) + SAL_WARN("extensions.scanner", mpThread->getError()); + mpThread.clear(); + mpCurMgr = nullptr; + mxMgr.clear(); +} + +bool Twain::InitializeNewShim(ScannerManager& rMgr, const VclPtr& xTopWindow) +{ + osl::MutexGuard aGuard(maMutex); + if (mpThread) + return false; // Have a shim for another task already! + + // hold reference to ScannerManager, to prevent premature death + mxMgr = mpCurMgr = &rMgr; + + mpThread.set(new ShimListenerThread(xTopWindow)); + mpThread->launch(); + const bool bSuccess = mpThread->WaitInitialization(); + if (!bSuccess) + Reset(); + + return bSuccess; +} + +void Twain::Notify(WPARAM nEvent) +{ + Application::PostUserEvent(LINK(this, Twain, ImpNotifyHdl), reinterpret_cast(nEvent)); +} + +void Twain::NotifyXFer(LPARAM nHandle) +{ + Application::PostUserEvent(LINK(this, Twain, ImpNotifyXferHdl), + reinterpret_cast(nHandle)); +} + +bool Twain::SelectSource(ScannerManager& rMgr, const VclPtr& xTopWindow) +{ + osl::MutexGuard aGuard(maMutex); + bool bRet = false; + + if (InitializeNewShim(rMgr, xTopWindow)) + { + meState = TWAIN_STATE_NONE; + bRet = mpThread->RequestSelectSource(); + } + + return bRet; +} + +bool Twain::PerformTransfer(ScannerManager& rMgr, + const css::uno::Reference& rxListener, + const VclPtr& xTopWindow) +{ + osl::MutexGuard aGuard(maMutex); + bool bRet = false; + + if (InitializeNewShim(rMgr, xTopWindow)) + { + mxListener = rxListener; + meState = TWAIN_STATE_NONE; + bRet = mpThread->RequestInitXfer(); + } + + return bRet; +} + +void Twain::WaitReadyForNextTask() +{ + while ([&]() { + osl::MutexGuard aGuard(maMutex); + return bool(mpThread); + }()) + { + Application::Reschedule(true); + } +} + +IMPL_LINK(Twain, ImpNotifyHdl, void*, pParam, void) +{ + osl::MutexGuard aGuard(maMutex); + WPARAM nEvent = reinterpret_cast(pParam); + switch (nEvent) + { + case TWAIN_EVENT_SCANNING: + meState = TWAIN_STATE_SCANNING; + break; + + case TWAIN_EVENT_QUIT: + { + if (meState != TWAIN_STATE_DONE) + meState = TWAIN_STATE_CANCELED; + + css::lang::EventObject event(mxMgr); // mxMgr will be cleared below + + if (mpThread) + Reset(); + + if (mxListener.is()) + { + mxListener->disposing(event); + mxListener.clear(); + } + } + break; + + default: + break; + } +} + +IMPL_LINK(Twain, ImpNotifyXferHdl, void*, pParam, void) +{ + osl::MutexGuard aGuard(maMutex); + if (mpThread) + { + mpCurMgr->SetData(pParam); + meState = pParam ? TWAIN_STATE_DONE : TWAIN_STATE_CANCELED; + + css::lang::EventObject event(mxMgr); // mxMgr will be cleared below + + Reset(); + + if (mxListener.is()) + mxListener->disposing(css::lang::EventObject(mxMgr)); + } + + mxListener.clear(); +} + +VclPtr ImplGetActiveFrameWindow() +{ + try + { + // query desktop instance + css::uno::Reference xDesktop + = css::frame::Desktop::create(comphelper::getProcessComponentContext()); + if (css::uno::Reference xActiveFrame = xDesktop->getActiveFrame()) + return VCLUnoHelper::GetWindow(xActiveFrame->getComponentWindow()); + } + catch (const css::uno::Exception&) + { + } + SAL_WARN("extensions.scanner", "ImplGetActiveFrame: Could not determine active frame!"); + return nullptr; +} + +} // namespace + +void ScannerManager::AcquireData() {} + +void ScannerManager::ReleaseData() +{ + if (mpData) + { + CloseHandle(static_cast(mpData)); + mpData = nullptr; + } +} + +css::awt::Size ScannerManager::getSize() +{ + css::awt::Size aRet; + + if (mpData) + { + HANDLE hMap = static_cast(mpData); + // map full size + const sal_Int8* pMap = static_cast(MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)); + if (pMap) + { + const BITMAPINFOHEADER* pBIH = reinterpret_cast(pMap + 4); + aRet.Width = pBIH->biWidth; + aRet.Height = pBIH->biHeight; + + UnmapViewOfFile(pMap); + } + } + + return aRet; +} + +css::uno::Sequence ScannerManager::getDIB() +{ + css::uno::Sequence aRet; + + if (mpData) + { + HANDLE hMap = static_cast(mpData); + // map full size + const sal_Int8* pMap = static_cast(MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)); + if (pMap) + { + DWORD nDIBSize; + memcpy(&nDIBSize, pMap, 4); // size of the following DIB + + const BITMAPINFOHEADER* pBIH = reinterpret_cast(pMap + 4); + + sal_uInt32 nColEntries = 0; + + switch (pBIH->biBitCount) + { + case 1: + case 4: + case 8: + nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : (1 << pBIH->biBitCount); + break; + + case 24: + nColEntries = pBIH->biClrUsed ? pBIH->biClrUsed : 0; + break; + + case 16: + case 32: + nColEntries = pBIH->biClrUsed; + if (pBIH->biCompression == BI_BITFIELDS) + nColEntries += 3; + break; + } + + aRet = css::uno::Sequence(sizeof(BITMAPFILEHEADER) + nDIBSize); + + sal_Int8* pBuf = aRet.getArray(); + SvMemoryStream* pMemStm + = new SvMemoryStream(pBuf, sizeof(BITMAPFILEHEADER), StreamMode::WRITE); + + pMemStm->WriteChar('B').WriteChar('M').WriteUInt32(0).WriteUInt32(0); + pMemStm->WriteUInt32(sizeof(BITMAPFILEHEADER) + pBIH->biSize + + (nColEntries * sizeof(RGBQUAD))); + + delete pMemStm; + memcpy(pBuf + sizeof(BITMAPFILEHEADER), pBIH, nDIBSize); + + UnmapViewOfFile(pMap); + } + + ReleaseData(); + } + + return aRet; +} + +css::uno::Sequence SAL_CALL ScannerManager::getAvailableScanners() +{ + osl::MutexGuard aGuard(maProtector); + css::uno::Sequence aRet(1); + + aRet.getArray()[0].ScannerName = "TWAIN"; + aRet.getArray()[0].InternalData = 0; + + return aRet; +} + +sal_Bool SAL_CALL ScannerManager::configureScannerAndScan( + ScannerContext& rContext, const css::uno::Reference& rxListener) +{ + osl::MutexGuard aGuard(maProtector); + css::uno::Reference xThis(this); + + if (rContext.InternalData != 0 || rContext.ScannerName != "TWAIN") + throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext); + + ReleaseData(); + + VclPtr xTopWindow = ImplGetActiveFrameWindow(); + if (xTopWindow) + xTopWindow + ->IncModalCount(); // to avoid changes between the two operations that each block the window + comphelper::ScopeGuard aModalGuard([xTopWindow]() { + if (xTopWindow) + xTopWindow->DecModalCount(); + }); + + const bool bSelected = aTwain.SelectSource(*this, xTopWindow); + if (bSelected) + { + aTwain.WaitReadyForNextTask(); + aTwain.PerformTransfer(*this, rxListener, xTopWindow); + } + return bSelected; +} + +void SAL_CALL +ScannerManager::startScan(const ScannerContext& rContext, + const css::uno::Reference& rxListener) +{ + osl::MutexGuard aGuard(maProtector); + css::uno::Reference xThis(this); + + if (rContext.InternalData != 0 || rContext.ScannerName != "TWAIN") + throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext); + + ReleaseData(); + aTwain.PerformTransfer(*this, rxListener, ImplGetActiveFrameWindow()); +} + +ScanError SAL_CALL ScannerManager::getError(const ScannerContext& rContext) +{ + osl::MutexGuard aGuard(maProtector); + css::uno::Reference xThis(this); + + if (rContext.InternalData != 0 || rContext.ScannerName != "TWAIN") + throw ScannerException("Scanner does not exist", xThis, ScanError_InvalidContext); + + return ((aTwain.GetState() == TWAIN_STATE_CANCELED) ? ScanError_ScanCanceled + : ScanError_ScanErrorNone); +} + +css::uno::Reference + SAL_CALL ScannerManager::getBitmap(const ScannerContext& /*rContext*/) +{ + osl::MutexGuard aGuard(maProtector); + return css::uno::Reference(this); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/scn.component b/extensions/source/scanner/scn.component new file mode 100644 index 000000000..19215a7c3 --- /dev/null +++ b/extensions/source/scanner/scn.component @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/extensions/source/scanner/twain32shim.cxx b/extensions/source/scanner/twain32shim.cxx new file mode 100644 index 000000000..beca35f4f --- /dev/null +++ b/extensions/source/scanner/twain32shim.cxx @@ -0,0 +1,604 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/* + * twain32shim.exe is a separate 32-bit executable that serves as a shim + * between LibreOffice and Windows' 32-bit TWAIN component. Without it, + * it's impossible for 64-bit program to use TWAIN on Windows. + * Using 64-bit TWAIN DSM library from twain.org to avoid using the shim + * is not an option, because scanner manufacturers only provide 32-bit + * drivers, and 64-bit drivers are only offered as 3rd-party commercial + * products. The shim is also used in 32-bit LibreOffice for uniformity. +*/ + +#include "twain32shim.hxx" +#include +#include +#include + +#define WM_TWAIN_FALLBACK (WM_SHIM_INTERNAL + 0) + +namespace +{ +double FixToDouble(const TW_FIX32& rFix) { return rFix.Whole + rFix.Frac / 65536.; } + +const wchar_t sTwainWndClass[] = L"TwainClass"; + +class ImpTwain +{ +public: + ImpTwain(HANDLE hParentThread); + ~ImpTwain(); + +private: + enum class TWAINState + { + DSMunloaded = 1, + DSMloaded = 2, + DSMopened = 3, + DSopened = 4, + DSenabled = 5, + DSreadyToXfer = 6, + Xferring = 7, + }; + + TW_IDENTITY m_aAppId; + TW_IDENTITY m_aSrcId; + DWORD m_nParentThreadId; + HANDLE m_hProc; + DSMENTRYPROC m_pDSM = nullptr; + HMODULE m_hMod = nullptr; + TWAINState m_nCurState = TWAINState::DSMunloaded; + HWND m_hTwainWnd = nullptr; + HHOOK m_hTwainHook = nullptr; + HANDLE m_hMap = nullptr; // the *duplicated* handle + + static bool IsTwainClassWnd(HWND hWnd); + static ImpTwain* GetImpFromWnd(HWND hWnd); + static void ImplCreateWnd(HWND hWnd, LPARAM lParam); + static LRESULT CALLBACK WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK MsgHook(int nCode, WPARAM wParam, LPARAM lParam); + + void Destroy() { ImplFallback(TWAIN_EVENT_QUIT); } + bool SelectSource(); + bool InitXfer(); + + void NotifyParent(WPARAM nEvent, LPARAM lParam); + bool ImplHandleMsg(MSG* pMsg); + void ImplOpenSourceManager(); + void ImplOpenSource(); + bool ImplEnableSource(); + void ImplXfer(); + void ImplFallback(WPARAM nEvent); + + void ImplFallbackHdl(WPARAM nEvent); + void ImplRequestHdl(WPARAM nRequest); +}; + +//static +bool ImpTwain::IsTwainClassWnd(HWND hWnd) +{ + const int nBufSize = SAL_N_ELEMENTS(sTwainWndClass); + wchar_t sClassName[nBufSize]; + return (GetClassNameW(hWnd, sClassName, nBufSize) && wcscmp(sClassName, sTwainWndClass) == 0); +} + +//static +ImpTwain* ImpTwain::GetImpFromWnd(HWND hWnd) +{ + if (!IsTwainClassWnd(hWnd)) + return nullptr; + return reinterpret_cast(GetWindowLongPtrW(hWnd, GWLP_USERDATA)); +} + +//static +void ImpTwain::ImplCreateWnd(HWND hWnd, LPARAM lParam) +{ + CREATESTRUCT* pCS = reinterpret_cast(lParam); + if (pCS && IsTwainClassWnd(hWnd)) + SetWindowLongPtrW(hWnd, GWLP_USERDATA, reinterpret_cast(pCS->lpCreateParams)); +} + +// static +LRESULT CALLBACK ImpTwain::WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) +{ + ImpTwain* pImpTwain = GetImpFromWnd(hWnd); + switch (nMsg) + { + case WM_CREATE: + ImplCreateWnd(hWnd, lParam); + break; + case WM_TWAIN_FALLBACK: + if (pImpTwain) + pImpTwain->ImplFallbackHdl(wParam); + break; + case WM_TWAIN_REQUEST: + if (pImpTwain) + pImpTwain->ImplRequestHdl(wParam); + break; + } + return DefWindowProcW(hWnd, nMsg, wParam, lParam); +} + +// static +LRESULT CALLBACK ImpTwain::MsgHook(int nCode, WPARAM wParam, LPARAM lParam) +{ + MSG* pMsg = reinterpret_cast(lParam); + if (nCode >= 0 && pMsg) + { + ImpTwain* pImpTwain = GetImpFromWnd(pMsg->hwnd); + if (pImpTwain && pImpTwain->ImplHandleMsg(pMsg)) + { + pMsg->message = WM_USER; + pMsg->lParam = 0; + + return 0; + } + } + + return CallNextHookEx(nullptr, nCode, wParam, lParam); +} + +HANDLE GetProcOfThread(HANDLE hThread) +{ + DWORD nProcId = GetProcessIdOfThread(hThread); + if (!nProcId) + ThrowLastError("GetProcessIdOfThread"); + HANDLE hRet = OpenProcess(PROCESS_DUP_HANDLE, FALSE, nProcId); + if (!hRet) + ThrowLastError("OpenProcess"); + return hRet; +} + +ImpTwain::ImpTwain(HANDLE hParentThread) + : m_aAppId{ /* Id */ 0, + { /* Version.MajorNum */ 1, + /* Version.MinorNum */ 0, + /* Version.Language */ TWLG_USA, + /* Version.Country */ TWCY_USA, + /* Version.Info */ "8.0" }, + /* ProtocolMajor */ TWON_PROTOCOLMAJOR, + /* ProtocolMinor */ TWON_PROTOCOLMINOR, + /* SupportedGroups */ DG_IMAGE | DG_CONTROL, + /* Manufacturer */ "Sun Microsystems", + /* ProductFamily */ "Office", + /* ProductName */ "Office" } + , m_nParentThreadId(GetThreadId(hParentThread)) + , m_hProc(GetProcOfThread(hParentThread)) +{ + WNDCLASSW aWc = { 0, &WndProc, 0, sizeof(WNDCLASSW), GetModuleHandleW(nullptr), + nullptr, nullptr, nullptr, nullptr, sTwainWndClass }; + if (!RegisterClassW(&aWc)) + ThrowLastError("RegisterClassW"); + m_hTwainWnd = CreateWindowExW(WS_EX_TOPMOST, aWc.lpszClassName, L"TWAIN", 0, 0, 0, 0, 0, + HWND_DESKTOP, nullptr, aWc.hInstance, this); + if (!m_hTwainWnd) + ThrowLastError("CreateWindowExW"); + m_hTwainHook = SetWindowsHookExW(WH_GETMESSAGE, &MsgHook, nullptr, GetCurrentThreadId()); + if (!m_hTwainHook) + ThrowLastError("SetWindowsHookExW"); + + NotifyParent(TWAIN_EVENT_NOTIFYHWND, reinterpret_cast(m_hTwainWnd)); +} + +ImpTwain::~ImpTwain() +{ + DestroyWindow(m_hTwainWnd); + UnhookWindowsHookEx(m_hTwainHook); +} + +bool ImpTwain::SelectSource() +{ + TW_UINT16 nRet = TWRC_FAILURE; + + ImplOpenSourceManager(); + + if (TWAINState::DSMopened == m_nCurState) + { + TW_IDENTITY aIdent; + + aIdent.Id = 0; + aIdent.ProductName[0] = '\0'; + NotifyParent(TWAIN_EVENT_SCANNING, 0); + nRet = m_pDSM(&m_aAppId, nullptr, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &aIdent); + } + + Destroy(); + return (TWRC_SUCCESS == nRet); +} + +bool ImpTwain::InitXfer() +{ + bool bRet = false; + + ImplOpenSourceManager(); + + if (TWAINState::DSMopened == m_nCurState) + { + ImplOpenSource(); + + if (TWAINState::DSopened == m_nCurState) + bRet = ImplEnableSource(); + } + + if (!bRet) + Destroy(); + + return bRet; +} + +void ImpTwain::ImplOpenSourceManager() +{ + if (TWAINState::DSMunloaded == m_nCurState) + { + m_hMod = LoadLibraryW(L"TWAIN_32.DLL"); + if (!m_hMod) + { + // Windows directory might not be in DLL search path sometimes, so try the full path + PWSTR sPath; + if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_Windows, 0, nullptr, &sPath))) + { + std::wstring sPathAndFile = sPath; + CoTaskMemFree(sPath); + sPathAndFile += L"\\TWAIN_32.DLL"; + m_hMod = LoadLibraryW(sPathAndFile.c_str()); + } + } + if (m_hMod) + { + m_nCurState = TWAINState::DSMloaded; + + m_pDSM = reinterpret_cast(GetProcAddress(m_hMod, "DSM_Entry")); + if (m_pDSM + && (m_pDSM(&m_aAppId, nullptr, DG_CONTROL, DAT_PARENT, MSG_OPENDSM, &m_hTwainWnd) + == TWRC_SUCCESS)) + { + m_nCurState = TWAINState::DSMopened; + } + } + } +} + +void ImpTwain::ImplOpenSource() +{ + if (TWAINState::DSMopened == m_nCurState) + { + if ((m_pDSM(&m_aAppId, nullptr, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &m_aSrcId) + == TWRC_SUCCESS) + && (m_pDSM(&m_aAppId, nullptr, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, &m_aSrcId) + == TWRC_SUCCESS)) + { + TW_CAPABILITY aCap + = { CAP_XFERCOUNT, TWON_ONEVALUE, GlobalAlloc(GHND, sizeof(TW_ONEVALUE)) }; + TW_ONEVALUE* pVal = static_cast(GlobalLock(aCap.hContainer)); + + pVal->ItemType = TWTY_INT16; + pVal->Item = 1; + GlobalUnlock(aCap.hContainer); + m_pDSM(&m_aAppId, &m_aSrcId, DG_CONTROL, DAT_CAPABILITY, MSG_SET, &aCap); + GlobalFree(aCap.hContainer); + m_nCurState = TWAINState::DSopened; + } + } +} + +bool ImpTwain::ImplEnableSource() +{ + bool bRet = false; + + if (TWAINState::DSopened == m_nCurState) + { + TW_USERINTERFACE aUI = { true, true, m_hTwainWnd }; + + NotifyParent(TWAIN_EVENT_SCANNING, 0); + m_nCurState = TWAINState::DSenabled; + + if (m_pDSM(&m_aAppId, &m_aSrcId, DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS, &aUI) + == TWRC_SUCCESS) + { + bRet = true; + } + else + { + // dialog failed + m_nCurState = TWAINState::DSopened; + } + } + + return bRet; +} + +void ImpTwain::NotifyParent(WPARAM nEvent, LPARAM lParam) +{ + PostThreadMessageW(m_nParentThreadId, WM_TWAIN_EVENT, nEvent, lParam); +} + +bool ImpTwain::ImplHandleMsg(MSG* pMsg) +{ + if (!m_pDSM) + return false; + + TW_EVENT aEvt = { pMsg, MSG_NULL }; + TW_UINT16 nRet = m_pDSM(&m_aAppId, &m_aSrcId, DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT, &aEvt); + + switch (aEvt.TWMessage) + { + case MSG_XFERREADY: + { + WPARAM nEvent = TWAIN_EVENT_QUIT; + + if (TWAINState::DSenabled == m_nCurState) + { + m_nCurState = TWAINState::DSreadyToXfer; + ImplXfer(); + + if (m_hMap) + nEvent = TWAIN_EVENT_XFER; + } + else if (TWAINState::Xferring == m_nCurState && m_hMap) + { + // Already sent TWAIN_EVENT_XFER; not processed yet; + // duplicate event + nEvent = TWAIN_EVENT_NONE; + } + + ImplFallback(nEvent); + } + break; + + case MSG_CLOSEDSREQ: + Destroy(); + break; + + case MSG_NULL: + nRet = TWRC_NOTDSEVENT; + break; + } + + return (TWRC_DSEVENT == nRet); +} + +void ImpTwain::ImplXfer() +{ + if (m_nCurState == TWAINState::DSreadyToXfer) + { + TW_IMAGEINFO aInfo; + HANDLE hDIB = nullptr; + double nXRes, nYRes; + + if (m_pDSM(&m_aAppId, &m_aSrcId, DG_IMAGE, DAT_IMAGEINFO, MSG_GET, &aInfo) == TWRC_SUCCESS) + { + nXRes = FixToDouble(aInfo.XResolution); + nYRes = FixToDouble(aInfo.YResolution); + } + else + nXRes = nYRes = -1; + + switch (m_pDSM(&m_aAppId, &m_aSrcId, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &hDIB)) + { + case TWRC_CANCEL: + m_nCurState = TWAINState::Xferring; + break; + + case TWRC_XFERDONE: + { + if (hDIB) + { + m_hMap = nullptr; + const HGLOBAL hGlob = static_cast(hDIB); + const SIZE_T nDIBSize = GlobalSize(hGlob); + const DWORD nMapSize = nDIBSize + 4; // leading 4 bytes for size + if (nMapSize > nDIBSize) // check for wrap + { + if (LPVOID pBmpMem = GlobalLock(hGlob)) + { + if ((nXRes > 0) && (nYRes > 0)) + { + // set resolution of bitmap + BITMAPINFOHEADER* pBIH = static_cast(pBmpMem); + + const auto[m, d] + = getConversionMulDiv(o3tl::Length::in, o3tl::Length::m); + pBIH->biXPelsPerMeter = std::round(o3tl::convert(nXRes, d, m)); + pBIH->biYPelsPerMeter = std::round(o3tl::convert(nYRes, d, m)); + } + + HANDLE hMap = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, + PAGE_READWRITE, 0, nMapSize, nullptr); + if (hMap) + { + LPVOID pMap = MapViewOfFile(hMap, FILE_MAP_WRITE, 0, 0, nMapSize); + if (pMap) + { + memcpy(pMap, &nMapSize, 4); // size of the following DIB + memcpy(static_cast(pMap) + 4, pBmpMem, nDIBSize); + FlushViewOfFile(pMap, nDIBSize); + UnmapViewOfFile(pMap); + + DuplicateHandle(GetCurrentProcess(), hMap, m_hProc, &m_hMap, 0, + FALSE, DUPLICATE_SAME_ACCESS); + } + + CloseHandle(hMap); + } + + GlobalUnlock(hGlob); + } + } + } + + GlobalFree(static_cast(hDIB)); + + m_nCurState = TWAINState::Xferring; + } + break; + + default: + break; + } + } +} + +void ImpTwain::ImplFallback(WPARAM nEvent) +{ + PostMessageW(m_hTwainWnd, WM_TWAIN_FALLBACK, nEvent, 0); +} + +void ImpTwain::ImplFallbackHdl(WPARAM nEvent) +{ + bool bFallback = true; + + switch (m_nCurState) + { + case TWAINState::Xferring: + case TWAINState::DSreadyToXfer: + { + TW_PENDINGXFERS aXfers; + + if (m_pDSM(&m_aAppId, &m_aSrcId, DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER, &aXfers) + == TWRC_SUCCESS) + { + if (aXfers.Count != 0) + m_pDSM(&m_aAppId, &m_aSrcId, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, &aXfers); + } + + m_nCurState = TWAINState::DSenabled; + } + break; + + case TWAINState::DSenabled: + { + TW_USERINTERFACE aUI = { true, true, m_hTwainWnd }; + + m_pDSM(&m_aAppId, &m_aSrcId, DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS, &aUI); + m_nCurState = TWAINState::DSopened; + } + break; + + case TWAINState::DSopened: + { + m_pDSM(&m_aAppId, nullptr, DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS, &m_aSrcId); + m_nCurState = TWAINState::DSMopened; + } + break; + + case TWAINState::DSMopened: + { + m_pDSM(&m_aAppId, nullptr, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, &m_hTwainWnd); + m_nCurState = TWAINState::DSMloaded; + } + break; + + case TWAINState::DSMloaded: + { + m_pDSM = nullptr; + FreeLibrary(m_hMod); + m_hMod = nullptr; + m_nCurState = TWAINState::DSMunloaded; + } + break; + + case TWAINState::DSMunloaded: + { + if (nEvent > TWAIN_EVENT_NONE) + NotifyParent(nEvent, reinterpret_cast(m_hMap)); + PostQuitMessage(0); + + bFallback = false; + } + break; + } + + if (bFallback) + ImplFallback(nEvent); +} + +void ImpTwain::ImplRequestHdl(WPARAM nRequest) +{ + switch (nRequest) + { + case TWAIN_REQUEST_QUIT: + Destroy(); + break; + case TWAIN_REQUEST_SELECTSOURCE: + NotifyParent(TWAIN_EVENT_REQUESTRESULT, LPARAM(SelectSource())); + break; + case TWAIN_REQUEST_INITXFER: + NotifyParent(TWAIN_EVENT_REQUESTRESULT, LPARAM(InitXfer())); + break; + } +} +} // namespace + +int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int) +{ + int argc = 0; + LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); + if (argc != 2) + return 1; // Wrong argument count + // 1st argument is parent thread handle; must be inherited. + // HANDLE is 32-bit in 32-bit applications, so wcstoul is OK. + HANDLE hParentThread = reinterpret_cast(wcstoul(argv[1], nullptr, 10)); + LocalFree(argv); + if (!hParentThread) + return 2; // Invalid parent thread handle argument value + + int nRet = 0; + try + { + ImpTwain aImpTwain(hParentThread); // creates main window + + MSG msg; + while (true) + { + DWORD nWaitResult + = MsgWaitForMultipleObjects(1, &hParentThread, FALSE, INFINITE, QS_ALLINPUT); + if (nWaitResult == WAIT_OBJECT_0) + return 5; // Parent process' thread died before we exited + if (nWaitResult == WAIT_FAILED) + return 6; // Some Win32 error + // nWaitResult == WAIT_OBJECT_0 + nCount => an event is in queue + bool bQuit = false; + while (PeekMessageW(&msg, nullptr, 0, 0, PM_REMOVE)) + { + // process it here + if (msg.message == WM_QUIT) + { + bQuit = true; + nRet = msg.wParam; + } + else + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + if (bQuit) + break; + } + } + catch (const std::exception& e) + { + printf("Exception thrown: %s", e.what()); + nRet = 7; + } + return nRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/scanner/twain32shim.hxx b/extensions/source/scanner/twain32shim.hxx new file mode 100644 index 000000000..c9e87ee8b --- /dev/null +++ b/extensions/source/scanner/twain32shim.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +// Don't use WM_USER + +// Notifications from shim to parent; wParam = event id +#define WM_TWAIN_EVENT (WM_USER + 1) + +// lParam is HWND +#define TWAIN_EVENT_NOTIFYHWND 0 + +// lParam is result (bool indicating success) +#define TWAIN_EVENT_REQUESTRESULT 1 + +// lParam is ignored +#define TWAIN_EVENT_NONE 10 +#define TWAIN_EVENT_QUIT 11 +#define TWAIN_EVENT_SCANNING 12 + +// lParam is HANDLE to shared file mapping valid in context of parent process +#define TWAIN_EVENT_XFER 13 + +// Requests from parent to shim; wParam = request id +#define WM_TWAIN_REQUEST (WM_USER + 2) + +#define TWAIN_REQUEST_QUIT 0 // Destroy() +#define TWAIN_REQUEST_SELECTSOURCE 1 +#define TWAIN_REQUEST_INITXFER 2 + +// messages starting from this are not to be used for interprocess communications +#define WM_SHIM_INTERNAL (WM_USER + 200) + +template std::string Num2Hex(IntType n) +{ + std::stringstream sMsg; + sMsg << "0x" << std::uppercase << std::setfill('0') << std::setw(sizeof(n) * 2) << std::hex + << n; + return sMsg.str(); +} + +void ThrowWin32Error(const char* sFunc, DWORD nWin32Error) +{ + std::stringstream sMsg; + sMsg << sFunc << " failed with Win32 error code " << Num2Hex(nWin32Error) << "!"; + + throw std::exception(sMsg.str().c_str()); +} + +void ThrowLastError(const char* sFunc) { ThrowWin32Error(sFunc, GetLastError()); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/actionlistener.hxx b/extensions/source/update/check/actionlistener.hxx new file mode 100644 index 000000000..8fdfd1565 --- /dev/null +++ b/extensions/source/update/check/actionlistener.hxx @@ -0,0 +1,39 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +class IActionListener : public virtual salhelper::SimpleReferenceObject +{ + public: + + virtual void cancel() = 0; + virtual void download() = 0; + virtual void install() = 0; + virtual void pause() = 0; + virtual void resume() = 0; + virtual void closeAfterFailure() = 0; + +protected: + virtual ~IActionListener() override {} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/download.cxx b/extensions/source/update/check/download.cxx new file mode 100644 index 000000000..ba371bdee --- /dev/null +++ b/extensions/source/update/check/download.cxx @@ -0,0 +1,427 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 "download.hxx" + +namespace beans = com::sun::star::beans ; +namespace container = com::sun::star::container ; +namespace lang = com::sun::star::lang ; +namespace uno = com::sun::star::uno ; + +namespace { + +struct OutData +{ + rtl::Reference< DownloadInteractionHandler >Handler; + OUString File; + OUString DestinationDir; + oslFileHandle FileHandle; + sal_uInt64 Offset; + osl::Condition& StopCondition; + CURL *curl; + + explicit OutData(osl::Condition& rCondition) : FileHandle(nullptr), Offset(0), StopCondition(rCondition), curl(nullptr) {}; +}; + +} + +static void openFile( OutData& out ) +{ + char * effective_url; + curl_easy_getinfo(out.curl, CURLINFO_EFFECTIVE_URL, &effective_url); + + curl_off_t nDownloadSize; + curl_easy_getinfo(out.curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &nDownloadSize); + + OString aURL(effective_url); + + // ensure no trailing '/' + sal_Int32 nLen = aURL.getLength(); + while( (nLen > 0) && ('/' == aURL[nLen-1]) ) + aURL = aURL.copy(0, --nLen); + + // extract file name last '/' + sal_Int32 nIndex = aURL.lastIndexOf('/'); + if( nIndex > 0 ) + { + out.File = out.DestinationDir + + OStringToOUString(aURL.subView(nIndex), RTL_TEXTENCODING_UTF8); + + oslFileError rc; + + // Give the user an overwrite warning if the target file exists + const sal_Int32 openFlags = osl_File_OpenFlag_Write | osl_File_OpenFlag_Create; + do + { + rc = osl_openFile(out.File.pData, &out.FileHandle, openFlags); + + if( osl_File_E_EXIST == rc && ! out.Handler->downloadTargetExists(out.File) ) + { + out.StopCondition.set(); + break; + } + + } while( osl_File_E_EXIST == rc ); + + if( osl_File_E_None == rc ) + out.Handler->downloadStarted(out.File, static_cast(nDownloadSize)); + } +} + + +static OString +getStringValue(const uno::Reference< container::XNameAccess >& xNameAccess, const OUString& aName) +{ + OSL_ASSERT(xNameAccess->hasByName(aName)); + uno::Any aValue = xNameAccess->getByName(aName); + + return OUStringToOString(aValue.get(), RTL_TEXTENCODING_UTF8); +} + + +static sal_Int32 +getInt32Value(const uno::Reference< container::XNameAccess >& xNameAccess, + const OUString& aName) +{ + OSL_ASSERT(xNameAccess->hasByName(aName)); + uno::Any aValue = xNameAccess->getByName(aName); + + sal_Int32 n = -1; + aValue >>= n; + return n; +} + + +static size_t +write_function( void *ptr, size_t size, size_t nmemb, void *stream ) +{ + OutData *out = static_cast < OutData * > (stream); + + if( nullptr == out->FileHandle ) + openFile(*out); + + sal_uInt64 nBytesWritten = 0; + + if( nullptr != out->FileHandle ) + osl_writeFile(out->FileHandle, ptr, size * nmemb, &nBytesWritten); + + return static_cast(nBytesWritten); +} + + +static int +progress_callback( void *clientp, curl_off_t dltotal, curl_off_t dlnow, SAL_UNUSED_PARAMETER curl_off_t, SAL_UNUSED_PARAMETER curl_off_t) +{ + OutData *out = static_cast < OutData * > (clientp); + + assert(out); + + if (out && !out->StopCondition.check()) + { + float fPercent = 0; + if ( dltotal + out->Offset ) + fPercent = (dlnow + out->Offset) * 100 / (dltotal + out->Offset); + if( fPercent < 0 ) + fPercent = 0; + + // Do not report progress for redirection replies + long nCode; + curl_easy_getinfo(out->curl, CURLINFO_RESPONSE_CODE, &nCode); + if( (nCode != 302) && (nCode != 303) && (dltotal > 0) ) + out->Handler->downloadProgressAt(static_cast(fPercent)); + + return 0; + } + + // If stop condition is set, return non 0 value to abort + return -1; +} + + +void +Download::getProxyForURL(std::u16string_view rURL, OString& rHost, sal_Int32& rPort) const +{ + uno::Reference< lang::XMultiServiceFactory > xConfigProvider( + css::configuration::theDefaultProvider::get( m_xContext ) ); + + beans::PropertyValue aProperty; + aProperty.Name = "nodepath"; + aProperty.Value <<= OUString("org.openoffice.Inet/Settings"); + + uno::Sequence< uno::Any > aArgumentList{ uno::Any(aProperty) }; + + uno::Reference< container::XNameAccess > xNameAccess( + xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", aArgumentList ), + uno::UNO_QUERY_THROW ); + + OSL_ASSERT(xNameAccess->hasByName("ooInetProxyType")); + uno::Any aValue = xNameAccess->getByName("ooInetProxyType"); + + sal_Int32 nProxyType = aValue.get< sal_Int32 >(); + if( 0 != nProxyType ) // type 0 means "direct connection to the internet + { + if( o3tl::starts_with(rURL, u"http:") ) + { + rHost = getStringValue(xNameAccess, "ooInetHTTPProxyName"); + rPort = getInt32Value(xNameAccess, "ooInetHTTPProxyPort"); + } + else if( o3tl::starts_with(rURL, u"https:") ) + { + rHost = getStringValue(xNameAccess, "ooInetHTTPSProxyName"); + rPort = getInt32Value(xNameAccess, "ooInetHTTPSProxyPort"); + } + else if( o3tl::starts_with(rURL, u"ftp:") ) + { + rHost = getStringValue(xNameAccess, "ooInetFTPProxyName"); + rPort = getInt32Value(xNameAccess, "ooInetFTPProxyPort"); + } + } +} + + +static bool curl_run(std::u16string_view rURL, OutData& out, const OString& aProxyHost, sal_Int32 nProxyPort) +{ + /* Need to investigate further whether it is necessary to call + * curl_global_init or not - leave it for now (as the ftp UCB content + * provider does as well). + */ + + CURL * pCURL = curl_easy_init(); + bool ret = false; + + if( nullptr != pCURL ) + { + out.curl = pCURL; + + OString aURL(OUStringToOString(rURL, RTL_TEXTENCODING_UTF8)); + (void)curl_easy_setopt(pCURL, CURLOPT_URL, aURL.getStr()); + + // abort on http errors + (void)curl_easy_setopt(pCURL, CURLOPT_FAILONERROR, 1); + + // enable redirection + (void)curl_easy_setopt(pCURL, CURLOPT_FOLLOWLOCATION, 1); + // only allow redirect to https:// +#if (LIBCURL_VERSION_MAJOR > 7) || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 85) + curl_easy_setopt(pCURL, CURLOPT_REDIR_PROTOCOLS_STR, "https"); +#else + curl_easy_setopt(pCURL, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS); +#endif + + // write function + (void)curl_easy_setopt(pCURL, CURLOPT_WRITEDATA, &out); + (void)curl_easy_setopt(pCURL, CURLOPT_WRITEFUNCTION, &write_function); + + // progress handler - Condition::check unfortunately is not defined const + (void)curl_easy_setopt(pCURL, CURLOPT_NOPROGRESS, 0); + (void)curl_easy_setopt(pCURL, CURLOPT_XFERINFOFUNCTION, &progress_callback); + (void)curl_easy_setopt(pCURL, CURLOPT_PROGRESSDATA, &out); + + // proxy + (void)curl_easy_setopt(pCURL, CURLOPT_PROXY, aProxyHost.getStr()); + (void)curl_easy_setopt(pCURL, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + if( -1 != nProxyPort ) + (void)curl_easy_setopt(pCURL, CURLOPT_PROXYPORT, nProxyPort); + + if( out.Offset > 0 ) + { + // curl_off_t offset = nOffset; libcurl seems to be compiled with large + // file support (and we not) .. + sal_Int64 offset = static_cast(out.Offset); + (void)curl_easy_setopt(pCURL, CURLOPT_RESUME_FROM_LARGE, offset); + } + + CURLcode cc = curl_easy_perform(pCURL); + + // treat zero byte downloads as errors + if( nullptr == out.FileHandle ) + openFile(out); + + if( CURLE_OK == cc ) + { + out.Handler->downloadFinished(out.File); + ret = true; + } + + if ( CURLE_PARTIAL_FILE == cc ) + { + // this sometimes happens, when a user throws away his user data, but has already + // completed the download of an update. + curl_off_t nDownloadSize; + curl_easy_getinfo( pCURL, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &nDownloadSize ); + if ( -1 == nDownloadSize ) + { + out.Handler->downloadFinished(out.File); + ret = true; + } + } + + // Avoid target file being removed + else if( (CURLE_ABORTED_BY_CALLBACK == cc) || out.StopCondition.check() ) + ret = true; + + // Only report errors when not stopped + else + { + OString aMessage("Unknown error"); + + const char * error_message = curl_easy_strerror(cc); + if( nullptr != error_message ) + aMessage = error_message; + + if ( CURLE_HTTP_RETURNED_ERROR == cc ) + { + long nError; + curl_easy_getinfo( pCURL, CURLINFO_RESPONSE_CODE, &nError ); + + if ( 403 == nError ) + aMessage += " 403: Access denied!"; + else if ( 404 == nError ) + aMessage += " 404: File not found!"; + else if ( 416 == nError ) + { + // we got this error probably, because we already downloaded the file + out.Handler->downloadFinished(out.File); + ret = true; + } + else + { + aMessage += ":error code = " + OString::number( nError ) + " !"; + } + } + if ( !ret ) + out.Handler->downloadStalled( OStringToOUString(aMessage, RTL_TEXTENCODING_UTF8) ); + } + + curl_easy_cleanup(pCURL); + } + + return ret; +} + + +bool +Download::start(const OUString& rURL, const OUString& rFile, const OUString& rDestinationDir) +{ + OSL_ASSERT( m_aHandler.is() ); + + OutData out(m_aCondition); + OUString aFile( rFile ); + + // when rFile is empty, there is no remembered file name. If there is already a file with the + // same name ask the user if she wants to resume a download or restart the download + if ( aFile.isEmpty() ) + { + // GetFileName() + OUString aURL( rURL ); + // ensure no trailing '/' + sal_Int32 nLen = aURL.getLength(); + while( (nLen > 0) && ('/' == aURL[ nLen-1 ]) ) + aURL = aURL.copy( 0, --nLen ); + + // extract file name last '/' + sal_Int32 nIndex = aURL.lastIndexOf('/'); + aFile = rDestinationDir + aURL.subView( nIndex ); + + // check for existing file + oslFileError rc = osl_openFile( aFile.pData, &out.FileHandle, osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); + osl_closeFile(out.FileHandle); + out.FileHandle = nullptr; + + if( osl_File_E_EXIST == rc ) + { + if ( m_aHandler->checkDownloadDestination( aURL.copy( nIndex+1 ) ) ) + { + osl_removeFile( aFile.pData ); + aFile.clear(); + } + else + m_aHandler->downloadStarted( aFile, 0 ); + } + else + { + osl_removeFile( aFile.pData ); + aFile.clear(); + } + } + + out.File = aFile; + out.DestinationDir = rDestinationDir; + out.Handler = m_aHandler; + + if( !aFile.isEmpty() ) + { + oslFileError rc = osl_openFile(aFile.pData, &out.FileHandle, osl_File_OpenFlag_Write); + + if( osl_File_E_None == rc ) + { + // Set file pointer to the end of the file on resume + if( osl_File_E_None == osl_setFilePos(out.FileHandle, osl_Pos_End, 0) ) + { + osl_getFilePos(out.FileHandle, &out.Offset); + } + } + else if( osl_File_E_NOENT == rc ) // file has been deleted meanwhile .. + out.File.clear(); + } + + OString aProxyHost; + sal_Int32 nProxyPort = -1; + getProxyForURL(rURL, aProxyHost, nProxyPort); + + bool ret = curl_run(rURL, out, aProxyHost, nProxyPort); + + if( nullptr != out.FileHandle ) + { + osl_syncFile(out.FileHandle); + osl_closeFile(out.FileHandle); + +// #i90930# Don't remove already downloaded bits, when curl_run reports an error +// because later calls might be successful +// if( ! ret ) +// osl_removeFile(out.File.pData); + } + + m_aCondition.reset(); + return ret; +} + + +void +Download::stop() +{ + m_aCondition.set(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/download.hxx b/extensions/source/update/check/download.hxx new file mode 100644 index 000000000..12a11ddde --- /dev/null +++ b/extensions/source/update/check/download.hxx @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include + +#include +#include +#include +#include + +struct DownloadInteractionHandler : public virtual salhelper::SimpleReferenceObject +{ + virtual bool checkDownloadDestination(const OUString& rFileName) = 0; + + // called if the destination file already exists, but resume is false + virtual bool downloadTargetExists(const OUString& rFileName) = 0; + + // called when curl reports an error + virtual void downloadStalled(const OUString& rErrorMessage) = 0; + + // progress handler + virtual void downloadProgressAt(sal_Int8 nPercent) = 0; + + // called on first progress notification + virtual void downloadStarted(const OUString& rFileName, sal_Int64 nFileSize) = 0; + + // called when download has been finished + virtual void downloadFinished(const OUString& rFileName) = 0; + +protected: + virtual ~DownloadInteractionHandler() override {} +}; + +class Download +{ +public: + Download(const css::uno::Reference& xContext, + const rtl::Reference& rHandler) + : m_xContext(xContext) + , m_aHandler(rHandler){}; + + // returns true when the content of rURL was successfully written to rLocalFile + bool start(const OUString& rURL, const OUString& rFile, const OUString& rDestinationDir); + + // stops the download after the next write operation + void stop(); + +protected: + // Determines the appropriate proxy settings for the given URL. Returns true if a proxy should be used + void getProxyForURL(std::u16string_view rURL, OString& rHost, sal_Int32& rPort) const; + +private: + osl::Condition m_aCondition; + const css::uno::Reference& m_xContext; + const rtl::Reference m_aHandler; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/onlinecheck.cxx b/extensions/source/update/check/onlinecheck.cxx new file mode 100644 index 000000000..af6ade879 --- /dev/null +++ b/extensions/source/update/check/onlinecheck.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 +#include + +#include "onlinecheck.hxx" + +#define WIN32_LEAN_AND_MEAN +#include +#include + +// #i71984 +extern "C" bool WNT_hasInternetConnection() +{ + DWORD dwFlags; + WCHAR szConnectionName[1024]; + + __try { + bool fIsConnected = InternetGetConnectedStateExW( + &dwFlags, + szConnectionName, + SAL_N_ELEMENTS(szConnectionName), + 0 ); + + return fIsConnected; + + } __except( EXCEPTION_EXECUTE_HANDLER ) { + return false; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/onlinecheck.hxx b/extensions/source/update/check/onlinecheck.hxx new file mode 100644 index 000000000..fcfedcf48 --- /dev/null +++ b/extensions/source/update/check/onlinecheck.hxx @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#if defined(_WIN32) +extern "C" bool WNT_hasInternetConnection(); +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/org/openoffice/Office/Addons.xcu b/extensions/source/update/check/org/openoffice/Office/Addons.xcu new file mode 100644 index 000000000..29aa55e47 --- /dev/null +++ b/extensions/source/update/check/org/openoffice/Office/Addons.xcu @@ -0,0 +1,42 @@ + + + + + + + + vnd.sun.star.job:alias=UpdateCheck + + + + + + ~Check for Updates... + + + _self + + + + + + + + + diff --git a/extensions/source/update/check/org/openoffice/Office/Jobs.xcu b/extensions/source/update/check/org/openoffice/Office/Jobs.xcu new file mode 100644 index 000000000..58db40480 --- /dev/null +++ b/extensions/source/update/check/org/openoffice/Office/Jobs.xcu @@ -0,0 +1,66 @@ + + + + + + + com.sun.star.setup.UpdateCheck + + + + true + + + 0 + + + + 604800 + + + + + + false + + + true + + + false + + + false + + + + + + + + + + + + + diff --git a/extensions/source/update/check/updatecheck.cxx b/extensions/source/update/check/updatecheck.cxx new file mode 100644 index 000000000..8669f890e --- /dev/null +++ b/extensions/source/update/check/updatecheck.cxx @@ -0,0 +1,1617 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 "updatecheck.hxx" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +#include "onlinecheck.hxx" +#include "updateprotocol.hxx" +#include "updatecheckconfig.hxx" + +namespace beans = com::sun::star::beans ; +namespace deployment = com::sun::star::deployment ; +namespace frame = com::sun::star::frame ; +namespace lang = com::sun::star::lang ; +namespace c3s = com::sun::star::system ; +namespace task = com::sun::star::task ; +namespace uno = com::sun::star::uno ; + +constexpr OUStringLiteral PROPERTY_TITLE = u"BubbleHeading"; +constexpr OUStringLiteral PROPERTY_TEXT = u"BubbleText"; +constexpr OUStringLiteral PROPERTY_SHOW_BUBBLE = u"BubbleVisible"; +constexpr OUStringLiteral PROPERTY_CLICK_HDL = u"MenuClickHDL"; +constexpr OUStringLiteral PROPERTY_SHOW_MENUICON = u"MenuIconVisible"; + +// Returns the URL of the release note for the given position +OUString getReleaseNote(const UpdateInfo& rInfo, sal_uInt8 pos, bool autoDownloadEnabled) +{ + for (auto const& elem : rInfo.ReleaseNotes) + { + if( pos == elem.Pos ) + { + if( (pos > 2) || !autoDownloadEnabled || elem.URL2.isEmpty() ) + return elem.URL; + } + else if( (pos == elem.Pos2) && ((1 == elem.Pos) || (2 == elem.Pos)) && autoDownloadEnabled ) + return elem.URL2; + } + + return OUString(); +} + + +namespace +{ + +OUString getBuildId() +{ + OUString aPathVal("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}"); + rtl::Bootstrap::expandMacros(aPathVal); + return aPathVal; +} + + +#if (defined LINUX || defined __sun) +OUString getBaseInstallation() +{ + OUString aPathVal("$BRAND_BASE_DIR"); + rtl::Bootstrap::expandMacros(aPathVal); + return aPathVal; +} +#endif + + +bool isObsoleteUpdateInfo(std::u16string_view rBuildId) +{ + return rBuildId != getBuildId() && !rBuildId.empty(); +} + + +OUString getImageFromFileName(const OUString& aFile) +{ +#ifndef _WIN32 + OUString aUnpackPath; + if( osl_getExecutableFile(&aUnpackPath.pData) == osl_Process_E_None ) + { + sal_uInt32 lastIndex = aUnpackPath.lastIndexOf('/'); + if ( lastIndex > 0 ) + { + aUnpackPath = OUString::Concat(aUnpackPath.subView( 0, lastIndex+1 )) + + "unpack_update"; + } + + oslFileHandle hOut = nullptr; + oslProcess hProcess = nullptr; + + OUString aSystemPath; + osl::File::getSystemPathFromFileURL(aFile, aSystemPath); + + oslProcessError rc = osl_executeProcess_WithRedirectedIO( + aUnpackPath.pData, // [in] Image name + &aSystemPath.pData, 1, // [in] Arguments + osl_Process_WAIT | osl_Process_NORMAL, // [in] Options + nullptr, // [in] Security + nullptr, // [in] Working directory + nullptr, 0, // [in] Environment variables + &hProcess, // [out] Process handle + nullptr, &hOut, nullptr // [out] File handles for redirected I/O + ); + + if( osl_Process_E_None == rc ) + { + // Create a guard to ensure correct cleanup in its dtor in any case + comphelper::ScopeGuard g([hOut, hProcess] () { + osl_closeFile(hOut); + osl_freeProcessHandle(hProcess); + }); + + oslProcessInfo aInfo; + aInfo.Size = sizeof(oslProcessInfo); + + if( osl_Process_E_None == osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &aInfo) ) + { + if( 0 == aInfo.Code ) + { + char szBuffer[4096]; + sal_uInt64 nBytesRead = 0; + const sal_uInt64 nBytesToRead = sizeof(szBuffer) - 1; + + OUString aImageName; + while( osl_File_E_None == osl_readFile(hOut, szBuffer, nBytesToRead, &nBytesRead) ) + { + char *pc = szBuffer + nBytesRead; + do + { + *pc = '\0'; --pc; + } + while( ('\n' == *pc) || ('\r' == *pc) ); + + aImageName += OUString(szBuffer, pc - szBuffer + 1, osl_getThreadTextEncoding()); + + if( nBytesRead < nBytesToRead ) + break; + } + + if( osl::FileBase::E_None == osl::FileBase::getFileURLFromSystemPath(aImageName, aImageName) ) + return aImageName; + } + } + } + } +#endif + + return aFile; +} + + +uno::Reference< beans::XPropertySet > createMenuBarUI( + const uno::Reference< uno::XComponentContext >& xContext, + const uno::Reference< task::XJob >& xJob) +{ + if( !xContext.is() ) + throw uno::RuntimeException( + "UpdateCheckJob: empty component context", uno::Reference< uno::XInterface > () ); + + uno::Reference< lang::XMultiComponentFactory > xServiceManager(xContext->getServiceManager()); + if( !xServiceManager.is() ) + throw uno::RuntimeException( + "UpdateCheckJob: unable to obtain service manager from component context", uno::Reference< uno::XInterface > () ); + + uno::Reference< beans::XPropertySet > xMenuBarUI( + xServiceManager->createInstanceWithContext( "com.sun.star.setup.UpdateCheckUI", xContext ), + uno::UNO_QUERY_THROW); + + xMenuBarUI->setPropertyValue( PROPERTY_CLICK_HDL, uno::Any( xJob ) ); + + return xMenuBarUI; +} + + +typedef sal_Bool (* OnlineCheckFunc) (); + +class UpdateCheckThread : public WorkerThread +{ + +public: + UpdateCheckThread( osl::Condition& rCondition, + const uno::Reference& xContext, + rtl::Reference const & controller ); + + virtual void SAL_CALL join() override; + virtual void SAL_CALL terminate() override; + virtual void cancel() override; + + void cancelAsSoonAsPossible(); + +protected: + virtual ~UpdateCheckThread() override; + + virtual void SAL_CALL run() override; + virtual void SAL_CALL onTerminated() override; + + /* Wrapper around checkForUpdates */ + bool runCheck( bool & rbExtensionsChecked ); + +private: + + /* Used to avoid dialup login windows (on platforms we know how to double this) */ + static bool hasInternetConnection() + { +#ifdef _WIN32 + return WNT_hasInternetConnection(); +#else + return true; +#endif + } + + /* Creates a new instance of UpdateInformationProvider and returns this instance */ + uno::Reference createProvider() + { + osl::MutexGuard aGuard(m_aMutex); + m_xProvider = deployment::UpdateInformationProvider::create(m_xContext); + return m_xProvider; + }; + + /* Returns the remembered instance of UpdateInformationProvider if any */ + uno::Reference getProvider() + { osl::MutexGuard aGuard(m_aMutex); return m_xProvider; }; + + /* Releases the remembered instance of UpdateInformationProvider if any */ + void clearProvider() + { osl::MutexGuard aGuard(m_aMutex); m_xProvider.clear(); }; + + osl::Mutex m_aMutex; + +protected: + osl::Condition& m_aCondition; + +private: + const uno::Reference m_xContext; + uno::Reference m_xProvider; + rtl::Reference m_controller; + bool m_cancelAsSoonAsPossible; +}; + + +class ManualUpdateCheckThread : public UpdateCheckThread +{ +public: + ManualUpdateCheckThread( osl::Condition& rCondition, const uno::Reference& xContext ) : + UpdateCheckThread(rCondition, xContext, {}) {}; + + virtual void SAL_CALL run() override; +}; + + +class MenuBarButtonJob : public ::cppu::WeakImplHelper< task::XJob > +{ +public: + explicit MenuBarButtonJob(const rtl::Reference< UpdateCheck >& rUpdateCheck); + + // XJob + virtual uno::Any SAL_CALL execute(const uno::Sequence&) override; + +private: + rtl::Reference< UpdateCheck > m_aUpdateCheck; +}; + +class DownloadThread : public WorkerThread +{ +public: + DownloadThread( + osl::Condition& rCondition, + const uno::Reference& xContext, + const rtl::Reference< DownloadInteractionHandler >& rHandler, + const OUString& rURL ); + + virtual void SAL_CALL run() override; + virtual void cancel() override; + virtual void SAL_CALL suspend() override; + virtual void SAL_CALL onTerminated() override; + +protected: + virtual ~DownloadThread() override; + +private: + osl::Condition& m_aCondition; + const uno::Reference m_xContext; + const OUString m_aURL; + Download m_aDownload; +}; + + +class ShutdownThread : public osl::Thread +{ +public: + explicit ShutdownThread(const uno::Reference& xContext); + + virtual void SAL_CALL run() override; + virtual void SAL_CALL onTerminated() override; + +protected: + virtual ~ShutdownThread() override; + +private: + osl::Condition m_aCondition; + const uno::Reference m_xContext; +}; + + +UpdateCheckThread::UpdateCheckThread( osl::Condition& rCondition, + const uno::Reference& xContext, + rtl::Reference const & controller ) : + m_aCondition(rCondition), + m_xContext(xContext), + m_controller(controller), + m_cancelAsSoonAsPossible(false) +{ + createSuspended(); + + // actually run the thread + resume(); +} + + +UpdateCheckThread::~UpdateCheckThread() +{ +} + + +void SAL_CALL +UpdateCheckThread::terminate() +{ + // Cancel potentially hanging http request .. + cancel(); + // .. before terminating + osl::Thread::terminate(); +} + + +void SAL_CALL +UpdateCheckThread::join() +{ + uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider()); + + // do not join during an update check until #i73893# is fixed + if( ! xProvider.is() ) + { + osl::Thread::join(); + } +} + + +void +UpdateCheckThread::cancel() +{ + uno::Reference< deployment::XUpdateInformationProvider > xProvider(getProvider()); + + if( xProvider.is() ) + xProvider->cancel(); +} + +void UpdateCheckThread::cancelAsSoonAsPossible() { + { + osl::MutexGuard g(m_aMutex); + m_cancelAsSoonAsPossible = true; + } + m_aCondition.set(); +} + +bool +UpdateCheckThread::runCheck( bool & rbExtensionsChecked ) +{ + bool ret = false; + UpdateState eUIState = UPDATESTATE_NO_UPDATE_AVAIL; + + UpdateInfo aInfo; + rtl::Reference< UpdateCheck > aController(UpdateCheck::get()); + + if( checkForUpdates(aInfo, m_xContext, aController->getInteractionHandler(), createProvider()) ) + { + aController->setUpdateInfo(aInfo); + eUIState = UpdateCheck::getUIState(aInfo); + ret = true; + } + else + aController->setCheckFailedState(); + + // We will only look for extension updates, when there is no 'check for office updates' dialog open + // and when there was no office update found + if ( ( eUIState != UPDATESTATE_UPDATE_AVAIL ) && + ( eUIState != UPDATESTATE_UPDATE_NO_DOWNLOAD ) && + !aController->isDialogShowing() && + !rbExtensionsChecked ) + { + bool bHasExtensionUpdates = checkForExtensionUpdates( m_xContext ); + aController->setHasExtensionUpdates( bHasExtensionUpdates ); + if ( bHasExtensionUpdates ) + aController->setUIState( UPDATESTATE_EXT_UPD_AVAIL ); + rbExtensionsChecked = true; + } + + // joining with this thread is safe again + clearProvider(); + return ret; +} + + +void SAL_CALL +UpdateCheckThread::onTerminated() +{ + delete this; +} + + +void SAL_CALL +UpdateCheckThread::run() +{ + osl_setThreadName("UpdateCheckThread"); + + TimeValue systime; + TimeValue nExtCheckTime; + osl_getSystemTime( &nExtCheckTime ); + + osl::Condition::Result aResult = osl::Condition::result_timeout; + TimeValue tv = { 10, 0 }; + + // Initial wait to avoid doing further time consuming tasks during start-up + aResult = m_aCondition.wait(&tv); + { + osl::MutexGuard g(m_aMutex); + if (m_cancelAsSoonAsPossible) { + goto done; + } + } + + try { + bool bExtensionsChecked = false; + + while( schedule() ) + { + /* Use cases: + * a) manual check requested from auto check thread - "last check" should not be checked (one time) + * a1) manual check was requested in the middle of a running auto check, + * condition is set + * a2) manual check was requested while waiting for a retry, + * condition is set + * a3) manual check was requested while waiting for time to next + * scheduled check elapsing, condition is set + * a4) manual check was requested during initial wait, condition is set + * b) check interval got changed, condition may be set - same sub-cases as a), + * but "last check" should be honored + * c) normal auto check mode, condition not set - "last check" should be honored + */ + + // Accessing const members without synchronization + rtl::Reference< UpdateCheck > aController(UpdateCheck::get()); + rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext, *aController); + + // FIXME: remember last & offset ? + sal_Int64 last = rModel->getLastChecked(); + sal_Int64 offset = rModel->getCheckInterval(); + + rModel.clear(); + + // last == 0 means check immediately + bool checkNow = last <= 0; + + // Reset the condition to avoid busy loops + if( osl::Condition::result_ok == aResult ) + { + m_aCondition.reset(); + aResult = osl::Condition::result_timeout; + checkNow = aController->isDialogShowing(); + } + + if( ! checkNow ) + { + osl_getSystemTime(&systime); + + // Go back to sleep until time has elapsed + sal_Int64 next = last + offset; + if( last + offset > systime.Seconds ) + { + // This can not be > 32 Bit for now .. + tv.Seconds = static_cast< sal_Int32 > (next - systime.Seconds); + aResult = m_aCondition.wait(&tv); + { + osl::MutexGuard g(m_aMutex); + if (m_cancelAsSoonAsPossible) { + goto done; + } + } + continue; + } + } + + static sal_uInt8 n = 0; + + if( ! hasInternetConnection() || ! runCheck( bExtensionsChecked ) ) + { + // the extension update check should be independent from the office update check + + osl_getSystemTime( &systime ); + if ( nExtCheckTime.Seconds + offset < systime.Seconds ) + bExtensionsChecked = false; + + // Increase next by 15, 60, .. minutes + static const sal_Int32 nRetryInterval[] = { 900, 3600, 14400, 86400 }; + + if( n < SAL_N_ELEMENTS(nRetryInterval) ) + ++n; + + tv.Seconds = nRetryInterval[n-1]; + aResult = m_aCondition.wait(&tv); + { + osl::MutexGuard g(m_aMutex); + if (m_cancelAsSoonAsPossible) { + goto done; + } + } + } + else // reset retry counter + { + n = 0; + bExtensionsChecked = false; + } + } + } + + catch(const uno::Exception&) { + // Silently catch all errors + TOOLS_WARN_EXCEPTION("extensions.update", "Caught exception, thread terminated" ); + } + +done: + if (m_controller.is()) { + m_controller->notifyUpdateCheckFinished(); + } +} + + +void SAL_CALL +ManualUpdateCheckThread::run() +{ + try { + bool bExtensionsChecked = false; + runCheck( bExtensionsChecked ); + m_aCondition.reset(); + } + catch(const uno::Exception&) { + // Silently catch all errors + TOOLS_WARN_EXCEPTION("extensions.update", "Caught exception, thread terminated" ); + } +} + + +MenuBarButtonJob::MenuBarButtonJob(const rtl::Reference< UpdateCheck >& rUpdateCheck) : + m_aUpdateCheck(rUpdateCheck) +{ +}; + + +uno::Any SAL_CALL +MenuBarButtonJob::execute(const uno::Sequence& ) +{ + if ( m_aUpdateCheck->shouldShowExtUpdDlg() ) + m_aUpdateCheck->showExtensionDialog(); + else + m_aUpdateCheck->showDialog(); + + return uno::Any(); +} + + +DownloadThread::DownloadThread(osl::Condition& rCondition, + const uno::Reference& xContext, + const rtl::Reference< DownloadInteractionHandler >& rHandler, + const OUString& rURL) : + m_aCondition(rCondition), + m_xContext(xContext), + m_aURL(rURL), + m_aDownload(xContext, rHandler) +{ + createSuspended(); +} + + +DownloadThread::~DownloadThread() +{ +} + + +void SAL_CALL +DownloadThread::run() +{ + osl_setThreadName("DownloadThread"); + +#ifdef _WIN32 + int nNbCallCoInitializeExForReinit = 0; + // for SystemShellExecute + o3tl::safeCoInitializeEx(COINIT_APARTMENTTHREADED, nNbCallCoInitializeExForReinit); +#endif + + while( schedule() ) + { + rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); + + OUString aLocalFile = rModel->getLocalFileName(); + OUString aDownloadDest = rModel->getDownloadDestination(); + + // release config class for now + rModel.clear(); + + static sal_uInt8 n = 0; + if( ! m_aDownload.start(m_aURL, aLocalFile, aDownloadDest ) ) + { + // retry every 15s unless the dialog is not visible + TimeValue tv; + tv.Seconds = 15; + + if( ! UpdateCheck::get()->isDialogShowing() ) + { + // Increase next by 1, 5, 15, 60, .. minutes + static const sal_Int16 nRetryInterval[] = { 60, 300, 900, 3600 }; + + if( n < SAL_N_ELEMENTS(nRetryInterval) ) + ++n; + + tv.Seconds = nRetryInterval[n-1]; + } + m_aCondition.wait(&tv); + } + else + { + // reset wait period after successful download + n=0; + } + } +#ifdef _WIN32 + o3tl::safeCoUninitializeReinit(COINIT_MULTITHREADED, nNbCallCoInitializeExForReinit); +#endif +} + + +void DownloadThread::cancel() +{ + m_aDownload.stop(); + resume(); + + rtl::Reference< UpdateCheck > aController(UpdateCheck::get()); + aController->cancelDownload(); +} + + +void SAL_CALL DownloadThread::suspend() +{ + osl::Thread::suspend(); + m_aDownload.stop(); +} + + +void SAL_CALL DownloadThread::onTerminated() +{ + delete this; +} + + +ShutdownThread::ShutdownThread( const uno::Reference& xContext) : + m_xContext( xContext ) +{ + create(); +} + + +ShutdownThread::~ShutdownThread() +{ +} + + +void SAL_CALL +ShutdownThread::run() +{ + osl_setThreadName("ShutdownThread"); + + TimeValue tv = { 0, 250 }; + + m_aCondition.wait(&tv); + + // Tell QuickStarter not to veto .. + uno::Reference< css::beans::XFastPropertySet > xQuickStarter = css::office::Quickstart::createDefault(m_xContext); + + xQuickStarter->setFastPropertyValue(0, uno::Any(false)); + + // Shutdown the office + uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(m_xContext); + + xDesktop->terminate(); +} + + +void SAL_CALL ShutdownThread::onTerminated() +{ + delete this; +} + + +} // anonymous namespace + +UpdateCheck::UpdateCheck() + : m_eState(NOT_INITIALIZED) + , m_eUpdateState(UPDATESTATES_COUNT) + , m_pThread(nullptr) + , m_bHasExtensionUpdate(false) + , m_bShowExtUpdDlg(false) + , m_updateCheckRunning(false) +{ +} + +UpdateCheck::~UpdateCheck() {} + +void +UpdateCheck::initialize(const uno::Sequence< beans::NamedValue >& rValues, + const uno::Reference& xContext) +{ + std::scoped_lock aGuard(m_aMutex); + + if( NOT_INITIALIZED == m_eState ) + { + NamedValueByNameAccess aNameAccess(rValues); + UpdateCheckROModel aModel( aNameAccess ); + m_xContext = xContext; + + OUString aUpdateEntryVersion = aModel.getUpdateEntryVersion(); + + aModel.getUpdateEntry(m_aUpdateInfo); + + bool obsoleteUpdateInfo = isObsoleteUpdateInfo(aUpdateEntryVersion); + bool bContinueDownload = false; + bool bDownloadAvailable = false; + + m_bHasExtensionUpdate = checkForPendingUpdates( xContext ); + m_bShowExtUpdDlg = false; + + OUString aLocalFileName = aModel.getLocalFileName(); + + if( !aLocalFileName.isEmpty() ) + { + bContinueDownload = true; + + // Try to get the number of bytes already on disk + osl::DirectoryItem aDirectoryItem; + if( osl::DirectoryItem::E_None == osl::DirectoryItem::get(aLocalFileName, aDirectoryItem) ) + { + osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileSize); + if( osl::DirectoryItem::E_None == aDirectoryItem.getFileStatus(aFileStatus) ) + { + sal_Int64 nDownloadSize = aModel.getDownloadSize(); + sal_Int64 nFileSize = aFileStatus.getFileSize(); + + if( nDownloadSize > 0 ) + { + if ( nDownloadSize <= nFileSize ) // we have already downloaded everything + { + bContinueDownload = false; + bDownloadAvailable = true; + m_aImageName = getImageFromFileName( aLocalFileName ); + } + else // Calculate initial percent value. + { + sal_Int32 nPercent = static_cast(100 * nFileSize / nDownloadSize); + getUpdateHandler()->setProgress( nPercent ); + } + } + } + } + + if ( bContinueDownload ) + { + bool downloadPaused = aModel.isDownloadPaused(); + + enableDownload(true, downloadPaused); + // coverity[lock_order : FALSE] - incorrect report of lock order error with std::recursive_mutex + setUIState(downloadPaused ? UPDATESTATE_DOWNLOAD_PAUSED : UPDATESTATE_DOWNLOADING); + } + + } + if ( !bContinueDownload ) + { + // We do this intentionally only if no download is in progress .. + if( obsoleteUpdateInfo ) + { + // Bring-up release note for position 5 .. + const OUString aURL(getReleaseNote(m_aUpdateInfo, 5)); + if( !aURL.isEmpty() ) + showReleaseNote(aURL); + + // Data is outdated, probably due to installed update + rtl::Reference< UpdateCheckConfig > aConfig = UpdateCheckConfig::get( xContext, *this ); + aConfig->clearUpdateFound(); + aConfig->clearLocalFileName(); + + + m_aUpdateInfo = UpdateInfo(); + // Remove outdated release notes + storeReleaseNote( 1, OUString() ); + storeReleaseNote( 2, OUString() ); + } + else + { + enableAutoCheck(aModel.isAutoCheckEnabled()); + if ( bDownloadAvailable ) + setUIState( UPDATESTATE_DOWNLOAD_AVAIL ); + else + { + // coverity[lock_order : FALSE] - incorrect report of lock order error with std::recursive_mutex + setUIState(getUIState(m_aUpdateInfo)); + } + } + } + } +} + + +void +UpdateCheck::cancel() +{ + std::unique_lock aGuard(m_aMutex); + + WorkerThread *pThread = m_pThread; + UpdateState eUIState = getUIState(m_aUpdateInfo); + + aGuard.unlock(); + + if( nullptr != pThread ) + pThread->cancel(); + + setUIState(eUIState); +} + + +void +UpdateCheck::download() +{ + std::unique_lock aGuard(m_aMutex); + UpdateInfo aInfo(m_aUpdateInfo); + State eState = m_eState; + aGuard.unlock(); + + if (aInfo.Sources.empty()) + { + SAL_WARN("extensions.update", "download called without source"); + return; + } + + if( aInfo.Sources[0].IsDirect ) + { + // Ignore second click of a double click + if( DOWNLOADING != eState ) + { + shutdownThread(true); + + { + std::scoped_lock aGuard2(m_aMutex); + enableDownload(true); + } + setUIState(UPDATESTATE_DOWNLOADING); + } + } + else + { + showReleaseNote(aInfo.Sources[0].URL); // Display in browser + } +} + + +void +UpdateCheck::install() +{ + std::scoped_lock aGuard(m_aMutex); + + const uno::Reference< c3s::XSystemShellExecute > xShellExecute = c3s::SystemShellExecute::create( m_xContext ); + + try { + // Construct install command ?? + + // Store release note for position 3 and 4 + OUString aURL(getReleaseNote(m_aUpdateInfo, 3)); + storeReleaseNote(1, aURL); + + aURL = getReleaseNote(m_aUpdateInfo, 4); + storeReleaseNote(2, aURL); + + OUString aInstallImage(m_aImageName); + osl::FileBase::getSystemPathFromFileURL(aInstallImage, aInstallImage); + + sal_Int32 nFlags; +#if (defined LINUX || defined __sun) + nFlags = 42; + OUString aParameter = getBaseInstallation(); + if( !aParameter.isEmpty() ) + osl::FileBase::getSystemPathFromFileURL(aParameter, aParameter); + + aParameter += " &"; +#else + nFlags = c3s::SystemShellExecuteFlags::DEFAULTS; + OUString const aParameter; +#endif + + rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get( m_xContext ); + rModel->clearLocalFileName(); + + xShellExecute->execute(aInstallImage, aParameter, nFlags); + new ShutdownThread( m_xContext ); + } catch(const uno::Exception&) { + m_aUpdateHandler->setErrorMessage( m_aUpdateHandler->getDefaultInstErrMsg() ); + } +} + + +void +UpdateCheck::pause() +{ + std::unique_lock aGuard(m_aMutex); + + if( nullptr != m_pThread ) + m_pThread->suspend(); + + rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); + aGuard.unlock(); + + rModel->storeDownloadPaused(true); + setUIState(UPDATESTATE_DOWNLOAD_PAUSED); +} + + +void +UpdateCheck::resume() +{ + std::unique_lock aGuard(m_aMutex); + + if( nullptr != m_pThread ) + m_pThread->resume(); + + rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); + aGuard.unlock(); + + rModel->storeDownloadPaused(false); + setUIState(UPDATESTATE_DOWNLOADING); +} + + +void +UpdateCheck::closeAfterFailure() +{ + std::unique_lock aGuard(m_aMutex); + + if ( ( m_eState == DISABLED ) || ( m_eState == CHECK_SCHEDULED ) ) + { + const UpdateState eUIState = getUIState( m_aUpdateInfo ); + aGuard.unlock(); + setUIState( eUIState, true ); + } +} + +void UpdateCheck::notifyUpdateCheckFinished() { + std::scoped_lock l(m_aMutex); + m_updateCheckRunning = false; + m_updateCheckFinished.notify_all(); +} + +void UpdateCheck::waitForUpdateCheckFinished() { + UpdateCheckThread * thread; + { + std::scoped_lock l(m_aMutex); + thread = dynamic_cast(m_pThread); + } + if (thread != nullptr) { + thread->cancelAsSoonAsPossible(); + } + for (;;) { + std::unique_lock lock(m_aMutex); + if (!m_updateCheckRunning) { + return; + } + m_updateCheckFinished.wait(lock); + } +} + +void +UpdateCheck::shutdownThread(bool join) +{ + std::unique_lock aGuard(m_aMutex); + + // copy thread object pointer to stack + osl::Thread *pThread = m_pThread; + m_pThread = nullptr; + aGuard.unlock(); + + if( nullptr != pThread ) + { + pThread->terminate(); + if( join ) + { + m_aCondition.set(); + pThread->join(); + m_aCondition.reset(); + } + } +} + + +void +UpdateCheck::enableAutoCheck(bool enable) +{ + if( enable ) + { + m_updateCheckRunning = true; + m_pThread = new UpdateCheckThread(m_aCondition, m_xContext, this); + } + + m_eState = enable ? CHECK_SCHEDULED : DISABLED; +} + + +void +UpdateCheck::enableDownload(bool enable, bool paused) +{ + OSL_ASSERT(nullptr == m_pThread); + + if( enable ) + { + m_pThread = new DownloadThread(m_aCondition, m_xContext, this, m_aUpdateInfo.Sources[0].URL ); + State eState = DISABLED; + if( !paused ) + { + eState = DOWNLOADING; + m_pThread->resume(); + } + else + eState = DOWNLOAD_PAUSED; + + m_eState = eState; + } + else { + enableAutoCheck(UpdateCheckConfig::get(m_xContext)->isAutoCheckEnabled()); + } + +} + + +bool +UpdateCheck::downloadTargetExists(const OUString& rFileName) +{ + std::unique_lock aGuard(m_aMutex); + + rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); + UpdateState eUIState = UPDATESTATE_DOWNLOADING; + + bool cont = false; + + if( aUpdateHandler->isVisible() ) + { + cont = aUpdateHandler->showOverwriteWarning(); + if( cont ) + { + if( osl_File_E_None != osl_removeFile(rFileName.pData) ) + { + // FIXME: error message + cont = false; + } + } + else + eUIState = getUIState(m_aUpdateInfo); + } + else + { + m_aImageName = getImageFromFileName(rFileName); + eUIState = UPDATESTATE_DOWNLOAD_AVAIL; + } + + if( !cont ) + { + shutdownThread(false); + enableDownload(false); + + aGuard.unlock(); + setUIState(eUIState); + } + + return cont; +} + + +bool UpdateCheck::checkDownloadDestination( const OUString& rFileName ) +{ + std::scoped_lock aGuard(m_aMutex); + + rtl::Reference< UpdateHandler > aUpdateHandler( getUpdateHandler() ); + + bool bReload = false; + + if( aUpdateHandler->isVisible() ) + { + bReload = aUpdateHandler->showOverwriteWarning( rFileName ); + } + + return bReload; +} + + +void +UpdateCheck::downloadStalled(const OUString& rErrorMessage) +{ + std::unique_lock aGuard(m_aMutex); + rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); + aGuard.unlock(); + + aUpdateHandler->setErrorMessage(rErrorMessage); + setUIState(UPDATESTATE_ERROR_DOWNLOADING); +} + + +void +UpdateCheck::downloadProgressAt(sal_Int8 nPercent) +{ + std::unique_lock aGuard(m_aMutex); + rtl::Reference< UpdateHandler > aUpdateHandler(getUpdateHandler()); + aGuard.unlock(); + + aUpdateHandler->setProgress(nPercent); + setUIState(UPDATESTATE_DOWNLOADING); +} + + +void +UpdateCheck::downloadStarted(const OUString& rLocalFileName, sal_Int64 nFileSize) +{ + if ( nFileSize > 0 ) + { + std::scoped_lock aGuard(m_aMutex); + + rtl::Reference< UpdateCheckConfig > aModel(UpdateCheckConfig::get(m_xContext)); + aModel->storeLocalFileName(rLocalFileName, nFileSize); + + // Bring-up release note for position 1 .. + const OUString aURL(getReleaseNote(m_aUpdateInfo, 1, aModel->isAutoDownloadEnabled())); + if( !aURL.isEmpty() ) + showReleaseNote(aURL); + } +} + + +void +UpdateCheck::downloadFinished(const OUString& rLocalFileName) +{ + std::unique_lock aGuard(m_aMutex); + + // no more retries + m_pThread->terminate(); + + m_aImageName = getImageFromFileName(rLocalFileName); + UpdateInfo aUpdateInfo(m_aUpdateInfo); + + aGuard.unlock(); + setUIState(UPDATESTATE_DOWNLOAD_AVAIL); + + // Bring-up release note for position 2 .. + rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get( m_xContext ); + const OUString aURL(getReleaseNote(aUpdateInfo, 2, rModel->isAutoDownloadEnabled())); + if( !aURL.isEmpty() ) + showReleaseNote(aURL); +} + + +void +UpdateCheck::cancelDownload() +{ + shutdownThread(true); + + std::scoped_lock aGuard(m_aMutex); + enableDownload(false); + + rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext); + + OUString aLocalFile(rModel->getLocalFileName()); + rModel->clearLocalFileName(); + rModel->storeDownloadPaused(false); + + if( isObsoleteUpdateInfo(rModel->getUpdateEntryVersion()) ) + { + rModel->clearUpdateFound(); // This wasn't done during init yet .. + m_aUpdateInfo = UpdateInfo(); + } + + /*oslFileError rc =*/ osl_removeFile(aLocalFile.pData); + // FIXME: error handling .. + +} + + +void +UpdateCheck::showDialog(bool forceCheck) +{ + std::unique_lock aGuard(m_aMutex); + + bool update_found = !m_aUpdateInfo.BuildId.isEmpty(); + bool bSetUIState = ! m_aUpdateHandler.is(); + + UpdateState eDialogState = UPDATESTATES_COUNT; + + switch( m_eState ) + { + case DISABLED: + case CHECK_SCHEDULED: + if( forceCheck || ! update_found ) // Run check when forced or if we did not find an update yet + { + eDialogState = UPDATESTATE_CHECKING; + bSetUIState = true; + } + else if(m_aUpdateInfo.Sources[0].IsDirect) + eDialogState = UPDATESTATE_UPDATE_AVAIL; + else + eDialogState = UPDATESTATE_UPDATE_NO_DOWNLOAD; + break; + + case DOWNLOADING: + eDialogState = UPDATESTATE_DOWNLOADING; + break; + + case DOWNLOAD_PAUSED: + eDialogState = UPDATESTATE_DOWNLOAD_PAUSED; + break; + + case NOT_INITIALIZED: + OSL_ASSERT( false ); + break; + } + + if( bSetUIState ) + { + aGuard.unlock(); + setUIState(eDialogState, true); // suppress bubble as Dialog will be visible soon + aGuard.lock(); + } + + getUpdateHandler()->setVisible(); + + // Run check in separate thread .. + if( UPDATESTATE_CHECKING == eDialogState ) + { + if( DISABLED == m_eState ) + { + // destructs itself when done, not cancellable for now .. + new ManualUpdateCheckThread(m_aCondition, m_xContext); + } + + m_aCondition.set(); + } +} + + +void +UpdateCheck::setUpdateInfo(const UpdateInfo& aInfo) +{ + std::unique_lock aGuard(m_aMutex); + + bool bSuppressBubble = aInfo.BuildId == m_aUpdateInfo.BuildId; + m_aUpdateInfo = aInfo; + + OSL_ASSERT(DISABLED == m_eState || CHECK_SCHEDULED == m_eState); + + // Ignore leading non direct download if we get direct ones + std::vector< DownloadSource >::iterator iter = std::find_if(m_aUpdateInfo.Sources.begin(), m_aUpdateInfo.Sources.end(), + [](const DownloadSource& rSource) { return rSource.IsDirect; }); + + if( (iter != m_aUpdateInfo.Sources.begin()) && + (iter != m_aUpdateInfo.Sources.end()) && + iter->IsDirect ) + { + m_aUpdateInfo.Sources.erase(m_aUpdateInfo.Sources.begin(), --iter); + } + + rtl::Reference< UpdateCheckConfig > rModel = UpdateCheckConfig::get(m_xContext, *this); + OSL_ASSERT( rModel.is() ); + + // Decide whether to use alternate release note pos .. + bool autoDownloadEnabled = rModel->isAutoDownloadEnabled(); + + for (auto & elem : m_aUpdateInfo.ReleaseNotes) + { + if( ((1 == elem.Pos) || (2 == elem.Pos)) && autoDownloadEnabled && !elem.URL2.isEmpty()) + { + elem.URL = elem.URL2; + elem.URL2.clear(); + elem.Pos = elem.Pos2; + elem.Pos2 = 0; + } + } + + // do not move below store/clear .. + rModel->updateLastChecked(); + + UpdateState eUIState; + if( !m_aUpdateInfo.Sources.empty() ) + { + rModel->storeUpdateFound(aInfo, getBuildId()); + + if( m_aUpdateInfo.Sources[0].IsDirect ) + { + eUIState = UPDATESTATE_UPDATE_AVAIL; + + if( rModel->isAutoDownloadEnabled() ) + { + shutdownThread(false); + eUIState = UPDATESTATE_DOWNLOADING; + enableDownload(true); + } + } + else + eUIState = UPDATESTATE_UPDATE_NO_DOWNLOAD; + } + else + { + eUIState = UPDATESTATE_NO_UPDATE_AVAIL; + rModel->clearUpdateFound(); + } + + aGuard.unlock(); + setUIState(eUIState, bSuppressBubble); +} + + +void +UpdateCheck::setCheckFailedState() +{ + setUIState(UPDATESTATE_ERROR_CHECKING); +} + + +void UpdateCheck::handleMenuBarUI( const rtl::Reference< UpdateHandler >& rUpdateHandler, + UpdateState& eState, + bool suppressBubble ) +{ + uno::Reference xMenuBarUI( m_xMenuBarUI ); + + if ( ( UPDATESTATE_NO_UPDATE_AVAIL == eState ) && m_bHasExtensionUpdate ) + eState = UPDATESTATE_EXT_UPD_AVAIL; + + if ( UPDATESTATE_EXT_UPD_AVAIL == eState ) + m_bShowExtUpdDlg = true; + else + m_bShowExtUpdDlg = false; + + if( xMenuBarUI.is() ) + { + if( UPDATESTATE_NO_UPDATE_AVAIL == eState ) + { + xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::Any(false) ); + } + else + { + xMenuBarUI->setPropertyValue( PROPERTY_TITLE, uno::Any(rUpdateHandler->getBubbleTitle(eState)) ); + xMenuBarUI->setPropertyValue( PROPERTY_TEXT, uno::Any(rUpdateHandler->getBubbleText(eState)) ); + + if( ! suppressBubble && ( ! rUpdateHandler->isVisible() || rUpdateHandler->isMinimized() ) ) + xMenuBarUI->setPropertyValue( PROPERTY_SHOW_BUBBLE, uno::Any( true ) ); + + if( UPDATESTATE_CHECKING != eState ) + xMenuBarUI->setPropertyValue( PROPERTY_SHOW_MENUICON, uno::Any(true) ); + } + } +} + + +void UpdateCheck::setUIState(UpdateState eState, bool suppressBubble) +{ + std::unique_lock aGuard(m_aMutex); + + if( ! m_xMenuBarUI.is() && + (DISABLED != m_eState) && + ( m_bHasExtensionUpdate || (UPDATESTATE_NO_UPDATE_AVAIL != eState)) && + (UPDATESTATE_CHECKING != eState) && + (UPDATESTATE_ERROR_CHECKING != eState) + ) + { + m_xMenuBarUI = createMenuBarUI(m_xContext, new MenuBarButtonJob(this)); + } + + // Show bubble only when the status has changed + if ( eState == m_eUpdateState ) + suppressBubble = true; + else + m_eUpdateState = eState; + + rtl::Reference aUpdateHandler(getUpdateHandler()); + OSL_ASSERT( aUpdateHandler.is() ); + + UpdateInfo aUpdateInfo(m_aUpdateInfo); + OUString aImageName(m_aImageName); + + aGuard.unlock(); + + handleMenuBarUI( aUpdateHandler, eState, suppressBubble ); + + if( (UPDATESTATE_UPDATE_AVAIL == eState) + || (UPDATESTATE_DOWNLOAD_PAUSED == eState) + || (UPDATESTATE_DOWNLOADING == eState) ) + { + uno::Reference< uno::XComponentContext > xContext(m_xContext); + + OUString aDownloadDestination = + UpdateCheckConfig::get(xContext, this)->getDownloadDestination(); + + osl_getSystemPathFromFileURL(aDownloadDestination.pData, &aDownloadDestination.pData); + + aUpdateHandler->setDownloadPath(aDownloadDestination); + } + else if( UPDATESTATE_DOWNLOAD_AVAIL == eState ) + { + aUpdateHandler->setDownloadFile(aImageName); + } + + aUpdateHandler->setDescription(aUpdateInfo.Description); + aUpdateHandler->setNextVersion(aUpdateInfo.Version); + aUpdateHandler->setState(eState); +} + + +UpdateState +UpdateCheck::getUIState(const UpdateInfo& rInfo) +{ + UpdateState eUIState = UPDATESTATE_NO_UPDATE_AVAIL; + + if( !rInfo.BuildId.isEmpty() ) + { + if( rInfo.Sources[0].IsDirect ) + eUIState = UPDATESTATE_UPDATE_AVAIL; + else + eUIState = UPDATESTATE_UPDATE_NO_DOWNLOAD; + } + + return eUIState; +} + + +void +UpdateCheck::showReleaseNote(const OUString& rURL) const +{ + const uno::Reference< c3s::XSystemShellExecute > xShellExecute( + c3s::SystemShellExecute::create( m_xContext ) ); + + try { + xShellExecute->execute(rURL, OUString(), c3s::SystemShellExecuteFlags::URIS_ONLY); + } catch(const c3s::SystemShellExecuteException&) { + } +} + + +bool +UpdateCheck::storeReleaseNote(sal_Int8 nNum, const OUString &rURL) +{ + osl::FileBase::RC rc; + OUString aTargetDir( UpdateCheckConfig::getAllUsersDirectory() + "/sun" ); + + osl::Directory::createPath( aTargetDir ); + + OUString aFileName = "releasenote" + + OUString::number( nNum ) + + ".url"; + + OUString aFilePath; + rc = osl::FileBase::getAbsoluteFileURL( aTargetDir, aFileName, aFilePath ); + if ( rc != osl::FileBase::E_None ) return false; + + osl::File::remove( aFilePath ); + + // don't store empty release notes, but delete old ones + if ( rURL.isEmpty() ) + return true; + + osl::File aFile( aFilePath ); + rc = aFile.open( osl_File_OpenFlag_Write | osl_File_OpenFlag_Create ); + if ( rc != osl::FileBase::E_None ) return false; + + OString aLineBuf("[InternetShortcut]\r\n"); + sal_uInt64 nWritten = 0; + + OUString aURL( rURL ); +#ifdef _WIN32 + rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten ); + if ( rc != osl::FileBase::E_None ) return false; + aURL = "URL=" + rURL; +#endif + aLineBuf = OUStringToOString( aURL, RTL_TEXTENCODING_UTF8 ); + rc = aFile.write( aLineBuf.getStr(), aLineBuf.getLength(), nWritten ); + if ( rc != osl::FileBase::E_None ) return false; + + aFile.close(); + return true; +} + + +void UpdateCheck::showExtensionDialog() +{ + uno::Reference< uno::XInterface > xService; + + if( ! m_xContext.is() ) + throw uno::RuntimeException( + "UpdateCheck::showExtensionDialog(): empty component context", uno::Reference< uno::XInterface > () ); + + uno::Reference< lang::XMultiComponentFactory > xServiceManager( m_xContext->getServiceManager() ); + if( !xServiceManager.is() ) + throw uno::RuntimeException( + "UpdateCheck::showExtensionDialog(): unable to obtain service manager from component context", uno::Reference< uno::XInterface > () ); + + xService = xServiceManager->createInstanceWithContext( "com.sun.star.deployment.ui.PackageManagerDialog", m_xContext ); + uno::Reference< task::XJobExecutor > xExecutable( xService, uno::UNO_QUERY ); + if ( xExecutable.is() ) + xExecutable->trigger( "SHOW_UPDATE_DIALOG" ); +} + + +rtl::Reference +UpdateCheck::getUpdateHandler() +{ + std::scoped_lock aGuard(m_aMutex); + + if( ! m_aUpdateHandler.is() ) + m_aUpdateHandler = new UpdateHandler(m_xContext, this); + + return m_aUpdateHandler; +} + + +uno::Reference< task::XInteractionHandler > +UpdateCheck::getInteractionHandler() const +{ + std::scoped_lock aGuard(m_aMutex); + + uno::Reference< task::XInteractionHandler > xHandler; + + if( m_aUpdateHandler.is() && m_aUpdateHandler->isVisible() ) + xHandler = m_aUpdateHandler.get(); + + return xHandler; +} + + +bool +UpdateCheck::isDialogShowing() const +{ + std::scoped_lock aGuard(m_aMutex); + return m_aUpdateHandler.is() && m_aUpdateHandler->isVisible(); +}; + + +void +UpdateCheck::autoCheckStatusChanged(bool enabled) +{ + std::unique_lock aGuard(m_aMutex); + + if( (CHECK_SCHEDULED == m_eState) && !enabled ) + shutdownThread(false); + + if( (DISABLED == m_eState) || (CHECK_SCHEDULED == m_eState) ) + { + enableAutoCheck(enabled); + UpdateState eState = getUIState(m_aUpdateInfo); + aGuard.unlock(); + setUIState(eState); + } +}; + + +void +UpdateCheck::autoCheckIntervalChanged() +{ + // just wake-up + m_aCondition.set(); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updatecheck.hxx b/extensions/source/update/check/updatecheck.hxx new file mode 100644 index 000000000..546616f57 --- /dev/null +++ b/extensions/source/update/check/updatecheck.hxx @@ -0,0 +1,189 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "updateinfo.hxx" +#include "updatecheckconfiglistener.hxx" +#include "actionlistener.hxx" +#include "updatehdl.hxx" +#include "download.hxx" + + +class UpdateCheck; + +class UpdateCheckInitData { + +public: + inline rtl::Reference< UpdateCheck > operator() () const; +}; + +class WorkerThread : public osl::Thread +{ +public: + virtual void cancel() = 0; +}; + +class UpdateCheck : + public UpdateCheckConfigListener, + public IActionListener, + public DownloadInteractionHandler, + public rtl::StaticWithInit< rtl::Reference< UpdateCheck >, UpdateCheckInitData > +{ + UpdateCheck(); + + virtual ~UpdateCheck() override; + +public: + operator rtl::Reference< UpdateCheckConfigListener > () + { return static_cast< UpdateCheckConfigListener * > (this); } + + void initialize(const css::uno::Sequence& rValues, + const css::uno::Reference& xContext); + + // Update internal update info member + void setUpdateInfo(const UpdateInfo& aInfo); + + /* This method turns on the menubar icon, triggers the bubble window or + * updates the dialog text when appropriate + */ + void setUIState(UpdateState eState, bool suppressBubble = false); + + // Returns the UI state that matches rInfo best + static UpdateState getUIState(const UpdateInfo& rInfo); + + // Check for updates failed + void setCheckFailedState(); + + // Executes the update check dialog for manual checks and downloads interaction + void showDialog(bool forceCheck = false); + + // Returns true if the update dialog is currently showing + bool isDialogShowing() const; + bool shouldShowExtUpdDlg() const { return ( m_bShowExtUpdDlg && m_bHasExtensionUpdate ); } + void showExtensionDialog(); + void setHasExtensionUpdates( bool bHasUpdates ) { m_bHasExtensionUpdate = bHasUpdates; } + bool hasOfficeUpdate() const { return (m_aUpdateInfo.BuildId.getLength() > 0); } + + // DownloadInteractionHandler + virtual bool downloadTargetExists(const OUString& rFileName) override; + virtual void downloadStalled(const OUString& rErrorMessage) override; + virtual void downloadProgressAt(sal_Int8 nProcent) override; + virtual void downloadStarted(const OUString& rLocalFileName, sal_Int64 nFileSize) override; + virtual void downloadFinished(const OUString& rLocalFileName) override; + // checks if the download target already exists and asks user what to do next + virtual bool checkDownloadDestination( const OUString& rFile ) override; + + // Cancels the download action (and resumes checking if enabled) + void cancelDownload(); + + // Returns the XInteractionHandler of the UpdateHandler instance if present (and visible) + css::uno::Reference< css::task::XInteractionHandler > getInteractionHandler() const; + + // UpdateCheckConfigListener + virtual void autoCheckStatusChanged(bool enabled) override; + virtual void autoCheckIntervalChanged() override; + + // IActionListener + void cancel() override; + void download() override; + void install() override; + void pause() override; + void resume() override; + void closeAfterFailure() override; + + void notifyUpdateCheckFinished(); + + void waitForUpdateCheckFinished(); + +private: + + // Schedules or cancels next automatic check for updates + void enableAutoCheck(bool enable); + + // Starts/resumes or stops a download + void enableDownload(bool enable, bool paused=false); + + // Shuts down the currently running thread + void shutdownThread(bool join); + + // Returns the update handler instance + rtl::Reference getUpdateHandler(); + + // Open the given URL in a browser + void showReleaseNote(const OUString& rURL) const; + + // stores the release note url on disk to be used by setup app + static bool storeReleaseNote(sal_Int8 nNum, const OUString &rURL); + + /* This method turns on the menubar icon and triggers the bubble window + */ + void handleMenuBarUI( const rtl::Reference< UpdateHandler >& rUpdateHandler, + UpdateState& eState, bool suppressBubble ); + enum State { + NOT_INITIALIZED, + DISABLED, + CHECK_SCHEDULED, + DOWNLOADING, + DOWNLOAD_PAUSED + }; + + State m_eState; + UpdateState m_eUpdateState; + + mutable std::recursive_mutex m_aMutex; + WorkerThread *m_pThread; + osl::Condition m_aCondition; + + UpdateInfo m_aUpdateInfo; + OUString m_aImageName; + bool m_bHasExtensionUpdate; + bool m_bShowExtUpdDlg; + + rtl::Reference m_aUpdateHandler; + css::uno::Reference m_xMenuBarUI; + css::uno::Reference m_xContext; + + bool m_updateCheckRunning = false; + std::condition_variable_any m_updateCheckFinished; + + friend class UpdateCheckInitData; +}; + +inline rtl::Reference< UpdateCheck > +UpdateCheckInitData::operator() () const +{ + return rtl::Reference< UpdateCheck > (new UpdateCheck()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updatecheckconfig.cxx b/extensions/source/update/check/updatecheckconfig.cxx new file mode 100644 index 000000000..e728d91e7 --- /dev/null +++ b/extensions/source/update/check/updatecheckconfig.cxx @@ -0,0 +1,660 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "updatecheckconfig.hxx" +#include "updatecheck.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +#include +#include +#endif + +namespace container = com::sun::star::container ; +namespace beans = com::sun::star::beans ; +namespace lang = com::sun::star::lang ; +namespace util = com::sun::star::util ; +namespace uno = com::sun::star::uno ; + +#define LAST_CHECK "LastCheck" +#define UPDATE_VERSION "UpdateVersion" +#define UPDATE_BUILDID "UpdateBuildId" +#define UPDATE_DESCRIPTION "UpdateDescription" +#define DOWNLOAD_URL "DownloadURL" +#define IS_DIRECT_DOWNLOAD "IsDirectDownload" +#define OLD_VERSION "UpdateFoundFor" +#define AUTOCHECK_ENABLED "AutoCheckEnabled" +#define AUTODOWNLOAD_ENABLED "AutoDownloadEnabled" +#define CHECK_INTERVAL "CheckInterval" +#define LOCAL_FILE "LocalFile" +#define DOWNLOAD_SIZE "DownloadSize" +#define DOWNLOAD_PAUSED "DownloadPaused" +#define DOWNLOAD_DESTINATION "DownloadDestination" +#define RELEASE_NOTE "ReleaseNote" + +#define PROPERTY_VERSION "Version" + +const char * const aUpdateEntryProperties[] = { + UPDATE_VERSION, + UPDATE_BUILDID, + UPDATE_DESCRIPTION, + DOWNLOAD_URL, + IS_DIRECT_DOWNLOAD, + RELEASE_NOTE"1", + RELEASE_NOTE"2", + RELEASE_NOTE"3", + RELEASE_NOTE"4", + RELEASE_NOTE"5", + OLD_VERSION +}; + +const sal_uInt32 nUpdateEntryProperties = SAL_N_ELEMENTS(aUpdateEntryProperties); + +css::uno::Any NamedValueByNameAccess::getValue(const char * pName) +{ + const sal_Int32 nLen = m_rValues.getLength(); + for( sal_Int32 n=0; n < nLen; ++n ) + { + if( m_rValues[n].Name.equalsAscii( pName ) ) + return m_rValues[n].Value; + } + return css::uno::Any(); +} + +bool +UpdateCheckROModel::isAutoCheckEnabled() const +{ + return m_aNameAccess.getValue(AUTOCHECK_ENABLED).get(); +} + +bool +UpdateCheckROModel::isDownloadPaused() const +{ + return m_aNameAccess.getValue(DOWNLOAD_PAUSED).get(); +} + +OUString +UpdateCheckROModel::getStringValue(const char * pStr) const +{ + uno::Any aAny( m_aNameAccess.getValue(pStr) ); + OUString aRet; + + aAny >>= aRet; + + return aRet; +} + +OUString UpdateCheckROModel::getLocalFileName() const +{ + return getStringValue(LOCAL_FILE); +}; + +sal_Int64 UpdateCheckROModel::getDownloadSize() const +{ + uno::Any aAny( m_aNameAccess.getValue(DOWNLOAD_SIZE) ); + sal_Int64 nRet = -1; + + aAny >>= nRet; + return nRet; +}; + +OUString +UpdateCheckROModel::getUpdateEntryVersion() const +{ + return getStringValue(OLD_VERSION); +} + +void +UpdateCheckROModel::getUpdateEntry(UpdateInfo& rInfo) const +{ + rInfo.BuildId = getStringValue(UPDATE_BUILDID); + rInfo.Version = getStringValue(UPDATE_VERSION); + rInfo.Description = getStringValue(UPDATE_DESCRIPTION); + + bool isDirectDownload = false; + m_aNameAccess.getValue(IS_DIRECT_DOWNLOAD) >>= isDirectDownload; + + rInfo.Sources.push_back( DownloadSource( isDirectDownload, getStringValue(DOWNLOAD_URL) ) ); + + for(sal_Int32 n=1; n < 6; ++n ) + { + OUString aUStr = getStringValue( + OString(OString::Concat(RELEASE_NOTE) + OString::number(n)).getStr()); + if( !aUStr.isEmpty() ) + rInfo.ReleaseNotes.push_back(ReleaseNote(static_cast(n), aUStr)); + } +} + +OUString UpdateCheckConfig::getDownloadsDirectory() +{ + OUString aRet; + +#ifdef _WIN32 + PWSTR szPath; + + if (SHGetKnownFolderPath(FOLDERID_Downloads, 0, nullptr, &szPath) == S_OK) + { + aRet = o3tl::toU(szPath); + CoTaskMemFree(szPath); + osl::FileBase::getFileURLFromSystemPath( aRet, aRet ); + } +#else + // This should become a desktop specific setting in some system backend .. + OUString aHomeDir; + osl::Security().getHomeDir( aHomeDir ); + aRet = aHomeDir + "/Desktop"; + + // Set path to home directory when there is no /Desktop directory + osl::Directory aDocumentsDir( aRet ); + if( osl::FileBase::E_None != aDocumentsDir.open() ) + aRet = aHomeDir; +#endif + + return aRet; +} + +OUString UpdateCheckConfig::getAllUsersDirectory() +{ + OUString aRet; + +#ifdef _WIN32 + WCHAR szPath[MAX_PATH]; + + if (TRUE == SHGetSpecialFolderPathW(nullptr, szPath, CSIDL_COMMON_DOCUMENTS, true)) + { + aRet = o3tl::toU(szPath); + osl::FileBase::getFileURLFromSystemPath( aRet, aRet ); + } +#else + osl::FileBase::getTempDirURL(aRet); +#endif + + return aRet; +} + +UpdateCheckConfig::UpdateCheckConfig( const uno::Reference& xContainer, + const uno::Reference& xAvailableUpdates, + const uno::Reference& xIgnoredUpdates, + const ::rtl::Reference< UpdateCheckConfigListener >& rListener ) : + m_xContainer( xContainer ), + m_xAvailableUpdates( xAvailableUpdates ), + m_xIgnoredUpdates( xIgnoredUpdates ), + m_rListener( rListener ) +{} + +UpdateCheckConfig::~UpdateCheckConfig() +{} + +::rtl::Reference< UpdateCheckConfig > +UpdateCheckConfig::get( + const uno::Reference& xContext, + const ::rtl::Reference< UpdateCheckConfigListener >& rListener) +{ + uno::Reference< lang::XMultiServiceFactory > xConfigProvider( + css::configuration::theDefaultProvider::get( xContext ) ); + + beans::PropertyValue aProperty; + aProperty.Name = "nodepath"; + aProperty.Value <<= OUString("org.openoffice.Office.Jobs/Jobs/UpdateCheck/Arguments"); + + uno::Sequence< uno::Any > aArgumentList{ uno::Any(aProperty) }; + + uno::Reference< container::XNameContainer > xContainer( + xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationUpdateAccess", aArgumentList ), + uno::UNO_QUERY_THROW ); + + aProperty.Value <<= OUString("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/IgnoredUpdates"); + aArgumentList = { uno::Any(aProperty) }; + uno::Reference< container::XNameContainer > xIgnoredExt( xConfigProvider->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationUpdateAccess", aArgumentList ), uno::UNO_QUERY_THROW ); + + aProperty.Value <<= OUString("/org.openoffice.Office.ExtensionManager/ExtensionUpdateData/AvailableUpdates"); + aArgumentList = { uno::Any(aProperty) }; + uno::Reference< container::XNameContainer > xUpdateAvail( xConfigProvider->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationUpdateAccess", aArgumentList ), uno::UNO_QUERY_THROW ); + + return new UpdateCheckConfig( xContainer, xUpdateAvail, xIgnoredExt, rListener ); +} + +bool +UpdateCheckConfig::isAutoCheckEnabled() const +{ + bool nValue = false; + const_cast < UpdateCheckConfig *> (this)->getByName( AUTOCHECK_ENABLED ) >>= nValue; + return nValue; +} + +bool +UpdateCheckConfig::isAutoDownloadEnabled() const +{ + bool nValue = false; + const_cast < UpdateCheckConfig *> (this)->getByName( AUTODOWNLOAD_ENABLED ) >>= nValue; + return nValue; +} + +OUString +UpdateCheckConfig::getUpdateEntryVersion() const +{ + OUString aValue; + + // getByName is defined as non const in XNameAccess + const_cast < UpdateCheckConfig *> (this)->getByName( OLD_VERSION ) >>= aValue; + + return aValue; +} + +sal_Int64 +UpdateCheckConfig::getLastChecked() const +{ + sal_Int64 nValue = 0; + + // getByName is defined as non const in XNameAccess + const_cast < UpdateCheckConfig *> (this)->getByName( LAST_CHECK ) >>= nValue; + + return nValue; +} + +sal_Int64 +UpdateCheckConfig::getCheckInterval() const +{ + sal_Int64 nValue = 0; + + // getByName is defined as non const in XNameAccess + const_cast < UpdateCheckConfig *> (this)->getByName( CHECK_INTERVAL ) >>= nValue; + + return nValue; +} + +OUString +UpdateCheckConfig::getLocalFileName() const +{ + OUString aName = LOCAL_FILE; + OUString aRet; + + if( m_xContainer->hasByName(aName) ) + m_xContainer->getByName(aName) >>= aRet; + + return aRet; +} + +OUString +UpdateCheckConfig::getDownloadDestination() const +{ + OUString aRet; + + const_cast (this)->getByName(DOWNLOAD_DESTINATION) >>= aRet; + + return aRet; +} + +void +UpdateCheckConfig::storeLocalFileName(const OUString& rLocalFileName, sal_Int64 nFileSize) +{ + const sal_uInt8 nItems = 2; + const OUString aNameList[nItems] = { OUString(LOCAL_FILE), OUString(DOWNLOAD_SIZE) }; + const uno::Any aValueList[nItems] = { uno::Any(rLocalFileName), uno::Any(nFileSize) }; + + for( sal_uInt8 i=0; i < nItems; ++i ) + { + if( m_xContainer->hasByName(aNameList[i]) ) + m_xContainer->replaceByName(aNameList[i], aValueList[i]); + else + m_xContainer->insertByName(aNameList[i], aValueList[i]); + } + + commitChanges(); +} + +void +UpdateCheckConfig::clearLocalFileName() +{ + const sal_uInt8 nItems = 2; + const OUString aNameList[nItems] = { OUString(LOCAL_FILE), OUString(DOWNLOAD_SIZE) }; + + for(const auto & i : aNameList) + { + if( m_xContainer->hasByName(i) ) + m_xContainer->removeByName(i); + } + + commitChanges(); +} + +void +UpdateCheckConfig::storeDownloadPaused(bool paused) +{ + replaceByName(DOWNLOAD_PAUSED , uno::Any(paused)); + commitChanges(); +} + +void +UpdateCheckConfig::updateLastChecked() +{ + TimeValue systime; + osl_getSystemTime(&systime); + + sal_Int64 lastCheck = systime.Seconds; + + replaceByName(LAST_CHECK, uno::Any(lastCheck)); +} + +void +UpdateCheckConfig::storeUpdateFound( const UpdateInfo& rInfo, const OUString& aCurrentBuild) + +{ + bool autoDownloadEnabled = isAutoDownloadEnabled(); + + uno::Any aValues[nUpdateEntryProperties] = + { + uno::Any(rInfo.Version), + uno::Any(rInfo.BuildId), + uno::Any(rInfo.Description), + uno::Any(rInfo.Sources[0].URL), + uno::Any(rInfo.Sources[0].IsDirect), + uno::Any(getReleaseNote(rInfo, 1, autoDownloadEnabled) ), + uno::Any(getReleaseNote(rInfo, 2, autoDownloadEnabled) ), + uno::Any(getReleaseNote(rInfo, 3, autoDownloadEnabled) ), + uno::Any(getReleaseNote(rInfo, 4, autoDownloadEnabled) ), + uno::Any(getReleaseNote(rInfo, 5, autoDownloadEnabled) ), + uno::Any(aCurrentBuild) + }; + + OUString aName; + for( sal_uInt32 n=0; n < nUpdateEntryProperties; ++n ) + { + aName = OUString::createFromAscii(aUpdateEntryProperties[n]); + + if( m_xContainer->hasByName(aName) ) + m_xContainer->replaceByName(aName, aValues[n]); + else + m_xContainer->insertByName(aName,aValues[n]); + } + + commitChanges(); +} + +void +UpdateCheckConfig::clearUpdateFound() +{ + OUString aName; + + for(const char* aUpdateEntryProperty : aUpdateEntryProperties) + { + aName = OUString::createFromAscii(aUpdateEntryProperty); + + try { + if( m_xContainer->hasByName(aName) ) + m_xContainer->removeByName(aName); + } catch(const lang::WrappedTargetException& ) { + // Can not remove value, probably in share layer + OSL_ASSERT(false); + m_xContainer->replaceByName(aName, uno::Any(OUString())); + } + } + + /* As we have removed UpdateVersionFound from the shared configuration + * existing entries in the user layer do not have a oor operation and + * thus are completely ignored (which also means they can not be removed). + */ + + commitChanges(); +} + +uno::Type SAL_CALL +UpdateCheckConfig::getElementType() +{ + return m_xContainer->getElementType(); +} + +sal_Bool SAL_CALL +UpdateCheckConfig::hasElements() +{ + return m_xContainer->hasElements(); +} + +uno::Any SAL_CALL +UpdateCheckConfig::getByName( const OUString& aName ) +{ + uno::Any aValue = m_xContainer->getByName( aName ); + + // Provide dynamic default value + if( aName == DOWNLOAD_DESTINATION ) + { + OUString aStr; + aValue >>= aStr; + + if( aStr.isEmpty() ) + aValue <<= getDownloadsDirectory(); + } + return aValue; +} + +uno::Sequence< OUString > SAL_CALL +UpdateCheckConfig::getElementNames() +{ + return m_xContainer->getElementNames(); +} + +sal_Bool SAL_CALL +UpdateCheckConfig::hasByName( const OUString& aName ) +{ + return m_xContainer->hasByName( aName ); +} + +void SAL_CALL +UpdateCheckConfig::replaceByName( const OUString& aName, const uno::Any& aElement ) +{ + return m_xContainer->replaceByName( aName, aElement ); +} + +// XChangesBatch + +void SAL_CALL +UpdateCheckConfig::commitChanges() +{ + uno::Reference< util::XChangesBatch > xChangesBatch(m_xContainer, uno::UNO_QUERY); + if( xChangesBatch.is() && xChangesBatch->hasPendingChanges() ) + { + util::ChangesSet aChangesSet = xChangesBatch->getPendingChanges(); + xChangesBatch->commitChanges(); + + if( m_rListener.is() ) + { + const sal_Int32 nChanges = aChangesSet.getLength(); + OUString aString; + + for( sal_Int32 i=0; i>= aString; + if( aString.endsWith(AUTOCHECK_ENABLED "']") ) + { + bool bEnabled = false; + aChangesSet[i].Element >>= bEnabled; + m_rListener->autoCheckStatusChanged(bEnabled); + } + else if( aString.endsWith(CHECK_INTERVAL "']") ) + { + m_rListener->autoCheckIntervalChanged(); + } + } + } + } + + xChangesBatch.set( m_xAvailableUpdates, uno::UNO_QUERY ); + if( xChangesBatch.is() && xChangesBatch->hasPendingChanges() ) + { + xChangesBatch->commitChanges(); + } + xChangesBatch.set( m_xIgnoredUpdates, uno::UNO_QUERY ); + if( xChangesBatch.is() && xChangesBatch->hasPendingChanges() ) + { + xChangesBatch->commitChanges(); + } +} + +sal_Bool SAL_CALL +UpdateCheckConfig::hasPendingChanges( ) +{ + uno::Reference< util::XChangesBatch > xChangesBatch(m_xContainer, uno::UNO_QUERY); + if( xChangesBatch.is() ) + return xChangesBatch->hasPendingChanges(); + + return false; +} + +uno::Sequence< util::ElementChange > SAL_CALL +UpdateCheckConfig::getPendingChanges( ) +{ + uno::Reference< util::XChangesBatch > xChangesBatch(m_xContainer, uno::UNO_QUERY); + if( xChangesBatch.is() ) + return xChangesBatch->getPendingChanges(); + + return uno::Sequence< util::ElementChange >(); +} + +bool UpdateCheckConfig::storeExtensionVersion( const OUString& rExtensionName, + const OUString& rVersion ) +{ + bool bNotify = true; + + if ( m_xAvailableUpdates->hasByName( rExtensionName ) ) + uno::Reference< beans::XPropertySet >( m_xAvailableUpdates->getByName( rExtensionName ), uno::UNO_QUERY_THROW )->setPropertyValue( PROPERTY_VERSION, uno::Any( rVersion ) ); + else + { + uno::Reference< beans::XPropertySet > elem( uno::Reference< lang::XSingleServiceFactory >( m_xAvailableUpdates, uno::UNO_QUERY_THROW )->createInstance(), uno::UNO_QUERY_THROW ); + elem->setPropertyValue( PROPERTY_VERSION, uno::Any( rVersion ) ); + m_xAvailableUpdates->insertByName( rExtensionName, uno::Any( elem ) ); + } + + if ( m_xIgnoredUpdates->hasByName( rExtensionName ) ) + { + OUString aIgnoredVersion; + uno::Any aValue( uno::Reference< beans::XPropertySet >( m_xIgnoredUpdates->getByName( rExtensionName ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) ); + aValue >>= aIgnoredVersion; + if ( aIgnoredVersion.isEmpty() ) // no version means ignore all updates + bNotify = false; + else if ( aIgnoredVersion == rVersion ) // the user wanted to ignore this update + bNotify = false; + } + + commitChanges(); + + return bNotify; +} + +bool UpdateCheckConfig::checkExtensionVersion( const OUString& rExtensionName, + const OUString& rVersion ) +{ + if ( m_xAvailableUpdates->hasByName( rExtensionName ) ) + { + OUString aStoredVersion; + uno::Any aValue( uno::Reference< beans::XPropertySet >( m_xAvailableUpdates->getByName( rExtensionName ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) ); + aValue >>= aStoredVersion; + + if ( m_xIgnoredUpdates->hasByName( rExtensionName ) ) + { + OUString aIgnoredVersion; + uno::Any aValue2( uno::Reference< beans::XPropertySet >( m_xIgnoredUpdates->getByName( rExtensionName ), uno::UNO_QUERY_THROW )->getPropertyValue( PROPERTY_VERSION ) ); + aValue2 >>= aIgnoredVersion; + if ( aIgnoredVersion.isEmpty() ) // no version means ignore all updates + return false; + else if ( aIgnoredVersion == aStoredVersion ) // the user wanted to ignore this update + return false; + // TODO: else delete ignored entry? + } + if ( isVersionGreater( rVersion, aStoredVersion ) ) + return true; + else + { + m_xAvailableUpdates->removeByName( rExtensionName ); + commitChanges(); + } + } + + return false; +} + +OUString UpdateCheckConfig::getSubVersion( const OUString& rVersion, + sal_Int32 *nIndex ) +{ + while ( *nIndex < rVersion.getLength() && rVersion[*nIndex] == '0') + { + ++*nIndex; + } + + return rVersion.getToken( 0, '.', *nIndex ); +} + +/// checks if the second version string is greater than the first one +bool UpdateCheckConfig::isVersionGreater( const OUString& rVersion1, + const OUString& rVersion2 ) +{ + for ( sal_Int32 i1 = 0, i2 = 0; i1 >= 0 || i2 >= 0; ) + { + OUString sSub1( getSubVersion( rVersion1, &i1 ) ); + OUString sSub2( getSubVersion( rVersion2, &i2 ) ); + + if ( sSub1.getLength() < sSub2.getLength() ) { + return true; + } else if ( sSub1.getLength() > sSub2.getLength() ) { + return false; + } else if ( sSub1 < sSub2 ) { + return true; + } else if ( sSub1 > sSub2 ) { + return false; + } + } + return false; +} + +OUString SAL_CALL +UpdateCheckConfig::getImplementationName() +{ + return "vnd.sun.UpdateCheckConfig"; +} + +sal_Bool SAL_CALL +UpdateCheckConfig::supportsService(OUString const & serviceName) +{ + return cppu::supportsService(this, serviceName); +} + +uno::Sequence< OUString > SAL_CALL +UpdateCheckConfig::getSupportedServiceNames() +{ + return { "com.sun.star.setup.UpdateCheckConfig" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_update_UpdateCheckConfig_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + return cppu::acquire(UpdateCheckConfig::get(context, *UpdateCheck::get()).get()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updatecheckconfig.hxx b/extensions/source/update/check/updatecheckconfig.hxx new file mode 100644 index 000000000..a9836c624 --- /dev/null +++ b/extensions/source/update/check/updatecheckconfig.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 . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "updatecheckconfiglistener.hxx" +#include "updateinfo.hxx" + +/* This helper class provides by name access to a sequence of named values */ +class NamedValueByNameAccess +{ + const css::uno::Sequence< css::beans::NamedValue >& m_rValues; + +public: + explicit NamedValueByNameAccess( + const css::uno::Sequence< css::beans::NamedValue >& rValues) : + m_rValues(rValues) {} ; + + css::uno::Any getValue(const char * pName); +}; + + +/* This class encapsulates the configuration item actually used for storing the state + * the update check is actually in. + */ +class UpdateCheckROModel +{ +public: + explicit UpdateCheckROModel(NamedValueByNameAccess& aNameAccess) : m_aNameAccess(aNameAccess) {}; + + bool isAutoCheckEnabled() const; + bool isDownloadPaused() const; + OUString getLocalFileName() const; + sal_Int64 getDownloadSize() const; + + OUString getUpdateEntryVersion() const; + void getUpdateEntry(UpdateInfo& rInfo) const; + +private: + + OUString getStringValue(const char *) const; + + NamedValueByNameAccess& m_aNameAccess; +}; + + +/* This class implements the non published UNO service com.sun.star.setup.UpdateCheckConfig, + * which primary use is to be able to track changes done in the Tools -> Options page of this + * component, as this is not supported by the OOo configuration for extendable groups. + */ + +class UpdateCheckConfig : public ::cppu::WeakImplHelper< + css::container::XNameReplace, + css::util::XChangesBatch, + css::lang::XServiceInfo > +{ + UpdateCheckConfig( const css::uno::Reference< css::container::XNameContainer >& xContainer, + const css::uno::Reference< css::container::XNameContainer >& xAvailableUpdates, + const css::uno::Reference< css::container::XNameContainer >& xIgnoredUpdates, + const ::rtl::Reference< UpdateCheckConfigListener >& rListener ); + + virtual ~UpdateCheckConfig() override; + +public: + + static ::rtl::Reference< UpdateCheckConfig > get( + const css::uno::Reference< css::uno::XComponentContext >& xContext, + const ::rtl::Reference< UpdateCheckConfigListener >& rListener = ::rtl::Reference< UpdateCheckConfigListener >()); + + // Should really implement ROModel... + bool isAutoCheckEnabled() const; + bool isAutoDownloadEnabled() const; + OUString getUpdateEntryVersion() const; + + /* Updates the timestamp of last check, but does not commit the change + * as either clearUpdateFound() or setUpdateFound() are expected to get + * called next. + */ + void updateLastChecked(); + + /* Returns the date of the last successful check in seconds since 1970 */ + sal_Int64 getLastChecked() const; + + /* Returns configured check interval in seconds */ + sal_Int64 getCheckInterval() const; + + /* Reset values of previously remembered update + */ + void clearUpdateFound(); + + /* Stores the specified data of an available update + */ + void storeUpdateFound(const UpdateInfo& rInfo, const OUString& aCurrentBuild); + + // Returns the local file name of a started download + OUString getLocalFileName() const; + + // Returns the local file name of a started download + OUString getDownloadDestination() const; + + // stores the local file name of a just started download + void storeLocalFileName(const OUString& rFileName, sal_Int64 nFileSize); + + // Removes the local file name of a download + void clearLocalFileName(); + + // Stores the bool value for manually paused downloads + void storeDownloadPaused(bool paused); + + // Returns the directory for downloaded files + static OUString getDownloadsDirectory(); + + // Returns a directory accessible for all users + static OUString getAllUsersDirectory(); + + // store and retrieve information about extensions + bool storeExtensionVersion( const OUString& rExtensionName, + const OUString& rVersion ); + bool checkExtensionVersion( const OUString& rExtensionName, + const OUString& rVersion ); + + // XElementAccess + virtual css::uno::Type SAL_CALL getElementType( ) override; + virtual sal_Bool SAL_CALL hasElements( ) 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; + + // XNameReplace + virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override; + + // XChangesBatch + virtual void SAL_CALL commitChanges( ) override; + virtual sal_Bool SAL_CALL hasPendingChanges( ) override; + virtual css::uno::Sequence< css::util::ElementChange > SAL_CALL getPendingChanges( ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +private: + + static OUString getSubVersion( const OUString& rVersion, sal_Int32 *nIndex ); + static bool isVersionGreater( const OUString& rVersion1, const OUString& rVersion2 ); + + const css::uno::Reference< css::container::XNameContainer > m_xContainer; + const css::uno::Reference< css::container::XNameContainer > m_xAvailableUpdates; + const css::uno::Reference< css::container::XNameContainer > m_xIgnoredUpdates; + const ::rtl::Reference< UpdateCheckConfigListener > m_rListener; +}; + +/// @throws css::uno::RuntimeException +template +T getValue( const css::uno::Sequence< css::beans::NamedValue >& rNamedValues, const char * pszName ) +{ + for( css::beans::NamedValue const & nv : rNamedValues ) + { + // Unfortunately gcc-3.3 does not like Any.get(); + if( nv.Name.equalsAscii( pszName ) ) + { + T value = T(); + if( ! (nv.Value >>= value) ) + throw css::uno::RuntimeException( + OUString( + cppu_Any_extraction_failure_msg( + &nv.Value, + ::cppu::getTypeFavourUnsigned(&value).getTypeLibType() ), + SAL_NO_ACQUIRE ), + css::uno::Reference< css::uno::XInterface >() ); + + return value; + } + } + + return T(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updatecheckconfiglistener.hxx b/extensions/source/update/check/updatecheckconfiglistener.hxx new file mode 100644 index 000000000..903200f68 --- /dev/null +++ b/extensions/source/update/check/updatecheckconfiglistener.hxx @@ -0,0 +1,37 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +/* This interface should be implemented by classes acting + * as controller (as in the MVC pattern). + */ + +struct UpdateCheckConfigListener : public virtual salhelper::SimpleReferenceObject +{ + virtual void autoCheckStatusChanged(bool enabled) = 0; + virtual void autoCheckIntervalChanged() = 0; + +protected: + virtual ~UpdateCheckConfigListener() override {} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updatecheckjob.cxx b/extensions/source/update/check/updatecheckjob.cxx new file mode 100644 index 000000000..82d2f7439 --- /dev/null +++ b/extensions/source/update/check/updatecheckjob.cxx @@ -0,0 +1,322 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include "updatecheck.hxx" +#include "updatecheckconfig.hxx" +#include "updatehdl.hxx" +#include "updateprotocol.hxx" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace beans = com::sun::star::beans ; +namespace frame = com::sun::star::frame ; +namespace lang = com::sun::star::lang ; +namespace task = com::sun::star::task ; +namespace uno = com::sun::star::uno ; + +namespace +{ + +class InitUpdateCheckJobThread : public osl::Thread +{ +public: + InitUpdateCheckJobThread( const uno::Reference< uno::XComponentContext > &xContext, + const uno::Sequence< beans::NamedValue > &xParameters, + bool bShowDialog ); + + virtual void SAL_CALL run() override; + + void setTerminating(); + +private: + osl::Condition m_aCondition; + uno::Reference m_xContext; + uno::Sequence m_xParameters; + bool m_bShowDialog; + bool m_bTerminating; + + std::mutex m_mutex; + rtl::Reference m_controller; +}; + +class UpdateCheckJob : + public ::cppu::WeakImplHelper< task::XJob, lang::XServiceInfo, frame::XTerminateListener > +{ + virtual ~UpdateCheckJob() override; + +public: + + UpdateCheckJob( + css::uno::Reference const & context, + css::uno::Reference const & desktop): + m_xContext(context), m_xDesktop(desktop) + {} + + // XJob + virtual uno::Any SAL_CALL execute(const uno::Sequence&) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName) override; + virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XEventListener + virtual void SAL_CALL disposing( css::lang::EventObject const & evt ) override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( lang::EventObject const & evt ) override; + virtual void SAL_CALL notifyTermination( lang::EventObject const & evt ) override; + +private: + uno::Reference m_xContext; + uno::Reference< frame::XDesktop2 > m_xDesktop; + std::unique_ptr< InitUpdateCheckJobThread > m_pInitThread; + + void handleExtensionUpdates( const uno::Sequence< beans::NamedValue > &rListProp ); + void terminateAndJoinThread(); +}; + +InitUpdateCheckJobThread::InitUpdateCheckJobThread( + const uno::Reference< uno::XComponentContext > &xContext, + const uno::Sequence< beans::NamedValue > &xParameters, + bool bShowDialog ) : + m_xContext( xContext ), + m_xParameters( xParameters ), + m_bShowDialog( bShowDialog ), + m_bTerminating( false ) +{ + create(); +} + + +void SAL_CALL InitUpdateCheckJobThread::run() +{ + osl_setThreadName("InitUpdateCheckJobThread"); + + if (!m_bShowDialog) { + TimeValue tv = { 25, 0 }; + m_aCondition.wait( &tv ); + if ( m_bTerminating ) + return; + } + + try { + rtl::Reference< UpdateCheck > aController( UpdateCheck::get() ); + // At least for the automatic ("onFirstVisibleTask", i.e., !m_bShowDialog) check, wait for + // m_controller during setTerminating, to prevent m_controller from still having threads + // running during exit (ideally, we would make sure that all threads are joined before exit, + // but the UpdateCheck logic is rather convoluted, so play it safe for now and only address + // the automatic update check that is known to cause issues during `make check`, not the + // manually triggered update check scenario): + if (!m_bShowDialog) { + std::scoped_lock l(m_mutex); + m_controller = aController; + } + aController->initialize( m_xParameters, m_xContext ); + + if ( m_bShowDialog ) + aController->showDialog( true ); + } catch (const uno::Exception &) { + // fdo#64962 - don't bring the app down on some unexpected exception. + TOOLS_WARN_EXCEPTION("extensions.update", "Caught init update exception, thread terminated" ); + { + std::scoped_lock l(m_mutex); + m_controller.clear(); + } + } +} + +void InitUpdateCheckJobThread::setTerminating() { + m_bTerminating = true; + m_aCondition.set(); + rtl::Reference controller; + { + std::scoped_lock l(m_mutex); + std::swap(controller, m_controller); + } + if (controller.is()) { + controller->waitForUpdateCheckFinished(); + } +} + +UpdateCheckJob::~UpdateCheckJob() +{ +} + +uno::Any +UpdateCheckJob::execute(const uno::Sequence& namedValues) +{ + for ( sal_Int32 n=namedValues.getLength(); n-- > 0; ) + { + if ( namedValues[ n ].Name == "DynamicData" ) + { + uno::Sequence aListProp; + if ( namedValues[n].Value >>= aListProp ) + { + for ( sal_Int32 i=aListProp.getLength(); i-- > 0; ) + { + if ( aListProp[ i ].Name == "updateList" ) + { + handleExtensionUpdates( aListProp ); + return uno::Any(); + } + } + } + } + } + + uno::Sequence aConfig = + getValue< uno::Sequence > (namedValues, "JobConfig"); + + /* Determine the way we got invoked here - + * see Developers Guide Chapter "4.7.2 Jobs" to understand the magic + */ + + uno::Sequence aEnvironment = + getValue< uno::Sequence > (namedValues, "Environment"); + + OUString aEventName = getValue< OUString > (aEnvironment, "EventName"); + + m_pInitThread.reset( + new InitUpdateCheckJobThread( + m_xContext, aConfig, + aEventName != "onFirstVisibleTask")); + + return uno::Any(); +} + + +void UpdateCheckJob::handleExtensionUpdates( const uno::Sequence< beans::NamedValue > &rListProp ) +{ + try { + uno::Sequence< uno::Sequence< OUString > > aList = + getValue< uno::Sequence< uno::Sequence< OUString > > > ( rListProp, "updateList" ); + bool bPrepareOnly = getValue< bool > ( rListProp, "prepareOnly" ); + + // we will first store any new found updates and then check, if there are any + // pending updates. + storeExtensionUpdateInfos( m_xContext, aList ); + + if ( bPrepareOnly ) + return; + + bool bHasUpdates = checkForPendingUpdates( m_xContext ); + + rtl::Reference aController( UpdateCheck::get() ); + if ( ! aController.is() ) + return; + + aController->setHasExtensionUpdates( bHasUpdates ); + + if ( ! aController->hasOfficeUpdate() ) + { + if ( bHasUpdates ) + aController->setUIState( UPDATESTATE_EXT_UPD_AVAIL, true ); + else + aController->setUIState( UPDATESTATE_NO_UPDATE_AVAIL, true ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("extensions.update", "Caught exception, thread terminated"); + } +} + + +OUString SAL_CALL +UpdateCheckJob::getImplementationName() +{ + return "vnd.sun.UpdateCheck"; +} + + +uno::Sequence< OUString > SAL_CALL +UpdateCheckJob::getSupportedServiceNames() +{ + return { "com.sun.star.setup.UpdateCheck" }; +} + +sal_Bool SAL_CALL +UpdateCheckJob::supportsService( OUString const & serviceName ) +{ + return cppu::supportsService(this, serviceName); +} + + +// XEventListener +void SAL_CALL UpdateCheckJob::disposing( lang::EventObject const & rEvt ) +{ + bool shutDown = ( rEvt.Source == m_xDesktop ); + + if ( shutDown && m_xDesktop.is() ) + { + terminateAndJoinThread(); + m_xDesktop->removeTerminateListener( this ); + m_xDesktop.clear(); + } +} + + +// XTerminateListener +void SAL_CALL UpdateCheckJob::queryTermination( lang::EventObject const & ) +{ +} + +void UpdateCheckJob::terminateAndJoinThread() +{ + if (m_pInitThread != nullptr) + { + m_pInitThread->setTerminating(); + m_pInitThread->join(); + m_pInitThread.reset(); + } +} + +void SAL_CALL UpdateCheckJob::notifyTermination( lang::EventObject const & ) +{ + terminateAndJoinThread(); +} + +} // anonymous namespace + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_update_UpdateCheckJob_get_implementation( + css::uno::XComponentContext* context , css::uno::Sequence const&) +{ + css::uno::Reference desktop( + css::frame::Desktop::create(context)); + rtl::Reference job(new UpdateCheckJob(context, desktop)); + desktop->addTerminateListener(job); + return cppu::acquire(job.get()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updatehdl.cxx b/extensions/source/update/check/updatehdl.cxx new file mode 100644 index 000000000..24fb96bda --- /dev/null +++ b/extensions/source/update/check/updatehdl.cxx @@ -0,0 +1,1281 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include + +#include "updatehdl.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 + +constexpr OUStringLiteral COMMAND_CLOSE = u"close"; + +constexpr OUStringLiteral CTRL_THROBBER = u"throbber"; +constexpr OUStringLiteral CTRL_PROGRESS = u"progress"; + +constexpr OUStringLiteral TEXT_STATUS = u"text_status"; +constexpr OUStringLiteral TEXT_PERCENT = u"text_percent"; +constexpr OUStringLiteral TEXT_DESCRIPTION = u"text_description"; + +constexpr OUStringLiteral FIXED_LINE_MODEL = u"com.sun.star.awt.UnoControlFixedLineModel"; +constexpr OUStringLiteral FIXED_TEXT_MODEL = u"com.sun.star.awt.UnoControlFixedTextModel"; +constexpr OUStringLiteral EDIT_FIELD_MODEL = u"com.sun.star.awt.UnoControlEditModel"; +constexpr OUStringLiteral BUTTON_MODEL = u"com.sun.star.awt.UnoControlButtonModel"; +constexpr OUStringLiteral GROUP_BOX_MODEL = u"com.sun.star.awt.UnoControlGroupBoxModel"; + +using namespace com::sun::star; + + +UpdateHandler::UpdateHandler( const uno::Reference< uno::XComponentContext > & rxContext, + const rtl::Reference< IActionListener > & rxActionListener ) : + mxContext( rxContext ), + mxActionListener( rxActionListener ), + meCurState( UPDATESTATES_COUNT ), + meLastState( UPDATESTATES_COUNT ), + mnPercent( 0 ), + mnLastCtrlState( -1 ), + mbDownloadBtnHasDots( false ), + mbVisible( false ), + mbStringsLoaded( false ), + mbMinimized( false ), + mbListenerAdded(false), + mbShowsMessageBox(false) +{ +} + + +UpdateHandler::~UpdateHandler() +{ + mxContext = nullptr; + mxUpdDlg = nullptr; + mxInteractionHdl = nullptr; + mxActionListener = nullptr; +} + + +void UpdateHandler::enableControls( short nCtrlState ) +{ + osl::MutexGuard aGuard( maMutex ); + + if ( nCtrlState == mnLastCtrlState ) + return; + + // the help button should always be the last button in the + // enum list and must never be disabled + for ( int i=0; i(nCtrlState >> i); + short nOldStateVal = static_cast(mnLastCtrlState >> i); + if ( ( nCurStateVal & 0x01 ) != ( nOldStateVal & 0x01 ) ) + { + bool bEnableControl = ( ( nCurStateVal & 0x01 ) == 0x01 ); + setControlProperty( msButtonIDs[i], "Enabled", uno::Any( bEnableControl ) ); + } + } + + mnLastCtrlState = nCtrlState; +} + + +void UpdateHandler::setDownloadBtnLabel( bool bAppendDots ) +{ + osl::MutexGuard aGuard( maMutex ); + + if ( mbDownloadBtnHasDots != bAppendDots ) + { + OUString aLabel( msDownload ); + + if ( bAppendDots ) + aLabel += "..."; + + setControlProperty( msButtonIDs[DOWNLOAD_BUTTON], "Label", uno::Any( aLabel ) ); + setControlProperty( msButtonIDs[DOWNLOAD_BUTTON], "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_DOWNLOAD2 )) ); + + mbDownloadBtnHasDots = bAppendDots; + } +} + + +void UpdateHandler::setState( UpdateState eState ) +{ + osl::MutexGuard aGuard( maMutex ); + + meCurState = eState; + + if ( mxUpdDlg.is() && mbVisible ) + updateState( meCurState ); +} + + +bool UpdateHandler::isVisible() const +{ + if ( !mxUpdDlg.is() ) return false; + + uno::Reference< awt::XWindow2 > xWindow( mxUpdDlg, uno::UNO_QUERY ); + + if ( xWindow.is() ) + return xWindow->isVisible(); + else + return false; +} + + +void UpdateHandler::setVisible( bool bVisible ) +{ + osl::MutexGuard aGuard( maMutex ); + + mbVisible = bVisible; + + if ( bVisible ) + { + if ( !mxUpdDlg.is() ) + createDialog(); + + // this should never happen, but if it happens we better return here + if ( !mxUpdDlg.is() ) + return; + + updateState( meCurState ); + + uno::Reference< awt::XWindow > xWindow( mxUpdDlg, uno::UNO_QUERY ); + + if ( xWindow.is() ) + xWindow->setVisible( bVisible ); + + uno::Reference< awt::XTopWindow > xTopWindow( mxUpdDlg, uno::UNO_QUERY ); + if ( xTopWindow.is() ) + { + xTopWindow->toFront(); + if ( !mbListenerAdded ) + { + xTopWindow->addTopWindowListener( this ); + mbListenerAdded = true; + } + } + } + else if ( mxUpdDlg.is() ) + { + uno::Reference< awt::XWindow > xWindow( mxUpdDlg, uno::UNO_QUERY ); + + if ( xWindow.is() ) + xWindow->setVisible( bVisible ); + } +} + + +void UpdateHandler::setProgress( sal_Int32 nPercent ) +{ + if ( nPercent > 100 ) + nPercent = 100; + else if ( nPercent < 0 ) + nPercent = 0; + + if ( nPercent != mnPercent ) + { + osl::MutexGuard aGuard( maMutex ); + + mnPercent = nPercent; + setControlProperty( CTRL_PROGRESS, "ProgressValue", uno::Any( nPercent ) ); + setControlProperty( TEXT_PERCENT, "Text", uno::Any( substVariables(msPercent) ) ); + } +} + + +void UpdateHandler::setErrorMessage( const OUString& rErrorMsg ) +{ + setControlProperty( TEXT_DESCRIPTION, "Text", uno::Any( rErrorMsg ) ); +} + + +void UpdateHandler::setDownloadFile( std::u16string_view rFilePath ) +{ + std::size_t nLast = rFilePath.rfind( '/' ); + if ( nLast != std::u16string_view::npos ) + { + msDownloadFile = rFilePath.substr( nLast+1 ); + const OUString aDownloadURL(rFilePath.substr( 0, nLast )); + osl::FileBase::getSystemPathFromFileURL( aDownloadURL, msDownloadPath ); + } +} + + +OUString UpdateHandler::getBubbleText( UpdateState eState ) +{ + osl::MutexGuard aGuard( maMutex ); + + OUString sText; + sal_Int32 nIndex = static_cast(eState); + + loadStrings(); + + if ( ( UPDATESTATE_UPDATE_AVAIL <= nIndex ) && ( nIndex < UPDATESTATES_COUNT ) ) + sText = substVariables( msBubbleTexts[ nIndex - UPDATESTATE_UPDATE_AVAIL ] ); + + return sText; +} + + +OUString UpdateHandler::getBubbleTitle( UpdateState eState ) +{ + osl::MutexGuard aGuard( maMutex ); + + OUString sText; + sal_Int32 nIndex = static_cast(eState); + + loadStrings(); + + if ( ( UPDATESTATE_UPDATE_AVAIL <= nIndex ) && ( nIndex < UPDATESTATES_COUNT ) ) + sText = substVariables( msBubbleTitles[ nIndex - UPDATESTATE_UPDATE_AVAIL] ); + + return sText; +} + + +OUString UpdateHandler::getDefaultInstErrMsg() +{ + osl::MutexGuard aGuard( maMutex ); + + loadStrings(); + + return substVariables( msInstallError ); +} + +// XActionListener + +void SAL_CALL UpdateHandler::disposing( const lang::EventObject& rEvt ) +{ + if ( rEvt.Source == mxUpdDlg ) + mxUpdDlg.clear(); +} + + +void SAL_CALL UpdateHandler::actionPerformed( awt::ActionEvent const & rEvent ) +{ + DialogControls eButton = BUTTON_COUNT; + for ( int i = 0; i < BUTTON_COUNT; i++ ) + { + if ( rEvent.ActionCommand == msButtonIDs[i] ) + { + eButton = static_cast(i); + break; + } + } + + if ( rEvent.ActionCommand == COMMAND_CLOSE ) + { + if ( ( mnLastCtrlState & ( 1 << CLOSE_BUTTON ) ) == ( 1 << CLOSE_BUTTON ) ) + eButton = CLOSE_BUTTON; + else + eButton = CANCEL_BUTTON; + } + + switch ( eButton ) { + case CANCEL_BUTTON: + { + bool bCancel = true; + + if ( ( meCurState == UPDATESTATE_DOWNLOADING ) || + ( meCurState == UPDATESTATE_DOWNLOAD_PAUSED ) || + ( meCurState == UPDATESTATE_ERROR_DOWNLOADING ) ) + bCancel = showWarning( msCancelMessage ); + + if ( bCancel ) + { + mxActionListener->cancel(); + setVisible( false ); + } + break; + } + case CLOSE_BUTTON: + setVisible( false ); + if ( meCurState == UPDATESTATE_ERROR_CHECKING ) + mxActionListener->closeAfterFailure(); + break; + case DOWNLOAD_BUTTON: + mxActionListener->download(); + break; + case INSTALL_BUTTON: + if ( showWarning( msInstallMessage ) ) + mxActionListener->install(); + break; + case PAUSE_BUTTON: + mxActionListener->pause(); + break; + case RESUME_BUTTON: + mxActionListener->resume(); + break; + case HELP_BUTTON: + break; + default: + OSL_FAIL( "UpdateHandler::actionPerformed: unknown command!" ); + } +} + +// XTopWindowListener + +void SAL_CALL UpdateHandler::windowOpened( const lang::EventObject& ) +{ +} + + +void SAL_CALL UpdateHandler::windowClosing( const lang::EventObject& e ) +{ + awt::ActionEvent aActionEvt; + aActionEvt.ActionCommand = COMMAND_CLOSE; + aActionEvt.Source = e.Source; + + actionPerformed( aActionEvt ); +} + + +void SAL_CALL UpdateHandler::windowClosed( const lang::EventObject& ) +{ +} + + +void SAL_CALL UpdateHandler::windowMinimized( const lang::EventObject& ) +{ + mbMinimized = true; +} + + +void SAL_CALL UpdateHandler::windowNormalized( const lang::EventObject& ) +{ + mbMinimized = false; +} + + +void SAL_CALL UpdateHandler::windowActivated( const lang::EventObject& ) +{ +} + + +void SAL_CALL UpdateHandler::windowDeactivated( const lang::EventObject& ) +{ +} + +// XInteractionHandler + +void SAL_CALL UpdateHandler::handle( uno::Reference< task::XInteractionRequest > const & rRequest) +{ + if ( !mxInteractionHdl.is() ) + { + if( !mxContext.is() ) + throw uno::RuntimeException( "UpdateHandler:: empty component context", *this ); + + uno::Reference< lang::XMultiComponentFactory > xServiceManager(mxContext->getServiceManager()); + + if( !xServiceManager.is() ) + throw uno::RuntimeException( "UpdateHandler: unable to obtain service manager from component context", *this ); + + mxInteractionHdl.set( + task::InteractionHandler::createWithParent(mxContext, nullptr), + uno::UNO_QUERY_THROW); + } + uno::Reference< task::XInteractionRequestStringResolver > xStrResolver = + task::InteractionRequestStringResolver::create( mxContext ); + beans::Optional< OUString > aErrorText = xStrResolver->getStringFromInformationalRequest( rRequest ); + if ( aErrorText.IsPresent ) + { + setControlProperty( TEXT_DESCRIPTION, "Text", uno::Any( aErrorText.Value ) ); + + uno::Sequence< uno::Reference< task::XInteractionContinuation > > xContinuations = rRequest->getContinuations(); + if ( xContinuations.getLength() == 1 ) + { + if ( meCurState == UPDATESTATE_CHECKING ) + setState( UPDATESTATE_ERROR_CHECKING ); + else if ( meCurState == UPDATESTATE_DOWNLOADING ) + setState( UPDATESTATE_ERROR_DOWNLOADING ); + + xContinuations[0]->select(); + } + else + mxInteractionHdl->handle( rRequest ); + } + else + mxInteractionHdl->handle( rRequest ); +} + + +// XTerminateListener + +void SAL_CALL UpdateHandler::queryTermination( const lang::EventObject& ) +{ + if ( mbShowsMessageBox ) + { + uno::Reference< awt::XTopWindow > xTopWindow( mxUpdDlg, uno::UNO_QUERY ); + if ( xTopWindow.is() ) + xTopWindow->toFront(); + + throw frame::TerminationVetoException( + "The office cannot be closed while displaying a warning!", + static_cast(this)); + } + else + setVisible( false ); +} + + +void SAL_CALL UpdateHandler::notifyTermination( const lang::EventObject& ) +{ + osl::MutexGuard aGuard( maMutex ); + + if ( mxUpdDlg.is() ) + { + uno::Reference< awt::XTopWindow > xTopWindow( mxUpdDlg, uno::UNO_QUERY ); + if ( xTopWindow.is() ) + xTopWindow->removeTopWindowListener( this ); + + uno::Reference< lang::XComponent > xComponent( mxUpdDlg, uno::UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + + mxUpdDlg.clear(); + } +} + + +void UpdateHandler::updateState( UpdateState eState ) +{ + if ( meLastState == eState ) + return; + + OUString sText; + + switch ( eState ) + { + case UPDATESTATE_CHECKING: + showControls( (1< RID_UPDATE_BUBBLE[] = + { + { RID_UPDATE_BUBBLE_UPDATE_AVAIL, RID_UPDATE_BUBBLE_T_UPDATE_AVAIL }, + { RID_UPDATE_BUBBLE_UPDATE_NO_DOWN, RID_UPDATE_BUBBLE_T_UPDATE_NO_DOWN }, + { RID_UPDATE_BUBBLE_AUTO_START, RID_UPDATE_BUBBLE_T_AUTO_START }, + { RID_UPDATE_BUBBLE_DOWNLOADING, RID_UPDATE_BUBBLE_T_DOWNLOADING }, + { RID_UPDATE_BUBBLE_DOWNLOAD_PAUSED, RID_UPDATE_BUBBLE_T_DOWNLOAD_PAUSED }, + { RID_UPDATE_BUBBLE_ERROR_DOWNLOADING, RID_UPDATE_BUBBLE_T_ERROR_DOWNLOADING }, + { RID_UPDATE_BUBBLE_DOWNLOAD_AVAIL, RID_UPDATE_BUBBLE_T_DOWNLOAD_AVAIL }, + { RID_UPDATE_BUBBLE_EXT_UPD_AVAIL, RID_UPDATE_BUBBLE_T_EXT_UPD_AVAIL } + }; + + static_assert(SAL_N_ELEMENTS(RID_UPDATE_BUBBLE) == UPDATESTATES_COUNT - UPDATESTATE_UPDATE_AVAIL, "mismatch"); + + // all update states before UPDATESTATE_UPDATE_AVAIL don't have a bubble + // so we can ignore them + for (size_t i = 0; i < SAL_N_ELEMENTS(RID_UPDATE_BUBBLE); ++i) + { + msBubbleTexts[i] = loadString(loc, RID_UPDATE_BUBBLE[i].first); + msBubbleTitles[i] = loadString(loc, RID_UPDATE_BUBBLE[i].second); + } + + for ( int i=0; i < BUTTON_COUNT; i++ ) + { + msButtonIDs[ i ] = "BUTTON_" + OUString::number( i ); + } +} + + +void UpdateHandler::startThrobber( bool bStart ) +{ + uno::Reference< awt::XControlContainer > xContainer( mxUpdDlg, uno::UNO_QUERY ); + uno::Reference< awt::XAnimation > xThrobber( xContainer->getControl( CTRL_THROBBER ), uno::UNO_QUERY ); + + if ( xThrobber.is() ) + { + if ( bStart ) + xThrobber->startAnimation(); + else + xThrobber->stopAnimation(); + } + + uno::Reference< awt::XWindow > xWindow( xContainer->getControl( CTRL_THROBBER ), uno::UNO_QUERY ); + if (xWindow.is() ) + xWindow->setVisible( bStart ); +} + + +void UpdateHandler::setControlProperty( const OUString &rCtrlName, + const OUString &rPropName, + const uno::Any &rPropValue ) +{ + if ( !mxUpdDlg.is() ) return; + + uno::Reference< awt::XControlContainer > xContainer( mxUpdDlg, uno::UNO_QUERY ); + uno::Reference< awt::XControl > xControl( xContainer->getControl( rCtrlName ), uno::UNO_SET_THROW ); + uno::Reference< awt::XControlModel > xControlModel( xControl->getModel(), uno::UNO_SET_THROW ); + uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY_THROW ); + + try { + xPropSet->setPropertyValue( rPropName, rPropValue ); + } + catch( const beans::UnknownPropertyException& ) + { + TOOLS_WARN_EXCEPTION( "extensions.update", "UpdateHandler::setControlProperty" ); + } +} + + +void UpdateHandler::showControl( const OUString &rCtrlName, bool bShow ) +{ + uno::Reference< awt::XControlContainer > xContainer( mxUpdDlg, uno::UNO_QUERY ); + + if ( !xContainer.is() ) + { + OSL_FAIL( "UpdateHandler::showControl: could not get control container!" ); + return; + } + + uno::Reference< awt::XWindow > xWindow( xContainer->getControl( rCtrlName ), uno::UNO_QUERY ); + if ( xWindow.is() ) + xWindow->setVisible( bShow ); +} + + +void UpdateHandler::focusControl( DialogControls eID ) +{ + uno::Reference< awt::XControlContainer > xContainer( mxUpdDlg, uno::UNO_QUERY ); + + if ( !xContainer.is() ) + { + OSL_FAIL( "UpdateHandler::focusControl: could not get control container!" ); + return; + } + + OSL_ENSURE( (eID < BUTTON_COUNT), "UpdateHandler::focusControl: id too big!" ); + + uno::Reference< awt::XWindow > xWindow( xContainer->getControl( msButtonIDs[static_cast(eID)] ), uno::UNO_QUERY ); + if ( xWindow.is() ) + xWindow->setFocus(); +} + + +void UpdateHandler::insertControlModel( uno::Reference< awt::XControlModel > const & rxDialogModel, + OUString const & rServiceName, + OUString const & rControlName, + awt::Rectangle const & rPosSize, + uno::Sequence< beans::NamedValue > const & rProps ) +{ + uno::Reference< lang::XMultiServiceFactory > xFactory (rxDialogModel, uno::UNO_QUERY_THROW); + uno::Reference< awt::XControlModel > xModel (xFactory->createInstance (rServiceName), uno::UNO_QUERY_THROW); + uno::Reference< beans::XPropertySet > xPropSet (xModel, uno::UNO_QUERY_THROW); + + for (beans::NamedValue const & prop : rProps) + { + xPropSet->setPropertyValue (prop.Name, prop.Value); + } + + // @see awt/UnoControlDialogElement.idl + xPropSet->setPropertyValue( "Name", uno::Any (rControlName) ); + xPropSet->setPropertyValue( "PositionX", uno::Any (rPosSize.X) ); + xPropSet->setPropertyValue( "PositionY", uno::Any (rPosSize.Y) ); + xPropSet->setPropertyValue( "Height", uno::Any (rPosSize.Height) ); + xPropSet->setPropertyValue( "Width", uno::Any (rPosSize.Width) ); + + // insert by Name into DialogModel container + uno::Reference< container::XNameContainer > xContainer (rxDialogModel, uno::UNO_QUERY_THROW); + xContainer->insertByName( rControlName, uno::Any (uno::Reference< uno::XInterface >(xModel, uno::UNO_QUERY))); +} + + +void UpdateHandler::setFullVersion( OUString& rString ) +{ + uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider( + css::configuration::theDefaultProvider::get( mxContext ) ); + + beans::PropertyValue aProperty; + aProperty.Name = "nodepath"; + aProperty.Value <<= OUString("org.openoffice.Setup/Product"); + + uno::Sequence< uno::Any > aArgumentList{ uno::Any(aProperty) }; + + uno::Reference< uno::XInterface > xConfigAccess = xConfigurationProvider->createInstanceWithArguments( "com.sun.star.configuration.ConfigurationAccess", + aArgumentList ); + + uno::Reference< container::XNameAccess > xNameAccess( xConfigAccess, uno::UNO_QUERY_THROW ); + + OUString aProductVersion; + xNameAccess->getByName("ooSetupVersion") >>= aProductVersion; + OUString aProductFullVersion; + xNameAccess->getByName("ooSetupVersionAboutBox") >>= aProductFullVersion; + rString = rString.replaceFirst( aProductVersion, aProductFullVersion ); +} + + +bool UpdateHandler::showWarning( const OUString &rWarningText ) const +{ + bool bRet = false; + + uno::Reference< awt::XControl > xControl( mxUpdDlg, uno::UNO_QUERY ); + if ( !xControl.is() ) return bRet; + + uno::Reference< awt::XWindowPeer > xPeer = xControl->getPeer(); + if ( !xPeer.is() ) return bRet; + + uno::Reference< awt::XToolkit > xToolkit = xPeer->getToolkit(); + if ( !xToolkit.is() ) return bRet; + + awt::WindowDescriptor aDescriptor; + + sal_Int32 nWindowAttributes = awt::WindowAttribute::BORDER | awt::WindowAttribute::MOVEABLE | awt::WindowAttribute::CLOSEABLE; + nWindowAttributes |= awt::VclWindowPeerAttribute::YES_NO; + nWindowAttributes |= awt::VclWindowPeerAttribute::DEF_NO; + + aDescriptor.Type = awt::WindowClass_MODALTOP; + aDescriptor.WindowServiceName = "warningbox"; + aDescriptor.ParentIndex = -1; + aDescriptor.Parent = xPeer; + aDescriptor.Bounds = awt::Rectangle( 10, 10, 250, 150 ); + aDescriptor.WindowAttributes = nWindowAttributes; + + uno::Reference< awt::XMessageBox > xMsgBox( xToolkit->createWindow( aDescriptor ), uno::UNO_QUERY ); + if ( xMsgBox.is() ) + { + mbShowsMessageBox = true; + sal_Int16 nRet; + // xMsgBox->setCaptionText( msCancelTitle ); + xMsgBox->setMessageText( rWarningText ); + nRet = xMsgBox->execute(); + if ( nRet == 2 ) // RET_YES == 2 + bRet = true; + mbShowsMessageBox = false; + } + + uno::Reference< lang::XComponent > xComponent( xMsgBox, uno::UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + + return bRet; +} + + +bool UpdateHandler::showWarning( const OUString &rWarningText, + const OUString &rBtnText_1, + const OUString &rBtnText_2 ) const +{ + bool bRet = false; + + uno::Reference< awt::XControl > xControl( mxUpdDlg, uno::UNO_QUERY ); + if ( !xControl.is() ) return bRet; + + uno::Reference< awt::XWindowPeer > xPeer = xControl->getPeer(); + if ( !xPeer.is() ) return bRet; + + uno::Reference< awt::XToolkit > xToolkit = xPeer->getToolkit(); + if ( !xToolkit.is() ) return bRet; + + awt::WindowDescriptor aDescriptor; + + sal_Int32 nWindowAttributes = awt::WindowAttribute::BORDER | awt::WindowAttribute::MOVEABLE | awt::WindowAttribute::CLOSEABLE; + nWindowAttributes |= awt::VclWindowPeerAttribute::YES_NO; + nWindowAttributes |= awt::VclWindowPeerAttribute::DEF_NO; + + aDescriptor.Type = awt::WindowClass_MODALTOP; + aDescriptor.WindowServiceName = "warningbox"; + aDescriptor.ParentIndex = -1; + aDescriptor.Parent = xPeer; + aDescriptor.Bounds = awt::Rectangle( 10, 10, 250, 150 ); + aDescriptor.WindowAttributes = nWindowAttributes; + + uno::Reference< awt::XMessageBox > xMsgBox( xToolkit->createWindow( aDescriptor ), uno::UNO_QUERY ); + if ( xMsgBox.is() ) + { + uno::Reference< awt::XVclContainer > xMsgBoxCtrls( xMsgBox, uno::UNO_QUERY ); + if ( xMsgBoxCtrls.is() ) + { + uno::Sequence< uno::Reference< awt::XWindow > > xChildren = xMsgBoxCtrls->getWindows(); + + for ( uno::Reference< awt::XWindow > const & child : std::as_const(xChildren) ) + { + uno::Reference< awt::XVclWindowPeer > xMsgBoxCtrl( child, uno::UNO_QUERY ); + if ( xMsgBoxCtrl.is() ) + { + bool bIsDefault = true; + uno::Any aValue = xMsgBoxCtrl->getProperty( "DefaultButton" ); + aValue >>= bIsDefault; + if ( bIsDefault ) + xMsgBoxCtrl->setProperty( "Text", uno::Any( rBtnText_1 ) ); + else + xMsgBoxCtrl->setProperty( "Text", uno::Any( rBtnText_2 ) ); + } + } + } + + sal_Int16 nRet; + // xMsgBox->setCaptionText( msCancelTitle ); + mbShowsMessageBox = true; + xMsgBox->setMessageText( rWarningText ); + nRet = xMsgBox->execute(); + if ( nRet == 2 ) // RET_YES == 2 + bRet = true; + + mbShowsMessageBox = false; + } + + uno::Reference< lang::XComponent > xComponent( xMsgBox, uno::UNO_QUERY ); + if ( xComponent.is() ) + xComponent->dispose(); + + return bRet; +} + + +bool UpdateHandler::showOverwriteWarning( std::u16string_view rFileName ) const +{ + return showWarning( + (msReloadWarning + .replaceAll( "%FILENAME", rFileName ) + .replaceAll( "%DOWNLOAD_PATH", msDownloadPath )), + msReloadContinue, msReloadReload ); +} + + +bool UpdateHandler::showOverwriteWarning() const +{ + return showWarning( msOverwriteWarning ); +} + + +#define BUTTON_HEIGHT 14 +#define BUTTON_WIDTH 50 +#define BUTTON_X_OFFSET 7 +#define BUTTON_Y_OFFSET 3 +#define LABEL_HEIGHT 10 + +#define DIALOG_WIDTH 300 +#define DIALOG_BORDER 5 +#define INNER_BORDER 3 +#define TEXT_OFFSET 1 +#define BOX_HEIGHT1 ( LABEL_HEIGHT + 3*BUTTON_HEIGHT + 2*BUTTON_Y_OFFSET + 2*INNER_BORDER ) +#define BOX_HEIGHT2 50 +#define EDIT_WIDTH ( DIALOG_WIDTH - 2 * DIALOG_BORDER ) +#define BOX1_BTN_X ( DIALOG_BORDER + EDIT_WIDTH - BUTTON_WIDTH - INNER_BORDER ) +#define BOX1_BTN_Y ( DIALOG_BORDER + LABEL_HEIGHT + INNER_BORDER) +#define THROBBER_WIDTH 16 +#define THROBBER_HEIGHT 16 +#define THROBBER_X_POS ( DIALOG_BORDER + 8 ) +#define THROBBER_Y_POS ( DIALOG_BORDER + 23 ) +#define BUTTON_BAR_HEIGHT 24 +#define LABEL_OFFSET ( LABEL_HEIGHT + 4 ) +#define DIALOG_HEIGHT ( BOX_HEIGHT1 + BOX_HEIGHT2 + LABEL_OFFSET + BUTTON_BAR_HEIGHT + 3 * DIALOG_BORDER ) +#define LABEL_Y_POS ( 2 * DIALOG_BORDER + BOX_HEIGHT1 ) +#define EDIT2_Y_POS ( LABEL_Y_POS + LABEL_HEIGHT ) +#define BUTTON_BAR_Y_POS ( EDIT2_Y_POS + DIALOG_BORDER + BOX_HEIGHT2 ) +#define BUTTON_Y_POS ( BUTTON_BAR_Y_POS + 8 ) +#define CLOSE_BTN_X ( DIALOG_WIDTH - DIALOG_BORDER - BUTTON_WIDTH ) +#define INSTALL_BTN_X ( CLOSE_BTN_X - 2 * BUTTON_X_OFFSET - BUTTON_WIDTH ) +#define DOWNLOAD_BTN_X ( INSTALL_BTN_X - BUTTON_X_OFFSET - BUTTON_WIDTH ) +#define PROGRESS_WIDTH 80 +#define PROGRESS_HEIGHT 10 +#define PROGRESS_X_POS ( DIALOG_BORDER + 8 ) +#define PROGRESS_Y_POS ( DIALOG_BORDER + 2*LABEL_OFFSET ) + + +void UpdateHandler::showControls( short nControls ) +{ + // The buttons from CANCEL_BUTTON to RESUME_BUTTON will be shown or + // hidden on demand + short nShiftMe; + for ( int i = 0; i <= int(RESUME_BUTTON); i++ ) + { + nShiftMe = static_cast(nControls >> i); + showControl( msButtonIDs[i], static_cast(nShiftMe & 0x01) ); + } + + nShiftMe = static_cast(nControls >> THROBBER_CTRL); + startThrobber( static_cast(nShiftMe & 0x01) ); + + nShiftMe = static_cast(nControls >> PROGRESS_CTRL); + showControl( CTRL_PROGRESS, static_cast(nShiftMe & 0x01) ); + showControl( TEXT_PERCENT, static_cast(nShiftMe & 0x01) ); + + // Status text needs to be smaller, when there are buttons at the right side of the dialog + if ( ( nControls & ( (1< xDesktop = frame::Desktop::create( mxContext ); + xDesktop->addTerminateListener( this ); + } + + loadStrings(); + + uno::Reference< lang::XMultiComponentFactory > xFactory( mxContext->getServiceManager(), uno::UNO_SET_THROW ); + uno::Reference< awt::XControlModel > xControlModel( xFactory->createInstanceWithContext( + "com.sun.star.awt.UnoControlDialogModel", + mxContext), uno::UNO_QUERY_THROW ); + { + // @see awt/UnoControlDialogModel.idl + uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY_THROW ); + + xPropSet->setPropertyValue( "Title", uno::Any( msDlgTitle ) ); + xPropSet->setPropertyValue( "Closeable", uno::Any( true ) ); + xPropSet->setPropertyValue( "Enabled", uno::Any( true ) ); + xPropSet->setPropertyValue( "Moveable", uno::Any( true ) ); + xPropSet->setPropertyValue( "Sizeable", uno::Any( true ) ); + xPropSet->setPropertyValue( "DesktopAsParent", uno::Any( true ) ); + xPropSet->setPropertyValue( "PositionX", uno::Any(sal_Int32( 100 )) ); + xPropSet->setPropertyValue( "PositionY", uno::Any(sal_Int32( 100 )) ); + xPropSet->setPropertyValue( "Width", uno::Any(sal_Int32( DIALOG_WIDTH )) ); + xPropSet->setPropertyValue( "Height", uno::Any(sal_Int32( DIALOG_HEIGHT )) ); + xPropSet->setPropertyValue( "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_DLG )) ); + } + { // Label (fixed text) + uno::Sequence< beans::NamedValue > aProps { { "Label", uno::Any( msStatusFL ) } }; + + insertControlModel( xControlModel, FIXED_TEXT_MODEL, "fixedLineStatus", + awt::Rectangle( DIALOG_BORDER+1, DIALOG_BORDER, EDIT_WIDTH-2, LABEL_HEIGHT ), + aProps ); + } + { // box around text + uno::Sequence< beans::NamedValue > aProps; + + insertControlModel( xControlModel, GROUP_BOX_MODEL, "StatusBox", + awt::Rectangle( DIALOG_BORDER, DIALOG_BORDER + LABEL_HEIGHT, EDIT_WIDTH, BOX_HEIGHT1 - LABEL_HEIGHT ), + aProps ); + } + { // Text (multiline edit) + uno::Sequence< beans::NamedValue > aProps + { + { "Text", uno::Any( substVariables(msChecking) ) }, + { "Border", uno::Any( sal_Int16( 0 ) ) }, + { "PaintTransparent", uno::Any( true ) }, + { "MultiLine", uno::Any( true ) }, + { "ReadOnly", uno::Any( true ) }, + { "AutoVScroll", uno::Any( true ) }, + { "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_STATUS )) } + }; + + insertControlModel( xControlModel, EDIT_FIELD_MODEL, TEXT_STATUS, + awt::Rectangle( DIALOG_BORDER + TEXT_OFFSET, + DIALOG_BORDER + LABEL_HEIGHT + TEXT_OFFSET, + EDIT_WIDTH - 2*TEXT_OFFSET, + BOX_HEIGHT1 - 4*TEXT_OFFSET - LABEL_HEIGHT ), + aProps ); + } + { // Text (edit) + uno::Sequence< beans::NamedValue > aProps + { + { "Text", uno::Any( substVariables(msPercent) ) }, + { "Border", uno::Any( sal_Int16( 0 ) ) }, + { "PaintTransparent", uno::Any( true ) }, + { "ReadOnly", uno::Any( true ) }, + }; + + insertControlModel( xControlModel, EDIT_FIELD_MODEL, TEXT_PERCENT, + awt::Rectangle( PROGRESS_X_POS + PROGRESS_WIDTH + DIALOG_BORDER, + PROGRESS_Y_POS, + EDIT_WIDTH - PROGRESS_WIDTH - BUTTON_WIDTH - 2*DIALOG_BORDER, + LABEL_HEIGHT ), + aProps ); + } + { // pause button + uno::Sequence< beans::NamedValue > aProps + { + { "DefaultButton", uno::Any( false ) }, + { "Enabled", uno::Any( true ) }, + { "PushButtonType", uno::Any( sal_Int16(awt::PushButtonType_STANDARD) ) }, + { "Label", uno::Any( msPauseBtn ) }, + { "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_PAUSE )) } + }; + + insertControlModel ( xControlModel, BUTTON_MODEL, msButtonIDs[PAUSE_BUTTON], + awt::Rectangle( BOX1_BTN_X, BOX1_BTN_Y, BUTTON_WIDTH, BUTTON_HEIGHT ), + aProps ); + } + { // resume button + uno::Sequence< beans::NamedValue > aProps + { + { "DefaultButton", uno::Any( false ) }, + { "Enabled", uno::Any( true ) }, + { "PushButtonType", uno::Any( sal_Int16(awt::PushButtonType_STANDARD) ) }, + { "Label", uno::Any( msResumeBtn ) }, + { "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_RESUME )) } + }; + + insertControlModel ( xControlModel, BUTTON_MODEL, msButtonIDs[RESUME_BUTTON], + awt::Rectangle( BOX1_BTN_X, + BOX1_BTN_Y + BUTTON_Y_OFFSET + BUTTON_HEIGHT, + BUTTON_WIDTH, + BUTTON_HEIGHT ), + aProps ); + } + { // abort button + uno::Sequence< beans::NamedValue > aProps + { + { "DefaultButton", uno::Any( false ) }, + { "Enabled", uno::Any( true ) }, + { "PushButtonType", uno::Any( sal_Int16(awt::PushButtonType_STANDARD) ) }, + { "Label", uno::Any( msCancelBtn ) }, + { "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_CANCEL )) } + }; + + insertControlModel ( xControlModel, BUTTON_MODEL, msButtonIDs[CANCEL_BUTTON], + awt::Rectangle( BOX1_BTN_X, + BOX1_BTN_Y + (2*(BUTTON_HEIGHT+BUTTON_Y_OFFSET)), + BUTTON_WIDTH, + BUTTON_HEIGHT ), + aProps ); + } + { // Label (FixedText) + uno::Sequence< beans::NamedValue > aProps { { "Label", uno::Any( msDescription ) } }; + + insertControlModel( xControlModel, FIXED_TEXT_MODEL, "fixedTextDescription", + awt::Rectangle( DIALOG_BORDER+1, LABEL_Y_POS, EDIT_WIDTH-2, LABEL_HEIGHT ), + aProps ); + } + { // box around text + uno::Sequence< beans::NamedValue > aProps; + + insertControlModel( xControlModel, GROUP_BOX_MODEL, "DescriptionBox", + awt::Rectangle( DIALOG_BORDER, EDIT2_Y_POS, EDIT_WIDTH, BOX_HEIGHT2 ), + aProps ); + } + { // Text (MultiLineEdit) + uno::Sequence< beans::NamedValue > aProps + { + { "Text", uno::Any( OUString() ) }, + { "Border", uno::Any( sal_Int16( 0 ) ) }, + { "PaintTransparent", uno::Any( true ) }, + { "MultiLine", uno::Any( true ) }, + { "ReadOnly", uno::Any( true ) }, + { "AutoVScroll", uno::Any( true ) }, + { "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_DESCRIPTION )) } + }; + + insertControlModel( xControlModel, EDIT_FIELD_MODEL, TEXT_DESCRIPTION, + awt::Rectangle( DIALOG_BORDER + TEXT_OFFSET, + EDIT2_Y_POS + 2*TEXT_OFFSET, + EDIT_WIDTH - 3*TEXT_OFFSET, + BOX_HEIGHT2 - 3*TEXT_OFFSET ), + aProps ); + } + { // @see awt/UnoControlFixedLineModel.idl + uno::Sequence< beans::NamedValue > aProps { { "Orientation", uno::Any( sal_Int32( 0 ) ) } }; + + insertControlModel( xControlModel, FIXED_LINE_MODEL, "fixedLine", + awt::Rectangle( 0, BUTTON_BAR_Y_POS, DIALOG_WIDTH, 5 ), + aProps ); + } + { // close button // @see awt/UnoControlButtonModel.idl + uno::Sequence< beans::NamedValue > aProps + { + { "DefaultButton", uno::Any( false ) }, + { "Enabled", uno::Any( true ) }, + // [property] short PushButtonType + // with own "ButtonActionListener" + { "PushButtonType", uno::Any( sal_Int16(awt::PushButtonType_STANDARD) ) }, + // with default ActionListener => endDialog(). + // setProperty( aProps, 2, "PushButtonType", uno::Any( sal_Int16(awt::PushButtonType_CANCEL) ) ); + // [property] string Label // only if PushButtonType_STANDARD + { "Label", uno::Any( msClose ) }, + { "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_CLOSE )) } + }; + + insertControlModel ( xControlModel, BUTTON_MODEL, msButtonIDs[ CLOSE_BUTTON ], + awt::Rectangle( CLOSE_BTN_X, BUTTON_Y_POS, BUTTON_WIDTH, BUTTON_HEIGHT ), + aProps ); + } + { // install button + uno::Sequence< beans::NamedValue > aProps + { + { "DefaultButton", uno::Any( false ) }, + { "Enabled", uno::Any( true ) }, + { "PushButtonType", uno::Any( sal_Int16(awt::PushButtonType_STANDARD) ) }, + { "Label", uno::Any( msInstall ) }, + { "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_INSTALL )) } + }; + + insertControlModel ( xControlModel, BUTTON_MODEL, msButtonIDs[INSTALL_BUTTON], + awt::Rectangle( INSTALL_BTN_X, BUTTON_Y_POS, BUTTON_WIDTH, BUTTON_HEIGHT ), + aProps ); + } + { // download button + uno::Sequence< beans::NamedValue > aProps + { + { "DefaultButton", uno::Any( false ) }, + { "Enabled", uno::Any( true ) }, + { "PushButtonType", uno::Any( sal_Int16(awt::PushButtonType_STANDARD) ) }, + { "Label", uno::Any( msDownload ) }, + { "HelpURL", uno::Any(OUString( INET_HID_SCHEME + HID_CHECK_FOR_UPD_DOWNLOAD )) } + }; + + insertControlModel ( xControlModel, BUTTON_MODEL, msButtonIDs[DOWNLOAD_BUTTON], + awt::Rectangle( DOWNLOAD_BTN_X, BUTTON_Y_POS, BUTTON_WIDTH, BUTTON_HEIGHT ), + aProps ); + } + { // help button + uno::Sequence< beans::NamedValue > aProps + { + { "DefaultButton", uno::Any( false ) }, + { "Enabled", uno::Any( true ) }, + { "PushButtonType", uno::Any( sal_Int16(awt::PushButtonType_HELP) ) } + }; + + insertControlModel( xControlModel, BUTTON_MODEL, msButtonIDs[HELP_BUTTON], + awt::Rectangle( DIALOG_BORDER, BUTTON_Y_POS, BUTTON_WIDTH, BUTTON_HEIGHT ), + aProps ); + } + { // @see awt/UnoControlThrobberModel.idl + uno::Sequence< beans::NamedValue > aProps; + + insertControlModel( xControlModel, "com.sun.star.awt.SpinningProgressControlModel", CTRL_THROBBER, + awt::Rectangle( THROBBER_X_POS, THROBBER_Y_POS, THROBBER_WIDTH, THROBBER_HEIGHT), + aProps ); + } + { // @see awt/UnoControlProgressBarModel.idl + uno::Sequence< beans::NamedValue > aProps + { + { "Enabled", uno::Any( true ) }, + { "ProgressValue", uno::Any( sal_Int32( 0 ) ) }, + { "ProgressValueMax", uno::Any( sal_Int32( 100 ) ) }, + { "ProgressValueMin", uno::Any( sal_Int32( 0 ) ) }, + }; + insertControlModel( xControlModel, "com.sun.star.awt.UnoControlProgressBarModel", CTRL_PROGRESS, + awt::Rectangle( PROGRESS_X_POS, PROGRESS_Y_POS, PROGRESS_WIDTH, PROGRESS_HEIGHT ), + aProps); + } + + uno::Reference< awt::XUnoControlDialog > xControl = awt::UnoControlDialog::create( mxContext ); + xControl->setModel( xControlModel ); + + if ( !mbVisible ) + { + xControl->setVisible( false ); + } + + xControl->createPeer( nullptr, nullptr ); + { + for ( int i = 0; i < HELP_BUTTON; i++ ) + { + uno::Reference< awt::XButton > xButton ( xControl->getControl( msButtonIDs[i] ), uno::UNO_QUERY); + if (xButton.is()) + { + xButton->setActionCommand( msButtonIDs[i] ); + xButton->addActionListener( this ); + } + } + } + + mxUpdDlg.set( xControl, uno::UNO_QUERY_THROW ); + mnLastCtrlState = -1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updatehdl.hxx b/extensions/source/update/check/updatehdl.hxx new file mode 100644 index 000000000..297cf730c --- /dev/null +++ b/extensions/source/update/check/updatehdl.hxx @@ -0,0 +1,207 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "actionlistener.hxx" + +enum DialogControls +{ + CANCEL_BUTTON = 0, + PAUSE_BUTTON, + RESUME_BUTTON, + INSTALL_BUTTON, + DOWNLOAD_BUTTON, + CLOSE_BUTTON, + HELP_BUTTON, + BUTTON_COUNT, + THROBBER_CTRL, + PROGRESS_CTRL +}; + +enum UpdateState { + UPDATESTATE_CHECKING = 0, + UPDATESTATE_ERROR_CHECKING, + UPDATESTATE_NO_UPDATE_AVAIL, + UPDATESTATE_UPDATE_AVAIL, + UPDATESTATE_UPDATE_NO_DOWNLOAD, + UPDATESTATE_AUTO_START, + UPDATESTATE_DOWNLOADING, + UPDATESTATE_DOWNLOAD_PAUSED, + UPDATESTATE_ERROR_DOWNLOADING, + UPDATESTATE_DOWNLOAD_AVAIL, + UPDATESTATE_EXT_UPD_AVAIL, + UPDATESTATES_COUNT +}; + +class UpdateHandler : public cppu::WeakImplHelper< css::awt::XActionListener, + css::awt::XTopWindowListener, + css::task::XInteractionHandler, + css::frame::XTerminateListener > +{ +private: + css::uno::Reference< css::uno::XComponentContext > mxContext; + css::uno::Reference< css::awt::XDialog > mxUpdDlg; + css::uno::Reference< css::task::XInteractionHandler > mxInteractionHdl; + rtl::Reference< IActionListener > mxActionListener; + + UpdateState meCurState; + UpdateState meLastState; + sal_Int32 mnPercent; + short mnLastCtrlState; + bool mbDownloadBtnHasDots; + bool mbVisible; + bool mbStringsLoaded; + bool mbMinimized; + bool mbListenerAdded; + mutable bool mbShowsMessageBox; + + osl::Mutex maMutex; + + OUString msNextVersion; + OUString msDownloadPath; + OUString msDownloadFile; + OUString msDescriptionMsg; + OUString msChecking; // RID_UPDATE_STR_CHECKING + OUString msCheckingError; // RID_UPDATE_STR_CHECKING_ERR + OUString msNoUpdFound; // RID_UPDATE_STR_NO_UPD_FOUND + OUString msUpdFound; // RID_UPDATE_STR_UPD_FOUND + OUString msDlgTitle; // RID_UPDATE_STR_DLG_TITLE + OUString msDownloadPause; // RID_UPDATE_STR_DOWNLOAD_PAUSE + OUString msDownloadError; // RID_UPDATE_STR_DOWNLOAD_ERR + OUString msDownloadWarning; // RID_UPDATE_STR_DOWNLOAD_WARN + OUString msDownloadDescr; // RID_UPDATE_STR_DOWNLOAD_WARN + OUString msDownloadNotAvail; // RID_UPDATE_STR_DOWNLOAD_UNAVAIL + OUString msDownloading; // RID_UPDATE_STR_DOWNLOADING + OUString msReady2Install; // RID_UPDATE_STR_READY_INSTALL + OUString msCancelMessage; // RID_UPDATE_STR_CANCEL_DOWNLOAD + OUString msInstallMessage; // RID_UPDATE_STR_BEGIN_INSTALL + OUString msInstallError; // RID_UPDATE_STR_INSTALL_ERROR + OUString msOverwriteWarning; // RID_UPDATE_STR_OVERWRITE_WARNING + OUString msPercent; // RID_UPDATE_STR_PERCENT + OUString msReloadWarning; // RID_UPDATE_STR_OVERWRITE_WARNING + OUString msReloadReload; // RID_UPDATE_STR_OVERWRITE_WARNING + OUString msReloadContinue; // RID_UPDATE_STR_OVERWRITE_WARNING + OUString msStatusFL; // RID_UPDATE_FT_STATUS + OUString msDescription; // RID_UPDATE_FT_DESCRIPTION + OUString msClose; // RID_UPDATE_BTN_CLOSE + OUString msDownload; // RID_UPDATE_BTN_DOWNLOAD + OUString msInstall; // RID_UPDATE_BTN_INSTALL + OUString msPauseBtn; // RID_UPDATE_BTN_PAUSE + OUString msResumeBtn; // RID_UPDATE_BTN_RESUME + OUString msCancelBtn; // RID_UPDATE_BTN_CANCEL + OUString msButtonIDs[ BUTTON_COUNT ]; + OUString msBubbleTexts[ UPDATESTATES_COUNT ]; + OUString msBubbleTitles[ UPDATESTATES_COUNT ]; + + void createDialog(); + void updateState( UpdateState eNewState ); + void startThrobber( bool bStart = true ); + void setControlProperty( const OUString &rCtrlName, + const OUString &rPropName, + const css::uno::Any &rPropValue ); + void showControl( const OUString &rCtrlName, bool bShow = true ); + void showControls( short nControls ); + void focusControl( DialogControls eID ); + void enableControls( short nCtrlState ); + void setDownloadBtnLabel( bool bAppendDots ); + void loadStrings(); + static OUString loadString(const std::locale& rLocale, + TranslateId pResourceId); + OUString substVariables( const OUString &rSource ) const; + static void insertControlModel( css::uno::Reference< css::awt::XControlModel > const & rxDialogModel, + OUString const & rServiceName, + OUString const & rControlName, + css::awt::Rectangle const & rPosSize, + css::uno::Sequence< css::beans::NamedValue > const & rProps ); + + void setFullVersion( OUString& rString ); + +public: + UpdateHandler( const css::uno::Reference< css::uno::XComponentContext > & rxContext, + const rtl::Reference< IActionListener > & rxActionListener ); + virtual ~UpdateHandler() override; + UpdateHandler(const UpdateHandler&) = delete; + UpdateHandler& operator=(const UpdateHandler&) = delete; + + bool isVisible() const; + bool isMinimized() const { return mbMinimized; } + void setVisible( bool bVisible = true ); + void setProgress( sal_Int32 nPercent ); + void setNextVersion( const OUString &rNextVersion ) { msNextVersion = rNextVersion; } + void setDownloadPath( const OUString &rPath ) { msDownloadPath = rPath; } + void setDownloadFile( std::u16string_view rPath ); + void setErrorMessage( const OUString &rErrorMsg ); + void setDescription( const OUString &rDescription ){ msDescriptionMsg = rDescription; } + + void setState( UpdateState eState ); + OUString getBubbleText( UpdateState eState ); + OUString getBubbleTitle( UpdateState eState ); + OUString getDefaultInstErrMsg(); + bool showWarning( const OUString &rWarning ) const; + bool showWarning( const OUString &rWarning, const OUString& rBtnText_1, const OUString& rBtnText_2 ) const; + bool showOverwriteWarning( std::u16string_view rFileName ) const; + bool showOverwriteWarning() const; + + // Allows runtime exceptions to be thrown by const methods + operator css::uno::Reference< css::uno::XInterface > () const + { return const_cast< cppu::OWeakObject * > (static_cast< cppu::OWeakObject const * > (this)); }; + + // XActionListener + virtual void SAL_CALL disposing( const css::lang::EventObject &rObj ) override; + virtual void SAL_CALL actionPerformed( css::awt::ActionEvent const & rEvent) 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; + + // XInteractionHandler + virtual void SAL_CALL handle( const css::uno::Reference< css::task::XInteractionRequest >& Request ) override; + + // XTerminateListener + virtual void SAL_CALL queryTermination( const css::lang::EventObject& e ) override; + virtual void SAL_CALL notifyTermination( const css::lang::EventObject& e ) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updateinfo.hxx b/extensions/source/update/check/updateinfo.hxx new file mode 100644 index 000000000..79387b358 --- /dev/null +++ b/extensions/source/update/check/updateinfo.hxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +#include + +struct DownloadSource +{ + bool IsDirect; + OUString URL; + + DownloadSource(bool bIsDirect, const OUString& aURL) : IsDirect(bIsDirect), URL(aURL) {}; + DownloadSource(const DownloadSource& ds) : IsDirect(ds.IsDirect), URL(ds.URL) {}; + + DownloadSource & operator=( const DownloadSource & ds ) { IsDirect = ds.IsDirect; URL = ds.URL; return *this; }; +}; + +struct ReleaseNote +{ + sal_uInt8 Pos; + OUString URL; + sal_uInt8 Pos2; + OUString URL2; + + ReleaseNote(sal_uInt8 pos, const OUString& aURL) : Pos(pos), URL(aURL), Pos2(0), URL2() {}; + + ReleaseNote(const ReleaseNote& rn) :Pos(rn.Pos), URL(rn.URL), Pos2(rn.Pos2), URL2(rn.URL2) {}; + ReleaseNote & operator=( const ReleaseNote& rn) { Pos=rn.Pos; URL=rn.URL; Pos2=rn.Pos2; URL2=rn.URL2; return *this; }; +}; + +struct UpdateInfo +{ + OUString BuildId; + OUString Version; + OUString Description; + std::vector< DownloadSource > Sources; + std::vector< ReleaseNote > ReleaseNotes; +}; + +// Returns the URL of the release note for the given position +OUString getReleaseNote(const UpdateInfo& rInfo, sal_uInt8 pos, bool autoDownloadEnabled=false); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updateprotocol.cxx b/extensions/source/update/check/updateprotocol.cxx new file mode 100644 index 000000000..db8319c79 --- /dev/null +++ b/extensions/source/update/check/updateprotocol.cxx @@ -0,0 +1,317 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include + +#include +#include + +#include "updateprotocol.hxx" +#include "updatecheckconfig.hxx" + +#include +#include + + +#include +#include +#include + +namespace container = css::container ; +namespace deployment = css::deployment ; +namespace uno = css::uno ; +namespace task = css::task ; +namespace xml = css::xml ; + + +static bool +getBootstrapData( + uno::Sequence< OUString > & rRepositoryList, + OUString & rGitID, + OUString & rInstallSetID) +{ + rGitID = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":buildid}"; + rtl::Bootstrap::expandMacros( rGitID ); + if ( rGitID.isEmpty() ) + return false; + + rInstallSetID = "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":UpdateID}"; + rtl::Bootstrap::expandMacros( rInstallSetID ); + if ( rInstallSetID.isEmpty() ) + return false; + + OUString aValue( "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":UpdateURL}" ); + rtl::Bootstrap::expandMacros( aValue ); + + if( !aValue.isEmpty() ) + { + rRepositoryList = { aValue }; + } + + return true; +} + + +// Returns 'true' if successfully connected to the update server +bool +checkForUpdates( + UpdateInfo& o_rUpdateInfo, + uno::Reference< uno::XComponentContext > const & rxContext, + uno::Reference< task::XInteractionHandler > const & rxInteractionHandler, + const uno::Reference< deployment::XUpdateInformationProvider >& rUpdateInfoProvider) +{ + OUString myArch; + OUString myOS; + + rtl::Bootstrap::get("_OS", myOS); + rtl::Bootstrap::get("_ARCH", myArch); + + uno::Sequence< OUString > aRepositoryList; + OUString aGitID; + OUString aInstallSetID; + + if( ! ( getBootstrapData(aRepositoryList, aGitID, aInstallSetID) && (aRepositoryList.getLength() > 0) ) ) + return false; + + return checkForUpdates( o_rUpdateInfo, rxContext, rxInteractionHandler, rUpdateInfoProvider, + myOS, myArch, + aRepositoryList, aGitID, aInstallSetID ); +} + +bool +checkForUpdates( + UpdateInfo& o_rUpdateInfo, + const uno::Reference< uno::XComponentContext > & rxContext, + const uno::Reference< task::XInteractionHandler > & rxInteractionHandler, + const uno::Reference< deployment::XUpdateInformationProvider >& rUpdateInfoProvider, + std::u16string_view rOS, + std::u16string_view rArch, + const uno::Sequence< OUString > &rRepositoryList, + std::u16string_view rGitID, + const OUString &rInstallSetID ) +{ + if( !rxContext.is() ) + throw uno::RuntimeException( "checkForUpdates: empty component context" ); + + OSL_ASSERT( rxContext->getServiceManager().is() ); + + // XPath implementation + uno::Reference< xml::xpath::XXPathAPI > xXPath = xml::xpath::XPathAPI::create(rxContext); + + xXPath->registerNS( "inst", "http://update.libreoffice.org/description" ); + + if( rxInteractionHandler.is() ) + rUpdateInfoProvider->setInteractionHandler(rxInteractionHandler); + + try + { + uno::Reference< container::XEnumeration > aUpdateInfoEnumeration = + rUpdateInfoProvider->getUpdateInformationEnumeration( rRepositoryList, rInstallSetID ); + + if ( !aUpdateInfoEnumeration.is() ) + return false; // something went wrong .. + + OUString aXPathExpression = + OUString::Concat("/child::inst:description[inst:os=\'")+ + rOS + + "\' and inst:arch=\'"+ + rArch + + "\' and inst:gitid!=\'"+ + rGitID + + "\']"; + + + while( aUpdateInfoEnumeration->hasMoreElements() ) + { + deployment::UpdateInformationEntry aEntry; + + if( aUpdateInfoEnumeration->nextElement() >>= aEntry ) + { + uno::Reference< xml::dom::XNode > xNode( aEntry.UpdateDocument ); + uno::Reference< xml::dom::XNodeList > xNodeList; + try { + xNodeList = xXPath->selectNodeList(xNode, aXPathExpression + + "/inst:update/attribute::src"); + } catch (const css::xml::xpath::XPathException &) { + // ignore + } + + sal_Int32 i, imax = xNodeList->getLength(); + for( i = 0; i < imax; ++i ) + { + uno::Reference< xml::dom::XNode > xNode2( xNodeList->item(i) ); + + if( xNode2.is() ) + { + uno::Reference< xml::dom::XElement > xParent(xNode2->getParentNode(), uno::UNO_QUERY_THROW); + OUString aType = xParent->getAttribute("type"); + bool bIsDirect = !aType.equalsIgnoreAsciiCase("text/html"); + + o_rUpdateInfo.Sources.push_back( DownloadSource(bIsDirect, xNode2->getNodeValue()) ); + } + } + + uno::Reference< xml::dom::XNode > xNode2; + try { + xNode2 = xXPath->selectSingleNode(xNode, aXPathExpression + + "/inst:version/text()"); + } catch (const css::xml::xpath::XPathException &) { + // ignore + } + + if( xNode2.is() ) + o_rUpdateInfo.Version = xNode2->getNodeValue(); + + try { + xNode2 = xXPath->selectSingleNode(xNode, aXPathExpression + + "/inst:buildid/text()"); + } catch (const css::xml::xpath::XPathException &) { + // ignore + } + + if( xNode2.is() ) + o_rUpdateInfo.BuildId = xNode2->getNodeValue(); + + o_rUpdateInfo.Description = aEntry.Description; + + // Release Notes + try { + xNodeList = xXPath->selectNodeList(xNode, aXPathExpression + + "/inst:relnote"); + } catch (const css::xml::xpath::XPathException &) { + // ignore + } + imax = xNodeList->getLength(); + for( i = 0; i < imax; ++i ) + { + uno::Reference< xml::dom::XElement > xRelNote(xNodeList->item(i), uno::UNO_QUERY); + if( xRelNote.is() ) + { + sal_Int32 pos = xRelNote->getAttribute("pos").toInt32(); + + ReleaseNote aRelNote(static_cast(pos), xRelNote->getAttribute("src")); + + if( xRelNote->hasAttribute("src2") ) + { + pos = xRelNote->getAttribute("pos2").toInt32(); + aRelNote.Pos2 = static_cast(pos); + aRelNote.URL2 = xRelNote->getAttribute("src2"); + } + + o_rUpdateInfo.ReleaseNotes.push_back(aRelNote); + } + } + + if( !o_rUpdateInfo.Sources.empty() ) + return true; + } + } + } + catch( ... ) + { + return false; + } + + return true; +} + + +bool storeExtensionUpdateInfos( const uno::Reference< uno::XComponentContext > & rxContext, + const uno::Sequence< uno::Sequence< OUString > > &rUpdateInfos ) +{ + bool bNotify = false; + + if ( rUpdateInfos.hasElements() ) + { + rtl::Reference< UpdateCheckConfig > aConfig = UpdateCheckConfig::get( rxContext ); + + for ( sal_Int32 i = rUpdateInfos.getLength() - 1; i >= 0; i-- ) + { + bNotify |= aConfig->storeExtensionVersion( rUpdateInfos[i][0], rUpdateInfos[i][1] ); + } + } + return bNotify; +} + + +// Returns 'true' if there are updates for any extension + +bool checkForExtensionUpdates( const uno::Reference< uno::XComponentContext > & rxContext ) +{ + uno::Sequence< uno::Sequence< OUString > > aUpdateList; + + uno::Reference< deployment::XPackageInformationProvider > xInfoProvider; + try + { + uno::Any aValue( rxContext->getValueByName( + "/singletons/com.sun.star.deployment.PackageInformationProvider" ) ); + OSL_VERIFY( aValue >>= xInfoProvider ); + } + catch( const uno::Exception& ) + { + OSL_FAIL( "checkForExtensionUpdates: could not create the PackageInformationProvider!" ); + } + + if ( !xInfoProvider.is() ) return false; + + aUpdateList = xInfoProvider->isUpdateAvailable( OUString() ); + bool bNotify = storeExtensionUpdateInfos( rxContext, aUpdateList ); + + return bNotify; +} + + +// Returns 'true' if there are any pending updates for any extension (offline check) + +bool checkForPendingUpdates( const uno::Reference< uno::XComponentContext > & rxContext ) +{ + uno::Sequence< uno::Sequence< OUString > > aExtensionList; + uno::Reference< deployment::XPackageInformationProvider > xInfoProvider; + try + { + uno::Any aValue( rxContext->getValueByName( + "/singletons/com.sun.star.deployment.PackageInformationProvider" ) ); + OSL_VERIFY( aValue >>= xInfoProvider ); + } + catch( const uno::Exception& ) + { + OSL_FAIL( "checkForExtensionUpdates: could not create the PackageInformationProvider!" ); + } + + if ( !xInfoProvider.is() ) return false; + + bool bPendingUpdateFound = false; + + aExtensionList = xInfoProvider->getExtensionList(); + if ( aExtensionList.hasElements() ) + { + rtl::Reference< UpdateCheckConfig > aConfig = UpdateCheckConfig::get( rxContext ); + + for ( sal_Int32 i = aExtensionList.getLength() - 1; i >= 0; i-- ) + { + bPendingUpdateFound = aConfig->checkExtensionVersion( aExtensionList[i][0], aExtensionList[i][1] ); + if ( bPendingUpdateFound ) + break; + } + } + + return bPendingUpdateFound; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updateprotocol.hxx b/extensions/source/update/check/updateprotocol.hxx new file mode 100644 index 000000000..4dedeb0d6 --- /dev/null +++ b/extensions/source/update/check/updateprotocol.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include + +#include + +#include +#include +#include + +#include "updateinfo.hxx" + +// Returns 'true' if successfully connected to the update server +bool checkForUpdates( + UpdateInfo& o_rUpdateInfo, + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference< css::task::XInteractionHandler >& rxInteractionHandler, + const css::uno::Reference< css::deployment::XUpdateInformationProvider >& rxProvider +); + +// The same as above, that does not read the info from bootstrap +SAL_DLLPUBLIC_EXPORT bool +checkForUpdates( + UpdateInfo& o_rUpdateInfo, + const css::uno::Reference< css::uno::XComponentContext > & rxContext, + const css::uno::Reference< css::task::XInteractionHandler > & rxInteractionHandler, + const css::uno::Reference< css::deployment::XUpdateInformationProvider >& rUpdateInfoProvider, + std::u16string_view rOS, + std::u16string_view rArch, + const css::uno::Sequence< OUString > &rRepositoryList, + std::u16string_view rGitID, + const OUString &rInstallID +); + +// Returns 'true' if there are updates for any extension +bool checkForExtensionUpdates( + const css::uno::Reference< css::uno::XComponentContext >& rxContext +); + +bool checkForPendingUpdates( + const css::uno::Reference< css::uno::XComponentContext >& rxContext +); + +bool storeExtensionUpdateInfos( + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Sequence< css::uno::Sequence< OUString > > &rUpdateInfos +); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updateprotocoltest.cxx b/extensions/source/update/check/updateprotocoltest.cxx new file mode 100644 index 000000000..070f930af --- /dev/null +++ b/extensions/source/update/check/updateprotocoltest.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 + +#include "updateprotocol.hxx" +#include + +#include +#include +#include +#include "sal/log.hxx" + +namespace task = ::com::sun::star::task; +namespace uno = ::com::sun::star::uno; + + +SAL_IMPLEMENT_MAIN() +{ + (void) argv; + (void) argc; + + if( osl_getCommandArgCount() != 0 ) + { + fprintf(stderr, "Usage: updateprotocoltest\n"); + return -1; + } + + // create the initial component context + uno::Reference< uno::XComponentContext > rComponentContext = cppu::defaultBootstrap_InitialComponentContext(); + + // initialize UCB (for backwards compatibility, in case some code still uses + // plain createInstance w/o args directly to obtain an instance): + css::ucb::UniversalContentBroker::create(rComponentContext); + + + OUString aURL; + OUString aVersion; + + try + { + if( checkForUpdates(rComponentContext, uno::Reference< task::XInteractionHandler > (), aURL, aVersion) ) + { + SAL_INFO("extensions.update", "Update found: " << aVersion << " on " << aURL); + } + else + { + SAL_INFO("extensions.update", "no updates found" ); + } + } + catch( ... ) + { + SAL_INFO("extensions.update", "unhandled exception caught" ); + } + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/check/updchk.uno.component b/extensions/source/update/check/updchk.uno.component new file mode 100644 index 000000000..f147e3065 --- /dev/null +++ b/extensions/source/update/check/updchk.uno.component @@ -0,0 +1,30 @@ + + + + + + + + + + + diff --git a/extensions/source/update/feed/test/updatefeedtest.cxx b/extensions/source/update/feed/test/updatefeedtest.cxx new file mode 100644 index 000000000..119aab24a --- /dev/null +++ b/extensions/source/update/feed/test/updatefeedtest.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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 deployment = ::com::sun::star::deployment; +namespace lang = ::com::sun::star::lang; +namespace uno = ::com::sun::star::uno; +namespace xml = ::com::sun::star::xml; + + +SAL_IMPLEMENT_MAIN() +{ + (void) argv; + (void) argc; + + if( osl_getCommandArgCount() != 1 ) + { + fprintf(stderr, "Usage: updatefeedtest \n"); + return -1; + } + + // create the initial component context + uno::Reference< uno::XComponentContext > rComponentContext = cppu::defaultBootstrap_InitialComponentContext(); + + // initialize UCB (for backwards compatibility, in case some code still uses + // plain createInstance w/o args directly to obtain an instance): + ucb::UniversalContentBroker::create(rComponentContext); + + // retrieve the update information provider + uno::Reference< deployment::XUpdateInformationProvider > rUpdateInformationProvider = + deployment::UpdateInformationProvider::create( rComponentContext ); + + uno::Sequence< OUString > theURLs(1); + osl_getCommandArg( 0, &theURLs[0].pData ); + // theURLs[0] = "http://localhost/~olli/atomfeed.xml"; + + OUString aExtension = "MyExtension"; + + try + { + uno::Sequence< uno::Reference< xml::dom::XElement > > theUpdateInfo = + rUpdateInformationProvider->getUpdateInformation( theURLs, aExtension ); + } + catch( const uno::Exception & ) + { + TOOLS_WARN_EXCEPTION("extensions.update", ""); + } + catch( ... ) + { + SAL_WARN("extensions.update", "exception of undetermined type caught" ); + } + + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/feed/updatefeed.component b/extensions/source/update/feed/updatefeed.component new file mode 100644 index 000000000..83e30a8c2 --- /dev/null +++ b/extensions/source/update/feed/updatefeed.component @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/extensions/source/update/feed/updatefeed.cxx b/extensions/source/update/feed/updatefeed.cxx new file mode 100644 index 000000000..ee83c3f9b --- /dev/null +++ b/extensions/source/update/feed/updatefeed.cxx @@ -0,0 +1,755 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance 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 + +namespace beans = com::sun::star::beans ; +namespace container = com::sun::star::container ; +namespace deployment = com::sun::star::deployment ; +namespace io = com::sun::star::io ; +namespace lang = com::sun::star::lang ; +namespace task = com::sun::star::task ; +namespace ucb = com::sun::star::ucb ; +namespace uno = com::sun::star::uno ; +namespace xml = com::sun::star::xml ; + + +namespace +{ + +#ifdef DEBUG + +class InputStreamWrapper : public ::cppu::WeakImplHelper< io::XInputStream > +{ + uno::Reference< io::XInputStream > m_xStream; + +public: + explicit InputStreamWrapper(const uno::Reference< io::XInputStream >& rxStream) : + m_xStream(rxStream) {}; + + virtual sal_Int32 SAL_CALL readBytes(uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) + { + sal_Int32 n = m_xStream->readBytes(aData, nBytesToRead); + return n; + }; + virtual sal_Int32 SAL_CALL readSomeBytes(uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) + { + sal_Int32 n = m_xStream->readSomeBytes(aData, nMaxBytesToRead); + return n; + }; + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + { m_xStream->skipBytes(nBytesToSkip); }; + virtual sal_Int32 SAL_CALL available() + { return m_xStream->available(); }; + virtual void SAL_CALL closeInput( ) + {}; +}; + +#define INPUT_STREAM(i) new InputStreamWrapper(i) +#else +#define INPUT_STREAM(i) i +#endif + + +class ActiveDataSink : public ::cppu::WeakImplHelper< io::XActiveDataSink > +{ + uno::Reference< io::XInputStream > m_xStream; + +public: + ActiveDataSink() {}; + + virtual uno::Reference< io::XInputStream > SAL_CALL getInputStream() override { return m_xStream; }; + virtual void SAL_CALL setInputStream( uno::Reference< io::XInputStream > const & rStream ) override { m_xStream = rStream; }; +}; + + +class UpdateInformationProvider : + public ::cppu::WeakImplHelper< deployment::XUpdateInformationProvider, + ucb::XWebDAVCommandEnvironment, + lang::XServiceInfo > +{ + OUString getUserAgent(bool bExtended); + bool isUserAgentExtended() const; +public: + uno::Reference< xml::dom::XElement > getDocumentRoot(const uno::Reference< xml::dom::XNode >& rxNode); + uno::Reference< xml::dom::XNode > getChildNode(const uno::Reference< xml::dom::XNode >& rxNode, std::u16string_view rName); + + + // XUpdateInformationService + virtual uno::Sequence< uno::Reference< xml::dom::XElement > > SAL_CALL + getUpdateInformation( + uno::Sequence< OUString > const & repositories, + OUString const & extensionId + ) override; + + virtual void SAL_CALL cancel() override; + + virtual void SAL_CALL setInteractionHandler( + uno::Reference< task::XInteractionHandler > const & handler ) override; + + virtual uno::Reference< container::XEnumeration > SAL_CALL + getUpdateInformationEnumeration( + uno::Sequence< OUString > const & repositories, + OUString const & extensionId + ) override; + + // XCommandEnvironment + virtual uno::Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() override; + + virtual uno::Reference< ucb::XProgressHandler > SAL_CALL getProgressHandler() override { return uno::Reference< ucb::XProgressHandler >(); }; + + // XWebDAVCommandEnvironment + virtual uno::Sequence< beans::StringPair > SAL_CALL getUserRequestHeaders( + const OUString&, ucb::WebDAVHTTPMethod ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName) override; + virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + UpdateInformationProvider(const uno::Reference& xContext, + const uno::Reference< ucb::XUniversalContentBroker >& xUniversalContentBroker, + const uno::Reference< xml::dom::XDocumentBuilder >& xDocumentBuilder, + const uno::Reference< xml::xpath::XXPathAPI >& xXPathAPI); + +protected: + + virtual ~UpdateInformationProvider() override; + static OUString getConfigurationItem(uno::Reference const & configurationProvider, OUString const & node, OUString const & item); + static uno::Any getConfigurationItemAny(uno::Reference const & configurationProvider, OUString const & node, OUString const & item); + +private: + uno::Reference< io::XInputStream > load(const OUString& rURL); + + void storeCommandInfo( sal_Int32 nCommandId, + uno::Reference< ucb::XCommandProcessor > const & rxCommandProcessor); + + const uno::Reference< uno::XComponentContext> m_xContext; + + const uno::Reference< ucb::XUniversalContentBroker > m_xUniversalContentBroker; + const uno::Reference< xml::dom::XDocumentBuilder > m_xDocumentBuilder; + const uno::Reference< xml::xpath::XXPathAPI > m_xXPathAPI; + + uno::Sequence< beans::StringPair > m_aRequestHeaderList; + + uno::Reference< ucb::XCommandProcessor > m_xCommandProcessor; + uno::Reference< task::XInteractionHandler > m_xInteractionHandler; + uno::Reference< task::XInteractionHandler > m_xPwContainerInteractionHandler; + + osl::Mutex m_aMutex; + osl::Condition m_bCancelled; + + sal_Int32 m_nCommandId; +}; + + +class UpdateInformationEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration > +{ +public: + UpdateInformationEnumeration(const uno::Reference< xml::dom::XNodeList >& xNodeList, + const rtl::Reference< UpdateInformationProvider >& xUpdateInformationProvider) : + m_xUpdateInformationProvider(xUpdateInformationProvider), + m_xNodeList(xNodeList), + m_nNodes(xNodeList.is() ? xNodeList->getLength() : 0), + m_nCount(0) + { + }; + + // XEnumeration + sal_Bool SAL_CALL hasMoreElements() override { return m_nCount < m_nNodes; }; + uno::Any SAL_CALL nextElement() override + { + OSL_ASSERT( m_xNodeList.is() ); + OSL_ASSERT( m_xUpdateInformationProvider.is() ); + + if( m_nCount >= m_nNodes ) + throw container::NoSuchElementException(OUString::number(m_nCount), *this); + + try + { + deployment::UpdateInformationEntry aEntry; + + uno::Reference< xml::dom::XNode > xAtomEntryNode( m_xNodeList->item(m_nCount++) ); + + uno::Reference< xml::dom::XNode > xSummaryNode( + m_xUpdateInformationProvider->getChildNode( xAtomEntryNode, u"summary/text()" ) + ); + + if( xSummaryNode.is() ) + aEntry.Description = xSummaryNode->getNodeValue(); + + uno::Reference< xml::dom::XNode > xContentNode( + m_xUpdateInformationProvider->getChildNode( xAtomEntryNode, u"content" ) ); + + if( xContentNode.is() ) + aEntry.UpdateDocument = m_xUpdateInformationProvider->getDocumentRoot(xContentNode); + + return uno::Any(aEntry); + } + catch( ucb::CommandAbortedException const &) + { + // action has been aborted + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetException( "Command aborted", *this, anyEx ); + } + catch( uno::RuntimeException const & ) + { + // let runtime exception pass + throw; + } + catch( uno::Exception const &) + { + // document not accessible + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetException( "Document not accessible", *this, anyEx ); + } + } + +private: + const rtl::Reference< UpdateInformationProvider > m_xUpdateInformationProvider; + const uno::Reference< xml::dom::XNodeList > m_xNodeList; + const sal_Int32 m_nNodes; + sal_Int32 m_nCount; +}; + + +class SingleUpdateInformationEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration > +{ +public: + explicit SingleUpdateInformationEnumeration(const uno::Reference< xml::dom::XElement >& xElement) + : m_nCount(0) { m_aEntry.UpdateDocument = xElement; }; + + // XEnumeration + sal_Bool SAL_CALL hasMoreElements() override { return 0 == m_nCount; }; + uno::Any SAL_CALL nextElement() override + { + if( m_nCount > 0 ) + throw container::NoSuchElementException(OUString::number(m_nCount), *this); + + ++m_nCount; + return uno::Any(m_aEntry); + }; + +private: + sal_Int32 m_nCount; + deployment::UpdateInformationEntry m_aEntry; +}; + +UpdateInformationProvider::UpdateInformationProvider( + const uno::Reference& xContext, + const uno::Reference< ucb::XUniversalContentBroker >& xUniversalContentBroker, + const uno::Reference< xml::dom::XDocumentBuilder >& xDocumentBuilder, + const uno::Reference< xml::xpath::XXPathAPI >& xXPathAPI) + : m_xContext(xContext) + , m_xUniversalContentBroker(xUniversalContentBroker) + , m_xDocumentBuilder(xDocumentBuilder) + , m_xXPathAPI(xXPathAPI) + , m_aRequestHeaderList(2) + , m_nCommandId(0) +{ + uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider( + css::configuration::theDefaultProvider::get(m_xContext)); + + auto pRequestHeaderList = m_aRequestHeaderList.getArray(); + pRequestHeaderList[0].First = "Accept-Language"; + pRequestHeaderList[0].Second = getConfigurationItem( xConfigurationProvider, "org.openoffice.Setup/L10N", "ooLocale" ); +} + +bool +UpdateInformationProvider::isUserAgentExtended() const +{ + bool bExtendedUserAgent = false; + try { + uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider( + css::configuration::theDefaultProvider::get(m_xContext)); + + uno::Any aExtended = getConfigurationItemAny( + xConfigurationProvider, + "org.openoffice.Office.Jobs/Jobs/UpdateCheck/Arguments", + "ExtendedUserAgent"); + aExtended >>= bExtendedUserAgent; + } catch (const uno::RuntimeException &) { + SAL_WARN("extensions.update", "Online update disabled"); + } + return bExtendedUserAgent; +} + +OUString UpdateInformationProvider::getUserAgent(bool bExtended) +{ + uno::Reference< lang::XMultiServiceFactory > xConfigurationProvider( + css::configuration::theDefaultProvider::get(m_xContext)); + + OUStringBuffer buf; + buf.append( + getConfigurationItem( + xConfigurationProvider, + "org.openoffice.Setup/Product", + "ooName")); + buf.append(' '); + buf.append( + getConfigurationItem( + xConfigurationProvider, + "org.openoffice.Setup/Product", + "ooSetupVersion")); + + OUString extension( + getConfigurationItem( + xConfigurationProvider, + "org.openoffice.Setup/Product", + "ooSetupExtension")); + if (!extension.isEmpty()) + buf.append(extension); + + OUString product(buf.makeStringAndClear()); + + OUString aUserAgent( "${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("version") ":UpdateUserAgent}" ); + OUString aExtended; + if( bExtended ) + { + aExtended = Application::GetHWOSConfInfo(); + } + rtl::Bootstrap::expandMacros( aUserAgent ); + aUserAgent = aUserAgent.replaceAll("", product); + aUserAgent = aUserAgent.replaceAll("", aExtended); + SAL_INFO("extensions.update", "UpdateUserAgent: " << aUserAgent); + + return aUserAgent; +} + +uno::Sequence< beans::StringPair > SAL_CALL UpdateInformationProvider::getUserRequestHeaders( + const OUString &aURL, ucb::WebDAVHTTPMethod ) +{ + bool bExtendedUserAgent; + uno::Sequence< beans::StringPair > aPair = m_aRequestHeaderList; + + // Internal use from cui/ some magic URLs + if( aURL.startsWith( "useragent:" ) ) + bExtendedUserAgent = (aURL == "useragent:extended"); + else + bExtendedUserAgent = isUserAgentExtended(); + + OUString aUserAgent = getUserAgent(bExtendedUserAgent); + + if( aUserAgent.isEmpty() ) + aPair.realloc(1); + else + { + auto pPair = aPair.getArray(); + pPair[1].First = "User-Agent"; + pPair[1].Second = aUserAgent; + } + + return aPair; +}; + +UpdateInformationProvider::~UpdateInformationProvider() +{ +} + +uno::Any +UpdateInformationProvider::getConfigurationItemAny(uno::Reference const & configurationProvider, OUString const & node, OUString const & item) +{ + beans::PropertyValue aProperty; + aProperty.Name = "nodepath"; + aProperty.Value <<= node; + + uno::Sequence< uno::Any > aArgumentList{ uno::Any(aProperty) }; + uno::Reference< container::XNameAccess > xNameAccess( + configurationProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", + aArgumentList ), + uno::UNO_QUERY_THROW); + + return xNameAccess->getByName(item); +} + +OUString +UpdateInformationProvider::getConfigurationItem(uno::Reference const & configurationProvider, OUString const & node, OUString const & item) +{ + OUString sRet; + getConfigurationItemAny(configurationProvider, node, item) >>= sRet; + return sRet; +} + +void +UpdateInformationProvider::storeCommandInfo( + sal_Int32 nCommandId, + uno::Reference< ucb::XCommandProcessor > const & rxCommandProcessor) +{ + osl::MutexGuard aGuard(m_aMutex); + + m_nCommandId = nCommandId; + m_xCommandProcessor = rxCommandProcessor; +} + +uno::Reference< io::XInputStream > +UpdateInformationProvider::load(const OUString& rURL) +{ + uno::Reference< ucb::XContentIdentifier > xId = m_xUniversalContentBroker->createContentIdentifier(rURL); + + if( !xId.is() ) + throw uno::RuntimeException( + "unable to obtain universal content id", *this); + + uno::Reference< ucb::XCommandProcessor > xCommandProcessor(m_xUniversalContentBroker->queryContent(xId), uno::UNO_QUERY_THROW); + rtl::Reference< ActiveDataSink > aSink(new ActiveDataSink()); + + // Disable KeepAlive in webdav - don't want millions of office + // instances phone home & clog up servers + uno::Sequence< beans::NamedValue > aProps { { "KeepAlive", uno::Any(false) } }; + + ucb::OpenCommandArgument3 aOpenArgument; + aOpenArgument.Mode = ucb::OpenMode::DOCUMENT; + aOpenArgument.Priority = 32768; + aOpenArgument.Sink = *aSink; + aOpenArgument.OpeningFlags = aProps; + + ucb::Command aCommand; + aCommand.Name = "open"; + aCommand.Argument <<= aOpenArgument; + + sal_Int32 nCommandId = xCommandProcessor->createCommandIdentifier(); + + storeCommandInfo(nCommandId, xCommandProcessor); + try + { + xCommandProcessor->execute(aCommand, nCommandId, + static_cast < XCommandEnvironment *> (this)); + } + catch( const uno::Exception & /* e */ ) + { + storeCommandInfo(0, uno::Reference< ucb::XCommandProcessor > ()); + + uno::Reference< ucb::XCommandProcessor2 > xCommandProcessor2(xCommandProcessor, uno::UNO_QUERY); + if( xCommandProcessor2.is() ) + xCommandProcessor2->releaseCommandIdentifier(nCommandId); + + throw; + } + storeCommandInfo(0, uno::Reference< ucb::XCommandProcessor > ()); + + uno::Reference< ucb::XCommandProcessor2 > xCommandProcessor2(xCommandProcessor, uno::UNO_QUERY); + if( xCommandProcessor2.is() ) + xCommandProcessor2->releaseCommandIdentifier(nCommandId); + + return INPUT_STREAM(aSink->getInputStream()); +} + + +// TODO: docu content node + +uno::Reference< xml::dom::XElement > +UpdateInformationProvider::getDocumentRoot(const uno::Reference< xml::dom::XNode >& rxNode) +{ + OSL_ASSERT(m_xDocumentBuilder.is()); + + uno::Reference< xml::dom::XElement > xElement(rxNode, uno::UNO_QUERY_THROW); + + // load the document referenced in 'src' attribute .. + if( xElement->hasAttribute( "src" ) ) + { + uno::Reference< xml::dom::XDocument > xUpdateXML = + m_xDocumentBuilder->parse(load(xElement->getAttribute( "src" ))); + + OSL_ASSERT( xUpdateXML.is() ); + + if( xUpdateXML.is() ) + return xUpdateXML->getDocumentElement(); + } + // .. or return the (single) child element + else + { + uno::Reference< xml::dom::XNodeList> xChildNodes = rxNode->getChildNodes(); + + // ignore possible #text nodes + sal_Int32 nmax = xChildNodes->getLength(); + for(sal_Int32 n=0; n < nmax; n++) + { + uno::Reference< xml::dom::XElement > xChildElement(xChildNodes->item(n), uno::UNO_QUERY); + if( xChildElement.is() ) + { + /* Copy the content to a dedicated document since XXPathAPI->selectNodeList + * seems to evaluate expression always relative to the root node. + */ + uno::Reference< xml::dom::XDocument > xUpdateXML = m_xDocumentBuilder->newDocument(); + xUpdateXML->appendChild( xUpdateXML->importNode(xChildElement, true ) ); + return xUpdateXML->getDocumentElement(); + } + } + } + + return uno::Reference< xml::dom::XElement > (); +} + + +uno::Reference< xml::dom::XNode > +UpdateInformationProvider::getChildNode(const uno::Reference< xml::dom::XNode >& rxNode, + std::u16string_view rName) +{ + OSL_ASSERT(m_xXPathAPI.is()); + try { + return m_xXPathAPI->selectSingleNode(rxNode, OUString::Concat("./atom:") + rName); + } catch (const xml::xpath::XPathException &) { + // ignore + return nullptr; + } +} + + +uno::Reference< container::XEnumeration > SAL_CALL +UpdateInformationProvider::getUpdateInformationEnumeration( + uno::Sequence< OUString > const & repositories, + OUString const & extensionId +) +{ + OSL_ASSERT(m_xDocumentBuilder.is()); + + // reset cancelled flag + m_bCancelled.reset(); + + for(sal_Int32 n=0; n xDocument = m_xDocumentBuilder->parse(load(repositories[n])); + uno::Reference< xml::dom::XElement > xElement; + + if( xDocument.is() ) + xElement = xDocument->getDocumentElement(); + + if( xElement.is() ) + { + if( xElement->getNodeName() == "feed" ) + { + OUString aXPathExpression; + + if( !extensionId.isEmpty() ) + aXPathExpression = "//atom:entry/atom:category[@term=\'" + extensionId + "\']/.."; + else + aXPathExpression = "//atom:entry"; + + uno::Reference< xml::dom::XNodeList > xNodeList; + try { + xNodeList = m_xXPathAPI->selectNodeList(xDocument, + aXPathExpression); + } catch (const xml::xpath::XPathException &) { + // ignore + } + + return new UpdateInformationEnumeration(xNodeList, this); + } + else + { + return new SingleUpdateInformationEnumeration(xElement); + } + } + + if( m_bCancelled.check() ) + break; + } + catch( uno::RuntimeException const& /*e*/) + { + // #i118675# ignore runtime exceptions for now + // especially the "unsatisfied query for interface of + // type com.sun.star.ucb.XCommandProcessor!" exception + } + + // rethrow only if last url in the list + catch( uno::Exception const & ) + { + if( n+1 >= repositories.getLength() ) + throw; + } + } + + return uno::Reference< container::XEnumeration >(); +} + + +uno::Sequence< uno::Reference< xml::dom::XElement > > SAL_CALL +UpdateInformationProvider::getUpdateInformation( + uno::Sequence< OUString > const & repositories, + OUString const & extensionId +) +{ + uno::Reference< container::XEnumeration > xEnumeration( + getUpdateInformationEnumeration(repositories, extensionId) + ); + + std::vector< uno::Reference< xml::dom::XElement > > aRet; + + if( xEnumeration.is() ) + { + while( xEnumeration->hasMoreElements() ) + { + try + { + deployment::UpdateInformationEntry aEntry; + if( (xEnumeration->nextElement() >>= aEntry ) && aEntry.UpdateDocument.is() ) + { + aRet.push_back(aEntry.UpdateDocument); + } + } + + catch( const lang::WrappedTargetException& e ) + { + // command aborted, return what we have got so far + if( e.TargetException.isExtractableTo( ::cppu::UnoType< css::ucb::CommandAbortedException >::get() ) ) + { + break; + } + + // ignore files that can't be loaded + } + } + } + + return comphelper::containerToSequence(aRet); +} + + +void SAL_CALL +UpdateInformationProvider::cancel() +{ + m_bCancelled.set(); + + osl::MutexGuard aGuard(m_aMutex); + if( m_xCommandProcessor.is() ) + m_xCommandProcessor->abort(m_nCommandId); +} + + +void SAL_CALL +UpdateInformationProvider::setInteractionHandler( + uno::Reference< task::XInteractionHandler > const & handler ) +{ + osl::MutexGuard aGuard(m_aMutex); + m_xInteractionHandler = handler; +} + + +uno::Reference< task::XInteractionHandler > SAL_CALL +UpdateInformationProvider::getInteractionHandler() +{ + osl::MutexGuard aGuard( m_aMutex ); + + if ( m_xInteractionHandler.is() ) + return m_xInteractionHandler; + else + { + try + { + // Supply an interaction handler that uses the password container + // service to obtain credentials without displaying a password gui. + + if ( !m_xPwContainerInteractionHandler.is() ) + m_xPwContainerInteractionHandler + = task::PasswordContainerInteractionHandler::create( + m_xContext ); + } + catch ( uno::RuntimeException const & ) + { + throw; + } + catch ( uno::Exception const & ) + { + } + return m_xPwContainerInteractionHandler; + } +} + + + +OUString SAL_CALL +UpdateInformationProvider::getImplementationName() +{ + return "vnd.sun.UpdateInformationProvider"; +} + + +uno::Sequence< OUString > SAL_CALL +UpdateInformationProvider::getSupportedServiceNames() +{ + return { "com.sun.star.deployment.UpdateInformationProvider" }; +} + +sal_Bool SAL_CALL +UpdateInformationProvider::supportsService( OUString const & serviceName ) +{ + return cppu::supportsService(this, serviceName); +} + +} // anonymous namespace + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_update_UpdateInformationProvider_get_implementation( + css::uno::XComponentContext* xContext , css::uno::Sequence const&) +{ + uno::Reference< ucb::XUniversalContentBroker > xUniversalContentBroker = + ucb::UniversalContentBroker::create(xContext); + + uno::Reference< xml::dom::XDocumentBuilder > xDocumentBuilder( + xml::dom::DocumentBuilder::create(xContext)); + + uno::Reference< xml::xpath::XXPathAPI > xXPath = xml::xpath::XPathAPI::create( xContext ); + + xXPath->registerNS( "atom", "http://www.w3.org/2005/Atom" ); + + return cppu::acquire( + new UpdateInformationProvider(xContext, xUniversalContentBroker, xDocumentBuilder, xXPath)); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/ui/updatecheckui.cxx b/extensions/source/update/ui/updatecheckui.cxx new file mode 100644 index 000000000..6a4462669 --- /dev/null +++ b/extensions/source/update/ui/updatecheckui.cxx @@ -0,0 +1,306 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +constexpr OUStringLiteral PROPERTY_TITLE = u"BubbleHeading"; +constexpr OUStringLiteral PROPERTY_TEXT = u"BubbleText"; +constexpr OUStringLiteral PROPERTY_IMAGE = u"BubbleImageURL"; +constexpr OUStringLiteral PROPERTY_SHOW_BUBBLE = u"BubbleVisible"; +constexpr OUStringLiteral PROPERTY_CLICK_HDL = u"MenuClickHDL"; +constexpr OUStringLiteral PROPERTY_SHOW_MENUICON = u"MenuIconVisible"; + +using namespace ::com::sun::star; + + +namespace +{ + +class UpdateCheckUI : public ::cppu::WeakImplHelper + < lang::XServiceInfo, document::XDocumentEventListener, beans::XPropertySet > +{ + uno::Reference< uno::XComponentContext > m_xContext; + uno::Reference< task::XJob > mrJob; + OUString maBubbleImageURL; + MenuBarUpdateIconManager maBubbleManager; + std::locale maSfxLocale; + +private: + DECL_LINK(ClickHdl, LinkParamNone*, void); + + Image GetBubbleImage( OUString const &rURL ); + +public: + explicit UpdateCheckUI(const uno::Reference&); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(OUString const & serviceName) override; + virtual uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XDocumentEventListener + virtual void SAL_CALL documentEventOccured(const document::DocumentEvent& Event) override; + virtual void SAL_CALL disposing(const lang::EventObject& Event) override; + + //XPropertySet + virtual uno::Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + virtual void SAL_CALL setPropertyValue(const OUString& PropertyName, const uno::Any& aValue) override; + virtual uno::Any SAL_CALL getPropertyValue(const OUString& PropertyName) override; + virtual void SAL_CALL addPropertyChangeListener(const OUString& PropertyName, + const uno::Reference< beans::XPropertyChangeListener > & aListener) override; + virtual void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, + const uno::Reference< beans::XPropertyChangeListener > & aListener) override; + virtual void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, + const uno::Reference< beans::XVetoableChangeListener > & aListener) override; + virtual void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, + const uno::Reference< beans::XVetoableChangeListener > & aListener) override; +}; + +UpdateCheckUI::UpdateCheckUI(const uno::Reference& xContext) + : m_xContext(xContext) +{ + maSfxLocale = Translate::Create("sfx"); + + uno::Reference< document::XDocumentEventBroadcaster > xBroadcaster( frame::theGlobalEventBroadcaster::get(m_xContext) ); + xBroadcaster->addDocumentEventListener( this ); + + SolarMutexGuard aGuard; + + maBubbleManager.SetBubbleImage(GetBubbleImage(maBubbleImageURL)); + maBubbleManager.SetClickHdl(LINK(this, UpdateCheckUI, ClickHdl)); +} + +OUString SAL_CALL +UpdateCheckUI::getImplementationName() +{ + return "vnd.sun.UpdateCheckUI"; +} + +uno::Sequence< OUString > SAL_CALL +UpdateCheckUI::getSupportedServiceNames() +{ + return { "com.sun.star.setup.UpdateCheckUI" }; +} + +sal_Bool SAL_CALL +UpdateCheckUI::supportsService( OUString const & serviceName ) +{ + return cppu::supportsService(this, serviceName); +} + +Image UpdateCheckUI::GetBubbleImage( OUString const &rURL ) +{ + Image aImage; + + if ( !maBubbleImageURL.isEmpty() ) + { + uno::Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + + if( !xContext.is() ) + throw uno::RuntimeException( + "UpdateCheckUI: unable to obtain service manager from component context" ); + + try + { + uno::Reference< graphic::XGraphicProvider > xGraphProvider(graphic::GraphicProvider::create(xContext)); + uno::Sequence< beans::PropertyValue > aMediaProps{ comphelper::makePropertyValue("URL", + rURL) }; + uno::Reference< graphic::XGraphic > xGraphic = xGraphProvider->queryGraphic( aMediaProps ); + if ( xGraphic.is() ) + { + aImage = Image( xGraphic ); + } + } + catch( const uno::Exception& ) + { + } + } + + if ( aImage.GetSizePixel().Width() == 0 ) + aImage = Image(StockImage::Yes, SV_RESID_BITMAP_INFOBOX); + + return aImage; +} + +void SAL_CALL UpdateCheckUI::documentEventOccured(const document::DocumentEvent& rEvent) +{ + SolarMutexGuard aGuard; + + if( rEvent.EventName == "OnPrepareViewClosing" ) + { + maBubbleManager.RemoveBubbleWindow(true); + } +} + +void SAL_CALL UpdateCheckUI::disposing(const lang::EventObject&) +{ +} + +uno::Reference< beans::XPropertySetInfo > UpdateCheckUI::getPropertySetInfo() +{ + return nullptr; +} + +void UpdateCheckUI::setPropertyValue(const OUString& rPropertyName, + const uno::Any& rValue) +{ + SolarMutexGuard aGuard; + + OUString aString; + + if( rPropertyName == PROPERTY_TITLE ) { + rValue >>= aString; + maBubbleManager.SetBubbleTitle(aString); + } + else if( rPropertyName == PROPERTY_TEXT ) { + rValue >>= aString; + maBubbleManager.SetBubbleText(aString); + } + else if( rPropertyName == PROPERTY_IMAGE ) { + rValue >>= aString; + if ( aString != maBubbleImageURL ) { + maBubbleImageURL = aString; + maBubbleManager.SetBubbleImage(GetBubbleImage(maBubbleImageURL)); + } + } + else if( rPropertyName == PROPERTY_SHOW_BUBBLE ) { + bool bShowBubble= false; + rValue >>= bShowBubble; + maBubbleManager.SetShowBubble(bShowBubble); + } + else if( rPropertyName == PROPERTY_CLICK_HDL ) { + uno::Reference< task::XJob > aJob; + rValue >>= aJob; + if ( !aJob.is() ) + throw lang::IllegalArgumentException(); + mrJob = aJob; + } + else if (rPropertyName == PROPERTY_SHOW_MENUICON ) { + bool bShowMenuIcon = false; + rValue >>= bShowMenuIcon; + maBubbleManager.SetShowMenuIcon(bShowMenuIcon); + } + else + throw beans::UnknownPropertyException(rPropertyName); +} + +uno::Any UpdateCheckUI::getPropertyValue(const OUString& rPropertyName) +{ + SolarMutexGuard aGuard; + + uno::Any aRet; + + if( rPropertyName == PROPERTY_TITLE ) + aRet <<= maBubbleManager.GetBubbleTitle(); + else if( rPropertyName == PROPERTY_TEXT ) + aRet <<= maBubbleManager.GetBubbleText(); + else if( rPropertyName == PROPERTY_SHOW_BUBBLE ) + aRet <<= maBubbleManager.GetShowBubble(); + else if( rPropertyName == PROPERTY_IMAGE ) + aRet <<= maBubbleImageURL; + else if( rPropertyName == PROPERTY_CLICK_HDL ) + aRet <<= mrJob; + else if( rPropertyName == PROPERTY_SHOW_MENUICON ) + aRet <<= maBubbleManager.GetShowMenuIcon(); + else + throw beans::UnknownPropertyException(rPropertyName); + + return aRet; +} + + +void UpdateCheckUI::addPropertyChangeListener( const OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) +{ + //no bound properties +} + + +void UpdateCheckUI::removePropertyChangeListener( const OUString& /*aPropertyName*/, + const uno::Reference< beans::XPropertyChangeListener > & /*aListener*/) +{ + //no bound properties +} + +void UpdateCheckUI::addVetoableChangeListener( const OUString& /*aPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + //no vetoable properties +} + +void UpdateCheckUI::removeVetoableChangeListener( const OUString& /*aPropertyName*/, + const uno::Reference< beans::XVetoableChangeListener > & /*aListener*/) +{ + //no vetoable properties +} + +IMPL_LINK_NOARG(UpdateCheckUI, ClickHdl, LinkParamNone*, void) +{ + SolarMutexGuard aGuard; + + if ( mrJob.is() ) + { + try { + uno::Sequence aEmpty; + mrJob->execute( aEmpty ); + } + catch(const uno::Exception&) { + std::unique_ptr xErrorBox(Application::CreateMessageDialog(nullptr, + VclMessageType::Warning, VclButtonsType::Ok, + Translate::get(STR_NO_WEBBROWSER_FOUND, maSfxLocale))); + xErrorBox->run(); + } + } +} + +} // anonymous namespace + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +extensions_update_UpdateCheckUI_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence const&) +{ + SolarMutexGuard aGuard; + return cppu::acquire(new UpdateCheckUI(context)); +} + + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/source/update/ui/updchk.component b/extensions/source/update/ui/updchk.component new file mode 100644 index 000000000..19c7dd86e --- /dev/null +++ b/extensions/source/update/ui/updchk.component @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/extensions/test/ole/AxTestComponents/AxTestComponents.cpp b/extensions/test/ole/AxTestComponents/AxTestComponents.cpp new file mode 100644 index 000000000..ca7d37457 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/AxTestComponents.cpp @@ -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 . + */ + +// Note: Proxy/Stub Information +// To build a separate proxy/stub DLL, +// run nmake -f AxTestComponentsps.mk in the project directory. + +#include "stdafx.h" +#include "resource.h" +#include + +#include "Basic.h" +#include "Foo.h" + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_Basic, CBasic) +OBJECT_ENTRY(CLSID_Foo, CFoo) +END_OBJECT_MAP() + +// DLL Entry Point + +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_AXTESTCOMPONENTSLib); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + return TRUE; // ok +} + +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow(void) { return (_Module.GetLockCount() == 0) ? S_OK : S_FALSE; } + +// Returns a class factory to create an object of the requested type + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + +// DllRegisterServer - Adds entries to the system registry + +STDAPI DllRegisterServer(void) +{ + // registers object, typelib and all interfaces in typelib + return _Module.RegisterServer(TRUE); +} + +// DllUnregisterServer - Removes entries from the system registry + +STDAPI DllUnregisterServer(void) { return _Module.UnregisterServer(TRUE); } + +//VT_I4 size_t V_ERROR VARIANT VARIANT_FALSE CComVariant FADF_EMBEDDED + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/AxTestComponents/AxTestComponents.def b/extensions/test/ole/AxTestComponents/AxTestComponents.def new file mode 100644 index 000000000..5d8c019ad --- /dev/null +++ b/extensions/test/ole/AxTestComponents/AxTestComponents.def @@ -0,0 +1,9 @@ +; AxTestComponents.def : Declares the module parameters. + +LIBRARY "AxTestComponents.DLL" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/extensions/test/ole/AxTestComponents/AxTestComponents.dsp b/extensions/test/ole/AxTestComponents/AxTestComponents.dsp new file mode 100644 index 000000000..43fbbe53d --- /dev/null +++ b/extensions/test/ole/AxTestComponents/AxTestComponents.dsp @@ -0,0 +1,325 @@ +# Microsoft Developer Studio Project File - Name="AxTestComponents" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=AxTestComponents - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "AxTestComponents.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "AxTestComponents.mak" CFG="AxTestComponents - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "AxTestComponents - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "AxTestComponents - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "AxTestComponents - Win32 Release MinSize" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "AxTestComponents - Win32 Release MinDependency" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "AxTestComponents - Win32 Unicode Release MinSize" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "AxTestComponents - Win32 Unicode Release MinDependency" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "AxTestComponents - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FR /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# Begin Custom Build - Performing registration +OutDir=.\Debug +TargetPath=.\Debug\AxTestComponents.dll +InputPath=.\Debug\AxTestComponents.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "AxTestComponents - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugU" +# PROP BASE Intermediate_Dir "DebugU" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# Begin Custom Build - Performing registration +OutDir=.\DebugU +TargetPath=.\DebugU\AxTestComponents.dll +InputPath=.\DebugU\AxTestComponents.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if "%OS%"=="" goto NOTNT + if not "%OS%"=="Windows_NT" goto NOTNT + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + goto end + :NOTNT + echo Warning : Cannot register Unicode DLL on Windows 95 + :end + +# End Custom Build + +!ELSEIF "$(CFG)" == "AxTestComponents - Win32 Release MinSize" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseMinSize" +# PROP BASE Intermediate_Dir "ReleaseMinSize" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseMinSize" +# PROP Intermediate_Dir "ReleaseMinSize" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\ReleaseMinSize +TargetPath=.\ReleaseMinSize\AxTestComponents.dll +InputPath=.\ReleaseMinSize\AxTestComponents.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "AxTestComponents - Win32 Release MinDependency" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseMinDependency" +# PROP BASE Intermediate_Dir "ReleaseMinDependency" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseMinDependency" +# PROP Intermediate_Dir "ReleaseMinDependency" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\ReleaseMinDependency +TargetPath=.\ReleaseMinDependency\AxTestComponents.dll +InputPath=.\ReleaseMinDependency\AxTestComponents.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "AxTestComponents - Win32 Unicode Release MinSize" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseUMinSize" +# PROP BASE Intermediate_Dir "ReleaseUMinSize" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseUMinSize" +# PROP Intermediate_Dir "ReleaseUMinSize" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\ReleaseUMinSize +TargetPath=.\ReleaseUMinSize\AxTestComponents.dll +InputPath=.\ReleaseUMinSize\AxTestComponents.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if "%OS%"=="" goto NOTNT + if not "%OS%"=="Windows_NT" goto NOTNT + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + goto end + :NOTNT + echo Warning : Cannot register Unicode DLL on Windows 95 + :end + +# End Custom Build + +!ELSEIF "$(CFG)" == "AxTestComponents - Win32 Unicode Release MinDependency" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseUMinDependency" +# PROP BASE Intermediate_Dir "ReleaseUMinDependency" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseUMinDependency" +# PROP Intermediate_Dir "ReleaseUMinDependency" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\ReleaseUMinDependency +TargetPath=.\ReleaseUMinDependency\AxTestComponents.dll +InputPath=.\ReleaseUMinDependency\AxTestComponents.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if "%OS%"=="" goto NOTNT + if not "%OS%"=="Windows_NT" goto NOTNT + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + goto end + :NOTNT + echo Warning : Cannot register Unicode DLL on Windows 95 + :end + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "AxTestComponents - Win32 Debug" +# Name "AxTestComponents - Win32 Unicode Debug" +# Name "AxTestComponents - Win32 Release MinSize" +# Name "AxTestComponents - Win32 Release MinDependency" +# Name "AxTestComponents - Win32 Unicode Release MinSize" +# Name "AxTestComponents - Win32 Unicode Release MinDependency" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\AxTestComponents.cpp +# End Source File +# Begin Source File + +SOURCE=.\AxTestComponents.def +# End Source File +# Begin Source File + +SOURCE=.\AxTestComponents.idl +# ADD MTL /tlb ".\AxTestComponents.tlb" /h "AxTestComponents.h" /iid "AxTestComponents_i.c" /Oicf +# End Source File +# Begin Source File + +SOURCE=.\AxTestComponents.rc +# End Source File +# Begin Source File + +SOURCE=.\Basic.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\Basic.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\Basic.rgs +# End Source File +# End Group +# End Target +# End Project + + diff --git a/extensions/test/ole/AxTestComponents/AxTestComponents.idl b/extensions/test/ole/AxTestComponents/AxTestComponents.idl new file mode 100644 index 000000000..6649483a7 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/AxTestComponents.idl @@ -0,0 +1,251 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// AxTestComponents.idl : IDL source for AxTestComponents.dll + + +// This file will be processed by the MIDL tool to +// produce the type library (AxTestComponents.tlb) and marshalling code. +// next id 86 +import "oaidl.idl"; +import "ocidl.idl"; + [ + object, + uuid(BFE10EBD-8584-11D4-8335-005004526AB4), + dual, + helpstring("IBasic Interface"), + pointer_default(unique) + ] + interface IBasic : IDispatch + { + [id(82), helpstring("method inBool")] HRESULT inBool([in]VARIANT_BOOL val); + [id(1), helpstring("method inByte")] HRESULT inByte([in] unsigned char val); + [id(2), helpstring("method inShort")] HRESULT inShort([in] short val); + [id(3), helpstring("method inLong")] HRESULT inLong([in] long val); + [id(4), helpstring("method inString")] HRESULT inString([in] BSTR val); + [id(5), helpstring("method inFloat")] HRESULT inFloat([in] float val); + [id(6), helpstring("method inDouble")] HRESULT inDouble([in] double val); + [id(7), helpstring("method inVariant")] HRESULT inVariant([in] VARIANT val); + [id(8), helpstring("method inArray")] HRESULT inArray([in] SAFEARRAY(VARIANT) val); + [id(9), helpstring("method inObject")] HRESULT inObject([in] IDispatch* val); + [id(83), helpstring("method inoutBool")] HRESULT inoutBool([in,out]VARIANT_BOOL* val); + [id(12), helpstring("method inoutByte")] HRESULT inoutByte([in,out] unsigned char* val); + [id(13), helpstring("method inoutShort")] HRESULT inoutShort([in,out] short* val); + [id(14), helpstring("method inoutLong")] HRESULT inoutLong([in,out] long * val); + [id(15), helpstring("method inoutString")] HRESULT inoutString([in, out] BSTR* val); + [id(16), helpstring("method inoutFloat")] HRESULT inoutFloat([in,out] float * val); + [id(17), helpstring("method inoutDouble")] HRESULT inoutDouble([in,out] double * val); + [id(18), helpstring("method inoutVariant")] HRESULT inoutVariant([in,out] VARIANT * val); + [id(19), helpstring("method inoutArray")] HRESULT inoutArray([in,out] SAFEARRAY(VARIANT) * val); + [id(20), helpstring("method inoutObject")] HRESULT inoutObject([in,out] IDispatch** val); + [id(84), helpstring("method outBool")] HRESULT outBool([out] VARIANT_BOOL* val); + [id(23), helpstring("method outByte")] HRESULT outByte([out] unsigned char* val); + [id(24), helpstring("method outShort")] HRESULT outShort([out] short* val); + [id(25), helpstring("method outLong")] HRESULT outLong([out] long* val); + [id(26), helpstring("method outString")] HRESULT outString([out] BSTR* val); + [id(27), helpstring("method outFloat")] HRESULT outFloat([out] float* val); + [id(28), helpstring("method outDouble")] HRESULT outDouble([out] double* val); + [id(29), helpstring("method outVariant")] HRESULT outVariant([out] VARIANT* val); + [id(30), helpstring("method outArray")] HRESULT outArray([out] SAFEARRAY(VARIANT) * val); + [id(31), helpstring("method outObject")] HRESULT outObject([out] IDispatch** val); + [propget, id(85), helpstring("property prpBool")] HRESULT prpBool([out, retval] VARIANT_BOOL *pVal); + [propput, id(85), helpstring("property prpBool")] HRESULT prpBool([in] VARIANT_BOOL newVal); + [propget, id(34), helpstring("property prpByte")] HRESULT prpByte([out, retval] unsigned char *pVal); + [propput, id(34), helpstring("property prpByte")] HRESULT prpByte([in] unsigned char newVal); + [propget, id(35), helpstring("property prpShort")] HRESULT prpShort([out, retval] short *pVal); + [propput, id(35), helpstring("property prpShort")] HRESULT prpShort([in] short newVal); + [propget, id(36), helpstring("property prpLong")] HRESULT prpLong([out, retval] long *pVal); + [propput, id(36), helpstring("property prpLong")] HRESULT prpLong([in] long newVal); + [propget, id(37), helpstring("property prpString")] HRESULT prpString([out, retval] BSTR *pVal); + [propput, id(37), helpstring("property prpString")] HRESULT prpString([in] BSTR newVal); + [propget, id(38), helpstring("property prpFloat")] HRESULT prpFloat([out, retval] float *pVal); + [propput, id(38), helpstring("property prpFloat")] HRESULT prpFloat([in] float newVal); + [propget, id(39), helpstring("property prpDouble")] HRESULT prpDouble([out, retval] double *pVal); + [propput, id(39), helpstring("property prpDouble")] HRESULT prpDouble([in] double newVal); + [propget, id(40), helpstring("property prpVariant")] HRESULT prpVariant([out, retval] VARIANT *pVal); + [propput, id(40), helpstring("property prpVariant")] HRESULT prpVariant([in] VARIANT newVal); + [propget, id(41), helpstring("property prpArray")] HRESULT prpArray([out, retval]SAFEARRAY(VARIANT) *pVal); + [propput, id(41), helpstring("property prpArray")] HRESULT prpArray([in] SAFEARRAY(VARIANT) newVal); + [propget, id(42), helpstring("property prpObject")] HRESULT prpObject([out, retval] IDispatch* *pVal); + [propput, id(42), helpstring("property prpObject")] HRESULT prpObject([in] IDispatch* newVal); + [id(43), helpstring("method mixed1")] HRESULT mixed1( + [in, out] unsigned char* aChar, + [in, out] float *aFloat, + [in,out] VARIANT* inoutVar); + [id(44), helpstring("method inSequenceLong")] HRESULT inSequenceLong([in] SAFEARRAY(long) ar); + [id(45), helpstring("method inSequenceByte")] HRESULT inSequenceByte([in] SAFEARRAY(byte) ar); + [id(46), helpstring("method inSequenceShort")] HRESULT inSequenceShort([in] SAFEARRAY(short) ar); + [id(47), helpstring("method inSequenceString")] HRESULT inSequenceString([in] SAFEARRAY( BSTR) ar); + [id(48), helpstring("method inSequenceFloat")] HRESULT inSequenceFloat([in] SAFEARRAY(float) ar); + [id(49), helpstring("method inSequenceDouble")] HRESULT inSequenceDouble([in] SAFEARRAY(double) ar); + [id(50), helpstring("method inSequenceObject")] HRESULT inSequenceObject([in] SAFEARRAY(IDispatch*) ar); + [id(51), helpstring("method outSequenceByte")] HRESULT outSequenceByte([out] SAFEARRAY(unsigned char)* val); + [id(52), helpstring("method outSequenceShort")] HRESULT outSequenceShort([out] SAFEARRAY(short)* val); + [id(53), helpstring("method outSequenceLong")] HRESULT outSequenceLong([out] SAFEARRAY(long )*val); + [id(54), helpstring("method outSequenceString")] HRESULT outSequenceString([out] SAFEARRAY(BSTR)* val); + [id(55), helpstring("method outSequenceFloat")] HRESULT outSequenceFloat([out] SAFEARRAY(float)* val); + [id(56), helpstring("method outSequenceDouble")] HRESULT outSequenceDouble([out] SAFEARRAY(double)* val); + [id(57), helpstring("method outSequenceObject")] HRESULT outSequenceObject([out] SAFEARRAY(IDispatch*)* val); + [id(58), helpstring("method inoutSequenceByte")] HRESULT inoutSequenceByte([in,out] SAFEARRAY(unsigned char)* val); + [id(59), helpstring("method inoutSequenceShort")] HRESULT inoutSequenceShort([in,out] SAFEARRAY(short)* val); + [id(60), helpstring("method inoutSequenceLong")] HRESULT inoutSequenceLong([in,out] SAFEARRAY( long)*val); + [id(61), helpstring("method inoutSequenceString")] HRESULT inoutSequenceString([in,out] SAFEARRAY(BSTR)* val); + [id(62), helpstring("method inoutSequenceFloat")] HRESULT inoutSequenceFloat([in,out] SAFEARRAY(float)* val); + [id(63), helpstring("method inoutSequenceDouble")] HRESULT inoutSequenceDouble([in,out] SAFEARRAY(double)* val); + [id(64), helpstring("method inoutSequenceObject")] HRESULT inoutSequenceObject([in,out] SAFEARRAY(IDispatch*)* val); + [id(65), helpstring("method inMulDimArrayLong")] HRESULT inMulDimArrayLong([in] SAFEARRAY(long) val ); + [id(66), helpstring("method inMulDimArrayVariant")] HRESULT inMulDimArrayVariant([in] SAFEARRAY(VARIANT) val); + [id(67), helpstring("method inMulDimArrayLong2")] HRESULT inMulDimArrayLong2([in] SAFEARRAY(long) val); + [id(68), helpstring("method inMulDimArrayVariant2")] HRESULT inMulDimArrayVariant2([in] SAFEARRAY(VARIANT) val); + [id(69), helpstring("method inMulDimArrayByte")] HRESULT inMulDimArrayByte([in] SAFEARRAY(unsigned char) val); + [id(70), helpstring("method inMulDimArrayByte2")] HRESULT inMulDimArrayByte2([in] SAFEARRAY(unsigned char) val); + [id(71), helpstring("method outMore")] HRESULT outMore([out]long* val1, [out]long* val2); + + [id(72), helpstring("method optional1")] + HRESULT optional1([in] long val1, [in, optional] VARIANT* val2); + [id(73), helpstring("method optional2")] + HRESULT optional2([out] long* val1, [out, optional] VARIANT* val2); + [id(74), helpstring("method optional3")] + HRESULT optional3([in, optional] VARIANT* val1, [in, optional] VARIANT* val2); + [id(75), helpstring("method optional4")] + HRESULT optional4([in, out, optional] VARIANT* val1, [in, out, optional] VARIANT* val2); + [id(76), helpstring("method optional5")] + HRESULT optional5([out, optional] VARIANT* val1, [out, optional] VARIANT* val2); + //midl creates for val4 a BSTR "4" as default value in the TLB. The midl complains + //but the error message seems to be not for this case. + //in defaultvalue2 val4 has a VT_I4 in the TLB. This must be a bug! + [id(77), helpstring("method defaultvalue1")] + HRESULT defaultvalue1([in, defaultvalue(1)] long val1, + [in, defaultvalue(2)] double* val2, + // [in, defaultvalue(3)] VARIANT val3, //ok + [in, defaultvalue(4)] VARIANT* val4); + + // bug in midl: when val3 and val4 are pointers then the generated header creates + // for all params default values: + //HRESULT STDMETHODCALLTYPE defaultvalue2( + // /* [defaultvalue][in] */ long *val1 = 10, + // /* [defaultvalue][in] */ double *val2 = 3.14, + // /* [defaultvalue][in] */ VARIANT *val3 = 10, + // /* [defaultvalue][in] */ VARIANT *val4 = 100) = 0; + // And that does not compile. + //Therefore we must not include the midl generated header, instead use + // #import to create the interface header + [id(78), helpstring("method defaultvalue2")] + HRESULT defaultvalue2([in, out, defaultvalue(1)]long* val1, + [in, out, defaultvalue(2)] double* val2, + // [in, out, defaultvalue(3)] VARIANT *val3, + [in, out, defaultvalue(4)] VARIANT *val4); + + [id(79), helpstring("method varargfunc1"),vararg] + HRESULT varargfunc1([in] long val1, [in] SAFEARRAY(VARIANT) val2); + [id(80), helpstring("method varargfunc2")] + HRESULT varargfunc2([out] long* val1, [out] SAFEARRAY(VARIANT)* val2); + + + [id(86), helpstring("method inSequenceByteDim2")] HRESULT inSequenceByteDim2([in] SAFEARRAY(byte) val); + [id(87), helpstring("method inCurrency")] HRESULT inCurrency([in] CY val); + [id(88), helpstring("method outCurrency")] HRESULT outCurrency([out] CY* val); + [id(89), helpstring("method inoutCurrency")] HRESULT inoutCurrency([in,out] CY* val); + [id(90), helpstring("method inDate")] HRESULT inDate([in] DATE val); + [id(91), helpstring("method outDate")] HRESULT outDate([out] DATE* val); + [id(92), helpstring("method inoutDate")] HRESULT inoutDate([in,out] DATE* val); + [propget, id(93), helpstring("property prpCY")] HRESULT prpCurrency([out, retval] CY* pVal); + [propput, id(93), helpstring("property prpCY")] HRESULT prpCurrency([in] CY newVal); + [propget, id(94), helpstring("property prpDate")] HRESULT prpDate([out, retval] DATE* pVal); + [propput, id(94), helpstring("property prpDate")] HRESULT prpDate([in] DATE newVal); + [id(95), helpstring("method inDecimal")] HRESULT inDecimal([in] DECIMAL val); + [id(96), helpstring("method outDecimal")] HRESULT outDecimal([out] DECIMAL* val); + [id(97), helpstring("method inoutDecimal")] HRESULT inoutDecimal([in,out] DECIMAL* val); + [propget, id(98), helpstring("property prpDecimal")] HRESULT prpDecimal([out, retval] DECIMAL* pVal); + [propput, id(98), helpstring("property prpDecimal")] HRESULT prpDecimal([in] DECIMAL newVal); + [id(99), helpstring("method inSCode")] HRESULT inSCode([in] SCODE val); + [id(100), helpstring("method outScode")] HRESULT outScode([out] SCODE* val); + [id(101), helpstring("method inoutSCode")] HRESULT inoutSCode([in,out] SCODE* val); + [propget, id(102), helpstring("property prpSCode")] HRESULT prpSCode([out, retval] SCODE* pVal); + [propput, id(102), helpstring("property prpSCode")] HRESULT prpSCode([in] SCODE newVal); + [id(103), helpstring("method inrefLong")] HRESULT inrefLong([in] LONG* val); + [id(104), helpstring("method inrefVARIANT")] HRESULT inrefVariant([in] VARIANT* val); + [id(105), helpstring("method inrefDecimal")] HRESULT inrefDecimal(DECIMAL* val); + [propget, id(106), helpstring("property prpRefLong")] HRESULT prpRefLong([out, retval] long* pVal); + [propputref, id(106), helpstring("property prpRefLong")] HRESULT prpRefLong([in] long* newVal); + [propget, id(107), helpstring("property prprefVariant")] HRESULT prprefVariant([out, retval] VARIANT* pVal); + [propputref, id(107), helpstring("property prprefVariant")] HRESULT prprefVariant([in] VARIANT* newVal); + [propget, id(108), helpstring("property prprefDecimal")] HRESULT prprefDecimal([out, retval] DECIMAL* pVal); + [propputref, id(108), helpstring("property prprefDecimal")] HRESULT prprefDecimal([in] DECIMAL* newVal); + [id(109), helpstring("method optional6")] HRESULT optional6([in,optional] VARIANT* val1, + [in,optional] VARIANT * val2, [in,optional] VARIANT* val3, [in,optional] VARIANT* val4); + [id(110), helpstring("method optional7")] HRESULT optional7([out,optional] VARIANT* val1, + [out,optional] VARIANT * val2, [out,optional] VARIANT* val3, [out,optional] VARIANT* val4); + + [propget, id(111), helpstring("property prpMultiArg1")] HRESULT prpMultiArg1([in,out,optional] VARIANT* val1, [in,out,optional] VARIANT* val2, [out, optional, retval] VARIANT* pVal); + [propput, id(111), helpstring("property prpMultiArg1")] HRESULT prpMultiArg1([in,out,optional] VARIANT* val1, [in,out,optional] VARIANT* val2, [in] VARIANT* newVal); + [propget, id(112), helpstring("property prpMultiArg2")] HRESULT prpMultiArg2([in] VARIANT val1, [out, retval] VARIANT* pVal); + [propput, id(112), helpstring("property prpMultiArg2")] HRESULT prpMultiArg2([in] VARIANT val1, [in] VARIANT newVal); + [id(113), helpstring("method prpMultiArg2GetValues")] HRESULT prpMultiArg2GetValues([out] VARIANT* val1, [out] VARIANT* valProperty); + [propget, id(114), helpstring("property prpMultiArg3")] HRESULT prpMultiArg3([in,out] LONG* val1, [out, retval] LONG* pVal); + [propput, id(114), helpstring("property prpMultiArg3")] HRESULT prpMultiArg3([in,out] LONG* val1, [in] LONG newVal); + [id(115), helpstring("method inUnknown")] HRESULT inUnknown([in] IUnknown* val); + [id(116), helpstring("method outUnknown")] HRESULT outUnknown([out] IUnknown** val); + [id(117), helpstring("method inoutUnknown")] HRESULT inoutUnknown([in,out] IUnknown** val); + [propget, id(118), helpstring("property prpUnknown")] HRESULT prpUnknown([out, retval] IUnknown** pVal); + [propput, id(118), helpstring("property prpUnknown")] HRESULT prpUnknown([in] IUnknown* newVal); +}; + +[ + object, + uuid(96E6105A-A436-48b3-BFE7-C9302D927CCF), + dual, + helpstring("IFoo Interface"), + pointer_default(unique) +] +interface IFoo : IUnknown +{ + HRESULT Foo([in] IUnknown* val); +}; + +[ + uuid(BFE10EB1-8584-11D4-8335-005004526AB4), + version(1.0), + helpstring("AxTestComponents 1.0 Type Library") +] +library AXTESTCOMPONENTSLib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + + [ + uuid(BFE10EBE-8584-11D4-8335-005004526AB4), + helpstring("Basic Class") + ] + coclass Basic + { + [default] interface IBasic; + }; + + [ + uuid(14DE9D5D-EB9D-4091-8E1B-A1B1672D8C1D), + helpstring("Foo Class") + ] + coclass Foo + { + [default] interface IFoo; + }; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/AxTestComponents/AxTestComponents.rc b/extensions/test/ole/AxTestComponents/AxTestComponents.rc new file mode 100644 index 000000000..da5d58f65 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/AxTestComponents.rc @@ -0,0 +1,155 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +//Microsoft Developer Studio generated resource script. + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS + + +// Generated from the TEXTINCLUDE 2 resource. + +#include "winres.h" + + +#undef APSTUDIO_READONLY_SYMBOLS + + +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + + + +// REGISTRY + + +IDR_BASIC REGISTRY DISCARDABLE "Basic.rgs" +IDR_FOO REGISTRY DISCARDABLE "Basic.rgs" +#endif // German (Germany) resources + + + + +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED + + +// TEXTINCLUDE + + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""AxTestComponents.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC + + +// Version + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "AxTestComponents Module\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "AxTestComponents\0" + VALUE "LegalCopyright", "Copyright 2000\0" + VALUE "OriginalFilename", "AxTestComponents.DLL\0" + VALUE "ProductName", "AxTestComponents Module\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "OLESelfRegister", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + + + +// String Table + + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "AxTestComponents" +END + +#endif // English (U.S.) resources + + + + +#ifndef APSTUDIO_INVOKED + + +// Generated from the TEXTINCLUDE 3 resource. + +1 TYPELIB "AxTestComponents.tlb" + + +#endif // not APSTUDIO_INVOKED + diff --git a/extensions/test/ole/AxTestComponents/AxTestComponents.sln b/extensions/test/ole/AxTestComponents/AxTestComponents.sln new file mode 100644 index 000000000..eadaa373e --- /dev/null +++ b/extensions/test/ole/AxTestComponents/AxTestComponents.sln @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AxTestComponents", "AxTestComponents.vcproj", "{CF6DC513-B04E-420A-A0F9-6D1F4046D098}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release MinDependency|Win32 = Release MinDependency|Win32 + Release MinSize|Win32 = Release MinSize|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release MinDependency|Win32 = Unicode Release MinDependency|Win32 + Unicode Release MinSize|Win32 = Unicode Release MinSize|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Debug|Win32.ActiveCfg = Debug|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Debug|Win32.Build.0 = Debug|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Release MinDependency|Win32.ActiveCfg = Release MinDependency|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Release MinDependency|Win32.Build.0 = Release MinDependency|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Release MinSize|Win32.ActiveCfg = Release MinSize|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Release MinSize|Win32.Build.0 = Release MinSize|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Unicode Release MinDependency|Win32.ActiveCfg = Unicode Release MinDependency|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Unicode Release MinDependency|Win32.Build.0 = Unicode Release MinDependency|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Unicode Release MinSize|Win32.ActiveCfg = Unicode Release MinSize|Win32 + {CF6DC513-B04E-420A-A0F9-6D1F4046D098}.Unicode Release MinSize|Win32.Build.0 = Unicode Release MinSize|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/test/ole/AxTestComponents/AxTestComponents.vcproj b/extensions/test/ole/AxTestComponents/AxTestComponents.vcproj new file mode 100644 index 000000000..078daba3d --- /dev/null +++ b/extensions/test/ole/AxTestComponents/AxTestComponents.vcproj @@ -0,0 +1,819 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/test/ole/AxTestComponents/Basic.cpp b/extensions/test/ole/AxTestComponents/Basic.cpp new file mode 100644 index 000000000..8aad56e8a --- /dev/null +++ b/extensions/test/ole/AxTestComponents/Basic.cpp @@ -0,0 +1,1356 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include "Basic.h" + + + +// CBasic +CBasic::CBasic(): m_cPrpByte(0),m_nPrpShort(0),m_lPrpLong(0),m_fPrpFloat(0), m_dPrpDouble(0),m_PrpArray(0), +m_safearray(NULL), m_bool(VARIANT_FALSE), +m_arByte(0), m_arShort(0), m_arLong(0), m_arString(0), m_arVariant(0), m_arFloat(0), +m_arDouble(0), m_arObject(0), m_arByteDim2(0), m_date(0.), m_scode(0) + +{ + memset(&m_cy, 0, sizeof(CY)); + memset(&m_decimal, 0, sizeof(DECIMAL)); +} + +CBasic::~CBasic() +{ + SafeArrayDestroy(m_safearray); + SafeArrayDestroy(m_arByte); + SafeArrayDestroy(m_arShort); + SafeArrayDestroy(m_arLong); + SafeArrayDestroy(m_arString); + SafeArrayDestroy(m_arVariant); + SafeArrayDestroy(m_arFloat); + SafeArrayDestroy(m_arDouble); + SafeArrayDestroy(m_arObject); + SafeArrayDestroy(m_arByteDim2); + +} +STDMETHODIMP CBasic::inBool(VARIANT_BOOL val) +{ + m_bool = val; + return S_OK; +} +STDMETHODIMP CBasic::inByte(unsigned char val) +{ + m_byte = val; + return S_OK; +} + +STDMETHODIMP CBasic::inShort(short val) +{ + m_short = val; + return S_OK; +} + +STDMETHODIMP CBasic::inLong(long val) +{ + m_long = val; + return S_OK; +} + +STDMETHODIMP CBasic::inString(BSTR val) +{ + m_bstr = val; + return S_OK; +} + +STDMETHODIMP CBasic::inFloat(float val) +{ + m_float = val; + return S_OK; +} + +STDMETHODIMP CBasic::inDouble(double val) +{ + m_double = val; + + CComVariant varDest; + CComVariant varSource(val); + HRESULT hr = VariantChangeType(&varDest, &varSource, 0, VT_BSTR); + return S_OK; +} + +STDMETHODIMP CBasic::inVariant(VARIANT val) +{ + m_var1 = val; + return S_OK; +} + +STDMETHODIMP CBasic::inArray(LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_safearray))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, &m_safearray))) + return hr; + return S_OK; +} + +STDMETHODIMP CBasic::inObject(IDispatch *val) +{ + m_obj = val; + return S_OK; +} + +STDMETHODIMP CBasic::inoutBool(VARIANT_BOOL* val) +{ + VARIANT_BOOL aBool = *val; + *val = m_bool; + m_bool = aBool; + return S_OK; +} + + +STDMETHODIMP CBasic::inoutByte(unsigned char* val) +{ + unsigned char aByte = *val; + *val = m_byte; + m_byte = aByte; + return S_OK; +} + +STDMETHODIMP CBasic::inoutShort(short *val) +{ + short aShort = *val; + *val = m_short; + m_short = aShort; + return S_OK; +} + +STDMETHODIMP CBasic::inoutLong(long *val) +{ + long aLong = *val; + *val = m_long; + m_long = aLong; + return S_OK; +} + +STDMETHODIMP CBasic::inoutString(BSTR *val) +{ + CComBSTR aStr = *val; + HRESULT hr = S_OK; + if (FAILED( hr = m_bstr.CopyTo(val))) + return hr; + m_bstr = aStr; + return S_OK; +} + +STDMETHODIMP CBasic::inoutFloat(float *val) +{ + float aFloat = *val; + *val = m_float; + m_float = aFloat; + return S_OK; +} + +STDMETHODIMP CBasic::inoutDouble(double *val) +{ + double aDouble = *val; + *val = m_double; + m_double = aDouble; + return S_OK; +} + +STDMETHODIMP CBasic::inoutVariant(VARIANT *val) +{ + CComVariant aVar = *val; + HRESULT hr = S_OK; + if (FAILED(hr = VariantCopy(val, &m_var1))) + return hr; + m_var1 = aVar; + return S_OK; +} + +/* The array contains VARIANT according to IDL. + If the VARIANTs contain strings then we append "out" to each string. +*/ +STDMETHODIMP CBasic::inoutArray(LPSAFEARRAY *val) +{ + SAFEARRAY* aAr = NULL; + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayCopy(*val, &aAr))) + return hr; + if (FAILED(hr = SafeArrayCopy(m_safearray, val))) + return hr; + if (FAILED(hr = SafeArrayCopy(aAr, & m_safearray))) + return hr; + return S_OK; +} + +STDMETHODIMP CBasic::inoutObject(IDispatch **val) +{ + CComPtr disp = *val; + if (*val) + (*val)->Release(); + *val = m_obj; + if (*val) + (*val)->AddRef(); + m_obj = disp; + return S_OK; +} + + +STDMETHODIMP CBasic::outBool(VARIANT_BOOL* val) +{ + *val = m_bool; + return S_OK; +} + +STDMETHODIMP CBasic::outByte(unsigned char *val) +{ + *val= m_byte; + return S_OK; +} + +STDMETHODIMP CBasic::outShort(short *val) +{ + *val= m_short; + return S_OK; +} + +STDMETHODIMP CBasic::outLong(long *val) +{ + *val= m_long; + return S_OK; +} + +STDMETHODIMP CBasic::outString(BSTR *val) +{ + *val= SysAllocString(m_bstr); + return S_OK; +} + +STDMETHODIMP CBasic::outFloat(float *val) +{ + *val= m_float; + return S_OK; +} + +STDMETHODIMP CBasic::outDouble(double *val) +{ + *val= m_double; + return S_OK; +} + +STDMETHODIMP CBasic::outVariant(VARIANT *val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = VariantCopy(val, &m_var1))) + return hr; + return S_OK; +} + +STDMETHODIMP CBasic::outArray(LPSAFEARRAY *val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayCopy(m_safearray, val))) + return false; + return S_OK; +} + +STDMETHODIMP CBasic::outObject(IDispatch* *val) +{ + *val = m_obj; + if (m_obj) + (*val)->AddRef(); + + return S_OK; +} + + +STDMETHODIMP CBasic::get_prpBool(VARIANT_BOOL* pVal) +{ + if (!pVal) return E_POINTER; + *pVal = m_bool; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpBool(VARIANT_BOOL val) +{ + m_bool = val; + return S_OK; +} + + +STDMETHODIMP CBasic::get_prpByte(unsigned char *pVal) +{ + if( !pVal) + return E_POINTER; + *pVal= m_cPrpByte; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpByte(unsigned char newVal) +{ + m_cPrpByte= newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpShort(short *pVal) +{ + if( !pVal) + return E_POINTER; + *pVal= m_nPrpShort; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpShort(short newVal) +{ + m_nPrpShort= newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpLong(long *pVal) +{ + if( !pVal) + return E_POINTER; + *pVal= m_lPrpLong; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpLong(long newVal) +{ + m_lPrpLong= newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpString(BSTR *pVal) +{ + if( !pVal) + return E_POINTER; + m_bstrPrpString.CopyTo( pVal ); + return S_OK; +} + +STDMETHODIMP CBasic::put_prpString(BSTR newVal) +{ + m_bstrPrpString= newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpFloat(float *pVal) +{ + if( !pVal) + return E_POINTER; + *pVal= m_fPrpFloat; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpFloat(float newVal) +{ + m_fPrpFloat= newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpDouble(double *pVal) +{ + if( !pVal) + return E_POINTER; + *pVal= m_dPrpDouble; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpDouble(double newVal) +{ + m_dPrpDouble= newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpVariant(VARIANT *pVal) +{ + if( !pVal) + return E_POINTER; + HRESULT hr = S_OK; + if (FAILED(hr = VariantCopy( pVal, &m_PropVariant))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::put_prpVariant(VARIANT newVal) +{ + m_PropVariant= newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpArray(LPSAFEARRAY *pVal) +{ + if( !pVal) + return E_POINTER; + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayCopy( m_PrpArray, pVal))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::put_prpArray(LPSAFEARRAY newVal) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy( m_PrpArray))) + return hr; + if (FAILED(hr = SafeArrayCopy( newVal, &m_PrpArray))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::get_prpObject(IDispatch **pVal) +{ + if( !pVal) + return E_POINTER; + *pVal= m_PrpObject; + if( *pVal != NULL) + (*pVal)->AddRef(); + return S_OK; +} + +STDMETHODIMP CBasic::put_prpObject(IDispatch *newVal) +{ + m_PrpObject= newVal; + return S_OK; +} + +STDMETHODIMP CBasic::mixed1( + /* [out][in] */ unsigned char *aChar, + /* [out][in] */ float *aFloat, + /* [out][in] */ VARIANT *aVar) + +{ + HRESULT hr= S_OK; + inoutByte(aChar); + inoutFloat(aFloat); + inoutVariant(aVar); + return hr; +} + + + + +// VT_UI1 + +STDMETHODIMP CBasic::inSequenceLong(LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_arLong))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, & m_arLong))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::inSequenceByte( LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_arByte))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, & m_arByte))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::inSequenceShort(LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_arShort))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, & m_arShort))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::inSequenceString(LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_arString))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, & m_arString))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::inSequenceFloat(LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_arFloat))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, & m_arFloat))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::inSequenceDouble(LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_arDouble))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, & m_arDouble))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::inSequenceObject(LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_arObject))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, & m_arObject))) + return hr; + return hr; +} + +void CBasic::printArray( LPSAFEARRAY val, BSTR message, VARTYPE type) +{ + + HRESULT hr= S_OK; + USES_CONVERSION; + long lbound=0; + long ubound= 0; + hr= SafeArrayGetLBound( val, 1, &lbound); + hr= SafeArrayGetUBound( val, 1, &ubound); + long length= ubound - lbound +1; + + CComVariant varElement; + char buf[1024]; + sprintf( buf,"%s", W2A(message)); + + for( long i= 0; i < length ; i++) + { + char tmp[1024]; + long data=0; + CComVariant var; + switch( type) + { + case VT_UI1: + case VT_I2: + case VT_I4: + case VT_ERROR: + hr= SafeArrayGetElement( val, &i, (void*)&data); + sprintf( tmp, "%ld \n", *(long*)&data); + break; + case VT_BSTR: + hr= SafeArrayGetElement( val, &i, (void*)&data); + sprintf( tmp, "%S \n", (BSTR)data); + break; + case VT_VARIANT: + hr= SafeArrayGetElement( val, &i, &var); + sprintf( tmp, "%x \n", var.byref); + break; + case VT_R4: + hr= SafeArrayGetElement( val, &i, (void*)&data); + sprintf( tmp, "%f \n", *(float*) &data); + break; + case VT_R8: ; + hr= SafeArrayGetElement( val, &i, (void*)&data); + sprintf( tmp, "%f \n", *(double*) &data); + break; + case VT_DISPATCH: + // we assume the objects are instances of this component and have the + // property prpString set. + hr= SafeArrayGetElement( val, &i, (void*)&data); + IDispatch* pdisp= ( IDispatch*) data; + CComDispatchDriver driver( pdisp); + CComVariant var; + if( pdisp) + { + driver.GetPropertyByName(L"prpString", &var); + sprintf( tmp, "%x : %S \n", *(long*)&data, var.bstrVal); + } + else + sprintf( tmp, "%x\n", *(long*)&data); + } + + strcat( buf, tmp); + } + MessageBox( NULL, _T(A2T(buf)), _T("AxTestComponents.Basic"), MB_OK); + +} +// V_ERROR OLECHAR VARIANT VT_UI1 + +STDMETHODIMP CBasic::outSequenceByte(LPSAFEARRAY* val) +{ + HRESULT hr= S_OK; + hr = SafeArrayCopy(m_arByte, val); + return hr; +} + +STDMETHODIMP CBasic::outSequenceShort(LPSAFEARRAY* val) +{ + HRESULT hr= S_OK; + hr = SafeArrayCopy(m_arShort, val); + return hr; +} + +STDMETHODIMP CBasic::outSequenceLong(LPSAFEARRAY* val) +{ + HRESULT hr= S_OK; + hr = SafeArrayCopy(m_arLong, val); + return hr; +} + +STDMETHODIMP CBasic::outSequenceString(LPSAFEARRAY* val) +{ + HRESULT hr= S_OK; + hr = SafeArrayCopy(m_arString, val); + return hr; +} + +STDMETHODIMP CBasic::outSequenceFloat(LPSAFEARRAY* val) +{ + HRESULT hr= S_OK; + hr = SafeArrayCopy(m_arFloat, val); + return hr; +} + +STDMETHODIMP CBasic::outSequenceDouble(LPSAFEARRAY* val) +{ + HRESULT hr= S_OK; + hr = SafeArrayCopy(m_arDouble, val); + return hr; +} + +STDMETHODIMP CBasic::outSequenceObject(LPSAFEARRAY* val) +{ + HRESULT hr = S_OK; + hr = SafeArrayCopy(m_arObject, val); + return S_OK; +} + +STDMETHODIMP CBasic::inoutSequenceByte(LPSAFEARRAY* val) +{ + HRESULT hr = S_OK; + SAFEARRAY *arTemp = NULL; + if (FAILED(hr = SafeArrayCopy(*val, &arTemp))) + return hr; + if (FAILED(hr = SafeArrayCopy(m_arByte, val))) + return hr; + m_arByte = arTemp; + return hr; +} + +STDMETHODIMP CBasic::inoutSequenceShort(LPSAFEARRAY* val) +{ + HRESULT hr = S_OK; + SAFEARRAY *arTemp = NULL; + if (FAILED(hr = SafeArrayCopy(*val, &arTemp))) + return hr; + if (FAILED(hr = SafeArrayCopy(m_arShort, val))) + return hr; + m_arShort = arTemp; + return hr; +} + +STDMETHODIMP CBasic::inoutSequenceLong(LPSAFEARRAY* val) +{ + HRESULT hr = S_OK; + SAFEARRAY *arTemp = NULL; + if (FAILED(hr = SafeArrayCopy(*val, &arTemp))) + return hr; + if (FAILED(hr = SafeArrayCopy(m_arLong, val))) + return hr; + m_arLong = arTemp; + return hr; +} + +STDMETHODIMP CBasic::inoutSequenceString(LPSAFEARRAY* val) +{ + HRESULT hr = S_OK; + SAFEARRAY *arTemp = NULL; + if (FAILED(hr = SafeArrayCopy(*val, &arTemp))) + return hr; + if (FAILED(hr = SafeArrayCopy(m_arString, val))) + return hr; + m_arString = arTemp; + return hr; +} + +STDMETHODIMP CBasic::inoutSequenceFloat(LPSAFEARRAY* val) +{ + HRESULT hr = S_OK; + SAFEARRAY *arTemp = NULL; + if (FAILED(hr = SafeArrayCopy(*val, &arTemp))) + return hr; + if (FAILED(hr = SafeArrayCopy(m_arFloat, val))) + return hr; + m_arFloat = arTemp; + return hr; +} + +STDMETHODIMP CBasic::inoutSequenceDouble(LPSAFEARRAY* val) +{ + HRESULT hr = S_OK; + SAFEARRAY *arTemp = NULL; + if (FAILED(hr = SafeArrayCopy(*val, &arTemp))) + return hr; + if (FAILED(hr = SafeArrayCopy(m_arDouble, val))) + return hr; + m_arDouble = arTemp; + return hr; +} + +STDMETHODIMP CBasic::inoutSequenceObject(LPSAFEARRAY* val) +{ + HRESULT hr = S_OK; + SAFEARRAY *arTemp = NULL; + if (FAILED(hr = SafeArrayCopy(*val, &arTemp))) + return hr; + if (FAILED(hr = SafeArrayCopy(m_arObject, val))) + return hr; + m_arObject = arTemp; + return hr; +} + +// 2-dimensional Array +STDMETHODIMP CBasic::inMulDimArrayLong(LPSAFEARRAY val) +{ + printMulArray( val, VT_I4); + return S_OK; +} +// 2-dimensional Array +STDMETHODIMP CBasic::inMulDimArrayVariant(LPSAFEARRAY val) +{ + printMulArray( val, VT_VARIANT); + return S_OK; +} +// 3-dimensional Array +STDMETHODIMP CBasic::inMulDimArrayLong2(LPSAFEARRAY val) +{ + printMulArray( val, VT_I4); + return S_OK; +} +// 3-dimensional Array +STDMETHODIMP CBasic::inMulDimArrayVariant2(LPSAFEARRAY val) +{ + return S_OK; +} + + +STDMETHODIMP CBasic::inMulDimArrayByte(LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_arByteDim2))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, & m_arByteDim2))) + return hr; + return hr; +} +// 3-dimensionales array +STDMETHODIMP CBasic::inMulDimArrayByte2(LPSAFEARRAY val) +{ + + // TODO: Add your implementation code here + //printMulArray( val, VT_UI1); + return S_OK; +} + +// supports 2 and 3 dimensional SAFEARRAY with elements of long or VARIANT +void CBasic::printMulArray( SAFEARRAY* val, VARTYPE type) +{ + HRESULT hr= S_OK; + UINT dims= SafeArrayGetDim( val); + long lbound1; + long ubound1; + long lbound2; + long ubound2; + long lbound3; + long ubound3; + long length1; + long length2; + + char buff[4096]; + buff[0]=0; + + if( dims == 2) + { + hr= SafeArrayGetLBound( val, 1, &lbound1); + hr= SafeArrayGetUBound( val, 1, &ubound1); + length1= ubound1 - lbound1 +1; + + hr= SafeArrayGetLBound( val, 2, &lbound2); + hr= SafeArrayGetUBound( val, 2, &ubound2); + length2= ubound2 - lbound2 + 1; + char tmpBuf[1024]; + tmpBuf[0]=0; + long index[2]; + for( long i= 0; i< length2; i++) + { + for( long j= 0; jvt != VT_ERROR) + m_var1 = *val2; + return S_OK; +} + +STDMETHODIMP CBasic::optional2(/*[out]*/ long* val1,/*[out, optional]*/ VARIANT* val2) +{ + HRESULT hr = S_OK; + *val1 = m_long; + + if (val2->vt != VT_ERROR) + hr = VariantCopy(val2, & m_var1); + return hr; +} + +STDMETHODIMP CBasic::optional3(/*[in, optional]*/ VARIANT* val1,/*[in, optional]*/ VARIANT* val2) +{ + //if (val1->vt != VT_ERROR) + m_var1 = *val1; + + //if (val2->vt != VT_ERROR) + m_var2 = *val2; + return S_OK; +} + +STDMETHODIMP CBasic::optional4(/*[in, out, optional]*/ VARIANT* val1, + /*[in, out, optional]*/ VARIANT* val2) +{ + HRESULT hr = S_OK; + //return the previously set in values + if (val1->vt != VT_ERROR) + { + CComVariant var1(*val1); + if (FAILED(hr = VariantCopy(val1, & m_var1))) + return hr; + m_var1 = var1; + } + if (val2->vt != VT_ERROR) + { + CComVariant var2(*val2); + if (FAILED(hr = VariantCopy(val2, & m_var2))) + return hr; + m_var2 = var2; + } + return hr; +} + +STDMETHODIMP CBasic::optional5(/*[out, optional]*/ VARIANT* val1, + /*[out, optional]*/ VARIANT* val2) +{ + HRESULT hr = S_OK; + if (FAILED(hr = VariantCopy(val1, &m_var1))) + return hr; + if (FAILED(hr = VariantCopy(val2, &m_var2))) + return hr; + return hr; +} + +STDMETHODIMP CBasic::defaultvalue1(/*[in, defaultvalue(10)]*/ long val1, + /*[in, defaultvalue(3.14)]*/ double* val2, + // /*[in, defaultvalue(10)]*/ VARIANT val3, + /*[in, defaultvalue(100)]*/ VARIANT* val4) +{ + m_long = val1; + m_double = *val2; +// m_var1 = val3; + m_var2 = *val4; + return S_OK; +} +STDMETHODIMP CBasic::defaultvalue2(/*[in, out, defaultvalue(10)]*/ long* val1, + /*[in, out, defaultvalue(3.14)]*/ double* val2, + // /*[in, out, defaultvalue(10)]*/ VARIANT* val3, + /*[in, out, defaultvalue(100)]*/ VARIANT* val4) +{ + HRESULT hr = S_OK; + long aLong = *val1; + double aDouble = *val2; +// CComVariant var1(*val3); + CComVariant var2(*val4); + *val1 = m_long; + *val2 = m_double; + //if (FAILED(hr = VariantCopy(val3, &m_var1))) + // return hr; + if (FAILED(hr = VariantCopy(val4, &m_var2))) + return hr; + m_long = aLong; + m_double = aDouble; +// m_var1 = var1; + m_var2 = var2; + return hr; +} +/* val2 contains the variable argument list. If no such arguments are supplied + then the safearray is invalid. SafeArrayCopy then returns E_INVALIDARG +*/ +STDMETHODIMP CBasic::varargfunc1(/*[in]*/ long val1,/*[in]*/ LPSAFEARRAY val2) +{ + m_long = val1; + + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_safearray))) + return hr; + if (FAILED(hr = SafeArrayCopy(val2, & m_safearray))) + { + if (hr != E_INVALIDARG) + return hr; + } + return S_OK; +} + +STDMETHODIMP CBasic::varargfunc2(/*[out]*/ long* val1, /*[out]*/ SAFEARRAY ** val2) +{ + *val1 = m_long; + HRESULT hr = SafeArrayCopy(m_safearray, val2); + return hr; +} + +STDMETHODIMP CBasic::inSequenceByteDim2(LPSAFEARRAY val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = SafeArrayDestroy(m_arByteDim2))) + return hr; + if (FAILED(hr = SafeArrayCopy(val, & m_arByteDim2))) + return hr; + return hr; +} + + +STDMETHODIMP CBasic::inCurrency(CY val) +{ + m_cy = val; + return S_OK; +} + +STDMETHODIMP CBasic::outCurrency(CY* val) +{ + *val = m_cy; + return S_OK; +} + +STDMETHODIMP CBasic::inoutCurrency(CY* val) +{ + CY tmp = *val; + *val = m_cy; + m_cy = tmp; + return S_OK; +} + +STDMETHODIMP CBasic::inDate(DATE val) +{ + m_date = val; + return S_OK; +} + +STDMETHODIMP CBasic::outDate(DATE* val) +{ + *val = m_date; + return S_OK; +} + +STDMETHODIMP CBasic::inoutDate(DATE* val) +{ + DATE tmp = *val; + *val = m_date; + m_date = tmp; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpCurrency(CY* pVal) +{ + *pVal = m_cy; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpCurrency(CY newVal) +{ + m_cy = newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpDate(DATE* pVal) +{ + *pVal = m_date; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpDate(DATE newVal) +{ + m_date = newVal; + return S_OK; +} + +//VT_I4 DECIMAL_NEG //tagVARIANT DISPATCH_PROPERTYPUT +STDMETHODIMP CBasic::inDecimal(DECIMAL val) +{ + m_decimal = val; + return S_OK; +} + +STDMETHODIMP CBasic::outDecimal(DECIMAL* val) +{ + * val = m_decimal; + return S_OK; +} + +STDMETHODIMP CBasic::inoutDecimal(DECIMAL* val) +{ + DECIMAL tmp; + tmp = * val; + * val = m_decimal; + m_decimal = tmp; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpDecimal(DECIMAL* pVal) +{ + * pVal = m_decimal; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpDecimal(DECIMAL newVal) +{ + m_decimal = newVal; + return S_OK; +} + +STDMETHODIMP CBasic::inSCode(SCODE val) +{ + m_scode = val; + return S_OK; +} + +STDMETHODIMP CBasic::outScode(SCODE* val) +{ + * val = m_scode; + return S_OK; +} + +STDMETHODIMP CBasic::inoutSCode(SCODE* val) +{ + SCODE tmp = *val; + * val = m_scode; + m_scode = tmp; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpSCode(SCODE* pVal) +{ + * pVal = m_scode; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpSCode(SCODE newVal) +{ + m_scode = newVal; + return S_OK; +} + +STDMETHODIMP CBasic::inrefLong(LONG* val) +{ + m_long = * val; + return S_OK; +} + +STDMETHODIMP CBasic::inrefVariant(VARIANT* val) +{ + HRESULT hr = S_OK; + if (FAILED(hr = VariantCopy( & m_var1, val))) + return hr; + return S_OK; +} + +STDMETHODIMP CBasic::inrefDecimal(DECIMAL* val) +{ + m_decimal = * val; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpRefLong(long* pVal) +{ + *pVal = m_long; + return S_OK; +} + +STDMETHODIMP CBasic::putref_prpRefLong(long* newVal) +{ + m_long = * newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prprefVariant(VARIANT* pVal) +{ + HRESULT hr = S_OK; + hr = VariantCopy(pVal, & m_var1); + return hr; +} + +STDMETHODIMP CBasic::putref_prprefVariant(VARIANT* newVal) +{ + m_var1 = * newVal; + return S_OK; +} + +STDMETHODIMP CBasic::get_prprefDecimal(DECIMAL* pVal) +{ + * pVal = m_decimal; + return S_OK; +} + +STDMETHODIMP CBasic::putref_prprefDecimal(DECIMAL* newVal) +{ + m_decimal = *newVal; + return S_OK; +} + + +STDMETHODIMP CBasic::optional6(VARIANT* val1, VARIANT* val2, VARIANT* val3, VARIANT* val4) +{ + HRESULT hr = S_OK; + if (FAILED(hr = m_var1.Copy(val1))) + return hr; + if (FAILED(hr = m_var2.Copy(val2))) + return hr; + if (FAILED(hr = m_var3.Copy(val3))) + return hr; + if (FAILED(hr = m_var4.Copy(val4))) + return hr; + return S_OK; +} + +STDMETHODIMP CBasic::optional7(VARIANT* val1, VARIANT* val2, VARIANT* val3, VARIANT* val4) +{ + HRESULT hr = S_OK; + if (FAILED(hr = VariantCopy(val1, & m_var1))) + return hr; + if (FAILED(hr = VariantCopy(val2, & m_var2))) + return hr; + if (FAILED(hr = VariantCopy(val3, & m_var3))) + return hr; + if (FAILED(hr = VariantCopy(val4, & m_var4))) + return hr; + + return S_OK; +} + +STDMETHODIMP CBasic::get_prpMultiArg1(VARIANT* val1, VARIANT* val2, VARIANT* pVal) +{ + HRESULT hr = S_OK; + CComVariant tmp1(*val1); + CComVariant tmp2(*val2); + + if (FAILED(hr = VariantCopy(val1, & m_var1))) + return hr; + if (FAILED(hr = VariantCopy(val2, & m_var2))) + return hr; + m_var1 = tmp1; + m_var2 = tmp2; + if (FAILED(hr = VariantCopy(pVal, & m_var3))) + return hr; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpMultiArg1(VARIANT* val1, VARIANT* val2, VARIANT* newVal) +{ + HRESULT hr = S_OK; + CComVariant tmp1( * val1); + CComVariant tmp2( * val2); + + if (FAILED(hr = VariantCopy(val1, & m_var1))) + return hr; + if (FAILED(hr = VariantCopy(val2, & m_var2))) + return hr; + m_var1 = tmp1; + m_var2 = tmp2; + + m_var3 = *newVal; + return S_OK; +} + +// tagVARIANT DISPATCH_PROPERTYPUT DISPID_PROPERTYPUT VARIANTARG LOCALE_USER_DEFAULT + +STDMETHODIMP CBasic::get_prpMultiArg2(VARIANT val1, VARIANT* pVal) +{ + HRESULT hr = S_OK; + m_var1 = val1; + + if (FAILED(hr = VariantCopy(pVal, & m_var2))) + return hr; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpMultiArg2(VARIANT val1, VARIANT newVal) +{ + m_var1 = val1; + m_var2 = newVal; + return S_OK; +} + +// returns the values set by prpMultiArg2 +STDMETHODIMP CBasic::prpMultiArg2GetValues(VARIANT* val1, VARIANT* valProperty) +{ + HRESULT hr = S_OK; + if (FAILED(VariantCopy(val1, & m_var1))) + return hr; + if (FAILED(VariantCopy(valProperty, & m_var2))) + return hr; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpMultiArg3(LONG* val1, LONG* pVal) +{ + long aLong = *val1; + *val1 = m_long; + m_long = aLong; + + * pVal = m_long2; + return S_OK; +} + +STDMETHODIMP CBasic::put_prpMultiArg3(LONG* val1, LONG newVal) +{ + long aLong = *val1; + *val1 = m_long; + m_long = aLong; + + m_long2 = newVal; + return S_OK; +} + +STDMETHODIMP CBasic::inUnknown(IUnknown* val) +{ + m_unknown = val; + + return S_OK; +} + +STDMETHODIMP CBasic::outUnknown(IUnknown** val) +{ + m_unknown.CopyTo(val); + return S_OK; +} + +STDMETHODIMP CBasic::inoutUnknown(IUnknown** val) +{ + CComPtr tmp = *val; + m_unknown.CopyTo(val); + m_unknown = tmp; + return S_OK; +} + +STDMETHODIMP CBasic::get_prpUnknown(IUnknown** pVal) +{ + m_prpUnknown.CopyTo(pVal); + return S_OK; +} + +STDMETHODIMP CBasic::put_prpUnknown(IUnknown* newVal) +{ + m_prpUnknown = newVal; + return S_OK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/AxTestComponents/Basic.h b/extensions/test/ole/AxTestComponents/Basic.h new file mode 100644 index 000000000..eec04aa08 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/Basic.h @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// Basic.h : Declaration of the CBasic + +#ifndef __BASIC_H_ +#define __BASIC_H_ + +#include "resource.h" +#import "AxTestComponents.tlb" no_namespace no_implementation raw_interfaces_only named_guids + + +// CBasic +class ATL_NO_VTABLE CBasic : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl + { +public: + CBasic(); + ~CBasic(); + + DECLARE_REGISTRY_RESOURCEID(IDR_BASIC) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CBasic) + COM_INTERFACE_ENTRY(IBasic) + COM_INTERFACE_ENTRY(IDispatch) + END_COM_MAP() + + // IBasic +public: + STDMETHOD(outMore)(/*[out]*/long* val1, /*[out]*/long* val2); + STDMETHOD(inMulDimArrayByte2)(LPSAFEARRAY val); + STDMETHOD(inMulDimArrayByte)(LPSAFEARRAY val); + STDMETHOD(inMulDimArrayVariant2)(LPSAFEARRAY val); + STDMETHOD(inMulDimArrayLong2)(LPSAFEARRAY val); + STDMETHOD(inMulDimArrayVariant)(LPSAFEARRAY val); + STDMETHOD(inMulDimArrayLong)( LPSAFEARRAY val); + STDMETHOD(inoutSequenceObject)(LPSAFEARRAY* val); + STDMETHOD(inoutSequenceDouble)(LPSAFEARRAY * val); + STDMETHOD(inoutSequenceFloat)(LPSAFEARRAY * val); + STDMETHOD(inoutSequenceString)(LPSAFEARRAY* val); + STDMETHOD(inoutSequenceLong)(LPSAFEARRAY * val); + STDMETHOD(inoutSequenceShort)(LPSAFEARRAY * val); + STDMETHOD(inoutSequenceByte)(LPSAFEARRAY * val); + STDMETHOD(outSequenceObject)(/*[out]*/ LPSAFEARRAY* val); + STDMETHOD(outSequenceDouble)(/*[out]*/ LPSAFEARRAY* val); + STDMETHOD(outSequenceFloat)(/*[out]*/ LPSAFEARRAY* val); + STDMETHOD(outSequenceString)(/*[out]*/ LPSAFEARRAY* val); + STDMETHOD(outSequenceLong)(/*[out]*/ LPSAFEARRAY* val); + STDMETHOD(outSequenceShort)(/*[out]*/ LPSAFEARRAY* val); + STDMETHOD(outSequenceByte)(/*[out]*/ LPSAFEARRAY* val); + STDMETHOD(inSequenceObject)(LPSAFEARRAY ar); + STDMETHOD(inSequenceDouble)(LPSAFEARRAY ar); + STDMETHOD(inSequenceFloat)(LPSAFEARRAY ar); + STDMETHOD(inSequenceString)(LPSAFEARRAY ar); + STDMETHOD(inSequenceShort)(LPSAFEARRAY ar); + STDMETHOD(inSequenceByte)(LPSAFEARRAY ar); + STDMETHOD(inSequenceLong)(LPSAFEARRAY ar); + STDMETHOD(mixed1)( + /* [out][in] */ unsigned char *aChar, + /* [out][in] */ float *aFloat, + /* [out][in] */ VARIANT *aVar); + STDMETHOD(get_prpObject)(/*[out, retval]*/ IDispatch* *pVal); + STDMETHOD(put_prpObject)(/*[in]*/ IDispatch* newVal); + STDMETHOD(get_prpArray)(/*[out, retval]*/ LPSAFEARRAY *pVal); + STDMETHOD(put_prpArray)(/*[in]*/ LPSAFEARRAY newVal); + STDMETHOD(get_prpVariant)(/*[out, retval]*/ VARIANT *pVal); + STDMETHOD(put_prpVariant)(/*[in]*/ VARIANT newVal); + STDMETHOD(get_prpDouble)(/*[out, retval]*/ double *pVal); + STDMETHOD(put_prpDouble)(/*[in]*/ double newVal); + STDMETHOD(get_prpFloat)(/*[out, retval]*/ float *pVal); + STDMETHOD(put_prpFloat)(/*[in]*/ float newVal); + STDMETHOD(get_prpString)(/*[out, retval]*/ BSTR *pVal); + STDMETHOD(put_prpString)(/*[in]*/ BSTR newVal); + STDMETHOD(get_prpLong)(/*[out, retval]*/ long *pVal); + STDMETHOD(put_prpLong)(/*[in]*/ long newVal); + STDMETHOD(get_prpShort)(/*[out, retval]*/ short *pVal); + STDMETHOD(put_prpShort)(/*[in]*/ short newVal); + STDMETHOD(get_prpByte)(/*[out, retval]*/ unsigned char *pVal); + STDMETHOD(put_prpByte)(/*[in]*/ unsigned char newVal); + STDMETHOD(get_prpBool)(/*[out, retval]*/ VARIANT_BOOL *pVal); + STDMETHOD(put_prpBool)(/*[in]*/ VARIANT_BOOL newVal); + + STDMETHOD(outObject)(/*[out]*/ IDispatch* *val); + STDMETHOD(outArray)(/*[out]*/ LPSAFEARRAY * val); + STDMETHOD(outVariant)(/*[out]*/ VARIANT* val); + STDMETHOD(outDouble)(/*[out]*/ double* val); + STDMETHOD(outFloat)(/*[out]*/ float* val); + STDMETHOD(outString)(/*[out]*/ BSTR* val); + STDMETHOD(outLong)(/*[out]*/ long* val); + STDMETHOD(outShort)(/*[out]*/ short* val); + STDMETHOD(outByte)(/*[out]*/ unsigned char* val); + STDMETHOD(outBool)(/*[out]*/ VARIANT_BOOL* val); + + STDMETHOD(inoutObject)(/*[in,out]*/ IDispatch* *val); + STDMETHOD(inoutArray)(/*[in,out]*/ LPSAFEARRAY * val); + STDMETHOD(inoutVariant)(/*[in,out]*/ VARIANT * val); + STDMETHOD(inoutDouble)(/*[in,out]*/ double * val); + STDMETHOD(inoutFloat)(/*[in,out]*/ float * val); + STDMETHOD(inoutString)(/*[in, out]*/ BSTR* val); + STDMETHOD(inoutLong)(/*[in,out]*/ long * val); + STDMETHOD(inoutShort)(/*[in,out]*/ short* val); + STDMETHOD(inoutByte)(/*[in,out]*/ unsigned char* val); + STDMETHOD(inoutBool)(/*[in,out]*/ VARIANT_BOOL* val); + + + STDMETHOD(inObject)(/*[in]*/ IDispatch* val); + STDMETHOD(inArray)(/*[in]*/ LPSAFEARRAY val); + STDMETHOD(inVariant)(/*[in]*/ VARIANT val); + STDMETHOD(inDouble)(/*[in]*/ double val); + STDMETHOD(inFloat)(/*[in]*/ float val); + STDMETHOD(inString)(/*[in]*/ BSTR val); + STDMETHOD(inLong)(/*[in]*/ long val); + STDMETHOD(inShort)(/*[in]*/ short val); + STDMETHOD(inByte)(/*[in]*/ unsigned char val); + STDMETHOD(inBool)(/*[in]*/ VARIANT_BOOL val); + + + STDMETHOD(optional1)(/*[in]*/ long val1, /*[in, optional]*/ VARIANT* val2); + STDMETHOD(optional2)(/*[out]*/ long* val1,/*[out, optional]*/ VARIANT* val2); + STDMETHOD(optional3)(/*[in, optional]*/ VARIANT* val1,/*[in, optional]*/ VARIANT* val2); + STDMETHOD(optional4)(/*[in, out, optional]*/ VARIANT* val1,/*[in, out, optional]*/ VARIANT* val2); + STDMETHOD(optional5)(/*[out, optional]*/ VARIANT* val1,/*[out, optional]*/ VARIANT* val2); + + + STDMETHOD(defaultvalue1)(/*[in, defaultvalue(10)]*/ long val1, + /*[in, defaultvalue(3.14)]*/ double* val2, + /*[in, defaultvalue(100)]*/ VARIANT* val4); + + STDMETHOD(defaultvalue2)(/*[in, out, defaultvalue(10)]*/ long* val1, + /*[in, out, defaultvalue(3.14)]*/ double* val2, + /*[in, out, defaultvalue(100)]*/ VARIANT* val4); + + STDMETHOD(varargfunc1)(/*[in]*/ long val1,/*[in]*/ LPSAFEARRAY val2); + + STDMETHOD(varargfunc2)(/*[out]*/ long* val1, /*[out]*/ SAFEARRAY ** val2); + + + // members for property implementations + unsigned char m_cPrpByte; + short m_nPrpShort; + long m_lPrpLong; + float m_fPrpFloat; + double m_dPrpDouble; + CComPtr m_PrpObject; + CComPtr m_prpUnknown; + + CComBSTR m_bstrPrpString; + CComVariant m_PropVariant; + LPSAFEARRAY m_PrpArray; +protected: + VARIANT_BOOL m_bool; + unsigned char m_byte; + short m_short; + long m_long; + long m_long2; + float m_float; + double m_double; + CComVariant m_var1; + CComVariant m_var2; + CComVariant m_var3; + CComVariant m_var4; + CComBSTR m_bstr; + CY m_cy; + DATE m_date; + DECIMAL m_decimal; + SCODE m_scode; + SAFEARRAY * m_safearray; + CComPtr m_obj; + CComPtr m_unknown; + + SAFEARRAY * m_arByte; + SAFEARRAY * m_arShort; + SAFEARRAY * m_arLong; + SAFEARRAY * m_arString; + SAFEARRAY * m_arVariant; + SAFEARRAY * m_arFloat; + SAFEARRAY * m_arDouble; + SAFEARRAY * m_arObject; + SAFEARRAY * m_arByteDim2; + + static void printArray(LPSAFEARRAY val, BSTR message, VARTYPE type); + static void printMulArray(LPSAFEARRAY val, VARTYPE type); + + +public: + STDMETHOD(inSequenceByteDim2)(LPSAFEARRAY val); + STDMETHOD(inCurrency)(CY val); + STDMETHOD(outCurrency)(CY* val); + STDMETHOD(inoutCurrency)(CY* val); + STDMETHOD(inDate)(DATE val); + STDMETHOD(outDate)(DATE* val); + STDMETHOD(inoutDate)(DATE* val); + STDMETHOD(get_prpCurrency)(CY* pVal); + STDMETHOD(put_prpCurrency)(CY newVal); + STDMETHOD(get_prpDate)(DATE* pVal); + STDMETHOD(put_prpDate)(DATE newVal); + STDMETHOD(inDecimal)(DECIMAL val); + STDMETHOD(outDecimal)(DECIMAL* val); + STDMETHOD(inoutDecimal)(DECIMAL* val); + STDMETHOD(get_prpDecimal)(DECIMAL* pVal); + STDMETHOD(put_prpDecimal)(DECIMAL newVal); + STDMETHOD(inSCode)(SCODE val); + STDMETHOD(outScode)(SCODE* val); + STDMETHOD(inoutSCode)(SCODE* val); + STDMETHOD(get_prpSCode)(SCODE* pVal); + STDMETHOD(put_prpSCode)(SCODE newVal); + STDMETHOD(inrefLong)(LONG* val); + STDMETHOD(inrefVariant)(VARIANT* val); + STDMETHOD(inrefDecimal)(DECIMAL* val); + STDMETHOD(get_prpRefLong)(long* pVal); + STDMETHOD(putref_prpRefLong)(long* newVal); + STDMETHOD(get_prprefVariant)(VARIANT* pVal); + STDMETHOD(putref_prprefVariant)(VARIANT* newVal); + STDMETHOD(get_prprefDecimal)(DECIMAL* pVal); + STDMETHOD(putref_prprefDecimal)(DECIMAL* newVal); + STDMETHOD(optional6)(VARIANT* val1, VARIANT* val2, VARIANT* val3, VARIANT* val4); + STDMETHOD(optional7)(VARIANT* val1, VARIANT* val2, VARIANT* val3, VARIANT* val4); + + STDMETHOD(get_prpMultiArg1)(VARIANT* val1, VARIANT* val2, VARIANT* pVal); + //STDMETHOD(get_prpMultiArg1)(VARIANT* val1, VARIANT* pVal); + STDMETHOD(put_prpMultiArg1)(VARIANT* val1, VARIANT* val2, VARIANT* newVal); + //STDMETHOD(put_prpMultiArg1)(VARIANT* val1, VARIANT* newVal); + STDMETHOD(get_prpMultiArg2)(VARIANT val1, VARIANT* pVal); + STDMETHOD(put_prpMultiArg2)(VARIANT val1, VARIANT newVal); + STDMETHOD(prpMultiArg2GetValues)(VARIANT* val1, VARIANT* valProperty); + STDMETHOD(get_prpMultiArg3)(LONG* val1, LONG* pVal); + STDMETHOD(put_prpMultiArg3)(LONG* val1, LONG newVal); + + // IFoo Methods +public: + STDMETHOD(inUnknown)(IUnknown* val); + STDMETHOD(outUnknown)(IUnknown** val); + STDMETHOD(inoutUnknown)(IUnknown** val); + STDMETHOD(get_prpUnknown)(IUnknown** pVal); + STDMETHOD(put_prpUnknown)(IUnknown* newVal); +}; + +#endif //__BASIC_H_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/AxTestComponents/Basic.rgs b/extensions/test/ole/AxTestComponents/Basic.rgs new file mode 100644 index 000000000..67fa86008 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/Basic.rgs @@ -0,0 +1,50 @@ +HKCR +{ + AxTestComponents.Basic.1 = s 'Basic Class' + { + CLSID = s '{BFE10EBE-8584-11D4-8335-005004526AB4}' + } + AxTestComponents.Basic = s 'Basic Class' + { + CLSID = s '{BFE10EBE-8584-11D4-8335-005004526AB4}' + CurVer = s 'AxTestComponents.Basic.1' + } + NoRemove CLSID + { + ForceRemove {BFE10EBE-8584-11D4-8335-005004526AB4} = s 'Basic Class' + { + ProgID = s 'AxTestComponents.Basic.1' + VersionIndependentProgID = s 'AxTestComponents.Basic' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{BFE10EB1-8584-11D4-8335-005004526AB4}' + } + } + AxTestComponents.Foo.1 = s 'Foo Class' + { + CLSID = s '{14DE9D5D-EB9D-4091-8E1B-A1B1672D8C1D}' + } + AxTestComponents.Foo = s 'Foo Class' + { + CLSID = s '{14DE9D5D-EB9D-4091-8E1B-A1B1672D8C1D}' + CurVer = s 'AxTestComponents.Foo.1' + } + NoRemove CLSID + { + ForceRemove {14DE9D5D-EB9D-4091-8E1B-A1B1672D8C1D} = s 'Foo Class' + { + ProgID = s 'AxTestComponents.Foo.1' + VersionIndependentProgID = s 'AxTestComponents.Foo' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{BFE10EB1-8584-11D4-8335-005004526AB4}' + } + } + +} diff --git a/extensions/test/ole/AxTestComponents/Foo.cpp b/extensions/test/ole/AxTestComponents/Foo.cpp new file mode 100644 index 000000000..9faefd393 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/Foo.cpp @@ -0,0 +1,30 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include "Foo.h" + +// CBasic +CFoo::CFoo() {} + +CFoo::~CFoo() {} + +STDMETHODIMP CFoo::Foo(IUnknown* pVal) { return S_OK; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/AxTestComponents/Foo.h b/extensions/test/ole/AxTestComponents/Foo.h new file mode 100644 index 000000000..3d0dc5bb5 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/Foo.h @@ -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 . + */ +// Basic.h : Declaration of the CBasic + +#pragma once + +#include "resource.h" +#import "AxTestComponents.tlb" no_namespace no_implementation raw_interfaces_only named_guids + + +// CBasic +class ATL_NO_VTABLE CFoo : + public CComObjectRootEx, + public CComCoClass, + public IFoo + +// public IDispatchImpl +{ +public: + CFoo(); + ~CFoo(); + + DECLARE_REGISTRY_RESOURCEID(IDR_BASIC) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CFoo) + COM_INTERFACE_ENTRY(IFoo) + END_COM_MAP() + + +STDMETHOD(Foo)(IUnknown* val); + + // IFoo Methods +public: +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/AxTestComponents/StdAfx.cpp b/extensions/test/ole/AxTestComponents/StdAfx.cpp new file mode 100644 index 000000000..71ebbdb6b --- /dev/null +++ b/extensions/test/ole/AxTestComponents/StdAfx.cpp @@ -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 . + */ + +#include "stdafx.h" + +#ifdef _ATL_STATIC_REGISTRY +#include +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/AxTestComponents/StdAfx.h b/extensions/test/ole/AxTestComponents/StdAfx.h new file mode 100644 index 000000000..211943ce4 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/StdAfx.h @@ -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 . + */ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#if !defined(AFX_STDAFX_H__BFE10EB4_8584_11D4_8335_005004526AB4__INCLUDED_) +#define AFX_STDAFX_H__BFE10EB4_8584_11D4_8335_005004526AB4__INCLUDED_ + +#ifdef _MSC_VER +#pragma once +#endif + +#define STRICT +#define _ATL_APARTMENT_THREADED + +#include +//You may derive a class from CComModule and use it if you want to override +//something, but do not change the name of _Module +extern CComModule _Module; +#include +#include +#include + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__BFE10EB4_8584_11D4_8335_005004526AB4__INCLUDED) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/AxTestComponents/readme.txt b/extensions/test/ole/AxTestComponents/readme.txt new file mode 100644 index 000000000..6f19ea610 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/readme.txt @@ -0,0 +1,3 @@ +The component does not use the AxTestComponent.h created by the midl +compiler. Instead #import is used. This is because of a bug when +using attribute "defaultvalue" in idl. diff --git a/extensions/test/ole/AxTestComponents/resource.h b/extensions/test/ole/AxTestComponents/resource.h new file mode 100644 index 000000000..e741826b5 --- /dev/null +++ b/extensions/test/ole/AxTestComponents/resource.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by AxTestComponents.rc + +#define IDS_PROJNAME 100 +#define IDR_BASIC 101 +//#define IDR_FOO 501 + +// Next default values for new objects + +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/DCOM/Clients/WriterDemo/Module1.bas b/extensions/test/ole/DCOM/Clients/WriterDemo/Module1.bas new file mode 100644 index 000000000..88153b174 --- /dev/null +++ b/extensions/test/ole/DCOM/Clients/WriterDemo/Module1.bas @@ -0,0 +1,25 @@ +rem +rem This file is part of the LibreOffice project. +rem +rem This Source Code Form is subject to the terms of the Mozilla Public +rem License, v. 2.0. If a copy of the MPL was not distributed with this +rem file, You can obtain one at http://mozilla.org/MPL/2.0/. +rem +rem This file incorporates work covered by the following license notice: +rem +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed +rem with this work for additional information regarding copyright +rem ownership. The ASF licenses this file to you under the Apache +rem License, Version 2.0 (the "License"); you may not use this file +rem except in compliance with the License. You may obtain a copy of +rem the License at http://www.apache.org/licenses/LICENSE-2.0 . +rem +Attribute VB_Name = "Module1" +Option Explicit + +Sub main() + Dim obj As Object + Set obj = CreateObject("dcomtest.writerdemo.wsc") + obj.run +End Sub diff --git a/extensions/test/ole/DCOM/Clients/WriterDemo/client_writerdemo.vbp b/extensions/test/ole/DCOM/Clients/WriterDemo/client_writerdemo.vbp new file mode 100644 index 000000000..ca477cff6 --- /dev/null +++ b/extensions/test/ole/DCOM/Clients/WriterDemo/client_writerdemo.vbp @@ -0,0 +1,33 @@ +Type=Exe +Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINNT\System32\stdole2.tlb#OLE Automation +Module=Module1; Module1.bas +Startup="Sub Main" +HelpFile="" +Command32="" +Name="client_writerdemo" +HelpContextID="0" +CompatibleMode="0" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionCompanyName="StarOffice" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=0 +Unattended=0 +Retained=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 + +[MS Transaction Server] +AutoRefresh=1 diff --git a/extensions/test/ole/DCOM/Clients/WriterDemo/client_writerdemo.vbw b/extensions/test/ole/DCOM/Clients/WriterDemo/client_writerdemo.vbw new file mode 100644 index 000000000..067d7529e --- /dev/null +++ b/extensions/test/ole/DCOM/Clients/WriterDemo/client_writerdemo.vbw @@ -0,0 +1 @@ +Module1 = 108, 108, 685, 544, diff --git a/extensions/test/ole/DCOM/Clients/WriterDemo/readme.txt b/extensions/test/ole/DCOM/Clients/WriterDemo/readme.txt new file mode 100644 index 000000000..1d5a63492 --- /dev/null +++ b/extensions/test/ole/DCOM/Clients/WriterDemo/readme.txt @@ -0,0 +1,4 @@ +Visual Basic client that instantiates a Windows Script Component +,dcomtest.writerdemo.wsc. That component is located in +extensions/test/ole/DCOM/scriptComponents/WriterDemo.wsc. Don't forget to +register that component (right-click,select register). diff --git a/extensions/test/ole/DCOM/dcom_test/Module1.bas b/extensions/test/ole/DCOM/dcom_test/Module1.bas new file mode 100644 index 000000000..27908068c --- /dev/null +++ b/extensions/test/ole/DCOM/dcom_test/Module1.bas @@ -0,0 +1,55 @@ +rem +rem This file is part of the LibreOffice project. +rem +rem This Source Code Form is subject to the terms of the Mozilla Public +rem License, v. 2.0. If a copy of the MPL was not distributed with this +rem file, You can obtain one at http://mozilla.org/MPL/2.0/. +rem +rem This file incorporates work covered by the following license notice: +rem +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed +rem with this work for additional information regarding copyright +rem ownership. The ASF licenses this file to you under the Apache +rem License, Version 2.0 (the "License"); you may not use this file +rem except in compliance with the License. You may obtain a copy of +rem the License at http://www.apache.org/licenses/LICENSE-2.0 . +rem +Attribute VB_Name = "Module1" +Option Explicit + +Sub main() + +MsgBox "hallo" + +'The service manager is always the starting point +'If there is no office running then an office is started up +Dim objServiceManager As Object +Set objServiceManager = CreateObject("com.sun.star.ServiceManager") + +'Create the CoreReflection service that is later used to create structs +Set objCoreReflection = objServiceManager.createInstance("com.sun.star.reflection.CoreReflection") + +'Create the Desktop +Set objDesktop = objServiceManager.createInstance("com.sun.star.frame.Desktop") + +'Open a new empty writer document + +Set objCoreReflection = objServiceManager.createInstance("com.sun.star.reflection.CoreReflection") +'get a type description class for Size +Set propClass = objCoreReflection.forName("com.sun.star.beans.PropertyValue") + +Dim prop +propClass.CreateObject prop +prop.Name = "Hidden" +prop.Value = True + +'create the actual object +Dim args(0) +Set args(0) = prop + +Dim args2() +'Set objDocument= objDesktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, args) +Set objDocument = objDesktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, args2) + +End Sub diff --git a/extensions/test/ole/DCOM/dcom_test/dcom_test.vbp b/extensions/test/ole/DCOM/dcom_test/dcom_test.vbp new file mode 100644 index 000000000..5b896434f --- /dev/null +++ b/extensions/test/ole/DCOM/dcom_test/dcom_test.vbp @@ -0,0 +1,37 @@ +Type=Exe +Reference=*\G{00020430-0000-0000-C000-000000000046}#2.0#0#C:\WINNT\System32\stdole2.tlb#OLE Automation +Module=Module1; ..\..\..\..\..\..\Projects\VBasic\dcom_test\Module1.bas +Startup="Sub Main" +HelpFile="" +Title="dcom_test" +ExeName32="dcom_test.exe" +Path32="..\..\..\..\..\..\Projects\VBasic\dcom_test" +Command32="" +Name="dcom_test" +HelpContextID="0" +CompatibleMode="0" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionCompanyName="StarOffice" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=0 +Unattended=0 +Retained=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 +DebugStartupOption=0 + +[MS Transaction Server] +AutoRefresh=1 diff --git a/extensions/test/ole/DCOM/dcom_test/dcom_test.vbw b/extensions/test/ole/DCOM/dcom_test/dcom_test.vbw new file mode 100644 index 000000000..dfe34e0d1 --- /dev/null +++ b/extensions/test/ole/DCOM/dcom_test/dcom_test.vbw @@ -0,0 +1 @@ +Module1 = 1, 1, 849, 604, Z diff --git a/extensions/test/ole/DCOM/dcom_test/readme.txt b/extensions/test/ole/DCOM/dcom_test/readme.txt new file mode 100644 index 000000000..215d6f409 --- /dev/null +++ b/extensions/test/ole/DCOM/dcom_test/readme.txt @@ -0,0 +1,5 @@ +The program creates the com.sun.star.Servicemanager on a remote machine: + +Set objServiceManager = CreateObject("com.sun.star.ServiceManager", "\\jl-1036") + +creates a document and writes in it. \ No newline at end of file diff --git a/extensions/test/ole/DCOM/scriptComponents/WriterDemo.wsc b/extensions/test/ole/DCOM/scriptComponents/WriterDemo.wsc new file mode 100644 index 000000000..51419022f --- /dev/null +++ b/extensions/test/ole/DCOM/scriptComponents/WriterDemo.wsc @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + diff --git a/extensions/test/ole/DCOM/scriptComponents/readme.txt b/extensions/test/ole/DCOM/scriptComponents/readme.txt new file mode 100644 index 000000000..5fa3a8bb7 --- /dev/null +++ b/extensions/test/ole/DCOM/scriptComponents/readme.txt @@ -0,0 +1,12 @@ +WriterDemo.wsc +================================================================================= +Register the component by right-clicking on the file in the file explorer and select +register. +The component registered as being remotable.That is, it has got an AppID entry (with +a DllSurrogate subkey).That enables us to use dcomcnfg.exe in order to set AccessPermissions,etc. +which is necessary because of the use of the JScript Array object. The automation +bridge will query for IDispatchEx,which is a call from server to client.Hence the server +needs the proper right within the client. + +The component implements a run function, which runs the demo example that is written +in JScript. diff --git a/extensions/test/ole/EventListenerSample/EventListener/EventListener.cpp b/extensions/test/ole/EventListenerSample/EventListener/EventListener.cpp new file mode 100644 index 000000000..ad42dda62 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/EventListener.cpp @@ -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 . + */ +// EventListener.cpp : Implementation of DLL Exports. + +// Note: Proxy/Stub Information +// To build a separate proxy/stub DLL, +// run nmake -f EventListenerps.mk in the project directory. + +#include "stdafx.h" +#include "resource.h" +#include +#include "EventListener.h" + +#include "EventListener_i.c" +#include "EvtListener.h" + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_EvtListener, CEvtListener) +END_OBJECT_MAP() + +// DLL Entry Point + +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_EVENTLISTENERLib); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + return TRUE; // ok +} + +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow(void) { return (_Module.GetLockCount() == 0) ? S_OK : S_FALSE; } + +// Returns a class factory to create an object of the requested type + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + +// DllRegisterServer - Adds entries to the system registry + +STDAPI DllRegisterServer(void) +{ + // registers object, typelib and all interfaces in typelib + return _Module.RegisterServer(TRUE); +} + +// DllUnregisterServer - Removes entries from the system registry + +STDAPI DllUnregisterServer(void) { return _Module.UnregisterServer(TRUE); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/EventListenerSample/EventListener/EventListener.def b/extensions/test/ole/EventListenerSample/EventListener/EventListener.def new file mode 100644 index 000000000..9d88a68f7 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/EventListener.def @@ -0,0 +1,9 @@ +; EventListener.def : Declares the module parameters. + +LIBRARY "EventListener.DLL" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/extensions/test/ole/EventListenerSample/EventListener/EventListener.idl b/extensions/test/ole/EventListenerSample/EventListener/EventListener.idl new file mode 100644 index 000000000..3ed514074 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/EventListener.idl @@ -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 . + */ + +// EventListener.idl : IDL source for EventListener.dll + + +// This file will be processed by the MIDL tool to +// produce the type library (EventListener.tlb) and marshalling code. + +import "oaidl.idl"; +import "ocidl.idl"; + [ + object, + uuid(86653399-24C6-4C2B-9E8A-564175250CB2), + dual, + helpstring("IEvtListener interface"), + pointer_default(unique) + ] + interface IEvtListener : IDispatch + { + [id(1), helpstring("Method disposing")] HRESULT disposing([in] IDispatch* source); + }; + +[ + uuid(E3E61535-3262-45E6-BFD9-EE8AED051BD1), + version(1.0), + helpstring("EventListener 1.0 Type Library") +] +library EVENTLISTENERLib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + + [ + uuid(830E0743-87C1-4C99-A77A-5FBA0C2EBD9A), + helpstring("EvtListener Class") + ] + coclass EvtListener + { + [default] interface IEvtListener; + }; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/EventListenerSample/EventListener/EventListener.rc b/extensions/test/ole/EventListenerSample/EventListener/EventListener.rc new file mode 100644 index 000000000..2de599591 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/EventListener.rc @@ -0,0 +1,154 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// Microsoft Developer Studio generated resource script. + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS + + +// Generated from the TEXTINCLUDE 2 resource. + +#include "winres.h" + + +#undef APSTUDIO_READONLY_SYMBOLS + + +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED + + +// TEXTINCLUDE + + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""EventListener.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC + + +// Version + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "EventListener Module\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "EventListener\0" + VALUE "LegalCopyright", "Copyright 2001\0" + VALUE "OriginalFilename", "EventListener.DLL\0" + VALUE "ProductName", "EventListener Module\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "OLESelfRegister", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + + + +// String Table + + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "EventListener" +END + +#endif // German (Germany) resources + + + + +// English (USA) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + + + +// REGISTRY + + +IDR_EVTLISTENER REGISTRY DISCARDABLE "EvtListener.rgs" +#endif // English (USA) resources + + + + +#ifndef APSTUDIO_INVOKED + + +// Generated from the TEXTINCLUDE 3 resource. + +1 TYPELIB "EventListener.tlb" + + +#endif // not APSTUDIO_INVOKED + diff --git a/extensions/test/ole/EventListenerSample/EventListener/EventListener.sln b/extensions/test/ole/EventListenerSample/EventListener/EventListener.sln new file mode 100644 index 000000000..3837163ef --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/EventListener.sln @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EventListener", "EventListener.vcproj", "{055137B6-A402-4913-AC11-9A096E866F5B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release MinDependency|Win32 = Release MinDependency|Win32 + Release MinSize|Win32 = Release MinSize|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release MinDependency|Win32 = Unicode Release MinDependency|Win32 + Unicode Release MinSize|Win32 = Unicode Release MinSize|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {055137B6-A402-4913-AC11-9A096E866F5B}.Debug|Win32.ActiveCfg = Debug|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Debug|Win32.Build.0 = Debug|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Release MinDependency|Win32.ActiveCfg = Release MinDependency|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Release MinDependency|Win32.Build.0 = Release MinDependency|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Release MinSize|Win32.ActiveCfg = Release MinSize|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Release MinSize|Win32.Build.0 = Release MinSize|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Unicode Release MinDependency|Win32.ActiveCfg = Unicode Release MinDependency|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Unicode Release MinDependency|Win32.Build.0 = Unicode Release MinDependency|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Unicode Release MinSize|Win32.ActiveCfg = Unicode Release MinSize|Win32 + {055137B6-A402-4913-AC11-9A096E866F5B}.Unicode Release MinSize|Win32.Build.0 = Unicode Release MinSize|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/test/ole/EventListenerSample/EventListener/EventListener.vcproj b/extensions/test/ole/EventListenerSample/EventListener/EventListener.vcproj new file mode 100644 index 000000000..e8aef5532 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/EventListener.vcproj @@ -0,0 +1,927 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/test/ole/EventListenerSample/EventListener/EvtListener.cpp b/extensions/test/ole/EventListenerSample/EventListener/EvtListener.cpp new file mode 100644 index 000000000..677981749 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/EvtListener.cpp @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// EvtListener.cpp : Implementation of CEvtListener +#include "stdafx.h" +#include "EventListener.h" +#include "EvtListener.h" + + +// CEvtListener + +STDMETHODIMP CEvtListener::disposing( IDispatch* source) +{ + ::MessageBox(NULL,_T("XEventListener::disposing"), + _T("EventListener.EvtListener component"), MB_OK); + return S_OK; +} + +CEvtListener::~CEvtListener() +{ + +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/EventListenerSample/EventListener/EvtListener.h b/extensions/test/ole/EventListenerSample/EventListener/EvtListener.h new file mode 100644 index 000000000..6705864db --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/EvtListener.h @@ -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 . + */ +// EvtListener.h : Declaration of CEvtListener + +#pragma once + +#include "resource.h" + + +// CEvtListener +class ATL_NO_VTABLE CEvtListener : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CEvtListener() + { + } + ~CEvtListener(); + +DECLARE_REGISTRY_RESOURCEID(IDR_EVTLISTENER) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CEvtListener) + COM_INTERFACE_ENTRY(IEvtListener) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + +// IEvtListener +public: + STDMETHOD(disposing)(IDispatch* source); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/EventListenerSample/EventListener/EvtListener.rgs b/extensions/test/ole/EventListenerSample/EventListener/EvtListener.rgs new file mode 100644 index 000000000..e0aa9bbb7 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/EvtListener.rgs @@ -0,0 +1,26 @@ +HKCR +{ + EventListener.EvtListener.1 = s 'EvtListener Class' + { + CLSID = s '{830E0743-87C1-4C99-A77A-5FBA0C2EBD9A}' + } + EventListener.EvtListener = s 'EvtListener Class' + { + CLSID = s '{830E0743-87C1-4C99-A77A-5FBA0C2EBD9A}' + CurVer = s 'EventListener.EvtListener.1' + } + NoRemove CLSID + { + ForceRemove {830E0743-87C1-4C99-A77A-5FBA0C2EBD9A} = s 'EvtListener Class' + { + ProgID = s 'EventListener.EvtListener.1' + VersionIndependentProgID = s 'EventListener.EvtListener' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{E3E61535-3262-45E6-BFD9-EE8AED051BD1}' + } + } +} diff --git a/extensions/test/ole/EventListenerSample/EventListener/StdAfx.cpp b/extensions/test/ole/EventListenerSample/EventListener/StdAfx.cpp new file mode 100644 index 000000000..da0608bfd --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/StdAfx.cpp @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +#ifdef _ATL_STATIC_REGISTRY +#include +#include +#endif + +#include + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/EventListenerSample/EventListener/StdAfx.h b/extensions/test/ole/EventListenerSample/EventListener/StdAfx.h new file mode 100644 index 000000000..c901a6dbe --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/StdAfx.h @@ -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 . + */ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#if !defined(AFX_STDAFX_H__E275407A_804A_477E_9A28_F5CA84E711C3__INCLUDED_) +#define AFX_STDAFX_H__E275407A_804A_477E_9A28_F5CA84E711C3__INCLUDED_ + +#ifdef _MSC_VER +#pragma once +#endif + +#define STRICT +#define _ATL_APARTMENT_THREADED + +#include +//You may derive a class from CComModule and use it if you want to override +//something, but do not change the name of _Module +extern CComModule _Module; +#include + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__E275407A_804A_477E_9A28_F5CA84E711C3__INCLUDED) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/EventListenerSample/EventListener/resource.h b/extensions/test/ole/EventListenerSample/EventListener/resource.h new file mode 100644 index 000000000..783a14507 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/EventListener/resource.h @@ -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 . + */ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by EventListener.rc + +#define IDS_PROJNAME 100 +#define IDR_EVTLISTENER 101 + +// Next default values for new objects + +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/EventListenerSample/VBEventListener/Module1.bas b/extensions/test/ole/EventListenerSample/VBEventListener/Module1.bas new file mode 100644 index 000000000..aafd265a0 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/VBEventListener/Module1.bas @@ -0,0 +1,9 @@ +Attribute VB_Name = "Module1" +Option Explicit + + +Sub Main() + +End Sub + + diff --git a/extensions/test/ole/EventListenerSample/VBEventListener/VBEventListener.cls b/extensions/test/ole/EventListenerSample/VBEventListener/VBEventListener.cls new file mode 100644 index 000000000..f3c09aa4d --- /dev/null +++ b/extensions/test/ole/EventListenerSample/VBEventListener/VBEventListener.cls @@ -0,0 +1,69 @@ +' +' This file is part of the LibreOffice project. +' +' This Source Code Form is subject to the terms of the Mozilla Public +' License, v. 2.0. If a copy of the MPL was not distributed with this +' file, You can obtain one at http://mozilla.org/MPL/2.0/. +' +' This file incorporates work covered by the following license notice: +' +' Licensed to the Apache Software Foundation (ASF) under one or more +' contributor license agreements. See the NOTICE file distributed +' with this work for additional information regarding copyright +' ownership. The ASF licenses this file to you under the Apache +' License, Version 2.0 (the "License"); you may not use this file +' except in compliance with the License. You may obtain a copy of +' the License at http://www.apache.org/licenses/LICENSE-2.0 . +' + +VERSION 1.0 CLASS +BEGIN + MultiUse = -1 'True + Persistable = 0 'NotPersistable + DataBindingBehavior = 0 'vbNone + DataSourceBehavior = 0 'vbNone + MTSTransactionMode = 0 'NotAnMTSObject +END +Attribute VB_Name = "VBEventListener" +Attribute VB_GlobalNameSpace = False +Attribute VB_Creatable = True +Attribute VB_PredeclaredId = False +Attribute VB_Exposed = True +Option Explicit +Private interfaces(0) As String +Private bDisposingCalled As Boolean +Private bQuiet As Boolean + +Public Property Get Bridge_ImplementedInterfaces() As Variant + Bridge_ImplementedInterfaces = interfaces +End Property + +Private Sub Class_Initialize() +interfaces(0) = "com.sun.star.lang.XEventListener" +bDisposingCalled = False +bQuiet = False +End Sub + +Private Sub Class_Terminate() + On Error Resume Next + Debug.Print "Terminate VBEventListener" +End Sub + +Public Sub disposing(ByVal source As Object) + If bQuiet = False Then + MsgBox "disposing called" + End If + bDisposingCalled = True +End Sub + +Public Sub setQuiet(quiet As Boolean) + bQuiet = quiet +End Sub + +Public Sub resetDisposing() + bDisposingCalled = False +End Sub + +Public Function disposingCalled() + disposingCalled = bDisposingCalled +End Function diff --git a/extensions/test/ole/EventListenerSample/VBEventListener/VBasicEventListener.vbp b/extensions/test/ole/EventListenerSample/VBEventListener/VBasicEventListener.vbp new file mode 100644 index 000000000..f89b866be --- /dev/null +++ b/extensions/test/ole/EventListenerSample/VBEventListener/VBasicEventListener.vbp @@ -0,0 +1,38 @@ +Type=OleDll +Class=VBEventListener; VBEventListener.cls +Module=Module1; Module1.bas +Startup="Sub Main" +HelpFile="" +ExeName32="VBasicEventListener.dll" +Command32="" +Name="VBasicEventListener" +HelpContextID="0" +Description="Implementation of UNO XEventListener" +CompatibleMode="1" +CompatibleEXE32="VBasicEventListener.dll" +MajorVer=1 +MinorVer=0 +RevisionVer=0 +AutoIncrementVer=0 +ServerSupportFiles=0 +VersionCompanyName="StarOffice" +CompilationType=0 +OptimizationType=0 +FavorPentiumPro(tm)=0 +CodeViewDebugInfo=0 +NoAliasing=0 +BoundsCheck=0 +OverflowCheck=0 +FlPointCheck=0 +FDIVCheck=0 +UnroundedFP=0 +StartMode=1 +Unattended=0 +Retained=0 +ThreadPerObject=0 +MaxNumberOfThreads=1 +ThreadingModel=1 +DebugStartupOption=0 + +[MS Transaction Server] +AutoRefresh=1 diff --git a/extensions/test/ole/EventListenerSample/VBEventListener/VBasicEventListener.vbw b/extensions/test/ole/EventListenerSample/VBEventListener/VBasicEventListener.vbw new file mode 100644 index 000000000..76699ee81 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/VBEventListener/VBasicEventListener.vbw @@ -0,0 +1,2 @@ +VBEventListener = 132, 132, 732, 748, +Module1 = 64, 33, 849, 530, diff --git a/extensions/test/ole/EventListenerSample/VBEventListener/readme.txt b/extensions/test/ole/EventListenerSample/VBEventListener/readme.txt new file mode 100644 index 000000000..417c102b0 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/VBEventListener/readme.txt @@ -0,0 +1,7 @@ +VBasicEventListener.dll is an ActiveX component written with VisualBasic. The +component registers on the system with a particular ID. When the library is build +this ID is generated, unless a previously build library exists. Then the ID of that +library is used. In order to use always the same ID, the library must be as binary in +the cvs. + +The library can be used under the licences noted in VBEventListener.cls. diff --git a/extensions/test/ole/EventListenerSample/events.htm b/extensions/test/ole/EventListenerSample/events.htm new file mode 100644 index 000000000..0fae7eee9 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/events.htm @@ -0,0 +1,115 @@ + + + + + +Document Title + + + + + + +

+The script on this page creates a new StarOffice document and connects an event listener +to it. When the document is closed then the XEventListener::disposing method is called on the +listener object. How the listener is set up depends on the button being clicked. +

+

+The button will run JScript code and that adds a JScript event listener to the document. +The listener is also implemented in JScript and is on this page. +

+ +

+ +The button runs JScript code that creates the ActiveX component EventListener.EvtListener that +is written in C++ and housed in a DLL. Then the event listener is added to the document. +

+ +

+The button runs VBScript code that creates the components EventListener.EvtListener and adds it +to the document. +

+ +

+Runs VBScript code that creates VBasicEventListener.VBEventListener ActiveX component which was +written with VB. +

+ + + + + + diff --git a/extensions/test/ole/EventListenerSample/readme.txt b/extensions/test/ole/EventListenerSample/readme.txt new file mode 100644 index 000000000..0e7b1f646 --- /dev/null +++ b/extensions/test/ole/EventListenerSample/readme.txt @@ -0,0 +1,20 @@ +EventListener +======================================== + +The folder EventListener contains an MSDEV project that builds a DLL that +contains the EventListener.EvtListener ActiveX component. The component +implements the XEventListener interface according to the rules of the +OleBridge. The component will be used from the HTML page events.htm. + + +VBEventListener: +======================================== + +Contains a Visual Basic project that builds an ActiveX component that implements +com.sun.star.lang.XEventListener. Its ProgId is +VBasicEventListener.VBEventListener. The DLL should also be checked in. VB needs +its TLB, so it uses the same CLSIDs on the next build. The component will create +a message box when its disposing function has been called. + +The project also contains a client that builds a Project1.exe (in the same +folder) that creates VBEventListener and adds it to a StarOffice document. diff --git a/extensions/test/ole/JScriptNewStyle.htm b/extensions/test/ole/JScriptNewStyle.htm new file mode 100644 index 000000000..28b928630 --- /dev/null +++ b/extensions/test/ole/JScriptNewStyle.htm @@ -0,0 +1,1071 @@ + + + + + +Document Title + + + + + + + +
+ + + +

JScript with _GetValueObject

+Tests Array/Sequence conversion.
+All methods receive a Sequence as Parameter. The element type of the Sequence is written on the buttons. +
+ + + + + + + + + + + + +

+ + +Out Parameter
+ + + + + + + + + + + + + + + + + +

+In Out Parameter
+ + + + + + + + + + + + + +

+ +Tests Array/Sequence conversion with Attributes. All params are of type Sequence and + the element type of the Sequence is written on the buttons.
+ + + + + + + + + + + + + +

+ + + +

Visual Basic Tests

+Test array /Sequence conversion and return value
+Template: Sequence < type > method( Sequence< type > ) +

+ + + + +

+ + +Out parameter
+Template: void method( Sequence < type > )
+ + +

+ + + + diff --git a/extensions/test/ole/MfcControl/MfcControl.cpp b/extensions/test/ole/MfcControl/MfcControl.cpp new file mode 100644 index 000000000..7ae701349 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControl.cpp @@ -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 . + */ +// MfcControl.cpp : Implementation of CMfcControlApp and DLL registration. + +#include "stdafx.h" +#include "MfcControl.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +CMfcControlApp theApp; + +const GUID CDECL BASED_CODE _tlid + = { 0xac221fb3, 0xa0d8, 0x11d4, { 0x83, 0x3b, 0, 0x50, 0x4, 0x52, 0x6a, 0xb4 } }; +const WORD _wVerMajor = 1; +const WORD _wVerMinor = 0; + +// CMfcControlApp::InitInstance - DLL initialization + +BOOL CMfcControlApp::InitInstance() +{ + BOOL bInit = COleControlModule::InitInstance(); + + if (bInit) + { + // TODO: Add your own module initialization code here. + } + + return bInit; +} + +// CMfcControlApp::ExitInstance - DLL termination + +int CMfcControlApp::ExitInstance() +{ + // TODO: Add your own module termination code here. + + return COleControlModule::ExitInstance(); +} + +// DllRegisterServer - Adds entries to the system registry + +STDAPI DllRegisterServer(void) +{ + AFX_MANAGE_STATE(_afxModuleAddrThis); + + if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid)) + return ResultFromScode(SELFREG_E_TYPELIB); + + if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE)) + return ResultFromScode(SELFREG_E_CLASS); + + return NOERROR; +} + +// DllUnregisterServer - Removes entries from the system registry + +STDAPI DllUnregisterServer(void) +{ + AFX_MANAGE_STATE(_afxModuleAddrThis); + + if (!AfxOleUnregisterTypeLib(_tlid, _wVerMajor, _wVerMinor)) + return ResultFromScode(SELFREG_E_TYPELIB); + + if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE)) + return ResultFromScode(SELFREG_E_CLASS); + + return NOERROR; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/MfcControl/MfcControl.def b/extensions/test/ole/MfcControl/MfcControl.def new file mode 100644 index 000000000..8c164a7b5 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControl.def @@ -0,0 +1,9 @@ +; MfcControl.def : Declares the module parameters. + +LIBRARY "MFCCONTROL.OCX" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE diff --git a/extensions/test/ole/MfcControl/MfcControl.dsp b/extensions/test/ole/MfcControl/MfcControl.dsp new file mode 100644 index 000000000..f327a9893 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControl.dsp @@ -0,0 +1,265 @@ +# Microsoft Developer Studio Project File - Name="MfcControl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=MfcControl - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "MfcControl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "MfcControl.mak" CFG="MfcControl - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "MfcControl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "MfcControl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "MfcControl - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "MfcControl - Win32 Unicode Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "MfcControl - Win32 Release" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Ext "ocx" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Ext "ocx" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Registering ActiveX Control... +OutDir=.\Release +TargetPath=.\Release\MfcControl.ocx +InputPath=.\Release\MfcControl.ocx +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "MfcControl - Win32 Debug" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Ext "ocx" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Ext "ocx" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /FR /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# Begin Custom Build - Registering ActiveX Control... +OutDir=.\Debug +TargetPath=.\Debug\MfcControl.ocx +InputPath=.\Debug\MfcControl.ocx +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "MfcControl - Win32 Unicode Debug" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugU" +# PROP BASE Intermediate_Dir "DebugU" +# PROP BASE Target_Ext "ocx" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Target_Ext "ocx" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "_DEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# Begin Custom Build - Registering ActiveX Control... +OutDir=.\DebugU +TargetPath=.\DebugU\MfcControl.ocx +InputPath=.\DebugU\MfcControl.ocx +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "MfcControl - Win32 Unicode Release" + +# PROP BASE Use_MFC 2 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseU" +# PROP BASE Intermediate_Dir "ReleaseU" +# PROP BASE Target_Ext "ocx" +# PROP BASE Target_Dir "" +# PROP Use_MFC 2 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseU" +# PROP Intermediate_Dir "ReleaseU" +# PROP Target_Ext "ocx" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WINDLL" /D "_AFXDLL" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +# ADD RSC /l 0x409 /d "NDEBUG" /d "_AFXDLL" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Registering ActiveX Control... +OutDir=.\ReleaseU +TargetPath=.\ReleaseU\MfcControl.ocx +InputPath=.\ReleaseU\MfcControl.ocx +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "MfcControl - Win32 Release" +# Name "MfcControl - Win32 Debug" +# Name "MfcControl - Win32 Unicode Debug" +# Name "MfcControl - Win32 Unicode Release" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\MfcControl.cpp +# End Source File +# Begin Source File + +SOURCE=.\MfcControl.def +# End Source File +# Begin Source File + +SOURCE=.\MfcControl.odl +# End Source File +# Begin Source File + +SOURCE=.\MfcControl.rc +# End Source File +# Begin Source File + +SOURCE=.\MfcControlCtl.cpp +# End Source File +# Begin Source File + +SOURCE=.\MfcControlPpg.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\MfcControl.h +# End Source File +# Begin Source File + +SOURCE=.\MfcControlCtl.h +# End Source File +# Begin Source File + +SOURCE=.\MfcControlPpg.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\MfcControlCtl.bmp +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project + diff --git a/extensions/test/ole/MfcControl/MfcControl.h b/extensions/test/ole/MfcControl/MfcControl.h new file mode 100644 index 000000000..49ef5e72f --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControl.h @@ -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 . + */ +#if !defined(AFX_MFCCONTROL_H__AC221FBC_A0D8_11D4_833B_005004526AB4__INCLUDED_) +#define AFX_MFCCONTROL_H__AC221FBC_A0D8_11D4_833B_005004526AB4__INCLUDED_ + +#ifdef _MSC_VER +#pragma once +#endif + +// MfcControl.h : main header file for MFCCONTROL.DLL + +#if !defined(__AFXCTL_H__) +#error include 'afxctl.h' before including this file +#endif + +#include "resource.h" + +// CMfcControlApp : See MfcControl.cpp for implementation. + +class CMfcControlApp : public COleControlModule +{ +public: + BOOL InitInstance(); + int ExitInstance(); +}; + +extern const GUID CDECL _tlid; +extern const WORD _wVerMajor; +extern const WORD _wVerMinor; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_MFCCONTROL_H__AC221FBC_A0D8_11D4_833B_005004526AB4__INCLUDED) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/MfcControl/MfcControl.odl b/extensions/test/ole/MfcControl/MfcControl.odl new file mode 100644 index 000000000..f00ebe518 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControl.odl @@ -0,0 +1,82 @@ +// MfcControl.odl : type library source for ActiveX Control project. + +// This file will be processed by the Make Type Library (mktyplib) tool to +// produce the type library (MfcControl.tlb) that will become a resource in +// MfcControl.ocx. + +#include +#include + +[ uuid(AC221FB3-A0D8-11D4-833B-005004526AB4), version(1.0), + helpfile("MfcControl.hlp"), + helpstring("MfcControl ActiveX Control module"), + control ] +library MFCCONTROLLib +{ + importlib(STDOLE_TLB); + importlib(STDTYPE_TLB); + + // Primary dispatch interface for CMfcControlCtrl + + [ uuid(AC221FB4-A0D8-11D4-833B-005004526AB4), + helpstring("Dispatch interface for MfcControl Control"), hidden ] + dispinterface _DMfcControl + { + properties: + // NOTE - ClassWizard will maintain property information here. + // Use extreme caution when editing this section. + //{{AFX_ODL_PROP(CMfcControlCtrl) + //}}AFX_ODL_PROP + + methods: + // NOTE - ClassWizard will maintain method information here. + // Use extreme caution when editing this section. + //{{AFX_ODL_METHOD(CMfcControlCtrl) + [id(1)] short inShort(short val); + [id(2)] long inLong(long val); + [id(3)] BSTR inString(BSTR* val); + [id(4)] float inFloat(float val); + [id(5)] double inDouble(double val); + [id(6)] VARIANT inVariant(VARIANT val); + [id(7)] IDispatch* inObject(IDispatch* val); + [id(8)] void outShort([out] short* val); + [id(9)] void outLong([out] long* val); + [id(10)] void outString([out] BSTR* val); + [id(11)] void outFloat([out] float* val); + [id(12)] void outDouble([out] double* val); + [id(13)] void outVariant([out] VARIANT* val); + [id(14)] void outObject([out] IDispatch** val); + //}}AFX_ODL_METHOD + }; + + // Event dispatch interface for CMfcControlCtrl + + [ uuid(AC221FB5-A0D8-11D4-833B-005004526AB4), + helpstring("Event interface for MfcControl Control") ] + dispinterface _DMfcControlEvents + { + properties: + // Event interface has no properties + + methods: + // NOTE - ClassWizard will maintain event information here. + // Use extreme caution when editing this section. + //{{AFX_ODL_EVENT(CMfcControlCtrl) + //}}AFX_ODL_EVENT + }; + + // Class information for CMfcControlCtrl + + [ uuid(AC221FB6-A0D8-11D4-833B-005004526AB4), + helpstring("MfcControl Control"), control ] + coclass MfcControl + { + [default] dispinterface _DMfcControl; + [default, source] dispinterface _DMfcControlEvents; + }; + + + //{{AFX_APPEND_ODL}} + //}}AFX_APPEND_ODL}} +}; +//VT_I2 diff --git a/extensions/test/ole/MfcControl/MfcControl.rc b/extensions/test/ole/MfcControl/MfcControl.rc new file mode 100644 index 000000000..49831c231 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControl.rc @@ -0,0 +1,163 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +//Microsoft Visual C++ generated resource script. + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS + + +// Generated from the TEXTINCLUDE 2 resource. + +#include "afxres.h" + + +#undef APSTUDIO_READONLY_SYMBOLS + +#ifdef APSTUDIO_INVOKED + + +// TEXTINCLUDE + + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""MfcControl.tlb""\r\n" + "\0" +END + + +#endif // APSTUDIO_INVOKED + + + + +// Version + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "Star Office Entwicklungs GmbH\0" + VALUE "FileDescription", "MfcControl ActiveX Control Module\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "MfcControl\0" + VALUE "LegalCopyright", "Copyright (C) 2000\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "MfcControl.OCX\0" + VALUE "ProductName", "MfcControl ActiveX Control Module\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "OLESelfRegister", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + + + +// Bitmap + + +//IDB_MFCCONTROL BITMAP DISCARDABLE "MfcControlCtl.bmp" + + + +// Dialog + + + +IDD_PROPPAGE_MFCCONTROL DIALOG DISCARDABLE 0, 0, 250, 62 +STYLE WS_CHILD +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "TODO: Place controls to manipulate properties of MfcControl Control on this dialog.", + IDC_STATIC,7,25,229,16 +END + + + + +// DESIGNINFO + + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_PROPPAGE_MFCCONTROL, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 243 + TOPMARGIN, 7 + BOTTOMMARGIN, 55 + END +END +#endif // APSTUDIO_INVOKED + + + +// String Table + + +STRINGTABLE DISCARDABLE +BEGIN + IDS_MFCCONTROL "MfcControl Control" + IDS_MFCCONTROL_PPG "MfcControl Property Page" + IDS_MFCCONTROL_PPG_CAPTION "General" + +END + + +#ifndef APSTUDIO_INVOKED + + +// Generated from the TEXTINCLUDE 3 resource. + +1 TYPELIB "MfcControl.tlb" + + +#endif // not APSTUDIO_INVOKED + diff --git a/extensions/test/ole/MfcControl/MfcControl.sln b/extensions/test/ole/MfcControl/MfcControl.sln new file mode 100644 index 000000000..24e646c86 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControl.sln @@ -0,0 +1,25 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MfcControl", "MfcControl.vcproj", "{07D59661-3519-4F10-AE9F-22DB0479E25A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release|Win32 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {07D59661-3519-4F10-AE9F-22DB0479E25A}.Debug|Win32.ActiveCfg = Debug|Win32 + {07D59661-3519-4F10-AE9F-22DB0479E25A}.Debug|Win32.Build.0 = Debug|Win32 + {07D59661-3519-4F10-AE9F-22DB0479E25A}.Release|Win32.ActiveCfg = Release|Win32 + {07D59661-3519-4F10-AE9F-22DB0479E25A}.Release|Win32.Build.0 = Release|Win32 + {07D59661-3519-4F10-AE9F-22DB0479E25A}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {07D59661-3519-4F10-AE9F-22DB0479E25A}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {07D59661-3519-4F10-AE9F-22DB0479E25A}.Unicode Release|Win32.ActiveCfg = Unicode Release|Win32 + {07D59661-3519-4F10-AE9F-22DB0479E25A}.Unicode Release|Win32.Build.0 = Unicode Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/test/ole/MfcControl/MfcControl.vcproj b/extensions/test/ole/MfcControl/MfcControl.vcproj new file mode 100644 index 000000000..6099d8242 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControl.vcproj @@ -0,0 +1,581 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/test/ole/MfcControl/MfcControlCtl.cpp b/extensions/test/ole/MfcControl/MfcControlCtl.cpp new file mode 100644 index 000000000..e64ed6570 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControlCtl.cpp @@ -0,0 +1,364 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// MfcControlCtl.cpp : Implementation of the CMfcControlCtrl ActiveX Control class. + +#include "stdafx.h" +#include "MfcControl.h" +#include "MfcControlCtl.h" +#include "MfcControlPpg.h" + + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + +IMPLEMENT_DYNCREATE(CMfcControlCtrl, COleControl) + + + +// Message map + +BEGIN_MESSAGE_MAP(CMfcControlCtrl, COleControl) + //{{AFX_MSG_MAP(CMfcControlCtrl) + // NOTE - ClassWizard will add and remove message map entries + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG_MAP + ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties) +END_MESSAGE_MAP() + + + +// Dispatch map + +BEGIN_DISPATCH_MAP(CMfcControlCtrl, COleControl) + //{{AFX_DISPATCH_MAP(CMfcControlCtrl) + DISP_FUNCTION(CMfcControlCtrl, "inShort", inShort, VT_I2, VTS_I2) + DISP_FUNCTION(CMfcControlCtrl, "inLong", inLong, VT_I4, VTS_I4) + DISP_FUNCTION(CMfcControlCtrl, "inString", inString, VT_BSTR, VTS_PBSTR) + DISP_FUNCTION(CMfcControlCtrl, "inFloat", inFloat, VT_R4, VTS_R4) + DISP_FUNCTION(CMfcControlCtrl, "inDouble", inDouble, VT_R8, VTS_R8) + DISP_FUNCTION(CMfcControlCtrl, "inVariant", inVariant, VT_VARIANT, VTS_VARIANT) + DISP_FUNCTION(CMfcControlCtrl, "inObject", inObject, VT_DISPATCH, VTS_DISPATCH) + DISP_FUNCTION(CMfcControlCtrl, "outShort", outShort, VT_EMPTY, VTS_PI2) + DISP_FUNCTION(CMfcControlCtrl, "outLong", outLong, VT_EMPTY, VTS_PI4) + DISP_FUNCTION(CMfcControlCtrl, "outString", outString, VT_EMPTY, VTS_PBSTR) + DISP_FUNCTION(CMfcControlCtrl, "outFloat", outFloat, VT_EMPTY, VTS_PR4) + DISP_FUNCTION(CMfcControlCtrl, "outDouble", outDouble, VT_EMPTY, VTS_PR8) + DISP_FUNCTION(CMfcControlCtrl, "outVariant", outVariant, VT_EMPTY, VTS_PVARIANT) + DISP_FUNCTION(CMfcControlCtrl, "outObject", outObject, VT_EMPTY, VTS_PDISPATCH) + //}}AFX_DISPATCH_MAP +END_DISPATCH_MAP() + + + +// Event map + +BEGIN_EVENT_MAP(CMfcControlCtrl, COleControl) + //{{AFX_EVENT_MAP(CMfcControlCtrl) + // NOTE - ClassWizard will add and remove event map entries + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_EVENT_MAP +END_EVENT_MAP() + + + +// Property pages + +// TODO: Add more property pages as needed. Remember to increase the count! +BEGIN_PROPPAGEIDS(CMfcControlCtrl, 1) + PROPPAGEID(CMfcControlPropPage::guid) +END_PROPPAGEIDS(CMfcControlCtrl) + + + +// Initialize class factory and guid + +IMPLEMENT_OLECREATE_EX(CMfcControlCtrl, "MFCCONTROL.MfcControlCtrl.1", + 0xac221fb6, 0xa0d8, 0x11d4, 0x83, 0x3b, 0, 0x50, 0x4, 0x52, 0x6a, 0xb4) + + + +// Type library ID and version + +IMPLEMENT_OLETYPELIB(CMfcControlCtrl, _tlid, _wVerMajor, _wVerMinor) + + + +// Interface IDs + +const IID BASED_CODE IID_DMfcControl = + { 0xac221fb4, 0xa0d8, 0x11d4, { 0x83, 0x3b, 0, 0x50, 0x4, 0x52, 0x6a, 0xb4 } }; +const IID BASED_CODE IID_DMfcControlEvents = + { 0xac221fb5, 0xa0d8, 0x11d4, { 0x83, 0x3b, 0, 0x50, 0x4, 0x52, 0x6a, 0xb4 } }; + + + +// Control type information + +static const DWORD BASED_CODE _dwMfcControlOleMisc = + OLEMISC_ACTIVATEWHENVISIBLE | + OLEMISC_SETCLIENTSITEFIRST | + OLEMISC_INSIDEOUT | + OLEMISC_CANTLINKINSIDE | + OLEMISC_RECOMPOSEONRESIZE; + +IMPLEMENT_OLECTLTYPE(CMfcControlCtrl, IDS_MFCCONTROL, _dwMfcControlOleMisc) + + + +// CMfcControlCtrl::CMfcControlCtrlFactory::UpdateRegistry - +// Adds or removes system registry entries for CMfcControlCtrl + +BOOL CMfcControlCtrl::CMfcControlCtrlFactory::UpdateRegistry(BOOL bRegister) +{ + // TODO: Verify that your control follows apartment-model threading rules. + // Refer to MFC TechNote 64 for more information. + // If your control does not conform to the apartment-model rules, then + // you must modify the code below, changing the 6th parameter from + // afxRegApartmentThreading to 0. + + if (bRegister) + return AfxOleRegisterControlClass( + AfxGetInstanceHandle(), + m_clsid, + m_lpszProgID, + IDS_MFCCONTROL, + IDB_MFCCONTROL, + afxRegApartmentThreading, + _dwMfcControlOleMisc, + _tlid, + _wVerMajor, + _wVerMinor); + else + return AfxOleUnregisterClass(m_clsid, m_lpszProgID); +} + + + +// CMfcControlCtrl::CMfcControlCtrl - Constructor + +CMfcControlCtrl::CMfcControlCtrl() +{ + InitializeIIDs(&IID_DMfcControl, &IID_DMfcControlEvents); + + // TODO: Initialize your control's instance data here. +} + + + +// CMfcControlCtrl::~CMfcControlCtrl - Destructor + +CMfcControlCtrl::~CMfcControlCtrl() +{ + // TODO: Cleanup your control's instance data here. +} + + + +// CMfcControlCtrl::OnDraw - Drawing function + +void CMfcControlCtrl::OnDraw( + CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid) +{ + // TODO: Replace the following code with your own drawing code. + pdc->FillRect(rcBounds, CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH))); + pdc->Ellipse(rcBounds); +} + + + +// CMfcControlCtrl::DoPropExchange - Persistence support + +void CMfcControlCtrl::DoPropExchange(CPropExchange* pPX) +{ + ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor)); + COleControl::DoPropExchange(pPX); + + // TODO: Call PX_ functions for each persistent custom property. + +} + + + +// CMfcControlCtrl::OnResetState - Reset control to default state + +void CMfcControlCtrl::OnResetState() +{ + COleControl::OnResetState(); // Resets defaults found in DoPropExchange + + // TODO: Reset any other control state here. +} + + + +// CMfcControlCtrl message handlers + + +short CMfcControlCtrl::inShort(short val) +{ + char buf[256]; + sprintf( buf, "inByte: value= %d", val); + ::MessageBoxA( NULL, buf, "MFCCONTROL.MfcControl", MB_OK); + return val+1; +} + +long CMfcControlCtrl::inLong(long val) +{ + char buf[256]; + sprintf( buf, "inLong: value= %d", val); + ::MessageBoxA( NULL, buf, "MFCCONTROL.MfcControl", MB_OK); + return val+1; +} + +BSTR CMfcControlCtrl::inString(BSTR* val) +{ + CString strResult; + strResult= *val; + char buf[256]; + sprintf( buf, "inString: value= %S", *val); + ::MessageBoxA( NULL, buf, "MFCCONTROL.MfcControl", MB_OK); + strResult += L" an appended string"; + return strResult.AllocSysString(); +} + +float CMfcControlCtrl::inFloat(float val) +{ + char buf[256]; + sprintf( buf, "inFloat: value= %f", val); + ::MessageBoxA( NULL, buf, "MFCCONTROL.MfcControl", MB_OK); + return val+1; +} + +double CMfcControlCtrl::inDouble(double val) +{ + char buf[256]; + sprintf( buf, "inDouble: value= %g", val); + ::MessageBoxA( NULL, buf, "MFCCONTROL.MfcControl", MB_OK); + return val+1; +} + +VARIANT CMfcControlCtrl::inVariant(const VARIANT& val) +{ + VARIANT vaResult; + VariantInit(&vaResult); + VariantCopyInd( &vaResult, const_cast(&val)); + if( vaResult.vt == VT_BSTR) + { + char buf[256]; + sprintf( buf, "inVariant: value= %S", vaResult.bstrVal); + ::MessageBoxA( NULL, buf, "MFCCONTROL.MfcControl", MB_OK); + + } + return _variant_t( L" a string from CMfcControlCtrl::inVariant"); +} + +LPDISPATCH CMfcControlCtrl::inObject(LPDISPATCH val) +{ + char buf[256]; + _bstr_t bstr; + HRESULT hr= S_OK; + COleVariant var; + DISPID id; + OLECHAR* name=L"prpString"; + if( SUCCEEDED(hr= val->GetIDsOfNames( IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &id))) + { + DISPPARAMS params={0,0,0,0}; + hr= val->Invoke( id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms, &var,0,0); + + } + + if( var.vt== VT_BSTR) + bstr= var.bstrVal; + sprintf( buf, "inObject: value= %S", (wchar_t*)bstr); + ::MessageBoxA( NULL, buf, "MFCCONTROL.MfcControl", MB_OK); + + return NULL; +} + + +void CMfcControlCtrl::outShort(short* val) +{ + *val= 123; +} + +void CMfcControlCtrl::outLong(long* val) +{ + *val= 1234; +} + +void CMfcControlCtrl::outString(BSTR* val) +{ + *val= SysAllocString(L"A string from CMfcControlCtrl::outString "); +} + +void CMfcControlCtrl::outFloat(float* val) +{ + *val= 3.14f; +} + +void CMfcControlCtrl::outDouble(double* val) +{ + *val= 3.145; +} + +void CMfcControlCtrl::outVariant(VARIANT* val) +{ + VariantInit( val); + val->vt= VT_BSTR; + val->bstrVal= SysAllocString( L"a string in a VARIANT"); +} + +void CMfcControlCtrl::outObject(LPDISPATCH* val) +{ + //{BFE10EBE-8584-11D4-005004526AB4} + HRESULT hr= S_OK; + CLSID clsTestControl; + hr= CLSIDFromProgID( L"AxTestComponents.Basic", &clsTestControl); + + IDispatch* pDisp= NULL; + hr= CoCreateInstance( clsTestControl, NULL, CLSCTX_ALL, __uuidof(IDispatch), (void**)&pDisp); + + if( SUCCEEDED( hr) && val) + { + COleVariant var; + DISPID id; + OLECHAR* name=L"prpString"; + if( SUCCEEDED(hr= pDisp->GetIDsOfNames( IID_NULL, &name, 1, LOCALE_USER_DEFAULT, &id))) + { + COleVariant vaParam1(_T("this is property prpString of AxTestComponents.Basic")); + DISPID dispidPut= DISPID_PROPERTYPUT; + DISPPARAMS params; + params.cArgs= 1; + params.cNamedArgs= 1; + params.rgdispidNamedArgs= &dispidPut; + params.rgvarg= &vaParam1; + + hr= pDisp->Invoke( id, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms, &var,0,0); + *val= pDisp; + } + + } + +} +// VT_I1 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/MfcControl/MfcControlCtl.h b/extensions/test/ole/MfcControl/MfcControlCtl.h new file mode 100644 index 000000000..b1d74270b --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControlCtl.h @@ -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 . + */ +#if !defined(AFX_MFCCONTROLCTL_H__AC221FC3_A0D8_11D4_833B_005004526AB4__INCLUDED_) +#define AFX_MFCCONTROLCTL_H__AC221FC3_A0D8_11D4_833B_005004526AB4__INCLUDED_ + +#ifdef _MSC_VER +#pragma once +#endif + +// MfcControlCtl.h : Declaration of the CMfcControlCtrl ActiveX Control class. + + +// CMfcControlCtrl : See MfcControlCtl.cpp for implementation. + +class CMfcControlCtrl : public COleControl +{ + DECLARE_DYNCREATE(CMfcControlCtrl) + +// Constructor +public: + CMfcControlCtrl(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CMfcControlCtrl) + public: + virtual void OnDraw(CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid); + virtual void DoPropExchange(CPropExchange* pPX); + virtual void OnResetState(); + //}}AFX_VIRTUAL + +// Implementation +protected: + ~CMfcControlCtrl(); + + DECLARE_OLECREATE_EX(CMfcControlCtrl) // Class factory and guid + DECLARE_OLETYPELIB(CMfcControlCtrl) // GetTypeInfo + DECLARE_PROPPAGEIDS(CMfcControlCtrl) // Property page IDs + DECLARE_OLECTLTYPE(CMfcControlCtrl) // Type name and misc status + +// Message maps + //{{AFX_MSG(CMfcControlCtrl) + // NOTE - ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +// Dispatch maps + //{{AFX_DISPATCH(CMfcControlCtrl) + afx_msg short inShort(short val); + afx_msg long inLong(long val); + afx_msg BSTR inString(BSTR* val); + afx_msg float inFloat(float val); + afx_msg double inDouble(double val); + afx_msg VARIANT inVariant(const VARIANT& val); + afx_msg LPDISPATCH inObject(LPDISPATCH val); + afx_msg void outShort(short* val); + afx_msg void outLong(long* val); + afx_msg void outString(BSTR* val); + afx_msg void outFloat(float* val); + afx_msg void outDouble(double* val); + afx_msg void outVariant(VARIANT* val); + afx_msg void outObject(LPDISPATCH* val); + //}}AFX_DISPATCH + DECLARE_DISPATCH_MAP() + +// Event maps + //{{AFX_EVENT(CMfcControlCtrl) + //}}AFX_EVENT + DECLARE_EVENT_MAP() + +// Dispatch and event IDs +public: + enum { + //{{AFX_DISP_ID(CMfcControlCtrl) + dispidInShort = 1L, + dispidInLong = 2L, + dispidInString = 3L, + dispidInFloat = 4L, + dispidInDouble = 5L, + dispidInVariant = 6L, + dispidInObject = 7L, + dispidOutShort = 8L, + dispidOutLong = 9L, + dispidOutString = 10L, + dispidOutFloat = 11L, + dispidOutDouble = 12L, + dispidOutVariant = 13L, + dispidOutObject = 14L, + //}}AFX_DISP_ID + }; +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_MFCCONTROLCTL_H__AC221FC3_A0D8_11D4_833B_005004526AB4__INCLUDED) +// BYTE + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/MfcControl/MfcControlCtl.png b/extensions/test/ole/MfcControl/MfcControlCtl.png new file mode 100644 index 000000000..77c4758c1 Binary files /dev/null and b/extensions/test/ole/MfcControl/MfcControlCtl.png differ diff --git a/extensions/test/ole/MfcControl/MfcControlPpg.cpp b/extensions/test/ole/MfcControl/MfcControlPpg.cpp new file mode 100644 index 000000000..367122363 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControlPpg.cpp @@ -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 . + */ +// MfcControlPpg.cpp : Implementation of the CMfcControlPropPage property page class. + +#include "stdafx.h" +#include "MfcControl.h" +#include "MfcControlPpg.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + + +IMPLEMENT_DYNCREATE(CMfcControlPropPage, COlePropertyPage) + + + +// Message map + +BEGIN_MESSAGE_MAP(CMfcControlPropPage, COlePropertyPage) + //{{AFX_MSG_MAP(CMfcControlPropPage) + // NOTE - ClassWizard will add and remove message map entries + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + + +// Initialize class factory and guid + +IMPLEMENT_OLECREATE_EX(CMfcControlPropPage, "MFCCONTROL.MfcControlPropPage.1", + 0xac221fb7, 0xa0d8, 0x11d4, 0x83, 0x3b, 0, 0x50, 0x4, 0x52, 0x6a, 0xb4) + + + +// CMfcControlPropPage::CMfcControlPropPageFactory::UpdateRegistry - +// Adds or removes system registry entries for CMfcControlPropPage + +BOOL CMfcControlPropPage::CMfcControlPropPageFactory::UpdateRegistry(BOOL bRegister) +{ + if (bRegister) + return AfxOleRegisterPropertyPageClass(AfxGetInstanceHandle(), + m_clsid, IDS_MFCCONTROL_PPG); + else + return AfxOleUnregisterClass(m_clsid, NULL); +} + + + +// CMfcControlPropPage::CMfcControlPropPage - Constructor + +CMfcControlPropPage::CMfcControlPropPage() : + COlePropertyPage(IDD, IDS_MFCCONTROL_PPG_CAPTION) +{ + //{{AFX_DATA_INIT(CMfcControlPropPage) + // NOTE: ClassWizard will add member initialization here + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_DATA_INIT +} + + + +// CMfcControlPropPage::DoDataExchange - Moves data between page and properties + +void CMfcControlPropPage::DoDataExchange(CDataExchange* pDX) +{ + //{{AFX_DATA_MAP(CMfcControlPropPage) + // NOTE: ClassWizard will add DDP, DDX, and DDV calls here + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_DATA_MAP + DDP_PostProcessing(pDX); +} + + + +// CMfcControlPropPage message handlers + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/MfcControl/MfcControlPpg.h b/extensions/test/ole/MfcControl/MfcControlPpg.h new file mode 100644 index 000000000..cb7cd7164 --- /dev/null +++ b/extensions/test/ole/MfcControl/MfcControlPpg.h @@ -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 . + */ +#if !defined(AFX_MFCCONTROLPPG_H__AC221FC5_A0D8_11D4_833B_005004526AB4__INCLUDED_) +#define AFX_MFCCONTROLPPG_H__AC221FC5_A0D8_11D4_833B_005004526AB4__INCLUDED_ + +#ifdef _MSC_VER +#pragma once +#endif + +// MfcControlPpg.h : Declaration of the CMfcControlPropPage property page class. + + +// CMfcControlPropPage : See MfcControlPpg.cpp.cpp for implementation. + +class CMfcControlPropPage : public COlePropertyPage +{ + DECLARE_DYNCREATE(CMfcControlPropPage) + DECLARE_OLECREATE_EX(CMfcControlPropPage) + +// Constructor +public: + CMfcControlPropPage(); + +// Dialog Data + //{{AFX_DATA(CMfcControlPropPage) + enum { IDD = IDD_PROPPAGE_MFCCONTROL }; + // NOTE - ClassWizard will add data members here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_DATA + +// Implementation +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + +// Message maps +protected: + //{{AFX_MSG(CMfcControlPropPage) + // NOTE - ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() + +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_MFCCONTROLPPG_H__AC221FC5_A0D8_11D4_833B_005004526AB4__INCLUDED) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/MfcControl/Resource.h b/extensions/test/ole/MfcControl/Resource.h new file mode 100644 index 000000000..598d26ba3 --- /dev/null +++ b/extensions/test/ole/MfcControl/Resource.h @@ -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 . + */ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by MfcControl.rc + + +#define IDS_MFCCONTROL 1 +#define IDS_MFCCONTROL_PPG 2 + +#define IDS_MFCCONTROL_PPG_CAPTION 200 + +#define IDD_PROPPAGE_MFCCONTROL 200 + + +#define IDB_MFCCONTROL 1 + + +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 32768 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/MfcControl/StdAfx.cpp b/extensions/test/ole/MfcControl/StdAfx.cpp new file mode 100644 index 000000000..13bae5702 --- /dev/null +++ b/extensions/test/ole/MfcControl/StdAfx.cpp @@ -0,0 +1,25 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/MfcControl/StdAfx.h b/extensions/test/ole/MfcControl/StdAfx.h new file mode 100644 index 000000000..6e8059a1b --- /dev/null +++ b/extensions/test/ole/MfcControl/StdAfx.h @@ -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 . + */ +#if !defined(AFX_STDAFX_H__AC221FBA_A0D8_11D4_833B_005004526AB4__INCLUDED_) +#define AFX_STDAFX_H__AC221FBA_A0D8_11D4_833B_005004526AB4__INCLUDED_ + +#ifdef _MSC_VER +#pragma once +#endif + +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers + +#include +#include +#include +#ifndef _AFX_NO_AFXCMN_SUPPORT +#include +#endif // _AFX_NO_AFXCMN_SUPPORT + +// Delete the two includes below if you do not wish to use the MFC +// database classes +#include +#include + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#include +#endif // !defined(AFX_STDAFX_H__AC221FBA_A0D8_11D4_833B_005004526AB4__INCLUDED_) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/OleClient/OleClient.ini b/extensions/test/ole/OleClient/OleClient.ini new file mode 100644 index 000000000..fa1ac118f --- /dev/null +++ b/extensions/test/ole/OleClient/OleClient.ini @@ -0,0 +1,5 @@ +[Bootstrap] +UNO_TYPES=types.rdb +UNO_SERVICES=services.rdb + + diff --git a/extensions/test/ole/OleClient/axhost.cxx b/extensions/test/ole/OleClient/axhost.cxx new file mode 100644 index 000000000..47709f383 --- /dev/null +++ b/extensions/test/ole/OleClient/axhost.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 "axhost.hxx" + +HostWin::HostWin(LPWSTR progid) +{ + controlName = progid; + RECT rcPos = { 0, 0, 200, 200 }; + Create(0, rcPos, _T("HostWin")); +} +HostWin::~HostWin() { DestroyWindow(); } + +LRESULT HostWin::OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) +{ + CAxWindow wnd(m_hWnd); + + HRESULT hr = wnd.CreateControlEx(controlName, NULL, NULL, &spControl.p); + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/OleClient/axhost.hxx b/extensions/test/ole/OleClient/axhost.hxx new file mode 100644 index 000000000..68a9069fb --- /dev/null +++ b/extensions/test/ole/OleClient/axhost.hxx @@ -0,0 +1,51 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include +extern CComModule _Module; +#include +#include + + +class HostWin: public CWindowImpl > +{ + CComBSTR controlName; + CComPtr spControl; +public: + explicit HostWin(LPWSTR progid); + + ~HostWin(); + + + BEGIN_MSG_MAP(HostWin) + MESSAGE_HANDLER( WM_CREATE, OnCreate) + END_MSG_MAP() + + IUnknown* GetHostedControl(){ + return spControl; + } + + LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/OleClient/clientTest.cxx b/extensions/test/ole/OleClient/clientTest.cxx new file mode 100644 index 000000000..00a78034d --- /dev/null +++ b/extensions/test/ole/OleClient/clientTest.cxx @@ -0,0 +1,1291 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include + +CComModule _Module; +#include +#include + +#include "axhost.hxx" + +#include +#include "typelib/typedescription.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BEGIN_OBJECT_MAP(ObjectMap) +END_OBJECT_MAP() + +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::script; +using namespace com::sun::star::bridge::oleautomation; +using namespace cppu; + + +Reference convertComObject( IUnknown* pUnk); +Reference getComObject( OUString progId); +bool checkOutArgs(const Sequence & outArgs, + const Sequence & indices, const Sequence & values); + +bool doSimpleTest(const Reference & inv); +bool doSimpleSequenceTest(const Reference & inv); +bool doParameterTest(const Reference & inv); +bool doPropertyWithArgumentTest(const Reference & inv); +bool equalSequences(const Any& orig, const Any& returned); +HRESULT doTest(); +HRESULT doTest2( Reference &); +Reference getComObject(OUString& ); + +HRESULT InitializeParameter(); +void printResultVariantArray( VARIANT & var); +void printVariant( VARIANT & var); +void printSequence( Sequence& val); + +extern "C" int SAL_CALL main( int , char **) +{ + HRESULT hr; + if( FAILED( hr=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) + { + _tprintf(_T("CoInitializeEx failed \n")); + return -1; + } + + + _Module.Init( ObjectMap, GetModuleHandle( NULL)); + + if( FAILED(hr=doTest())) + { + _com_error err( hr); + const TCHAR * errMsg= err.ErrorMessage(); + MessageBox( NULL, errMsg, "Test failed", MB_ICONERROR); + } + else + { + MessageBox( NULL,NULL , "Test succeeded", MB_ICONINFORMATION); + } + + + _Module.Term(); + CoUninitialize(); + return 0; +} +//Also supports named args + +bool doParameterTest(const Reference & inv) +{ + Sequence< sal_Int16> seqIndices; + Sequence seqOut; + + Any arArgs[2]; + Any arArgs1[4]; + + NamedArgument arg1(OUString(L"val1"), makeAny((sal_Int32) 123)); + NamedArgument arg2(OUString(L"val2"), makeAny((sal_Int32) 456)); + NamedArgument arg3(OUString(L"val3"), makeAny((sal_Int32) 0xff)); + NamedArgument arg4(OUString(L"val4"), makeAny((sal_Int32) 0xffff)); + + NamedArgument argOut1(OUString(L"val1"), Any()); + NamedArgument argOut2(OUString(L"val2"), Any()); + Sequence seqNoArgs; + arArgs[0] <<= (sal_Int32) 0; + arArgs[1] <<= (sal_Int32) 0; + Sequence seqPositional0(arArgs, 2); + + + arArgs[0] <<= arg1; + arArgs[1] <<= arg2; + Sequence seqNamed(arArgs, 2); + arArgs[0] <<= arg2; + arArgs[1] <<= arg1; + Sequence seqNamed2(arArgs, 2); + arArgs[0] <<= argOut1; + arArgs[1] <<= argOut2; + Sequence seqNamed3(arArgs, 2); + arArgs[0] <<= argOut2; + arArgs[1] <<= argOut1; + Sequence seqNamed4(arArgs, 2); + + arArgs[0] <<= arg1; + Sequence seqNamed5(arArgs, 1); + arArgs[0] <<= arg2; + Sequence seqNamed6(arArgs, 1); + + arArgs[0] <<= (sal_Int32) 123; + arArgs[1] <<= (sal_Int32) 456; + Sequence seqPositional(arArgs, 2); + arArgs[0] <<= (sal_Int32) 123; + Sequence seqPositional2(arArgs, 1); + + arArgs[0].clear(); + arArgs[1].clear(); + Sequence seqPositional3(arArgs, 2); + + arArgs[0] <<= (sal_Int32) 123; + arArgs[1] <<= SCode(DISP_E_PARAMNOTFOUND); + Sequence seqOutOpt1(arArgs, 2); + + arArgs[0] <<= SCode(DISP_E_PARAMNOTFOUND); + arArgs[1] <<= SCode(DISP_E_PARAMNOTFOUND); + Sequence seqOutOpt2(arArgs, 2); + + arArgs[0] <<= SCode(DISP_E_PARAMNOTFOUND); + arArgs[1] <<= (sal_Int32) 456; + Sequence seqOutOpt3(arArgs, 2); + + arArgs1[0] <<= (sal_Int32) 0; + arArgs1[1] <<= (sal_Int32) 0; + arArgs1[2] <<= (sal_Int32) 0; + arArgs1[3] <<= (sal_Int32) 0; + Sequence seqMix0(arArgs1, 4); + + arArgs1[0] <<= (sal_Int32) 123; + arArgs1[1] <<= (sal_Int32) 456; + arArgs1[2] <<= arg3; + arArgs1[3] <<= arg4; + Sequence seqMix(arArgs1, 4); + + arArgs1[0].clear(); + arArgs1[1] <<= (sal_Int32) 456; + arArgs1[2] <<= arg4; + Sequence seqMix2(arArgs1, 3); + + arArgs1[0] <<= SCode(DISP_E_PARAMNOTFOUND); + arArgs1[1] <<= (sal_Int32) 456; + arArgs1[2] <<= SCode(DISP_E_PARAMNOTFOUND); + arArgs1[3] <<= arg4.Value; + Sequence seqMixOut(arArgs1, 4); + + arArgs1[0] <<= SCode(DISP_E_PARAMNOTFOUND); + arArgs1[1].clear(); + arArgs1[2] <<= arg4; + Sequence seqMix2Out(arArgs1, 3); + + + //in args + out, optional, positional----------------------------------------- + //first general test + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqPositional, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional5"), seqPositional, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqPositional)) + return false; + + //2 optional args, 1 provided + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqPositional0, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqPositional2, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional5"), seqPositional, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqOutOpt1)) + return false; + + //2 optional args, 0 provided + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqPositional0, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqNoArgs, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional5"), seqPositional3, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqOutOpt2)) + return false; + + //named args -------------------------------------------- + + // 2 named args, correct position + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqPositional0, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqNamed, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional5"), seqPositional0, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqPositional)) + return false; + + // 2named args, position differs + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqPositional0, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqNamed2, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional5"), seqPositional, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqPositional)) + return false; + + //named out args, 2 named args with correct position + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqNamed, seqIndices, seqOut); + seqIndices.realloc(0); + seqIndices.realloc(0); + inv->invoke(OUString(L"optional5"), seqNamed3, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqNamed )) + return false; + + //named out args, 2 named args with different position + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqNamed, seqIndices, seqOut); + seqIndices.realloc(0); + seqIndices.realloc(0); + inv->invoke(OUString(L"optional5"), seqNamed4, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqNamed2 )) + return false; + + + //2 args, 1 provided (correct order) + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqPositional0, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqNamed5, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional5"), seqPositional, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqOutOpt1)) + return false; + //2 args, 1 provided (incorrect order) + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqPositional0, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional3"), seqNamed6, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional5"), seqPositional, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqOutOpt3)) + return false; + + //2position + 2 2named args, correct order + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional6"), seqMix0, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional6"), seqMix, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional7"), seqMix, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqMix)) + return false; + + // 4 in args, 1 positional, 1 named, 1 positional omitted + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional6"), seqMix0, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional6"), seqMix2, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional7"), seqMix0, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqMixOut)) + return false; + + // 4 out args, 1 positional, 1 named, 1 positional omitted + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional6"), seqMix2, seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"optional7"), seqMix2Out, seqIndices, seqOut); + if ( ! checkOutArgs(seqOut, seqIndices, seqMix2Out)) + return false; + + + return true; +} +bool doPropertyTest(const Reference & inv) +{ + Sequence< sal_Int16> seqIndices; + Sequence seqOut; + + Any inBool, outBool; + Any inByte, outByte; + Any inShort, outShort; + Any inLong, outLong; + Any inString, outString; + Any inFloat, outFloat; + Any inDouble, outDouble; + Any inVariant, outVariant; + Any inObject, outObject; + Any inUnknown, outUnknown; + Any inCY, outCY; + Any inDate, outDate; + Any inDecimal, outDecimal; + Any inSCode, outSCode; + Any inrefLong, outrefLong; + Any inrefVariant, outrefVariant; + Any inrefDecimal, outrefDecimal; + Any inParamsLong, outParamsLong; + Reference xintUnknown(getComObject(L"AxTestComponents.Foo")); + + inBool <<= (sal_Bool) sal_True; + inv->setValue(OUString(L"prpBool"), inBool); + outBool = inv->getValue(OUString(L"prpBool")); + + inByte <<= (sal_Int8) 100; + inv->setValue(OUString(L"prpByte"), inByte); + outByte = inv->getValue(OUString(L"prpByte")); + + inShort <<= static_cast( -1); + inv->setValue(OUString(L"prpShort"), inShort); + outShort = inv->getValue(OUString(L"prpShort")); + + inLong <<= ( sal_Int32) 1234567; + inv->setValue(OUString(L"prpLong"), inLong // TODO: Add your implementation code here +); + outLong = inv->getValue(OUString(L"prpLong")); + + inString <<= OUString(L" this is clientTest.exe"); + inv->setValue(OUString(L"prpString"), inString); + outString = inv->getValue(OUString(L"prpString")); + + inFloat <<= 3.14f; + inv->setValue(OUString(L"prpFloat"), inFloat); + outFloat = inv->getValue(OUString(L"prpFloat")); + + inDouble <<= ( double) 3.145; + inv->setValue(OUString(L"prpDouble"), inDouble); + outDouble = inv->getValue(OUString(L"prpDouble")); + + inVariant <<= OUString(L"A string in an any"); + inv->setValue(OUString(L"prpVariant"), inVariant); + outVariant = inv->getValue(OUString(L"prpVariant")); + + inObject <<= inv; + inv->setValue(OUString(L"prpObject"), inObject); + outObject = inv->getValue(OUString(L"prpObject")); + + inUnknown <<= xintUnknown; + inv->setValue(OUString(L"prpUnknown"), inUnknown); + outUnknown = inv->getValue(OUString(L"prpUnknown")); + + Currency cur(99999); + inCY <<= cur; + inv->setValue(OUString(L"prpCurrency"), inCY); + outCY = inv->getValue(OUString(L"prpCurrency")); + + Date d(37889.0); + inDate <<= d; + inv->setValue(OUString(L"prpDate"), inDate); + outDate = inv->getValue(OUString(L"prpDate")); + + Decimal dec(20, 0, 0xffffffff, 0xffffffff, 0x0fffffff); + inDecimal <<= dec; + inv->setValue(OUString(L"prpDecimal"), inDecimal); + outDecimal = inv->getValue(OUString(L"prpDecimal")); + + SCode code(DISP_E_BADVARTYPE); + inSCode <<= code; + inv->setValue(OUString(L"prpSCode"), inSCode); + outSCode = inv->getValue(OUString(L"prpSCode")); + + inrefLong <<= (sal_Int32) 123456; + inv->setValue(OUString(L"prprefLong"), inrefLong); + outrefLong = inv->getValue(OUString(L"prprefLong")); + + inrefVariant <<= OUString(L"A string in an any"); + inv->setValue(OUString(L"prprefVariant"), inrefVariant); + outrefVariant = inv->getValue(OUString(L"prprefVariant")); + + Decimal decref(20, 0, 0xffffffff, 0xffffffff, 0x0fffffff); + inrefDecimal <<= decref; + inv->setValue(OUString(L"prprefDecimal"), inrefDecimal); + outrefDecimal = inv->getValue(OUString(L"prprefDecimal")); + + if (inBool != outBool || inByte != outByte || inShort != outShort || inLong != outLong + || inFloat != outFloat || inDouble != outDouble || inString != outString + || inVariant != outVariant || inObject != outObject + || inUnknown != outUnknown || inCY != outCY + || inDate != outDate || inDecimal != outDecimal || inSCode != outSCode + || inrefLong != outrefLong ||inrefVariant != outrefVariant + || inrefDecimal != outrefDecimal) + return false; + return true; +} + +bool doPropertyWithArgumentTest(const Reference & inv) +{ + Sequence< sal_Int16> seqIndices; + Sequence seqOut; + + Any arMultiArgs[3]; + arMultiArgs[0] = makeAny((sal_Int32) 0); + arMultiArgs[1] = makeAny((sal_Int32) 0); + arMultiArgs[2] <<= PropertyPutArgument(makeAny((sal_Int32) 0)); + Sequence seqMultiArgPut0(arMultiArgs, 3); + + arMultiArgs[0] = makeAny((sal_Int32) 1); + arMultiArgs[1] = makeAny((sal_Int32) 2); + arMultiArgs[2] <<= PropertyPutArgument(makeAny((sal_Int32) 3)); + Sequence seqMultiArgPut1(arMultiArgs, 3); + + arMultiArgs[0] = makeAny((sal_Int32) 1); + arMultiArgs[1] <<= PropertyPutArgument(makeAny((sal_Int32) 3)); + Sequence seqMultiArgPut2(arMultiArgs, 2); + + arMultiArgs[0] <<= NamedArgument(OUString(L"val2"), makeAny((sal_Int32) 1)); + arMultiArgs[1] <<= PropertyPutArgument(makeAny((sal_Int32) 3)); + Sequence seqMultiArgPut3(arMultiArgs, 2); + + arMultiArgs[0] <<= NamedArgument(OUString(L"val2"), makeAny((sal_Int32) 1)); + arMultiArgs[1] <<= NamedArgument(OUString(L"val3"), makeAny((sal_Int32) 3)); + Sequence seqMultiArgPut4(arMultiArgs, 2); + + arMultiArgs[0] = makeAny((sal_Int32) 0); + arMultiArgs[1] = makeAny((sal_Int32) 0); + Sequence seqMultiArgGet0(arMultiArgs, 2); + + arMultiArgs[0] = makeAny((sal_Int32) 1); + arMultiArgs[1] = makeAny((sal_Int32) 2); + Sequence seqMultiArgGet1(arMultiArgs, 2); + Sequence seqMultiArgGet2(arMultiArgs, 1); + + + arMultiArgs[0] = makeAny((sal_Int32) 0); + arMultiArgs[1] <<= PropertyPutArgument(makeAny((sal_Int32) 0)); + Sequence seqMultiArgPut5(arMultiArgs, 2); + + arMultiArgs[0] = makeAny((sal_Int32) 1); + arMultiArgs[1] <<= PropertyPutArgument(makeAny((sal_Int32) 2)); + Sequence seqMultiArgPut6(arMultiArgs, 2); + + arMultiArgs[0].clear(); + arMultiArgs[1].clear(); + Sequence seqMultiVoid(arMultiArgs, 2); + + arMultiArgs[0] = makeAny((sal_Int32) 0); + arMultiArgs[1] = makeAny((sal_Int32) 0); + Sequence seqMultiVoid2(arMultiArgs, 2); + + //[propput, ...] HRESULT prpMultiArg1([in,out,optional] VARIANT* val1, [in,out,optional] VARIANT* val2, [in] VARIANT* newVal); + //[propget, ...] HRESULT prpMultiArg1([in,out,optional] VARIANT* val1, [in,out,optional] VARIANT* val2, [out, optional, retval] VARIANT* pVal); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg1"), seqMultiArgPut0, seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg1"), seqMultiArgPut1, seqIndices, seqOut); + //check in/out args + seqIndices.realloc( 0); + seqOut.realloc(0); + Any anyRet = inv->invoke(OUString(L"prpMultiArg1"), seqMultiArgGet0, + seqIndices, seqOut); + + if (anyRet != ((PropertyPutArgument const *)seqMultiArgPut1[2].getValue())->Value + || ! checkOutArgs(seqOut, seqIndices, Sequence(seqMultiArgPut1.getArray(), 2))) + { + return false; + } + // test optional (one arg omitted + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg1"), seqMultiArgPut0, seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg1"), seqMultiArgPut2, seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + anyRet = inv->invoke(OUString(L"prpMultiArg1"), seqMultiArgGet0, + seqIndices, seqOut); + + arMultiArgs[0] = makeAny((sal_Int32) 1); + arMultiArgs[1] = makeAny((SCode(DISP_E_PARAMNOTFOUND))); + + if (anyRet != ((PropertyPutArgument const *) seqMultiArgPut2[1].getValue())->Value + || ! checkOutArgs(seqOut, seqIndices, Sequence(arMultiArgs, 2))) + { + return false; + } + + //test one named arg and one omitted + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg1"), seqMultiArgPut0, seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg1"), seqMultiArgPut3, seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + anyRet = inv->invoke(OUString(L"prpMultiArg1"), seqMultiArgGet0, + seqIndices, seqOut); + + arMultiArgs[0] = makeAny((SCode(DISP_E_PARAMNOTFOUND))); + arMultiArgs[1] = ((NamedArgument const*) seqMultiArgPut3[0].getValue())->Value; + if (anyRet != ((PropertyPutArgument const*) seqMultiArgPut3[1].getValue())->Value + || ! checkOutArgs(seqOut, seqIndices, Sequence(arMultiArgs, 2))) + { + return false; + } + +// [propget,...] HRESULT prpMultiArg2([in] VARIANT val1, [out, retval] VARIANT* pVal); +// [propput,...] HRESULT prpMultiArg2([in] VARIANT val1, [in] VARIANT newVal); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg2"), seqMultiArgPut5, seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg2GetValues"), seqMultiVoid, seqIndices, seqOut); + + if ( ! checkOutArgs(seqOut, seqIndices, seqMultiVoid2)) + return false; + seqIndices.realloc( 0); + seqOut.realloc(0); + anyRet = inv->invoke(OUString(L"prpMultiArg2"), seqMultiArgPut6, + seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + anyRet = inv->invoke(OUString(L"prpMultiArg2GetValues"), seqMultiVoid, + seqIndices, seqOut); + +// [propget,...] HRESULT prpMultiArg3([in,out] LONG* val1, [out, retval] LONG* pVal); +// [propput,...] HRESULT prpMultiArg3([in,out] LONG* val1, [in] LONG newVal); + + if ( ! checkOutArgs(seqOut, seqIndices, seqMultiArgGet1 )) + return false; + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg3"), seqMultiArgPut5, seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"prpMultiArg3"), seqMultiArgPut6, seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + anyRet = inv->invoke(OUString(L"prpMultiArg3"), seqMultiArgGet2, seqIndices, seqOut); + + if ( anyRet != ((PropertyPutArgument const*) seqMultiArgPut6[1].getValue())->Value + || !checkOutArgs(seqOut, seqIndices, seqMultiArgGet2)) + return false; + + + //hasProperty, hasMethod + if (inv->hasProperty("prpMultiArg1")) + return false; + if ( ! inv->hasMethod("prpMultiArg1")) + return false; + if ( ! inv->hasProperty("prprefLong")) + return false; + if (inv->hasMethod("prprefLong")) + return false; + if ( ! inv->hasMethod("inLong")) + return false; + + return true; +} +bool doSimpleTest(const Reference & inv) +{ + Sequence< sal_Int16> seqIndices; + Sequence seqOut; + + Any inBool, outBool; + Any inByte, outByte; + Any inShort, outShort; + Any inLong, outLong; + Any inString, outString; + Any inFloat, outFloat; + Any inDouble, outDouble; + Any inVariant, outVariant; + Any inObject, outObject; + Any inUnknown, outUnknown; + Any inCY, outCY; + Any inDate, outDate; + Any inDecimal, outDecimal; + Any inSCode, outSCode; + Any inrefLong, outrefLong; + Any inrefVariant, outrefVariant; + Any inrefDecimal, outrefDecimal; + + Reference xIntFoo(getComObject(L"AxTestComponents.Foo")); + + // in and out parameter + + sal_Bool aBool = sal_True; + inBool.setValue(&aBool, cppu::UnoType::get()); + inv->invoke(OUString(L"inBool"), Sequence< Any > ( &inBool, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outBool"), Sequence< Any > ( & outBool, 1), seqIndices, seqOut); + outBool <<= seqOut[0]; + + inByte <<= (sal_Int8) 127; + inv->invoke(OUString(L"inByte"), Sequence< Any > ( & inByte, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outByte"), Sequence< Any > ( & outByte, 1), seqIndices, seqOut); + outByte <<= seqOut[0]; + + inShort <<= static_cast(-1); + inv->invoke(OUString(L"inShort"), Sequence< Any > ( & inShort, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outShort"), Sequence< Any > ( & outShort, 1), seqIndices, seqOut); + outShort <<= seqOut[0]; + + inLong <<= ( sal_Int32) 1234567; + inv->invoke(OUString(L"inLong"), Sequence< Any > ( & inLong, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outLong"), Sequence< Any > ( & outLong, 1 ), seqIndices, seqOut); + outLong <<= seqOut[0]; + + inString <<= OUString(L" this is clientTest.exe"); + inv->invoke(OUString(L"inString"), Sequence< Any > ( & inString, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outString"), Sequence< Any > ( & outString, 1 ), seqIndices, seqOut); + outString <<= seqOut[0]; + + inFloat <<= 3.14f; + inv->invoke(OUString(L"inFloat"), Sequence< Any > ( & inFloat, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outFloat"), Sequence< Any > ( & outFloat, 1 ), seqIndices, seqOut); + outFloat <<= seqOut[0]; + + inDouble <<= ( double) 3.145; + inv->invoke(OUString(L"inDouble"), Sequence< Any > ( & inDouble, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outDouble"), Sequence< Any > ( & outDouble, 1 ), seqIndices, seqOut); + outDouble <<= seqOut[0]; + + inVariant <<= OUString(L" A string in an any"); + inv->invoke(OUString(L"inVariant"), Sequence< Any > ( & inVariant, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outVariant"), Sequence< Any > (&outVariant, 1), seqIndices, seqOut); + outVariant <<= seqOut[0]; + + inObject <<= inv; + inv->invoke(OUString(L"inObject"), Sequence< Any > ( & inObject, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outObject"), Sequence< Any > (& outObject, 1), seqIndices, seqOut); + outObject <<= seqOut[0]; + + inUnknown <<= xIntFoo; + inv->invoke(OUString(L"inUnknown"), Sequence< Any > ( & inUnknown, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outUnknown"), Sequence< Any > (& outUnknown, 1), seqIndices, seqOut); + outUnknown <<= seqOut[0]; + + Currency cur(999999); + inCY <<= cur; + inv->invoke(OUString(L"inCurrency"), Sequence( & inCY, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outCurrency"), Sequence< Any > (& outCY, 1), seqIndices, seqOut); + outCY <<= seqOut[0]; + + Date dDate(37889.0); + inDate <<= dDate; + inv->invoke(OUString(L"inDate"), Sequence( & inDate, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outDate"), Sequence< Any > (& outDate, 1), seqIndices, seqOut); + outDate <<= seqOut[0]; + + Decimal dec(3, 0, 0xffffffff, 0xffffffff, 0xfffffff0); + inDecimal <<= dec; + inv->invoke(OUString(L"inDecimal"), Sequence( & inDecimal, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outDecimal"), Sequence< Any > (& outDecimal, 1), seqIndices, seqOut); + outDecimal <<= seqOut[0]; + + SCode code(DISP_E_BADVARTYPE); + inSCode <<= code; + inv->invoke(OUString(L"inSCode"), Sequence( & inSCode, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outSCode"), Sequence< Any > (& outSCode, 1), seqIndices, seqOut); + outSCode <<= seqOut[0]; + + if (inBool != outBool || inByte != outByte || inShort != outShort || inLong != outLong + || inFloat != outFloat || inDouble != outDouble || inString != outString + || inVariant != outVariant || inObject != outObject || inUnknown != outUnknown + || inCY != outCY + || inDate != outDate || inDecimal != outDecimal || inSCode != outSCode) + return false; + + // in/out parameter + + outBool = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutBool"), Sequence< Any > ( & inBool, 1), seqIndices, seqOut); + outBool <<= seqOut[0]; + + outByte = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutByte"), Sequence< Any > ( & inByte, 1), seqIndices, seqOut); + outByte <<= seqOut[0]; + + outShort = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutShort"), Sequence< Any > ( & inShort, 1), seqIndices, seqOut); + outShort <<= seqOut[0]; + + outLong = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutLong"), Sequence< Any > ( & inLong, 1), seqIndices, seqOut); + outLong <<= seqOut[0]; + + outString = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutString"), Sequence< Any > ( & inString, 1), seqIndices, seqOut); + outString <<= seqOut[0]; + + outFloat = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutFloat"), Sequence< Any > ( & inFloat, 1), seqIndices, seqOut); + outFloat <<= seqOut[0]; + + outDouble = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutDouble"), Sequence< Any > ( &inDouble, 1), seqIndices, seqOut); + outDouble <<= seqOut[0]; + + outVariant = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutVariant"), Sequence< Any > ( & inVariant, 1), seqIndices, seqOut); + outVariant <<= seqOut[0]; + + outObject = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutObject"), Sequence< Any > ( & inObject, 1), seqIndices, seqOut); + outObject <<= seqOut[0]; + + outCY = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutCurrency"), Sequence< Any > ( & inCY, 1), seqIndices, seqOut); + outCY <<= seqOut[0]; + + outDate = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutDate"), Sequence< Any > ( & inDate, 1), seqIndices, seqOut); + outDate <<= seqOut[0]; + + outDecimal = Any(); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutDecimal"), Sequence< Any > (& inDecimal, 1), seqIndices, seqOut); + outDecimal <<= seqOut[0]; + + outSCode = Any(); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutSCode"), Sequence< Any > (& inSCode, 1), seqIndices, seqOut); + outSCode <<= seqOut[0]; + + if (inBool != outBool || inByte != outByte || inShort != outShort || inLong != outLong + || inFloat != outFloat || inDouble != outDouble || inString != outString + || inVariant != outVariant || inObject != outObject || inCY != outCY + || inDate != outDate || inDecimal != outDecimal || inSCode != outSCode) + return false; + + + // in byref parameters + + + inrefLong <<= (sal_Int32) 1234; + inv->invoke(OUString(L"inrefLong"), Sequence( & inrefLong, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outLong"), Sequence< Any > (& outrefLong, 1), seqIndices, seqOut); + outrefLong <<= seqOut[0]; + + inrefVariant <<= OUString(L" A string in an any"); + inv->invoke(OUString(L"inrefVariant"), Sequence< Any > ( & inrefVariant, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outVariant"), Sequence< Any > (&outrefVariant, 1), seqIndices, seqOut); + outrefVariant <<= seqOut[0]; + + Decimal refdec(5, 1, 0xffff, 0xff, 0x1); + inrefDecimal <<= refdec; + inv->invoke(OUString(L"inrefDecimal"), Sequence< Any > ( & inrefDecimal, 1), seqIndices, seqOut); + seqIndices.realloc( 0); + seqOut.realloc(0); + inv->invoke(OUString(L"outDecimal"), Sequence< Any > (&outrefDecimal, 1), seqIndices, seqOut); + outrefDecimal <<= seqOut[0]; + + if (inrefLong != outrefLong || inrefVariant != outrefVariant + || inrefDecimal != outrefDecimal) + return false; + + + // mixed parameter + + // mixed1 + seqIndices.realloc( 0); + seqOut.realloc(0); + Any param[3]; + param[0] = inByte; + param[1] = inFloat; + param[2] = inVariant; + inv->invoke(OUString(L"mixed1"), Sequence< Any >(param, 3), seqIndices, seqOut); + + if (seqOut.getLength() != 3 || inByte != seqOut[0] || inFloat != seqOut[1] + || inVariant != seqOut[2]) + return false; + return true; +} + +bool doSimpleSequenceTest(const Reference & inv) +{ + bool ret = true; + Sequence seqIndices; + Sequence seqOut; + Any voidAny; + Any inArAny; + Any outArray; + Any inArBool, outArBool; + Any inArByte, outArByte; + Any inArShort, outArShort; + Any inArLong, outArLong; + Any inArString, outArString; + Any inArFloat, outArFloat; + Any inArDouble, outArDouble; + Any inArObject, outArObject; + Any outVariant; + + //Initialize arrays + OUString arStr[]= {L"string0", L"string1", L"string2"}; + Sequence seq( arStr, 3); + inArString <<= seq; + + Any arAnyStrTmp[3]; + arAnyStrTmp[0]<<= arStr[0]; + arAnyStrTmp[1]<<= arStr[1]; + arAnyStrTmp[2]<<= arStr[2]; + Sequence seq_1( arAnyStrTmp, 3); + inArAny <<= seq_1; + + // in, out Sequences + + //Test sequence containing Anys of Strings + inv->invoke(OUString(L"inArray"), Sequence< Any > ( & inArAny, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outArray"), Sequence( & voidAny, 1), seqIndices, seqOut); + if (inArAny != seqOut[0]) + return false; + + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"inArray"), Sequence< Any >( & inArString, 1), seqIndices, seqOut); + inv->invoke(OUString(L"outArray"), Sequence< Any >( & voidAny, 1), seqIndices, seqOut); + outArray <<= seqOut[0]; + + sal_Int8 arByte[]={1,2,3}; + Sequence seqByte(arByte, 3); + inArByte <<= seqByte; + inv->invoke(OUString(L"inSequenceByte"),Sequence( & inArByte, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outSequenceByte"), Sequence< Any >( & voidAny, 1), seqIndices, seqOut); + outArByte <<= seqOut[0]; + + sal_Int16 arShort[]={4,5,6}; + Sequence seqShort(arShort, 3); + inArShort<<= seqShort; + inv->invoke(OUString(L"inSequenceShort"),Sequence< Any >( & inArShort, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outSequenceShort"), Sequence< Any >( & voidAny, 1), seqIndices, seqOut); + outArShort <<= seqOut[0]; + + sal_Int32 arLong[] = {7,8,9}; + Sequence seqLong(arLong, 3); + inArLong <<= seqLong; + inv->invoke(OUString(L"inSequenceLong"),Sequence< Any > ( & inArLong, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outSequenceLong"), Sequence< Any >( & voidAny, 1), seqIndices, seqOut); + outArLong <<= seqOut[0]; + + inv->invoke(OUString(L"inSequenceLong"),Sequence< Any > ( & inArLong, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outSequenceLong"), Sequence< Any >( & voidAny, 1), seqIndices, seqOut); + outArLong <<= seqOut[0]; + + inv->invoke( OUString(L"inSequenceString"),Sequence< Any > ( & inArString, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outSequenceString"), Sequence< Any >( & voidAny, 1), seqIndices, seqOut); + outArString <<= seqOut[0]; + + float arFloat[]={3.14f, 31.4f, 314.f}; + Sequence seqFloat( arFloat, 3); + inArFloat <<= seqFloat; + inv->invoke( OUString(L"inSequenceFloat"),Sequence< Any > ( & inArFloat, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outSequenceFloat"), Sequence< Any >( & voidAny, 1), seqIndices, seqOut); + outArFloat <<= seqOut[0]; + + double arDouble[]={3.145, 31.45, 3145.}; + Sequence seqDouble( arDouble, 3); + inArDouble <<= seqDouble; + inv->invoke(OUString(L"inSequenceDouble"),Sequence< Any >( & inArDouble, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outSequenceDouble"), Sequence< Any >( & voidAny, 1), seqIndices, seqOut); + outArDouble <<= seqOut[0]; + + Sequence > seqObj(2); + seqObj[0]= getComObject(L"AxTestComponents.Basic"); + seqObj[1]= getComObject(L"AxTestComponents.Basic"); + inArObject <<= seqObj; + inv->invoke(OUString(L"inSequenceObject"),Sequence< Any >( & inArObject, 1), seqIndices, seqOut); + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"outSequenceObject"), Sequence< Any >( & voidAny, 1), seqIndices, seqOut); + outArObject <<= seqOut[0]; + + if ( ! equalSequences(inArByte, outArByte) || ! equalSequences(inArShort, outArShort) + || ! equalSequences(inArLong, outArLong) || ! equalSequences(inArString, outArray) + || ! equalSequences(inArFloat, outArFloat) || ! equalSequences(inArDouble, outArDouble) + || ! equalSequences(inArString, outArString) || ! equalSequences(inArObject, outArObject)) + return false; + + + // in/out Sequences + + seqIndices.realloc(0); + seqOut.realloc(0); + inv->invoke(OUString(L"inoutArray"), Sequence< Any >( & inArString, 1), seqIndices, seqOut); + inv->invoke(OUString(L"inoutArray"), Sequence< Any >( & inArString, 1), seqIndices, seqOut); + outArray <<= seqOut[0]; + + inv->invoke(OUString(L"inoutSequenceByte"), Sequence( & inArByte, 1), seqIndices, seqOut); + inv->invoke(OUString(L"inoutSequenceByte"), Sequence( & inArByte, 1), seqIndices, seqOut); + outArByte <<= seqOut[0]; + + inv->invoke(OUString(L"inoutSequenceShort"), Sequence( & inArShort, 1), seqIndices, seqOut); + inv->invoke(OUString(L"inoutSequenceShort"), Sequence( & inArShort, 1), seqIndices, seqOut); + outArShort <<= seqOut[0]; + + inv->invoke(OUString(L"inoutSequenceLong"), Sequence( & inArLong, 1), seqIndices, seqOut); + inv->invoke(OUString(L"inoutSequenceLong"), Sequence< Any >( & inArLong, 1), seqIndices, seqOut); + outArLong <<= seqOut[0]; + + inv->invoke(OUString(L"inoutSequenceString"), Sequence( & inArString, 1), seqIndices, seqOut); + inv->invoke(OUString(L"inoutSequenceString"), Sequence( & inArString, 1), seqIndices, seqOut); + outArString <<= seqOut[0]; + + inv->invoke(OUString(L"inoutSequenceFloat"), Sequence( & inArFloat, 1), seqIndices, seqOut); + inv->invoke(OUString(L"inoutSequenceFloat"), Sequence( & inArFloat, 1), seqIndices, seqOut); + outArFloat <<= seqOut[0]; + + inv->invoke(OUString(L"inoutSequenceDouble"), Sequence( & inArDouble, 1), seqIndices, seqOut); + inv->invoke(OUString(L"inoutSequenceDouble"), Sequence( & inArDouble, 1), seqIndices, seqOut); + outArDouble <<= seqOut[0]; + + inv->invoke(OUString(L"inoutSequenceObject"), Sequence( & inArObject, 1), seqIndices, seqOut); + inv->invoke(OUString(L"inoutSequenceObject"), Sequence( & inArObject, 1), seqIndices, seqOut); + outArObject <<= seqOut[0]; + + if ( ! equalSequences(inArByte, outArByte) || ! equalSequences(inArShort, outArShort) + || ! equalSequences(inArLong, outArLong) || ! equalSequences(inArString, outArray) + || ! equalSequences(inArFloat, outArFloat) || ! equalSequences(inArDouble, outArDouble) + || ! equalSequences(inArString, outArString) || ! equalSequences(inArObject, outArObject)) + return false; + + return ret; +} + +HRESULT doTest() +{ + HRESULT hr= S_OK; + USES_CONVERSION; + Reference inv= getComObject( L"AxTestComponents.Basic"); + + HostWin* pWin= new HostWin( L"MFCCONTROL.MfcControlCtrl.1"); + CComPtr spUnk= pWin->GetHostedControl(); + Reference invMfc= convertComObject( spUnk.p); + + Sequence< sal_Int16> seqIndices; + Sequence seqOut; + + Any aAny; + Any anyOut; + char buff[1024]; + Any seqAny; + + if (! doSimpleTest(inv)) + { + fprintf(stdout, "### Test failed!\n"); + return E_FAIL; + } + + if (! doPropertyTest(inv)) + { + fprintf(stdout, "### Test failed!\n"); + return E_FAIL; + } + + if ( ! doSimpleSequenceTest(inv)) + { + fprintf(stdout, "### Test failed! \n"); + return E_FAIL; + } + + if ( ! doParameterTest(inv)) + { + fprintf(stdout, "### Test failed! \n"); + return E_FAIL; + } + + if ( ! doPropertyWithArgumentTest(inv)) + { + fprintf(stdout, "### Test failed! \n"); + return E_FAIL; + } + + +// // in multi Sequences + +// // inMulDimArrayLong + sal_Int32 arLongi[]={1,2,3}; + sal_Int32 arLongi2[]={4,5,6,7}; + sal_Int32 arLongi3[]={8,9,10,11,12}; + + Sequence seqLongi1( arLongi, 3); + Sequence seqLongi2( arLongi2, 4); + Sequence seqLongi3( arLongi3, 5); + + Sequence< Sequence< sal_Int32 > > seq2i(3); + seq2i[0]= seqLongi1; + seq2i[1]= seqLongi2; + seq2i[2]= seqLongi3; + seqAny<<= seq2i; + // dimension length 3,5 + inv->invoke( OUString(L"inMulDimArrayLong"),Sequence< Any > ( &seqAny, 1), seqIndices, seqOut); + + //inMulDimArrayVariant + inv->invoke( OUString(L"inMulDimArrayVariant"),Sequence< Any > ( &seqAny, 1), seqIndices, seqOut); + + //inMulDimArrayLong2 + sal_Int32 arLongii1[]={1,2,3}; + sal_Int32 arLongii2[]={4,5,6,7}; + sal_Int32 arLongii3[]={8,9,10,11,12}; + sal_Int32 arLongii4[]={13,14,15,16}; + sal_Int32 arLongii5[]={17,18,19}; + + Sequence seqLongii1( arLongii1, 3); + Sequence seqLongii2( arLongii2, 4); + Sequence seqLongii3( arLongii3, 5); + Sequence seqLongii4( arLongii4, 4); + Sequence seqLongii5( arLongii5, 3); + + Sequence< Sequence< sal_Int32 > > seq2ii(3); + Sequence< Sequence< sal_Int32> > seq2ii2(2); + seq2ii[0]= seqLongii1; + seq2ii[1]= seqLongii2; + seq2ii[2]= seqLongii3; + + seq2ii2[0]= seqLongii4; + seq2ii2[1]= seqLongii5; + + Sequence< Sequence< Sequence< sal_Int32> > > seq3ii(2); + seq3ii[0]=seq2ii; + seq3ii[1]=seq2ii2; + seqAny<<= seq3ii; + inv->invoke( OUString(L"inMulDimArrayLong2"),Sequence< Any > ( &seqAny, 1), seqIndices, seqOut); + + // inMulDimArrayByte2 + sal_Int8 arByteii1[]={1,2,3}; + sal_Int8 arByteii2[]={4,5,6,7}; + sal_Int8 arByteii3[]={8,9,10,11,12}; + sal_Int8 arByteii4[]={13,14,15,16}; + sal_Int8 arByteii5[]={17,18,19}; + + Sequence seqByteii1( arByteii1, 3); + Sequence seqByteii2( arByteii2, 4); + Sequence seqByteii3( arByteii3, 5); + Sequence seqByteii4( arByteii4, 4); + Sequence seqByteii5( arByteii5, 3); + + Sequence< Sequence< sal_Int8 > > seq2Byteii(3); + Sequence< Sequence< sal_Int8> > seq2Byteii2(2); + seq2Byteii[0]= seqByteii1; + seq2Byteii[1]= seqByteii2; + seq2Byteii[2]= seqByteii3; + + seq2Byteii2[0]= seqByteii4; + seq2Byteii2[1]= seqByteii5; + + Sequence< Sequence< Sequence< sal_Int8> > > seq3Byteii(2); + seq3Byteii[0]=seq2Byteii; + seq3Byteii[1]=seq2Byteii2; + seqAny<<= seq3Byteii; + inv->invoke( OUString(L"inMulDimArrayByte2"),Sequence< Any > ( &seqAny, 1), seqIndices, seqOut); + + + // Tests with a MFC ActiveX control, ( pure dispinterface) + + + // in parameter MFC ActiveX + + // unsigned char is not supported by MFC + // aAny <<= ( sal_Int8) 127; + // invMfc->invoke( OUString(L"inByte"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + if ( ! invMfc.is()) + return hr; + aAny <<= static_cast(-1); + aAny= invMfc->invoke( OUString(L"inShort"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + + + aAny <<= ( sal_Int32) 1234567; + aAny=invMfc->invoke( OUString(L"inLong"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + sal_Int32 retLong= *(sal_Int32*)aAny.getValue(); + + OUString str_1(L" this is clientTest.exe"); + aAny <<= str_1; + aAny=invMfc->invoke( OUString(L"inString"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + aAny>>= str_1; + + aAny <<= ( float) 3.14; + aAny=invMfc->invoke( OUString(L"inFloat"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + + aAny <<= ( double) 3.145; + aAny=invMfc->invoke( OUString(L"inDouble"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + + aAny <<= OUString( L" A string in an any"); + aAny=invMfc->invoke( OUString(L"inVariant"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + + + Reference < XInvocation > inv5= getComObject(L"AxTestComponents.Basic"); + Any anyVal4; + anyVal4 <<= OUString(L"this is the value of prpString"); + inv5->setValue( OUString(L"prpString"), anyVal4); + aAny <<= inv5; + aAny=invMfc->invoke( OUString(L"inObject"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + + +// // out parameter MFC ActiveX + + +// // outShort + aAny= invMfc->invoke( OUString(L"outShort"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + anyOut<<= seqOut[0]; + sprintf(buff, "MFC outShort %d", *(sal_Int16*)anyOut.getValue()); + MessageBox( NULL, buff, _T("clientTest"), MB_OK); + + // outLong + aAny= invMfc->invoke( OUString(L"outLong"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + anyOut<<= seqOut[0]; + sprintf(buff, "MFC outLong %d", *(sal_Int32*)anyOut.getValue()); + MessageBox( NULL, buff, _T("clientTest"), MB_OK); + + // outString + aAny= invMfc->invoke( OUString(L"outString"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + anyOut<<= seqOut[0]; + sprintf(buff, "MFC outString %S", ((OUString*)anyOut.getValue())->getStr()); + MessageBox( NULL, buff, _T("clientTest"), MB_OK); + + // outFloat + aAny= invMfc->invoke( OUString(L"outFloat"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + anyOut<<= seqOut[0]; + sprintf(buff, "MFC outFloat %f", *(float*)anyOut.getValue()); + MessageBox( NULL, buff, _T("clientTest"), MB_OK); + + // outDouble + aAny= invMfc->invoke( OUString(L"outDouble"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + anyOut<<= seqOut[0]; + sprintf(buff, "MFC outFloat %f", *(double*)anyOut.getValue()); + MessageBox( NULL, buff, _T("clientTest"), MB_OK); + + // outVariant + // we expect a string!! ( VT_BSTR) + aAny= invMfc->invoke( OUString(L"outVariant"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + anyOut<<= seqOut[0]; + sprintf(buff, "MFC outVariant %S", ((OUString*)anyOut.getValue())->getStr()); + MessageBox( NULL, buff, _T("clientTest"), MB_OK); + + // outDouble + aAny= invMfc->invoke( OUString(L"outObject"), Sequence< Any > ( &aAny, 1), seqIndices, seqOut); + Reference invOut5; + seqOut[0]>>= invOut5; + // we assume that an object of AxTestControls.Basic is being returned. + anyOut= invOut5->getValue( OUString(L"prpString")); + OUString tmpStr; + anyOut>>=tmpStr; + sprintf(buff, "MFC outObject, property: %S", tmpStr.getStr()); + MessageBox( NULL, buff, _T("clientTest"), MB_OK); + + + // Sequence parameter MFC ActiveX + + // Sequences are not directly supported. + + + delete pWin; + return hr; + +} + + +//VARIANT_TRUE VT_UI1 + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/OleClient/funcs.cxx b/extensions/test/ole/OleClient/funcs.cxx new file mode 100644 index 000000000..a72c7c49e --- /dev/null +++ b/extensions/test/ole/OleClient/funcs.cxx @@ -0,0 +1,345 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include +#include +#include "cppuhelper/bootstrap.hxx" +#include "rtl/process.h" +#include "typelib/typedescription.hxx" + +#include "com/sun/star/bridge/ModelDependent.hpp" +#include "com/sun/star/bridge/XBridgeSupplier2.hpp" +#include "com/sun/star/uno/TypeClass.hpp" +#include "com/sun/star/script/XInvocation.hpp" +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include +#include "rtl/ustring.hxx" + +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::ModelDependent; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::script; +using namespace com::sun::star::bridge::oleautomation; +using namespace cppu; + + +template< class T > +bool equalSequences(const Sequence& seqIn, const Sequence & returned); + + +Reference< XMultiServiceFactory > objectFactory; + + +Reference getMultiServiceFactory() +{ + static Reference< XMultiServiceFactory > factory; + if( ! objectFactory.is() ) + { + Reference context = defaultBootstrap_InitialComponentContext(); + factory.set(context->getServiceManager(), UNO_QUERY); + + } + return factory; +} + +Reference getComObject( OUString progId) +{ + HRESULT hr= S_OK; + Reference< XInvocation > ret; + if( ! objectFactory.is()) + { Reference mgr= getMultiServiceFactory(); + Reference xInt= mgr->createInstance( + "com.sun.star.bridge.oleautomation.Factory"); + objectFactory.set(xInt, UNO_QUERY); + } + + if( objectFactory.is()) + { + Reference xIntAx= objectFactory->createInstance( progId.getStr()); + if( xIntAx.is() ) + { + Reference< XInvocation > xInv( xIntAx, UNO_QUERY); + ret= xInv; + } + } + return ret; +} + +Reference convertComObject( IUnknown* pUnk) +{ + Reference< XMultiServiceFactory > mgr= getMultiServiceFactory(); + Reference< XInterface > xIntSupplier= mgr->createInstance("com.sun.star.bridge.OleBridgeSupplier2"); + Reference< XBridgeSupplier2 > xSuppl( xIntSupplier, UNO_QUERY); + + Any any; + CComVariant var( pUnk); + any <<= (sal_uIntPtr) &var; + sal_uInt8 arId[16]; + rtl_getGlobalProcessId( arId); + Any target= xSuppl->createBridge( any, Sequence( (sal_Int8*)arId, 16), OLE, UNO ); + + Reference ret; + target>>= ret; + return ret; +} + +/* + Parameter values contains the expected return values. The value at index 0 + correspond to parameter 0 (left - most). For parameters which are not out or + in/out the value must be a void any. + + The number of items in value must be the + same as the number of provided parameter during the call on the method. + + The parameter outArgs, indices correspond to the sequences which are + arguments to XInvocation::invoke + */ +bool checkOutArgs(const Sequence & outArgs, + const Sequence & indices, const Sequence & values) +{ + if (values.getLength() != outArgs.getLength()) + return false; + //iterate over all parameters. i represents the parameter index + for (int i = 0; i < values.getLength(); i++) + { + if (values[i].getValueType() == cppu::UnoType::get()) + continue; + //out parameter + //Based on the parameter index find the correspondent out value + int indexOutSeq = -1; + for (int iIndices = indices.getLength() - 1; iIndices >= 0; iIndices --) + { + if (indices[iIndices] == i) + { + indexOutSeq = iIndices; + break; + } + } + if (indexOutSeq == -1) + return false; + + Any value; + Any out; + values[i] >>= value; + outArgs[indexOutSeq] >>=out; + NamedArgument naVal; + NamedArgument naOut; + value >>= naVal; + out >>= naOut; + if (values[i].getValueType() == cppu::UnoType::get()) + { + NamedArgument inNamed; + values[i] >>= inNamed; + value <<= inNamed.Value; + } + if (value != outArgs[indexOutSeq]) + return false; + } + return true; +} + +/* The returned sequence always contains Any elements +*/ +bool equalSequences(const Any& orig, const Any& returned) +{ + if (orig.getValueTypeClass() != TypeClass_SEQUENCE) + { + OSL_ASSERT(0); + return false; + } + TypeDescription td(orig.getValueTypeRef()); + typelib_IndirectTypeDescription * indirect_td = (typelib_IndirectTypeDescription *) td.get(); + + switch (indirect_td->pType->eTypeClass) + { + case TypeClass_CHAR: + { + Sequence seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + case TypeClass_BOOLEAN: + { + Sequence seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + case TypeClass_BYTE: + { + Sequence seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + case TypeClass_SHORT: + { + Sequence seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + case TypeClass_LONG: + { + Sequence seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + case TypeClass_FLOAT: + { + Sequence seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + case TypeClass_DOUBLE: + { + Sequence seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + case TypeClass_STRING: + { + Sequence seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + case TypeClass_ANY: + { + Sequence seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + case TypeClass_SEQUENCE: + { + //Sequence seq; + //orig >>= seq; + //Sequence seq2; + //returned >>= seq2; + //return equalSequences(seq, seq2); + break; + } + case TypeClass_INTERFACE: + { + Sequence > seq; + orig >>= seq; + Sequence seq2; + returned >>= seq2; + return equalSequences(seq, seq2); + } + default: + return false; + } + return false; +} + +template< class T > +bool equalSequences(const Sequence& seqIn, const Sequence & seqOut) +{ + if (seqIn.getLength() != seqOut.getLength()) + return false; + int len = seqIn.getLength(); + for (int i = 0; i < len; i++) + { + Any anyIn; + anyIn <<= seqIn[i]; + Any anyOut = seqOut[i]; + if (anyIn != anyOut) + return false; + } + + return true; +} + +void printSequence( Sequence& val) +{ + +// typelib_TypeDescription* desc; +// val.getValueTypeDescription( &desc); +// typelib_typedescription_release( desc); + + USES_CONVERSION; + char buff[1024]; + buff[0]=0; + char tmpBuf[1024]; + tmpBuf[0]=0; + sal_Int32 i; + + for( i=0; i< val.getLength(); i++) + { + Any& elem= val[i]; + switch ( elem.getValueTypeClass()) + { + case TypeClass_BYTE: + sprintf( tmpBuf, "sal_Int8 %d \n", *(sal_Int8*)elem.getValue()); + break; + case TypeClass_SHORT: + sprintf( tmpBuf, "sal_Int16 %d \n", *(sal_Int16*)elem.getValue()); + break; + case TypeClass_LONG: + sprintf( tmpBuf, "sal_Int32 %d \n", *(sal_Int32*)elem.getValue()); + break; + case TypeClass_DOUBLE: + sprintf( tmpBuf, "double %f \n", *(double*)elem.getValue()); + break; + case TypeClass_FLOAT: + sprintf( tmpBuf, "float %f \n", *(float*)elem.getValue()); + break; + case TypeClass_STRING: + sprintf( tmpBuf, "%S \n", (*(OUString*)elem.getValue()).getStr()); + break; + case TypeClass_INTERFACE: + { + // we assume that the interface is XInvocation of an AxTestControls.Basic component. + Reference inv; + elem>>= inv; + if( inv.is()) + { + Any prpVal= inv->getValue( OUString( L"prpString")); + sprintf( tmpBuf, "Property prpString: %S \n", (*(OUString*)prpVal.getValue()).getStr()); + } + break; + } + default:break; + } + strcat( buff, tmpBuf); + + } + + MessageBox( NULL, A2T(buff), _T("clientTest: printing Sequence elements"), MB_OK); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/OleClient/readme.txt b/extensions/test/ole/OleClient/readme.txt new file mode 100644 index 000000000..bcee8edde --- /dev/null +++ b/extensions/test/ole/OleClient/readme.txt @@ -0,0 +1,10 @@ +The program tests the OleObjectFactory service which enables to use COM components +through XInvocation. + +Requirements: + +types.rdb and services.rdb and OleClient.ini have to be next to the executable. +COM component: XCallback_Impl.Simple ( extensions/test/ole/unotocomcalls/XCallback_Impl ) +ActiveX controls: AxTestComponent.Basic ( extensions/test/ole/AxTestComponents) + MFCCONTROL.MfcControlCtrl.1 (extensions/test/ole/MfcControl) + diff --git a/extensions/test/ole/OleConverterVar1/convTest.cxx b/extensions/test/ole/OleConverterVar1/convTest.cxx new file mode 100644 index 000000000..8fc27177e --- /dev/null +++ b/extensions/test/ole/OleConverterVar1/convTest.cxx @@ -0,0 +1,647 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#pragma warning (disable: 4917) +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +extern CComModule _Module; +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +CComModule _Module; +BEGIN_OBJECT_MAP(ObjectMap) +END_OBJECT_MAP() + +#include "smartarray.h" +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::ModelDependent; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace oletest; +using namespace cppu; + + +HRESULT doTest(); +HRESULT InitializeParameter(); +void printResultVariantArray( VARIANT & var); +void printVariant( VARIANT & var); + + +int SAL_CALL main( int argc, char* argv[] ) +{ + HRESULT hr; + if( FAILED( hr=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) + { + printf("CoInitializeEx failed \n"); + return -1; + } + + + _Module.Init( ObjectMap, GetModuleHandleA( NULL)); + + if( FAILED(hr=doTest())) + { + _com_error err( hr); + const CHAR * errMsg= err.ErrorMessage(); + MessageBoxA( NULL, errMsg, "Test failed", MB_ICONERROR); + } + + + _Module.Term(); + CoUninitialize(); + return 0; +} +char _c[]={ 1,2,3,4,5}; +short _short[]={0xffff, 1, 11 ,111, 1111 }; +unsigned short _ushort[]={0xffff, 1, 11 ,111, 1111 }; +long _long[]= { 0xffffffff, 11, 111 ,1111, 1111 }; +unsigned long _ulong[]= { 0xffffffff, 11, 111 ,1111, 1111 }; +float _float[]= { 12345.f, 1234.5f, 123.45f, 12.345f, 1.2345f}; +double _double[]= {12345, 1234.5, 123.45, 12.345, 1.2345}; + +CComVariant _variant[]= {L"variant 1", L"variant2", L"variant3"}; +wchar_t _wchar[]= {L'1', L'2', L'3', L'A', L' '}; +BSTR _bstr[]={L"Ich", L"bin", L"ein", L"Hamburger", L"Jung"}; +SmartArray arByte( _c, 5, VT_I1); +SmartArray< short> arShort( _short, 5, VT_I2); +//SmartArray< unsigned short> arUShort( _ushort, 5, VT_UI2); +SmartArray< long> arLong( _long, 5, VT_I4); +//SmartArray< unsigned long> arULong( _ulong, 5, VT_UI4); +//SmartArray< float> arFloat( _float, 5, VT_R4 ); +SmartArray< double> arDouble( _double, 5, VT_R8 ); +//SmartArray< unsigned short> arWChar( _wchar, 5, VT_UI2 ); +SmartArray< wchar_t* > arString( _bstr, 5, VT_BSTR); +SmartArray< VARIANT > arVariant( _variant, 3, VT_VARIANT); + + +HRESULT doTest() +{ + HRESULT hr; + USES_CONVERSION; + CComPtr spUnkMgr; + + putenv("UNO_TYPES=types.rdb"); + putenv("UNO_SERVICES=services.rdb"); + Reference xContext = defaultBootstrap_InitialComponentContext(); + + Reference< XMultiComponentFactory > mgr = xContext->getServiceManager();//createRegistryServiceFactory( OUString(L"services.rdb")); + Reference< XInterface > xIntSupplier= mgr->createInstanceWithContext( + "com.sun.star.bridge.OleBridgeSupplierVar1", xContext); + Reference< XBridgeSupplier2 > xSuppl( xIntSupplier, UNO_QUERY); + Reference xOletest= mgr->createInstanceWithContext( + "oletest.OleTest", xContext); + Any any; + any <<= xOletest; + sal_uInt8 arId[16]; + rtl_getGlobalProcessId( arId); + Any target= xSuppl->createBridge( any, Sequence( (sal_Int8*)arId, 16), UNO, OLE); + CComDispatchDriver oletest; + if (target.getValueTypeClass() == cppu::UnoType::get().getTypeClass()) + { + VARIANT* pVariant = *(VARIANT**)target.getValue(); + + oletest= pVariant->pdispVal; + + VariantClear(pVariant); + CoTaskMemFree(pVariant); + } + + CComVariant varRet; + CComVariant varParam1; + CComVariant varParam2; + CComVariant varParam3; + CComVariant varParam4; + + long value= 100; + varParam1.vt= VT_I1 | VT_BYREF; + varParam1.plVal= &value; + + // Testing the caching of DISPIDs and the process of acquiring member information + // on demand in IDispatch::Invoke + // Step through the corresponding IDispatch implementation of the ole bridge + hr= oletest.Invoke1(static_cast(L"testinout_methodByte"), &varParam1, &varRet); + hr= oletest.Invoke1(static_cast(L"testinout_methodByte"), &varParam1, &varRet); + // Name ok but different case + hr= oletest.Invoke1(static_cast(L"Testinout_methodByte"), &varParam1, &varRet); + hr= oletest.Invoke1(static_cast(L"Testinout_methodByte"), &varParam1, &varRet); + // not existing member + hr= oletest.Invoke1(static_cast(L"Testinout"), &varParam1, &varRet); + hr= oletest.Invoke1(static_cast(L"Testinout"), &varParam1, &varRet); + + // Property + varParam1.vt= VT_ARRAY | VT_I1; + varParam1.parray= (SAFEARRAY*)arByte; + hr= oletest.PutPropertyByName( static_cast(L"AttrByte"), &varParam1); + hr= oletest.PutPropertyByName( static_cast(L"AttrByte"), &varParam1); + // Name ok but different case + hr= oletest.PutPropertyByName( static_cast(L"attrByte"), &varParam1); + hr= oletest.PutPropertyByName( static_cast(L"attrByte"), &varParam1); + // not existing member + hr= oletest.PutPropertyByName( static_cast(L"attr"), &varParam1); + hr= oletest.PutPropertyByName( static_cast(L"attr"), &varParam1); + + // PropertyGet + hr= oletest.GetPropertyByName( static_cast(L"AttrByte"), &varRet); + + hr= oletest.GetPropertyByName( static_cast(L"attrByte"), &varRet); + hr= oletest.GetPropertyByName( static_cast(L"attrByte"), &varRet); + //not existing member + hr= oletest.GetPropertyByName( static_cast(L"attrBy"), &varRet); + hr= oletest.GetPropertyByName( static_cast(L"attrBy"), &varRet); + + DISPID dispid; + LPOLESTR method= L"methodByte"; + hr = oletest.p->GetIDsOfNames(IID_NULL, &method, 1, LOCALE_USER_DEFAULT, &dispid); + + + CComVariant arg[1]; + arg[0].vt= VT_ARRAY | VT_I1; + arg[0].parray= (SAFEARRAY*)arByte; + DISPPARAMS params={ arg,0,1,0}; + + hr = oletest.p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, + DISPATCH_METHOD | DISPATCH_PROPERTYPUT, ¶ms, &varRet, NULL, NULL); + + hr = oletest.p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, + DISPATCH_METHOD | DISPATCH_PROPERTYPUT, ¶ms, &varRet, NULL, NULL); + + // different case + LPOLESTR method2= L"MEthodByte"; + hr = oletest.p->GetIDsOfNames(IID_NULL, &method2, 1, LOCALE_USER_DEFAULT, &dispid); + + hr = oletest.p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, + DISPATCH_METHOD | DISPATCH_PROPERTYPUT, ¶ms, &varRet, NULL, NULL); + + hr = oletest.p->Invoke(dispid, IID_NULL, LOCALE_USER_DEFAULT, + DISPATCH_METHOD | DISPATCH_PROPERTYPUT, ¶ms, &varRet, NULL, NULL); + + LPOLESTR attrib= L"AttrByte"; + hr = oletest.p->GetIDsOfNames(IID_NULL, &attrib, 1, LOCALE_USER_DEFAULT, &dispid); + + hr = oletest.p->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT, + DISPATCH_METHOD | DISPATCH_PROPERTYPUTREF, ¶ms, &varRet, NULL, NULL); + + hr = oletest.p->Invoke( dispid, IID_NULL, LOCALE_USER_DEFAULT, + DISPATCH_METHOD | DISPATCH_PROPERTYGET, ¶ms, &varRet, NULL, NULL); + + + CComVariant varByteArray; + varByteArray.vt= VT_ARRAY | VT_I1; + varByteArray.parray= (SAFEARRAY*)arByte; + CComVariant varShortArray; + varShortArray.vt= VT_ARRAY | VT_I2; + varShortArray.parray= (SAFEARRAY*)arShort; + CComVariant varLongArray; + varLongArray.vt= VT_ARRAY | VT_I4; + varLongArray.parray= (SAFEARRAY*)arLong; + CComVariant varDoubleArray; + varDoubleArray.vt= VT_ARRAY | VT_R8; + varDoubleArray.parray= (SAFEARRAY*)arDouble; + CComVariant varStringArray; + varStringArray.vt= VT_ARRAY | VT_BSTR; + varStringArray.parray= (SAFEARRAY*)arString; + CComVariant varArray; + varArray.vt= VT_ARRAY | VT_VARIANT; + varArray.parray= (SAFEARRAY*)arVariant; + + FONTDESC fd={ sizeof( fd), L"ARIAL", 10, FW_NORMAL, 0, 0, 0, 0}; + + + CComPtr< IUnknown > unk1; + CComPtr< IUnknown > unk2; + CComPtr< IUnknown > unk3; + + IUnknown* _unknown[3]; + hr= OleCreateFontIndirect( &fd, __uuidof( IUnknown), (void**)&unk1.p); + hr= OleCreateFontIndirect( &fd, __uuidof( IUnknown), (void**)&unk2.p); + hr= OleCreateFontIndirect( &fd, __uuidof( IUnknown), (void**)&unk3.p); + _unknown[0]= unk1; + _unknown[1]= unk2; + _unknown[2]= unk3; + SmartArray arUnknown( _unknown, 3, VT_UNKNOWN); + + CComVariant varUnkArray; + varUnkArray.vt= VT_ARRAY | VT_UNKNOWN; + varUnkArray.parray= (SAFEARRAY*)arUnknown; + + // preparing out parameter; + char byteOut; + CComVariant varOutByte; + varOutByte.vt= VT_BYREF | VT_UI1; + V_I1REF(&varOutByte)= &byteOut; + short shortOut; + CComVariant varOutShort; + varOutShort.vt= VT_BYREF | VT_I2; + V_I2REF( &varOutShort)= &shortOut; + long longOut; + CComVariant varOutLong; + varOutLong.vt= VT_BYREF | VT_I4; + V_I4REF( &varOutLong)= &longOut; + double doubleOut; + CComVariant varOutDouble; + varOutDouble.vt= VT_BYREF | VT_R8; + V_R8REF( &varOutDouble)= &doubleOut; + BSTR bstrOut= NULL; + CComVariant varOutString; + varOutString.vt= VT_BYREF | VT_BSTR; + V_BSTRREF(&varOutString)= &bstrOut; + CComVariant variantOut; + CComVariant varOutAny; + varOutAny.vt= VT_BYREF | VT_VARIANT; + V_VARIANTREF(&varOutAny)= &variantOut; + + CComPtr dispOut; + CComVariant varOutXInterface; + varOutXInterface.vt= VT_BYREF |VT_DISPATCH; + V_DISPATCHREF(&varOutXInterface)= &dispOut.p; + + // In Parameter ( all of type Sequence ########################################################### + OutputDebugStringA( "In parameter of type Sequence ###########################################\n" + "The functions return the Sequence parameter \n\n"); + + OutputDebugStringA("methodByte | Params: \n"); + printVariant( varByteArray); + hr= oletest.Invoke1(static_cast(L"methodByte"), &varByteArray, &varRet); + OutputDebugStringA("methodByte | return value \n"); + printVariant( varRet); + + OutputDebugStringA("methodShort | Params: \n"); + printVariant( varShortArray); + hr= oletest.Invoke1(static_cast(L"methodShort"), &varShortArray, &varRet); + OutputDebugStringA("methodShort | return value \n"); + printVariant( varRet); + + OutputDebugStringA("methodLong | Params: \n"); + printVariant( varLongArray); + hr= oletest.Invoke1(static_cast(L"methodLong"), &varLongArray, &varRet); + OutputDebugStringA("methodLong | return value \n"); + printVariant( varRet); + + OutputDebugStringA("methodDouble | Params: \n"); + printVariant( varDoubleArray); + hr= oletest.Invoke1(static_cast(L"methodDouble"), &varDoubleArray, &varRet); + OutputDebugStringA("methodDouble | return value \n"); + printVariant( varRet); + + OutputDebugStringA("methodString | Params: \n"); + printVariant( varStringArray); + hr= oletest.Invoke1(static_cast(L"methodString"), &varStringArray, &varRet); + OutputDebugStringA("methodString | return value \n"); + printVariant( varRet); + + OutputDebugStringA("methodAny | Params: \n"); + printVariant( varArray); + hr= oletest.Invoke1(static_cast(L"methodAny"), &varArray, &varRet); + OutputDebugStringA("methodAny | return value \n"); + printVariant( varRet); + + OutputDebugStringA("methodXInterface | Params: \n"); + printVariant( varUnkArray); + hr= oletest.Invoke1(static_cast(L"methodXInterface"), &varUnkArray, &varRet); + OutputDebugStringA("methodAny | return value \n"); + printVariant( varRet); + + // Out Parameter ########################################################################### + OutputDebugStringA("Out parameter ###########################################\n\n"); + + OutputDebugStringA("testout_methodByte \n"); + hr= oletest.InvokeN(static_cast(L"testout_methodByte"), &varOutByte, 1, &varRet); + OutputDebugStringA("testout_methodByte | out value: \n"); + printVariant( varOutByte); + + OutputDebugStringA("testout_methodShort \n"); + hr= oletest.Invoke1(static_cast(L"testout_methodShort"), &varOutShort, &varRet); + OutputDebugStringA("testout_methodShort | out value: \n"); + printVariant( varOutShort); + + OutputDebugStringA("testout_methodLong \n"); + hr= oletest.Invoke1(static_cast(L"testout_methodLong"), &varOutLong, &varRet); + OutputDebugStringA("testout_methodLong | out value: \n"); + printVariant( varOutLong); + + OutputDebugStringA("testout_methodDouble \n"); + hr= oletest.Invoke1(static_cast(L"testout_methodDouble"), &varOutDouble, &varRet); + OutputDebugStringA("testout_methodDouble | out value: \n"); + printVariant( varOutDouble); + + OutputDebugStringA("testout_methodString \n"); + hr= oletest.Invoke1(static_cast(L"testout_methodString"), &varOutString, &varRet); + OutputDebugStringA("testout_methodString | out value: \n"); + printVariant( varOutString); + + OutputDebugStringA("testout_methodAny \n"); + hr= oletest.Invoke1(static_cast(L"testout_methodAny"), &varOutAny, &varRet); + OutputDebugStringA("methodAny | out value: \n"); + printVariant( varOutAny); + + OutputDebugStringA("testout_methodXInterface \n"); + hr= oletest.Invoke1(static_cast(L"testout_methodXInterface"), &varOutXInterface, &varRet); + OutputDebugStringA("methodAny | out value: \n"); + printVariant( varOutXInterface); + CComDispatchDriver outDisp( *varOutXInterface.ppdispVal); + CComVariant varAttr3; + outDisp.GetPropertyByName(L"AttrAny2", &varAttr3); + ATLTRACE("property OleTest.AttrAny2: %s", W2A(varAttr3.bstrVal)); + + OutputDebugStringA("testout_methodMulParams1 ( 2 out Parameter) \n"); + long longOut2=0; + CComVariant _params[2]; + longOut=0; + _params[0]= varOutLong; + _params[1].vt= VT_BYREF | VT_I4; + V_I4REF(& _params[1])= &longOut2; + hr= oletest.InvokeN( static_cast(L"testout_methodMulParams1"), (VARIANT*)&_params, 2); + OutputDebugStringA("testout_methodMulParams1 | out values: \n"); + printVariant( _params[1]); + printVariant( _params[0]); + + OutputDebugStringA("testout_methodMulParams2 ( 3 out Parameter) \n"); + CComVariant _params2[3]; + _params2[2]= varOutLong; + _params2[1].vt= VT_BYREF | VT_I4; + V_I4REF(& _params2[1])= &longOut2; + _params2[0]= varOutString; + hr= oletest.InvokeN( static_cast( L"testout_methodMulParams2"), (VARIANT*)&_params2, 3); + OutputDebugStringA("testout_methodMulParams2 | out values: \n"); + printVariant( _params2[2]); + printVariant( _params2[1]); + printVariant( _params2[0]); + + OutputDebugStringA("testout_methodMulParams3 ( 1 in and 1 out Parameter) \n"); + CComVariant _params3[2]; + _params3[1]= CComBSTR(L" In string"); + _params3[0]= varOutString; + hr= oletest.InvokeN( static_cast( L"testout_methodMulParams3"), (VARIANT*)&_params3, 2); + OutputDebugStringA("testout_methodMulParams3 | out values: \n"); + printVariant( _params3[1]); + printVariant( _params3[0]); + + //In Out Parameter ########################################################################### + OutputDebugStringA("In Out parameter ###########################################\n\n"); + + *V_I1REF(&varOutByte)= 5; + ATLTRACE("testinout_methodByte | in value: %d \n", *V_I1REF(&varOutByte)); + hr= oletest.InvokeN(static_cast(L"testinout_methodByte"), &varOutByte, 1, &varRet); + OutputDebugStringA("testinout_methodByte | out value: \n"); + printVariant( varOutByte); + + OutputDebugStringA("testinout_methodShort | in value= 1000 \n"); + *V_UI2REF(&varOutShort)= 1000; + hr= oletest.Invoke1(static_cast(L"testinout_methodShort"), &varOutShort, &varRet); + OutputDebugStringA("testinout_methodShort | out value: \n"); + printVariant( varOutShort); + + OutputDebugStringA("testinout_methodLong | in value= 10000 \n"); + *V_UI4REF(&varOutLong)= 10000; + hr= oletest.Invoke1(static_cast(L"testinout_methodLong"), &varOutLong, &varRet); + OutputDebugStringA("testinout_methodLong | out value: \n"); + printVariant( varOutLong); + + *V_R8REF(&varOutDouble)= 3.14; + ATLTRACE("testinou_methodDouble in value: %f \n",*V_R8REF(&varOutDouble)); + hr= oletest.Invoke1(static_cast(L"testinout_methodDouble"), &varOutDouble, &varRet); + OutputDebugStringA("testinout_methodDouble | out value: \n"); + printVariant( varOutDouble); + + SysFreeString( *V_BSTRREF(&varOutString)); + *V_BSTRREF(&varOutString)= SysAllocString( L"this is a in string"); + ATLTRACE("testinout_methodString | value: %s \n", W2A(*V_BSTRREF(&varOutString))); + hr= oletest.Invoke1(static_cast(L"testinout_methodString"), &varOutString, &varRet); + OutputDebugStringA("testinout_methodString | out value: \n"); + printVariant( varOutString); + + CComVariant var1(CComBSTR(L" this is a string in a VARIANT")); + CComVariant outVar1; + outVar1.vt= VT_BYREF | VT_VARIANT; + outVar1.pvarVal= &var1; + ATLTRACE("testinout_methodAny | parameter: %s\n", W2A(var1.bstrVal)); + hr= oletest.Invoke1(static_cast(L"testinout_methodAny"), &varOutAny, &varRet); + OutputDebugStringA("testinout_methodAny | out value: \n"); + printVariant( varOutAny); + + CComPtr< IUnknown > objectIn = unk1; + CComVariant varOutIFace; + varOutIFace.vt= VT_BYREF | VT_UNKNOWN; + varOutIFace.ppunkVal= &objectIn.p; + (*varOutIFace.ppunkVal)->AddRef(); + OutputDebugStringA("testinout_methodXInterface | in value: \n"); + printVariant(varOutIFace); + hr= oletest.Invoke1(static_cast(L"testinout_methodXInterface"), &varOutIFace, &varRet); + OutputDebugStringA("testinout_methodXInterface | out value: \n"); + printVariant( varOutIFace); + + // Properties ###################################################################### + OutputDebugStringA(" Properties ###########################################\n\n"); + + OutputDebugStringA("set property \"AttrByte\" | value"); + //CComVariant propArByte; + //propArByte.vt= VT_ARRAY | VT_I1; + varParam1.parray= (SAFEARRAY*)arByte; + printVariant( varParam1); + hr= oletest.PutPropertyByName( static_cast(L"AttrByte"), &varParam1); + OutputDebugStringA("get property \"AttrByte\" | value:"); + varRet.Clear(); + hr= oletest.GetPropertyByName( static_cast(L"AttrByte"), &varRet); + printVariant( varRet); + + + return S_OK; + + +} + + +void printVariant( VARIANT & _var) +{ + HRESULT hr; + USES_CONVERSION; + CComVariant var; + hr= VariantCopyInd( &var, &_var); + if( var.vt & VT_ARRAY) + { + VARTYPE type= var.vt ^ VT_ARRAY; + SAFEARRAY * sarray= var.parray; + long lbound; + long ubound; + hr= SafeArrayGetLBound( sarray, 1, &lbound); + hr= SafeArrayGetUBound( sarray, 1, &ubound); + long count= ubound - lbound + 1; + char charValue; + BYTE byteValue; + short shortValue; + long longValue; + double doubleValue; + IUnknown* unkValue; + BSTR bstrValue; + OutputDebugStringA("# Array \n"); + for( long i= 0; i < count; i++) + { +// CComVariant variantValue; + CHAR buf[256]; + wsprintfA( buf, "%d : ", i); + OutputDebugStringA( buf); + VARIANT varTemp; + VariantInit( &varTemp); + VARIANT variantValue; + VariantInit( &variantValue); + switch( type) + { + case VT_UI1: + hr= SafeArrayGetElement( sarray, &i, &byteValue); + varTemp.vt= VT_UI1; + V_UI1( &varTemp)= byteValue; + printVariant( varTemp); + break; + case VT_I1: + hr= SafeArrayGetElement( sarray, &i, &charValue); + varTemp.vt= VT_I1; + V_I1( &varTemp)= charValue; + printVariant( varTemp); + break; + case VT_I2: + hr= SafeArrayGetElement( sarray, &i, &shortValue); + varTemp.vt= VT_I2; + V_I2( &varTemp)= shortValue; + printVariant( varTemp); + break; + + case VT_UI2: + case VT_I4: + hr= SafeArrayGetElement( sarray, &i, &longValue); + varTemp.vt= VT_I4; + V_I4( &varTemp)= longValue; + printVariant( varTemp); + break; + case VT_R8: + hr= SafeArrayGetElement( sarray, &i, &doubleValue); + varTemp.vt= VT_R8; + V_R8( &varTemp)= doubleValue; + printVariant( varTemp); + break; + case VT_BSTR: + hr= SafeArrayGetElement( sarray, &i, &bstrValue); + varTemp.vt= VT_BSTR; + varTemp.bstrVal= bstrValue; + printVariant( varTemp); + break; + case VT_VARIANT: + hr= SafeArrayGetElement( sarray, &i, &varTemp); + printVariant( varTemp); + break; + + case VT_UNKNOWN: + hr= SafeArrayGetElement( sarray, &i, &unkValue); + varTemp.vt= VT_UNKNOWN; + varTemp.punkVal= unkValue; + printVariant( varTemp); + break; + } + + VariantClear( &varTemp); + VariantClear( &variantValue); + } + + } + else + { + CHAR buf[256]; + switch (var.vt) + { + case VT_I1: wsprintfA( buf, " VT_I1: %d \n", V_I1( &var) ); + break; + case VT_UI1: wsprintfA( buf, " VT_UI1: %d \n", V_I1( &var) ); + break; + + case VT_I2: wsprintfA( buf, " VT_I2: %d \n", V_I2( &var) ); + break; + case VT_I4: wsprintfA( buf, " VT_I4: %d \n", V_I4( &var) ); + break; + case VT_R8: + { + +// int decimal, sign; +// char *buffer; +// int precision = 14; +// double source = 3.1415926535; + +// buffer = _ecvt( V_R8(&var), precision, &decimal, &sign ); + sprintf( buf, " VT_R8: %f \n",V_R8( &var) ); + break; + } + case VT_UNKNOWN: + // The object implement IFont + { + CComDispatchDriver disp( var.punkVal); + CComVariant ret; + hr= disp.GetPropertyByName( static_cast(L"Name"), &ret); + wsprintfA( buf, " VT_UNKNOWN: property \"Name\": %s \n", W2A(ret.bstrVal)); + break; + } + case VT_DISPATCH: + // The object implement IFont + { + CComDispatchDriver disp( var.punkVal); + CComVariant ret; + if( SUCCEEDED( hr= disp.GetPropertyByName( static_cast(L"Name"), &ret))) + wsprintfA( buf, " VT_DISPATCH: property \"Name\": %s \n", W2A(ret.bstrVal)); + else + wsprintfA( buf, " VT_DISPATCH \n"); + + break; + } + + + case VT_BSTR: + { + CHAR* str= W2A( var.bstrVal); + wsprintfA( buf, " VT_BSTR: %s \n", str); + } + break; + default: + wsprintfA( buf, "\n"); + + } + + OutputDebugStringA( buf); + } + + return; + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/OleConverterVar1/makefile.mk b/extensions/test/ole/OleConverterVar1/makefile.mk new file mode 100644 index 000000000..d37219256 --- /dev/null +++ b/extensions/test/ole/OleConverterVar1/makefile.mk @@ -0,0 +1,57 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +PRJ=..$/..$/.. + +PRJNAME=extensions +TARGET=convTest +TARGETTYPE=CUI +LIBTARGET=NO + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings --- + +.INCLUDE : settings.mk + +# --- Files --- + +INCPRE+=-I$(ATL_INCLUDE) + + +APP1TARGET= $(TARGET) +APP1OBJS= $(OBJ)$/convTest.obj + + +APP1STDLIBS= \ + $(SALLIB) \ + $(CPPUHELPERLIB) \ + $(CPPULIB) \ + $(USER32LIB) \ + $(KERNEL32LIB) \ + $(OLE32LIB) \ + $(OLEAUT32LIB) \ + $(UUIDLIB) \ + $(COMDLG32LIB) \ + $(COMPATH)$/atlmfc$/lib$/atls.lib \ + $(ADVAPI32LIB) + +APP1DEF= $(MISC)\$(APP1TARGET).def + +# --- Targets --- +.INCLUDE : target.mk diff --git a/extensions/test/ole/OleConverterVar1/readme.txt b/extensions/test/ole/OleConverterVar1/readme.txt new file mode 100644 index 000000000..67bc8d920 --- /dev/null +++ b/extensions/test/ole/OleConverterVar1/readme.txt @@ -0,0 +1,10 @@ +Currently broken!! + +The program test the Service com.sun.star.bridge.OleBridgeSupplierVar1. +While running in debug mode it writes infos to the debug - output. + +The executable needs a services.rdb present with the registered services +com.sun.star.bridge.OleBridgeSupplierVar1, oletest.OleTest. The OleTest +component resides in extensions/test/ole/cpnt. The build creates an +oletest.rdb file that must be merged with the types.rdb and OleTest +must be registered to the services.rdb. diff --git a/extensions/test/ole/OleConverterVar1/smartarray.h b/extensions/test/ole/OleConverterVar1/smartarray.h new file mode 100644 index 000000000..1c8fbd6e6 --- /dev/null +++ b/extensions/test/ole/OleConverterVar1/smartarray.h @@ -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 . + */ +#pragma once + + +template< class sourceType> +class SmartArray +{ + SAFEARRAY *m_array; +public: + + SmartArray( sourceType * parParams, int count, VARTYPE destVartype): m_array(NULL) + { + HRESULT hr= S_OK; + SAFEARRAYBOUND rgsabound[1]; + rgsabound[0].cElements= count; + rgsabound[0].lLbound= 0; + m_array= SafeArrayCreate( destVartype, 1, rgsabound); + SafeArrayLock( m_array); + + void* pData; + if( m_array && (SUCCEEDED( SafeArrayAccessData( m_array, (void**)&pData)) ) ) + { + + for( int i=0; i< count; i++) + { + CComVariant varSource( parParams[i]); + switch (destVartype) + { + case VT_I1: + { + char* p= (char*) pData; + if( SUCCEEDED( hr= varSource.ChangeType( destVartype))) + p[i]= V_I1( &varSource); + break; + } + case VT_I2: + { + short* p= (short*) pData; + if( SUCCEEDED( hr=varSource.ChangeType( destVartype))) + p[i]= V_I2( &varSource); + break; + } + case VT_UI2: + { + unsigned short* p= (unsigned short*) pData; + if( SUCCEEDED( hr=varSource.ChangeType( destVartype))) + p[i]= V_UI2( &varSource); + break; + } + case VT_I4: + { + long* p= (long*)pData; + if( SUCCEEDED( hr=varSource.ChangeType( destVartype))) + p[i]= V_I4( &varSource); + break; + } + case VT_UI4: + { + unsigned long* p= (unsigned long*)pData; + if( SUCCEEDED( hr=varSource.ChangeType( destVartype))) + p[i]= V_UI4( &varSource); + break; + } + case VT_R4: + { + float* p= (float*)pData; + if( SUCCEEDED( hr=varSource.ChangeType( destVartype))) + p[i]= V_R4( &varSource); + break; + } + case VT_R8: + { + double* p= (double*)pData; + if( SUCCEEDED( hr=varSource.ChangeType( destVartype))) + p[i]= V_R8( &varSource); + break; + } + case VT_BOOL: + { + VARIANT_BOOL* p= (VARIANT_BOOL*)pData; + if( SUCCEEDED( hr=varSource.ChangeType( destVartype))) + p[i]= V_BOOL( &varSource); + break; + } + case VT_BSTR: + { + BSTR* pBstr= ( BSTR*)pData; + if( SUCCEEDED( hr=varSource.ChangeType( destVartype))) + pBstr[i]= SysAllocString(V_BSTR( &varSource)); + break; + } + case VT_VARIANT: + { + VARIANT *pVariant= (VARIANT*)pData; + hr= VariantCopy( &pVariant[i], &varSource); break; + } +// case VT_UNKNOWN: +// { +// long* pUnk= (long*)pData; +// pUnk[i]= reinterpret_cast(parParams[i]); +// ((IUnknown*)pUnk[i])->AddRef(); break; +// } +// case VT_DISPATCH: +// { +// long* pDisp= (long*)pData; +// pDisp[i]= (long)parParams[i]; +// ((IDispatch*)pDisp[i])->AddRef(); break; +// } + default: + hr= E_FAIL; + } + } + if( FAILED( hr)) + { + SafeArrayDestroy( m_array); + m_array= NULL; + } + } + SafeArrayUnaccessData( m_array); + } + ~SmartArray(){ + SafeArrayUnlock( m_array); + SafeArrayDestroy( m_array ); + } + + operator bool (){ return m_array == NULL ? false : true; } + + operator SAFEARRAY* (){ return m_array;} + +}; + +template<> +class SmartArray +{ + SAFEARRAY *m_array; +public: + + SmartArray( sourceType * parParams, int count, VARTYPE destVartype); +// { +// ATLTRACE("SmartArray"); +// HRESULT hr= S_OK; +// SAFEARRAYBOUND rgsabound[1]; +// rgsabound[0].cElements= count; +// rgsabound[0].lLbound= 0; +// m_array= SafeArrayCreateVector( VT_UNKNOWN, 0, count); +// SafeArrayLock( m_array); + +// IUnknown* *pData; +// if( m_array && (SUCCEEDED( SafeArrayAccessData( m_array, (void**)&pData)) ) ) +// { + +// for( int i=0; i< count; i++) +// { +// CComVariant varSource( parParams[i]); +// switch (destVartype) +// { + +// case VT_UNKNOWN: +// { +// pData[i]= parParams[i]; +// pData[i]->AddRef(); +// } +// default: +// hr= E_FAIL; +// } +// } +// if( FAILED( hr)) +// { +// SafeArrayDestroy( m_array); +// m_array= NULL; +// } +// } +// SafeArrayUnaccessData( m_array); +// } + ~SmartArray(){ + SafeArrayUnlock( m_array); + SafeArrayDestroy( m_array ); + } + + operator bool (){ return m_array == NULL ? false : true; } + + operator SAFEARRAY* (){ return m_array;} + +}; + +template <> SmartArray ::SmartArray(sourceType * parParams, int count, VARTYPE destVartype):m_array(NULL) +{ + ATLTRACE("SmartArray"); + HRESULT hr= S_OK; + m_array= SafeArrayCreateVector( VT_UNKNOWN, 0, count); + SafeArrayLock( m_array); + + IUnknown* *pData; + if( m_array && (SUCCEEDED( SafeArrayAccessData( m_array, (void**)&pData)) ) ) + { + for( int i=0; i< count; i++) + { + pData[i]= parParams[i]; + pData[i]->AddRef(); + } + } + SafeArrayUnaccessData( m_array); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/OleTest.htm b/extensions/test/ole/OleTest.htm new file mode 100644 index 000000000..acca9fda0 --- /dev/null +++ b/extensions/test/ole/OleTest.htm @@ -0,0 +1,1080 @@ + + + + + +Document Title + + + + + + + +

+ + + +

JScript

+Tests Array/Sequence conversion.
+All methods receive a Sequence as Parameter. The element type of the Sequence is written on the buttons. +
+ + + + + + + + + + + + + + + + +

+ +

+Out Parameter
+ + + + + + + + + + + + + + + + + + + + +

+In Out Parameter
+ + + + + + + + + + + + + + +

+ +Tests Array/Sequence conversion with Attributes. All params are of type Sequence and + the element type of the Sequence is written on the buttons.
+ + + + + + + + + + + + + +

+ +Test of Any parameter in a method. Any contains:
+ + + + + +

+Test of Any parameter in a property. Any contains:
+ + + + + +

+Test of Struct conversions
+ + + + + + + +

+ + +

Visual Basic Tests

+Test array /Sequence conversion and return value
+Template: Sequence < type > method( Sequence< type > )
+ + + + + + + + + + +
+
+ + +IN/Out parameter
+Template: void method(type )
+ + + + + + + + + +
+ +Simple out parameter
+ + +
+ + +Tests Array/Sequence conversion with Attributes. All params are of type Sequence and + the element type of the Sequence is written on the buttons.
+ + + + + + + + + + +
+ +In Out parameter
+ +

+Structs
+ + + + + + diff --git a/extensions/test/ole/ScriptTest.html b/extensions/test/ole/ScriptTest.html new file mode 100644 index 000000000..7cf188f45 --- /dev/null +++ b/extensions/test/ole/ScriptTest.html @@ -0,0 +1,1555 @@ + + + + +Document Title + + + + + + + + + + + + + diff --git a/extensions/test/ole/StarBasic_OleClient/oleclient.bas b/extensions/test/ole/StarBasic_OleClient/oleclient.bas new file mode 100644 index 000000000..e640d434d --- /dev/null +++ b/extensions/test/ole/StarBasic_OleClient/oleclient.bas @@ -0,0 +1,622 @@ +rem +rem This file is part of the LibreOffice project. +rem +rem This Source Code Form is subject to the terms of the Mozilla Public +rem License, v. 2.0. If a copy of the MPL was not distributed with this +rem file, You can obtain one at http://mozilla.org/MPL/2.0/. +rem +rem This file incorporates work covered by the following license notice: +rem +rem Licensed to the Apache Software Foundation (ASF) under one or more +rem contributor license agreements. See the NOTICE file distributed +rem with this work for additional information regarding copyright +rem ownership. The ASF licenses this file to you under the Apache +rem License, Version 2.0 (the "License"); you may not use this file +rem except in compliance with the License. You may obtain a copy of +rem the License at http://www.apache.org/licenses/LICENSE-2.0 . +rem + +OPTION EXPLICIT +OPTION COMPATIBLE + +Sub Main +COMPATIBILITYMODE(true) + +If runtest = -1 Then + MsgBox "Test Failed!!!" +Else + MsgBox "Test Succeeded" +End If + +End Sub + +Function runtest() As Integer +Dim inBool As Boolean, inBool2 As Boolean, outBool As Boolean +Dim inByte As Integer, inByte2 As Integer +Dim inShort As Integer, inShort2 As Integer +Dim inLong As Long, inLong2 As Long, inLong3 As Long, inLong4 As Long +Dim inString As String, inString2 As String +Dim inFloat As Single, inFloat2 As Single +Dim inDouble As Double, inDouble2 As Double +Dim inVariant, inVariant2 +Dim inAr, inAr2 +Dim inDate As Date,inDate2 As Date, outDate As Date +Dim inCurrency As Currency, inCurrency2 As Currency, outCurrency As Currency +Dim inSCode As New com.sun.star.bridge.oleautomation.SCode +Dim inSCode2 As New com.sun.star.bridge.oleautomation.SCode +Dim inDecimal As Variant, inDecimal2 As Variant, outDecimal As Variant +Dim inrefDecimal As Variant, outrefDecimal As Variant +Dim outSCode As New com.sun.star.bridge.oleautomation.SCode +Dim outByte As Integer +Dim outShort As Integer +Dim outLong, outLong2 As Long +Dim outString As String +Dim outFloat As Single +Dim outDouble As Double +Dim outVariant +'bug #109936 causes an errOr when outObject is used As out param +Dim inObject As Object, inObject2 As Object, outObject As Object +Dim objNOTHING As Object +Dim inUnknown As Object, inUnknown2 As Object, outUnknown As Object + +Dim inArray, outArray, outArray2 +Dim len1, len2 +Dim arString(1) As String +arString(0)= "String one" +arString(1)= "String two" + +Dim factory As Object +factory= createUnoService("com.sun.star.bridge.OleObjectFactory") +Dim obj As Object +obj= factory.createInstance("AxTestComponents.Basic") + +Dim objFoo As Object +objFoo = factory.createInstance("AxTestComponents.Foo") + + +'in parameter ------------------------------------------------------------------- +inBool = true +inByte = 10 +inShort = 11 +inLong = 111 +inString = "Hello World" +inFloat = 3.14 +inDouble = 3.145 +inVariant = "bla" +inDate = NOW() +inCurrency = 12345.6789 +inSCode.Value = &h80020004 +inDecimal = CDec("-9223372036854775808") 'lowest int64 + +obj.inBool(inBool) +obj.inByte(inByte) +obj.inShort(inShort) +obj.inLong(inLong) +obj.inString(inString) +obj.inFloat(inFloat) +obj.inDouble(inDouble) +obj.inVariant(inVariant) +'obj.prpString= "a string property" +obj.inObject(obj) +obj.inArray(arString()) +obj.inDate(inDate) +obj.inCurrency(inCurrency) +obj.inSCode(inSCode) +obj.inUnknown(objFoo) +obj.inDecimal(inDecimal) + +'out parameter ------------------------------------------------------------------------- +outBool = false +obj.outBool(outBool) +outByte = 0 +obj.outByte(outByte) +outShort = 0 +obj.outShort(outShort) +outLong = 0 +obj.outLong(outLong) +outFloat = 0 +obj.outFloat(outFloat) +outDouble = 0 +obj.outDouble(outDouble) +outString = "" +obj.outString(outString) +outVariant = 0 +obj.outVariant(outVariant) +outObject = NOTHING +obj.outObject(outObject) +outArray = 0 +obj.outArray(outArray) +obj.outDate(outDate) +obj.outCurrency(outCurrency) +obj.outSCode(outSCode) +obj.outUnknown(outUnknown) +obj.outDecimal(outDecimal) + + +If inBool <> outBool Or inByte <> outByte Or inShort <> outShort Or inLong <> outLong Or _ + inFloat <> outFloat Or inDouble <> outDouble Or inString <> outString Or _ + inVariant <> outVariant Or NOT equalUnoObjects(obj, outObject) Or NOT _ + equalArrays(arString(), outArray()) Or inDate <> outDate Or inCurrency <> outCurrency Or _ + inSCode.Value <> outSCode.Value Or Not equalUnoObjects(objFoo, outUnknown) Or _ + inDecimal <> outDecimal Then + runtest = -1 + exit Function +End If + + +'in-out parameter ------------------------------------------------------------- +'implementation of inout methods returns the previously set value in out param +inBool = true +inBool2 = inBool +obj.inoutBool(inBool2) +outBool = false +obj.inoutBool(outBool) +inByte = 10 +inByte2 = inByte +obj.inoutByte(inByte2) +outByte = 0 +obj.inoutByte(outByte) +inShort = 10 +inShort2 = inShort +obj.inShort(inShort2) +outShort = 0 +obj.inoutShort(outShort) +inLong = 10 +inLong2 = inLong +obj.inoutLong(inLong2) +outLong = 0 +obj.inoutLong(outLong) +inFloat = 3.14 +inFloat2 = inFloat +obj.inoutFloat(inFloat2) +outFloat = 0 +obj.inoutFloat(outFloat) +inDouble= 3.14 +inDouble2 = inDouble +obj.inoutDouble(inDouble2) +outDouble = 0 +obj.inoutDouble(outDouble) +inString = "in" +inString2 = inString +obj.inoutString(inString2) +outString = "" +obj.inoutString(outString) +inVariant = "in" +inVariant2 = inVariant +obj.inoutVariant(inVariant2) +outVariant = 0 +obj.inoutVariant(outVariant) +inObject = factory.createInstance("AxTestComponents.Basic") +inObject2 = inObject +obj.inoutObject(inObject2) +outObject = NOTHING +obj.inoutObject(outObject) +inAr = arString() +inAr2 = inAr +obj.inoutArray(inAr2) +outArray = 0 +obj.outArray(outArray()) +inDate = NOW() +inDate2 = inDate +obj.inoutDate(inDate2) +outDate = 0 +obj.inoutDate(outDate) +inCurrency = 1234.5678 +inCurrency2 = inCurrency +obj.inoutCurrency(inCurrency2) +outCurrency = 0 +obj.inoutCurrency(outCurrency) +inSCode.Value = &h80020004 +inSCode2 = inSCode +obj.inoutSCode(inSCode2) +outSCode.Value = 0 +obj.inoutSCode(outSCode) +inUnknown = objFoo +inUnknown2 = inUnknown +obj.inoutUnknown(inUnknown2) +outUnknown = Nothing +obj.inoutUnknown(outUnknown) +inDecimal = CDec("18446744073709551615") 'highest positive value of unsigned int64 +inDecimal2 = inDecimal +obj.inoutDecimal(inDecimal2) +outDecimal = 0 +obj.inoutDecimal(outDecimal) + +If inBool <> outBool Or inByte <> outByte Or inShort <> outShort Or inLong <> outLong Or _ + inFloat <> outFloat Or inDouble <> outDouble Or inString <> outString Or _ + inVariant <> outVariant Or NOT equalUnoObjects(inObject, outObject) Or _ + NOT equalArrays(inAr, outArray) Or inDate <> outDate Or inCurrency <> outCurrency Or _ + inSCode.Value <> outSCode.Value Or Not equalUnoObjects(inUnknown, outUnknown) Or _ + inDecimal <> outDecimal Then + runtest = -1 + Exit Function +End If + +'properties ------------------------------------------------------------------------- +inBool = false +outBool = true +obj.prpBool = inBool +outBool = obj.prpBool +inByte = 11 +outByte = 0 +obj.prpByte = inByte +outByte= obj.prpByte +inShort = 127 +outShort = 0 +obj.prpShort= inShort +outShort= obj.prpShort +inLong = 1000 +outLong = 0 +obj.prpLong = inLong +outLong= obj.prpLong +inFloat = 3.14 +outFloat = 0 +obj.prpFloat = inFloat +outFloat= obj.prpFloat +inDouble = 3.123 +outDouble = 0 +obj.prpDouble = inDouble +outDouble= obj.prpDouble +inString = "bla" +outString = "" +obj.prpString = inString +outString = obj.prpString +inObject = obj +outObject = objNOTHING +obj.prpObject = inObject +outObject = obj.prpObject +inVariant = "bla" +outVariant = 0 +obj.prpVariant = inVariant +outVariant= obj.prpVariant +inArray = arString() +outArray = 0 +obj.prpArray = inArray() +outArray= obj.prpArray +inDate = NOW() +outDate = 0 +obj.prpDate = inDate +outDate = obj.prpDate +inCurrency = 1234.5678 +outCurrency = 0 +obj.prpCurrency = inCurrency +outCurrency = obj.prpCurrency +inSCode.Value = &h80020004 +outSCode.Value = 0 +obj.prpSCode = inSCode +outSCode = obj.prpSCode +inUnknown = objFoo +outUnknown= Nothing +obj.prpUnknown = inUnknown +outUnknown = obj.prpUnknown +inDecimal = CDec("18446744073709551615")' highest unsigned int64 +outDecimal = 0 +obj.prpDecimal = inDecimal +outDecimal = obj.prpDecimal + +If inBool <> outBool Or inByte <> outByte Or inShort <> outShort Or inLong <> outLong Or _ + inFloat <> outFloat Or inDouble <> outDouble Or inString <> outString Or _ + inVariant <> outVariant Or NOT equalUnoObjects(inObject, outObject) Or _ + NOT equalArrays(inArray, outArray) Or inDate <> outDate Or inCurrency <> outCurrency Or _ + inSCode.Value <> outSCode.Value Or Not equalUnoObjects(inUnknown, outUnknown) Or _ + inDecimal <> outDecimal Then + runtest = -1 + Exit Function +End If + +' ref parameter ------------------------------------------------------------------------ +obj.inLong(0) +inLong = 123 +outLong = 0 +obj.inLong(0) +obj.inrefLong(inLong) +obj.outLong(outLong) +inVariant = "bla" +outVariant = 0 +obj.inVariant(0) +obj.inrefVariant(inVariant) +obj.outVariant(outVariant) +If inLong <> outLong Or inVariant <> outVariant Then + runtest = -1 + Exit Function +End If + +outLong = 0 +obj.prprefLong = inLong +outLong = obj.prprefLong +outVariant = 0 +obj.prprefVariant = inVariant +outVariant = obj.prprefVariant +If inLong <> outLong Or inVariant <> outVariant Then + runtest = -1 + Exit Function +End If + + +'vararg -------------------------------------------------------------------------------- +inLong=1 +inLong2 = 2 +inLong3 = 3 +obj.varargfunc1(inLong) +outArray = 0 +outLong = 0 +obj.varargfunc2(outLong, outArray) +If inLong <> outLong Then + runtest = -1 + Exit Function +End If +len1 = UBound(outArray) - LBound(outArray) +1 +If len1 <> 0 Then + runtest = -1 + Exit Function +End If +outArray = 0 +obj.varargfunc1(inLong, inLong2, inLong3) +obj.varargfunc2(outLong, outArray) +len1 = UBound(outArray) - LBound(outArray) +1 +If len1 <> 2 Or outArray(0) <> inLong2 Or outArray(1) <> inLong3 Then + runtest = -1 + Exit Function +End If + + +'defaultvalue --------------------------------------------------------------------------- +inLong = 0 +inFloat = 0 +inVariant = 0 +inVariant2 = 0 +'defaults are: 1, 2, 4 +'The third parameter is a VARIANT with a default value of 4. COM gives it the type BSTR +obj.defaultvalue1() +obj.defaultvalue2(inLong, inFloat, inVariant) +If inLong <> 1 Or inFloat <> 2 Or inVariant <> "4" Then + runtest = -1 + Exit Function +End If +inLong = 10 +inFloat = 11 +inLong2 = inLong +inFloat2 = inFloat +inVariant = 0 +inVariant = 0 +obj.defaultvalue1(inLong, inFloat) +obj.defaultvalue2(inLong, inFloat, inVariant) +If inLong <> inLong2 Or inFloat <> inFloat2 Or inVariant <> "4" Then + runtest = -1 + Exit Function +End If + +'optional parameters ---------------------------------------------------------------- +inLong = 100 +outLong = 0 +obj.optional1(inLong) +obj.optional2(outLong) +If inLong <> outLong Then + runtest = -1 + Exit Function +End If + +inLong2 = 101 +outLong2 = 0 +obj.optional1(inLong, inLong2) +obj.optional2(outLong, outLong2) +If inLong <> outLong AND inLong2 <> outLong2 Then + runtest = -1 + Exit Function +End If + +inLong2 = 101 +outLong2 = 0 +obj.optional1(inLong, inLong2) +obj.optional1(inLong) +obj.optional2(outLong, outLong2) +If inLong <> outLong AND inLong2 <> outLong2 Then + runtest = -1 + Exit Function +End If + +inLong = 10 +inLong2 = 100 +outLong = 5 +outLong2 = 6 +obj.optional3() +obj.optional3(inLong, inLong2) +obj.optional4(outLong, outLong2) 'outLong = 10, outLong2 = 100 +If inLong <> outLong AND inLong2 <> outLong2 Then + runtest = -1 + Exit Function +End If +inLong = 10 +inLong2 = 100 +inLong3 = inLong +inLong4 = inLong2 +obj.optional4(inLong, inLong) +outLong = 0 +outLong2 = 0 +obj.optional5(outLong, outLong2) +If inLong3 <> outLong AND inLong4 <> outLong2 Then + runtest = -1 + Exit Function +End If + +inLong = 10 +outLong = 5 +obj.optional3(inLong) +obj.optional4(outLong) +If inLong <> outLong Then + runtest = -1 + Exit Function +End If +inLong = 10 +inLong2 = inLong +outLong = 0 +obj.optional4(inLong) +obj.optional5(outLong) +If inLong2 <> outLong Then + runtest = -1 + Exit Function +End If + +'named arguments------------------------------------------------------------------------- +'all args As named args, different order +obj.optional6(0, 0, 0, 0) +inLong = 1 +inLong2 = 2 +inLong3 = 3 +inLong4 = 4 +obj.optional6(val4:= inLong4, val3:=inLong3, val2:=inLong2, val1:= inLong) +Dim outLong3 As Long +Dim outLong4 As Long +outLong = 0 +outLong2 = 0 +outLong3 = 0 +outLong4 = 0 +obj.optional7(outLong, outLong2, outLong3, outLong4) +If inLong <> outLong Or inLong2 <> outLong2 _ + Or inLong3 <> outLong3 Or inLong4 <> outLong4 Then + runtest = -1 + Exit Function +End If + +'mixed positional and named args with omitted args +Dim scode_paramNotFound As New com.sun.star.bridge.oleautomation.SCode +scode_paramNotFound.Value = &h80020004 + +obj.optional6(0, 0, 0, 0) +'val1 and val3 will be DISP_E_PARAMNOTFOUND +obj.optional6(, inLong2, val4:=inLong4) +Dim outSCode1, outSCode2 +obj.optional7(outSCode, outLong2, outSCode2, outLong4) +If outSCode.Value <> scode_paramNotFound.Value Or inLong2 <> outLong2 _ + Or outSCode2.Value <> scode_paramNotFound.Value Or inLong4 <> outLong4 Then + runtest = -1 + Exit Function +End If + +'mixed positional and named args with omitted args as out -args +inLong = 1 +inLong2 = 2 +inLong3 = 3 +inLong4 = 4 +obj.optional6(inLong, inLong2, inLong3, inLong4) +outLong2 = 0 +outLong3 = 0 +obj.optional7(,outLong2, val3:= outLong3) +If inLong2 <> outLong2 Or inLong3 <> outLong3 Then + runtest = -1 + Exit Function +End If + +'test properties with additional arguments ------------------------------------ +inLong = 10 +inLong2 = 20 +inLong3 = 30 +outLong = 0 +outLong2 = 0 +outLong3 = 0 +obj.prpMultiArg1(0,0) = 0 +'obj.prpMultiArg1 = 0 +obj.prpMultiArg1(inLong,inLong2) = inLong3 +outLong3 = obj.prpMultiArg1(outLong, outLong2) +If outLong <> 10 Or outLong2 <> 02 Or outLong3 <> 30 Then + runtest = -1 + Exit Function +End If + +outLong = 0 +outLong2 = 0 +obj.prpMultiArg1(0,0) = 0 +obj.prpMultiArg1(1) = 3 +outLong2 = obj.prpMultiArg1(outLong) +If outLong <> 1 Or outLong2 <> 3 Then + runtest = -1 + Exit Function +End If + +outLong = 0 +outLong2 = 0 +obj.prpMultiArg1(0,0) = 0 +obj.prpMultiArg1(val2:= 1) = 3 +outLong2 = obj.prpMultiArg1(val2:=outLong) +If outLong <> 1 Or outLong2 <> 3 Then + runtest = -1 + Exit Function +End If + +outLong = -1 +outLong2 = -1 +obj.prpMultiArg2(0) = 0 +outLong = obj.prpMultiArg2GetValues(outLong, outLong2) +If outLong <> 0 Or outLong2 <> 0 Then + runtest = -1 + Exit Function +End If + + +outLong = 0 +outLong2 = 0 +obj.prpMultiArg2(1) = 2 +obj.prpMultiArg2GetValues(outLong, outLong2) +If outLong <> 1 Or outLong2 <> 2 Then + runtest = -1 + Exit Function +End If + + + +' other tests ------------------------------------------------------------------ +obj.inObject(NOTHING) +outObject = NOTHING +'bridge should return an XInterface any with null pointer +'A basic errOr should occur if this is not the case +obj.outObject(outObject) + +If Not IsNull(outObject) Then + runtest = -1 + Exit Function +End If +'Decimal passed by reference +inrefDecimal = CDec("9223372036854775807") 'highest positive value of int64 +obj.inrefDecimal(inrefDecimal) +outrefDecimal = 0 +obj.outDecimal(outrefDecimal) +If inrefDecimal <> outrefDecimal Then + runtest = -1 + Exit Function +End If + +' Test Automation object with dual interfaces ------------------------------------ +dim dispatcher as object +dim oExplorer as object +dispatcher = createUnoService("com.sun.star.bridge.OleObjectFactory") +oExplorer = dispatcher.createInstance("InternetExplorer.Application") +If Not IsNull(oExplorer) Then + oExplorer.visible = true + oExplorer.Navigate2("http://www.openoffice.org") +Else + MsgBox("Could not perform test with Internet Explorer!") +End If + + +End Function + +'One dimensional arrays with simple types. +'lower bound must be 0 +Function equalArrays(ar1, ar2) +Dim len1 +Dim len2 +len1 = UBound(ar1) - LBound(ar1) + 1 +len2 = UBound(ar2) - LBound(ar2) + 1 +If len1 <> len2 Then + equalArrays = false + Exit Function +End If +Dim counter +FOr counter = 0 To len1 - 1 + If ar1(counter) <> ar2(counter) Then + equalArrays = false + Exit Function + End If +Next +equalArrays = true +End Function diff --git a/extensions/test/ole/StarBasic_OleClient/readme.txt b/extensions/test/ole/StarBasic_OleClient/readme.txt new file mode 100644 index 000000000..d3ee22237 --- /dev/null +++ b/extensions/test/ole/StarBasic_OleClient/readme.txt @@ -0,0 +1,10 @@ +oleclient.bas is a StarBasic script that uses the +"com.sun.star.bridge.OleObjectFactory" service to instantiate +the ActiveX component "AxTestComponents.Basic" and calls +functions on it. + +------------------------------------------------------------ +Requirements: + +ActiveX component: AxTestComponent.Basic must be registered. +It is contained in extensions/test/ole/AxTestComponents diff --git a/extensions/test/ole/VisualBasic/AssemblyInfo.vb b/extensions/test/ole/VisualBasic/AssemblyInfo.vb new file mode 100644 index 000000000..c4b1d4ff5 --- /dev/null +++ b/extensions/test/ole/VisualBasic/AssemblyInfo.vb @@ -0,0 +1,51 @@ +' +' This file is part of the LibreOffice project. +' +' This Source Code Form is subject to the terms of the Mozilla Public +' License, v. 2.0. If a copy of the MPL was not distributed with this +' file, You can obtain one at http://mozilla.org/MPL/2.0/. +' +' This file incorporates work covered by the following license notice: +' +' Licensed to the Apache Software Foundation (ASF) under one or more +' contributor license agreements. See the NOTICE file distributed +' with this work for additional information regarding copyright +' ownership. The ASF licenses this file to you under the Apache +' License, Version 2.0 (the "License"); you may not use this file +' except in compliance with the License. You may obtain a copy of +' the License at http://www.apache.org/licenses/LICENSE-2.0 . +' + +Imports System.Reflection +Imports System.Runtime.CompilerServices +Imports System.Runtime.InteropServices + +' General Information about an assembly is controlled through the following +' set of attributes. Change these attribute values to modify the information +' associated with an assembly. + + +' TODO: Review the values of the assembly attributes + + + + + + + + + + +' Version information for an assembly consists of the following four values: + +' Major version +' Minor Version +' Build Number +' Revision + +' You can specify all the values or you can default the Build and Revision Numbers +' by using the '*' as shown below: + + + + diff --git a/extensions/test/ole/VisualBasic/Module1.vb b/extensions/test/ole/VisualBasic/Module1.vb new file mode 100644 index 000000000..63b8bbdeb --- /dev/null +++ b/extensions/test/ole/VisualBasic/Module1.vb @@ -0,0 +1,871 @@ +' +' This file is part of the LibreOffice project. +' +' This Source Code Form is subject to the terms of the Mozilla Public +' License, v. 2.0. If a copy of the MPL was not distributed with this +' file, You can obtain one at http://mozilla.org/MPL/2.0/. +' +' This file incorporates work covered by the following license notice: +' +' Licensed to the Apache Software Foundation (ASF) under one or more +' contributor license agreements. See the NOTICE file distributed +' with this work for additional information regarding copyright +' ownership. The ASF licenses this file to you under the Apache +' License, Version 2.0 (the "License"); you may not use this file +' except in compliance with the License. You may obtain a copy of +' the License at http://www.apache.org/licenses/LICENSE-2.0 . +' + +Option Strict Off +Option Explicit On +Module Module1 + +Private objServiceManager As Object +Private objCoreReflection As Object +Private objOleTest As Object +Private objEventListener As Object +'General counter +Dim i As Integer +Dim j As Integer +Dim sError As String +Dim outHyper, inHyper, retHyper As Object + +Public Sub Main() + objServiceManager = CreateObject("com.sun.star.ServiceManager") + objCoreReflection = objServiceManager.createInstance("com.sun.star.reflection.CoreReflection") + ' extensions/test/ole/cpnt + objOleTest = objServiceManager.createInstance("oletest.OleTest") + ' extensions/test/ole/EventListenerSample/VBEventListener + objEventListener = CreateObject("VBasicEventListener.VBEventListener") + Debug.Print(TypeName(objOleTest)) + + + testBasics() + testHyper() + testAny() + testObjects() + testGetStruct() + ''dispose not working i103353 + 'testImplementedInterfaces() + testGetValueObject() + testArrays() + testProps() + + End Sub + Function testProps() As Object + + Dim aToolbarItemProp1 As Object + aToolbarItemProp1 = objOleTest.Bridge_GetStruct("com.sun.star.beans.PropertyValue") + Dim aToolbarItemProp2 As Object + aToolbarItemProp2 = objOleTest.Bridge_GetStruct("com.sun.star.beans.PropertyValue") + Dim aToolbarItemProp3 As Object + aToolbarItemProp3 = objOleTest.Bridge_GetStruct("com.sun.star.beans.PropertyValue") + Dim properties(2) As Object + + aToolbarItemProp1.Name = "CommandURL" + aToolbarItemProp1.Value = "macro:///standard.module1.TestIt" + aToolbarItemProp2.Name = "Label" + aToolbarItemProp2.Value = "Test" + aToolbarItemProp3.Name = "Type" + aToolbarItemProp3.Value = 0 + + properties(0) = aToolbarItemProp1 + properties(1) = aToolbarItemProp2 + properties(2) = aToolbarItemProp3 + + + Dim dummy(-1) As Object + + Dim Desktop As Object + Desktop = objServiceManager.createInstance("com.sun.star.frame.Desktop") + Dim Doc As Object + Doc = Desktop.loadComponentFromURL("private:factory/swriter", "_blank", 2, dummy) + Dim LayoutManager As Object + LayoutManager = Doc.currentController.Frame.LayoutManager + + LayoutManager.createElement("private:resource/toolbar/user_toolbar1") + LayoutManager.showElement("private:resource/toolbar/user_toolbar1") + Dim ToolBar As Object + ToolBar = LayoutManager.getElement("private:resource/toolbar/user_toolbar1") + Dim settings As Object + settings = ToolBar.getSettings(True) + + 'the changes are here: + Dim aany As Object + aany = objServiceManager.Bridge_GetValueObject() + Call aany.Set("[]com.sun.star.beans.PropertyValue", properties) + Call settings.insertByIndex(0, aany) + Call ToolBar.setSettings(settings) + + + End Function + + + Function testBasics() As Object + ' In Parameter, simple types + '============================================ + Dim tmpVar As Object + Dim ret As Object + Dim outByte, inByte, retByte As Byte + Dim outBool, inBool, retBool As Boolean + Dim outShort, inShort, retShort As Short + Dim outUShort, inUShort, retUShort As Short + Dim outLong, inLong, retLong As Integer + Dim outULong, inULong, retULong As Integer + Dim outHyper, inHyper, retHyper As Object + Dim outUHyper, inUHyper, retUHyper As Object + Dim outFloat, inFloat, retFloat As Single + Dim outDouble, inDouble, retDouble As Double + Dim outString, inString, retString As String + Dim retChar, inChar, outChar, retChar2 As Short + Dim outCharAsString, inCharAsString, retCharAsString As String + Dim outAny, inAny, retAny As Object + Dim outType, inType, retType As Object + Dim outXInterface, inXInterface, retXInterface As Object + Dim outXInterface2, inXInterface2, retXInterface2 As Object + + + Dim outVarByte As Object + Dim outVarBool As Object + Dim outVarShort As Object + Dim outVarUShort As Object + Dim outVarLong As Object + Dim outVarULong As Object + Dim outVarFloat As Object + Dim outVarDouble As Object + Dim outVarString As Object + Dim outVarChar As Object + Dim outVarAny As Object + Dim outVarType As Object + + inByte = 10 + inBool = True + inShort = -10 + inUShort = -100 + inLong = -1000 + inHyper = CDec("-9223372036854775808") 'lowest int64 + inUHyper = CDec("18446744073709551615") ' highest unsigned int64 + inULong = 10000 + inFloat = 3.14 + inDouble = 3.14 + inString = "Hello World!" + inChar = 65 + inCharAsString = "A" + inAny = "Hello World" + inType = objServiceManager.Bridge_CreateType("[]long") + inXInterface = objCoreReflection + inXInterface2 = objEventListener + + retByte = objOleTest.in_methodByte(inByte) + retBool = objOleTest.in_methodBool(inBool) + retShort = objOleTest.in_methodShort(inShort) + retUShort = objOleTest.in_methodUShort(inUShort) + retLong = objOleTest.in_methodLong(inLong) + retULong = objOleTest.in_methodULong(inULong) + retHyper = objOleTest.in_methodHyper(inHyper) + retUHyper = objOleTest.in_methodUHyper(inUHyper) + retFloat = objOleTest.in_methodFloat(inFloat) + retDouble = objOleTest.in_methodDouble(inDouble) + retString = objOleTest.in_methodString(inString) + retChar = objOleTest.in_methodChar(inChar) + retChar2 = objOleTest.in_methodChar(inCharAsString) + retAny = objOleTest.in_methodAny(inAny) + retType = objOleTest.in_methodType(inType) + retXInterface = objOleTest.in_methodXInterface(inXInterface) ' UNO object + retXInterface2 = objOleTest.in_methodXInterface(inXInterface2) + + If retByte <> inByte Or retBool <> inBool Or retShort <> inShort Or retUShort <> inUShort _ + Or retLong <> inLong Or retULong <> inULong Or retHyper <> inHyper _ + Or retUHyper <> inUHyper Or retFloat <> inFloat Or retDouble <> inDouble _ + Or retString <> inString Or retChar <> inChar Or retChar2 <> Asc(inCharAsString) _ + Or retAny <> inAny Or Not (retType.Name = inType.Name) _ + Or inXInterface IsNot retXInterface Or inXInterface2 IsNot retXInterface2 Then + sError = "in - parameter and return value test failed" + MsgBox(sError) + + End If + + 'Out Parameter simple types + '================================================ + + + objOleTest.testout_methodByte(outByte) + objOleTest.testout_methodFloat(outFloat) + objOleTest.testout_methodDouble(outDouble) + objOleTest.testout_methodBool(outBool) + objOleTest.testout_methodShort(outShort) + objOleTest.testout_methodUShort(outUShort) + objOleTest.testout_methodLong(outLong) + objOleTest.testout_methodULong(outULong) + objOleTest.testout_methodHyper(outHyper) + objOleTest.testout_methodUHyper(outUHyper) + objOleTest.testout_methodString(outString) + objOleTest.testout_methodChar(outChar) + 'outCharAsString is a string. Therefore the returned sal_Unicode value of 65 will be converted + 'to a string "65" + objOleTest.testout_methodChar(outCharAsString) + objOleTest.testout_methodAny(outAny) + objOleTest.testout_methodType(outType) + 'objOleTest.in_methodXInterface (inXInterface) ' UNO object + Call objOleTest.in_methodXInterface(inXInterface) ' UNO object + objOleTest.testout_methodXInterface(outXInterface) + Call objOleTest.in_methodXInterface(inXInterface2) ' COM object + objOleTest.testout_methodXInterface(outXInterface2) + + If outByte <> inByte Or outFloat <> inFloat Or outDouble <> inDouble _ + Or outBool <> inBool Or outShort <> inShort Or outUShort <> inUShort _ + Or outLong <> inLong Or outULong <> inULong Or outHyper <> inHyper _ + Or outUHyper <> inUHyper Or outString <> inString Or outChar <> inChar _ + Or Not (outCharAsString = "65") Or outAny <> inAny _ + Or Not (outType.Name = inType.Name) Or inXInterface IsNot outXInterface _ + Or inXInterface2 IsNot outXInterface2 Then + + sError = "out - parameter test failed!" + MsgBox(sError) + End If + + 'Out Parameter simple types (VARIANT var) + '==================================================== + objOleTest.testout_methodByte(outVarByte) + objOleTest.testout_methodBool(outVarBool) + objOleTest.testout_methodChar(outVarChar) + objOleTest.testout_methodShort(outVarShort) + objOleTest.testout_methodUShort(outVarUShort) + objOleTest.testout_methodLong(outVarLong) + objOleTest.testout_methodULong(outVarULong) + objOleTest.testout_methodString(outVarString) + objOleTest.testout_methodFloat(outVarFloat) + objOleTest.testout_methodDouble(outVarDouble) + objOleTest.testout_methodAny(outVarAny) + objOleTest.testout_methodType(outVarType) + + If outVarByte <> inByte Or outVarBool <> inBool Or outVarChar <> inChar _ + Or outVarShort <> inShort Or outVarUShort <> inUShort _ + Or outVarLong <> inLong Or outVarULong <> inULong Or outVarString <> inString _ + Or outVarFloat <> inFloat Or outVarDouble <> inDouble Or outVarAny <> inAny _ + Or Not (outVarType.Name = inType.Name) Then + sError = "out - parameter (VARIANT) test failed!" + MsgBox(sError) + End If + + 'In/Out simple types + '============================================ + objOleTest.in_methodByte(0) + objOleTest.in_methodBool(False) + objOleTest.in_methodShort(0) + objOleTest.in_methodUShort(0) + objOleTest.in_methodLong(0) + objOleTest.in_methodULong(0) + objOleTest.in_methodHyper(0) + objOleTest.in_methodUHyper(0) + objOleTest.in_methodFloat(0) + objOleTest.in_methodDouble(0) + objOleTest.in_methodString(0) + objOleTest.in_methodChar(0) + objOleTest.in_methodAny(0) + objOleTest.in_methodType(objServiceManager.Bridge_CreateType("boolean")) + outXInterface = Nothing + Call objOleTest.in_methodXInterface(outXInterface) + + outByte = 10 + retByte = outByte + objOleTest.testinout_methodByte(retByte) + objOleTest.testinout_methodByte(retByte) + outBool = True + retBool = outBool + objOleTest.testinout_methodBool(retBool) + objOleTest.testinout_methodBool(retBool) + outShort = 10 + retShort = outShort + objOleTest.testinout_methodShort(retShort) + objOleTest.testinout_methodShort(retShort) + outUShort = 20 + retUShort = outUShort + objOleTest.testinout_methodUShort(retUShort) + objOleTest.testinout_methodUShort(retUShort) + outLong = 30 + retLong = outLong + objOleTest.testinout_methodLong(retLong) + objOleTest.testinout_methodLong(retLong) + outULong = 40 + retULong = outULong + objOleTest.testinout_methodULong(retLong) + objOleTest.testinout_methodULong(retLong) + outHyper = CDec("9223372036854775807") 'highest positive value of int64 + retHyper = outHyper + objOleTest.testinout_methodHyper(retHyper) + objOleTest.testinout_methodHyper(retHyper) + outUHyper = CDec("18446744073709551615") 'highest value of unsigned int64 + retUHyper = outUHyper + objOleTest.testinout_methodUHyper(retUHyper) + objOleTest.testinout_methodUHyper(retUHyper) + outFloat = 3.14 + retFloat = outFloat + objOleTest.testinout_methodFloat(retFloat) + objOleTest.testinout_methodFloat(retFloat) + outDouble = 4.14 + retDouble = outDouble + objOleTest.testinout_methodDouble(retDouble) + objOleTest.testinout_methodDouble(retDouble) + outString = "Hello World!" + retString = outString + objOleTest.testinout_methodString(retString) + objOleTest.testinout_methodString(retString) + outChar = 66 + retChar = outChar + objOleTest.testinout_methodChar(retChar) + objOleTest.testinout_methodChar(retChar) + outCharAsString = "H" + retCharAsString = outCharAsString + objOleTest.testinout_methodChar(retCharAsString) + objOleTest.testinout_methodChar(retCharAsString) + outAny = "Hello World 2!" + retAny = outAny + objOleTest.testinout_methodAny(retAny) + objOleTest.testinout_methodAny(retAny) + outType = objServiceManager.Bridge_CreateType("long") + retType = outType + objOleTest.testinout_methodType(retType) + objOleTest.testinout_methodType(retType) + + outXInterface = objCoreReflection + retXInterface = outXInterface + objOleTest.testinout_methodXInterface2(retXInterface) + + If outByte <> retByte Or outBool <> retBool Or outShort <> retShort _ + Or outUShort <> retUShort Or outLong <> retLong Or outULong <> retULong _ + Or outHyper <> retHyper Or outUHyper <> outUHyper _ + Or outFloat <> retFloat Or outDouble <> retDouble _ + Or outString <> retString Or outChar <> retChar _ + Or outCharAsString <> retCharAsString _ + Or outAny <> retAny Or Not (outType.Name = retType.Name) _ + Or outXInterface IsNot retXInterface Then + sError = "in/out - parameter test failed!" + MsgBox(sError) + End If + + 'Attributes + objOleTest.AByte = inByte + retByte = 0 + retByte = objOleTest.AByte + objOleTest.AFloat = inFloat + retFloat = 0 + retFloat = objOleTest.AFloat + objOleTest.AType = inType + retType = Nothing + + retType = objOleTest.AType + + If inByte <> retByte Or inFloat <> retFloat Or Not (inType.Name = retType.Name) Then + sError = "Attributes - test failed!" + MsgBox(sError) + End If + + End Function + Function testHyper() As Object + + '====================================================================== + ' Other Hyper tests + Dim emptyVar As Object + Dim retAny As Object + + retAny = emptyVar + inHyper = CDec("9223372036854775807") 'highest positive value of int64 + retAny = objOleTest.in_methodAny(inHyper) + sError = "hyper test failed" + If inHyper <> retAny Then + MsgBox(sError) + End If + inHyper = CDec("-9223372036854775808") 'lowest negative value of int64 + retAny = objOleTest.in_methodAny(inHyper) + + If inHyper <> retAny Then + MsgBox(sError) + End If + inHyper = CDec("18446744073709551615") 'highest positive value of unsigned int64 + retAny = objOleTest.in_methodAny(inHyper) + + If inHyper <> retAny Then + MsgBox(sError) + End If + inHyper = CDec(-1) + retAny = objOleTest.in_methodAny(inHyper) + If inHyper <> retAny Then + MsgBox(sError) + End If + inHyper = CDec(0) + retAny = objOleTest.in_methodAny(inHyper) + If inHyper <> retAny Then + MsgBox(sError) + End If + + '============================================================================== + + + End Function + Function testAny() As Object + Dim outVAr As Object + + 'Any test. We pass in an any as value object. If it is not correct converted + 'then the target component throws a RuntimeException + Dim lengthInAny As Integer + + lengthInAny = 10 + Dim seqLongInAny(10) As Integer + For i = 0 To lengthInAny - 1 + seqLongInAny(i) = i + 10 + Next + Dim anySeqLong As Object + anySeqLong = objOleTest.Bridge_GetValueObject() + anySeqLong.Set("[]long", seqLongInAny) + Dim anySeqRet As Object + Err.Clear() + On Error Resume Next + anySeqRet = objOleTest.other_methodAny(anySeqLong, "[]long") + + If Err.Number <> 0 Then + MsgBox("error") + End If + End Function + + Function testObjects() As Object + ' COM obj + Dim outVAr As Object + Dim retObj As Object + 'OleTest receives a COM object that implements XEventListener + 'OleTest then calls a disposing on the object. The object then will be + 'asked if it has been called + objEventListener.setQuiet(True) + objEventListener.resetDisposing() + retObj = objOleTest.in_methodInvocation(objEventListener) + Dim ret As Object + ret = objEventListener.disposingCalled + If ret = False Then + MsgBox("Error") + End If + + 'The returned object should be objEventListener, test it by calling disposing + ' takes an IDispatch as Param ( EventObject).To provide a TypeMismatch + 'we put in another IDispatch + retObj.resetDisposing() + retObj.disposing(objEventListener) + If retObj.disposingCalled = False Then + MsgBox("Error") + End If + + ' out param gives out the OleTestComponent + 'objOleTest.testout_methodXInterface retObj + 'outVAr = Null + 'retObj.testout_methodAny outVAr + 'Debug.Print "test out Interface " & CStr(outVAr) + 'If outVAr <> "I am a string in an any" Then + ' MsgBox "error" + 'End If + + + 'in out + ' in: UNO object, the same is expected as out param + ' the function expects OleTest as parameter and sets a value + + Dim myAny As Object + + + + Dim objOleTest2 As Object + objOleTest2 = objServiceManager.createInstance("oletest.OleTest") + 'Set a value + objOleTest2.AttrAny2 = "VBString " + + 'testinout_methodXInterfaces substitutes the argument with the object set in in_methodXInterface + objOleTest.AttrAny2 = "VBString this string was written in the UNO component to the inout pararmeter" + objOleTest.in_methodXInterface(objOleTest) + objOleTest.testinout_methodXInterface2(objOleTest2) + Dim tmpVar As Object + tmpVar = System.DBNull.Value + tmpVar = objOleTest2.AttrAny2 + Debug.Print("in: Uno out: the same object // " & CStr(tmpVar)) + If tmpVar <> "VBString this string was written in the UNO component to the inout pararmeter" Then + MsgBox("error") + End If + + + 'create a struct + Dim structClass As Object + structClass = objCoreReflection.forName("oletest.SimpleStruct") + Dim structInstance As Object + structClass.CreateObject(structInstance) + structInstance.message = "Now we are in VB" + Debug.Print("struct out " & structInstance.message) + If structInstance.message <> "Now we are in VB" Then + MsgBox("error") + End If + + 'put the struct into OleTest. The same struct will be returned with an added String + Dim structRet As Object + structRet = objOleTest.in_methodStruct(structInstance) + Debug.Print("struct in - return " & structRet.message) + If structRet.message <> "Now we are in VBThis string was set in OleTest" Then + MsgBox("error") + End If + + + End Function + Function testGetStruct() As Object + 'Bridge_GetStruct + '======================================================== + Dim objDocument As Object + objDocument = createHiddenDocument() + 'dispose not working i103353 + 'objDocument.dispose() + objDocument.close(True) + End Function + + Function testImplementedInterfaces() As Object + 'Bridge_ImplementedInterfaces + '================================================= + ' call a UNO function that takes an XEventListener interface + 'We provide a COM implementation (IDispatch) as EventListener + 'Open a new empty writer document + + Dim objDocument As Object + objDocument = createHiddenDocument() + objEventListener.resetDisposing() + objDocument.addEventListener(objEventListener) + objDocument.dispose() + If objEventListener.disposingCalled = False Then + MsgBox("Error") + End If + End Function + + Function testGetValueObject() As Object + 'Bridge_GetValueObject + '================================================== + Dim objVal As Object + objVal = objOleTest.Bridge_GetValueObject() + Dim arrByte(9) As Byte + Dim countvar As Integer + For countvar = 0 To 9 + arrByte(countvar) = countvar + Next countvar + + objVal.Set("[]byte", arrByte) + Dim ret As Object + ret = 0 + ret = objOleTest.methodByte(objVal) + 'Test if ret is the same array + + Dim key As Object + key = 0 + For Each key In ret + If ret(key) <> arrByte(key) Then + MsgBox("Error") + End If + Debug.Print(ret(key)) + Next key + + Dim outByte As Byte + outByte = 77 + Dim retByte As Byte + retByte = outByte + objVal.InitInOutParam("byte", retByte) + objOleTest.testinout_methodByte(objVal) + objVal.InitInOutParam("byte", retByte) + objOleTest.testinout_methodByte(objVal) + + ret = 0 + ret = objVal.Get() + Debug.Print(ret) + If ret <> outByte Then + MsgBox("error") + End If + + objVal.InitOutParam() + Dim inChar As Short + inChar = 65 + objOleTest.in_methodChar(inChar) + objOleTest.testout_methodChar(objVal) 'Returns 'A' (65) + ret = 0 + ret = objVal.Get() + Debug.Print(ret) + If ret <> inChar Then + MsgBox("error") + End If + + End Function + + Function testArrays() As Object + 'Arrays + '======================================== + Dim arrLong(2) As Integer + Dim arrObj(2) As Object + Dim countvar As Integer + For countvar = 0 To 2 + arrLong(countvar) = countvar + 10 + Debug.Print(countvar) + arrObj(countvar) = CreateObject("VBasicEventListener.VBEventListener") + arrObj(countvar).setQuiet(True) + Next + + 'Arrays always contain VARIANTS + Dim seq() As Object + seq = objOleTest.methodLong(arrLong) + + For countvar = 0 To 2 + Debug.Print(CStr(seq(countvar))) + If arrLong(countvar) <> seq(countvar) Then + MsgBox("error") + End If + Next + seq = objOleTest.methodXInterface(arrObj) + Dim tmp As Object + For countvar = 0 To 2 + seq(countvar).resetDisposing() + seq(countvar).disposing(CObj(tmp)) + If seq(countvar).disposingCalled = False Then + MsgBox("Error") + End If + Next + + 'Array containing interfaces (element type is VT_DISPATCH) + Dim arEventListener(2) As Object + For countvar = 0 To 2 + arEventListener(countvar) = CreateObject("VBasicEventListener.VBEventListener") + arEventListener(countvar).setQuiet(True) + Next + + 'The function calls disposing on the listeners + seq = objOleTest.methodXEventListeners(arEventListener) + Dim count As Object + For countvar = 0 To 2 + If arEventListener(countvar).disposingCalled = False Then + MsgBox("Error") + End If + Next + 'Array containing interfaces (element type is VT_VARIANT which contains VT_DISPATCH + Dim arEventListener2(2) As Object + For countvar = 0 To 2 + arEventListener2(countvar) = CreateObject("VBasicEventListener.VBEventListener") + arEventListener2(countvar).setQuiet(True) + Next + seq = objOleTest.methodXEventListeners(arEventListener2) + For countvar = 0 To 2 + If arEventListener2(countvar).disposingCalled = False Then + MsgBox("Error") + End If + Next + + 'Variant containing Array containing interfaces (element type is VT_VARIANT which contains VT_DISPATCH + Dim arEventListener3(2) As Object + Dim var As Object + For countvar = 0 To 2 + arEventListener3(countvar) = CreateObject("VBasicEventListener.VBEventListener") + arEventListener3(countvar).setQuiet(True) + Next + Dim varContAr As Object + varContAr = VB6.CopyArray(arEventListener3) + seq = objOleTest.methodXEventListeners(varContAr) + For countvar = 0 To 2 + If arEventListener3(countvar).disposingCalled = False Then + MsgBox("Error") + End If + Next + + 'Get a sequence created in UNO, out param is Variant ( VT_BYREF|VT_VARIANT) + Dim seqX As Object + + objOleTest.testout_methodSequence(seqX) + Dim key As Object + For Each key In seqX + Debug.Print(CStr(seqX(key))) + If seqX(key) <> key Then + MsgBox("error") + End If + Next key + 'Get a sequence created in UNO, out param is array Variant ( VT_BYREF|VT_VARIANT|VT_ARRAY) + Dim seqX2() As Object + objOleTest.testout_methodSequence(seqX2) + + For Each key In seqX2 + Debug.Print(CStr(seqX2(key))) + Next key + + 'pass it to UNO and get it back + Dim seq7() As Object + seq7 = objOleTest.methodLong(seqX) + Dim key2 As Object + For Each key2 In seq7 + Debug.Print(CStr(seq7(key2))) + If seqX2(key) <> key Then + MsgBox("error") + End If + Next key2 + + 'array with starting index != 0 + Dim seqIndex(2) As Integer + Dim seq8() As Object + Dim longVal1, longVal2 As Integer + longVal1 = 1 + longVal2 = 2 + seqIndex(1) = longVal1 + seqIndex(2) = longVal2 + 'The bridge returns a Safearray of Variants. It does not yet convert to an _ + 'array of a particular type! + 'Comparing of elements from seq8 (Object) with long values worked without _ + 'explicit cast as is necessary in VS 2008. Also arrays in VS 2008 start at _ + 'index 0 + seq8 = objOleTest.methodLong(seqIndex) + If longVal1 <> CInt(seq8(1)) And longVal2 <> CInt(seq8(2)) Then + MsgBox("error") + End If + + 'in out Array + ' arrLong is Long Array + Dim inoutVar(2) As Object + + For countvar = 0 To 2 + inoutVar(countvar) = countvar + 10 + Next + + objOleTest.testinout_methodSequence(inoutVar) + + countvar = 0 + For countvar = 0 To 2 + Debug.Print(CStr(inoutVar(countvar))) + If inoutVar(countvar) <> countvar + 11 Then + MsgBox("error") + End If + Next + + 'Multidimensional array + '============================================================ + ' Sequence< Sequence > methodSequence( Sequence< Sequence long> >) + ' Real multidimensional array Array + ' 9 is Dim 1 (least significant) with C API + Dim mulAr(9, 1) As Integer + For i = 0 To 1 + For j = 0 To 9 + mulAr(j, i) = i * 10 + j + Next j + Next i + + Dim resMul As Object + resMul = objOleTest.methodSequence(mulAr) + + Dim countDim1 As Integer + Dim countDim2 As Integer + Dim arr As Object + For countDim2 = 0 To 1 + arr = resMul(countDim2) + For countDim1 = 0 To 9 + Debug.Print(arr(countDim1)) + If arr(countDim1) <> mulAr(countDim1, countDim2) Then + MsgBox("Error Multidimensional Array") + End If + Next countDim1 + Next countDim2 + IsArray(resMul) + + 'Array of VARIANTs containing arrays + Dim mulAr2(1) As Object + Dim arr2(9) As Integer + For i = 0 To 1 + ' Dim arr(9) As Long + For j = 0 To 9 + arr2(j) = i * 10 + j + Next j + mulAr2(i) = VB6.CopyArray(arr2) + Next i + + resMul = 0 + resMul = objOleTest.methodSequence(mulAr2) + arr = 0 + Dim tmpVar As Object + For countDim2 = 0 To 1 + arr = resMul(countDim2) + tmpVar = mulAr2(countDim2) + For countDim1 = 0 To 9 + Debug.Print(arr(countDim1)) + If arr(countDim1) <> tmpVar(countDim1) Then + MsgBox("Error Multidimensional Array") + End If + Next countDim1 + Next countDim2 + + 'Array containing interfaces (element type is VT_DISPATCH) + Dim arArEventListener(1, 2) As Object + For i = 0 To 1 + For j = 0 To 2 + arArEventListener(i, j) = CreateObject("VBasicEventListener.VBEventListener") + arArEventListener(i, j).setQuiet(True) + Next + Next + 'The function calls disposing on the listeners + seq = objOleTest.methodXEventListenersMul(arArEventListener) + For i = 0 To 1 + For j = 0 To 2 + If arArEventListener(i, j).disposingCalled = False Then + MsgBox("Error") + End If + Next + Next + + 'Array containing interfaces (element type is VT_VARIANT containing VT_DISPATCH) + Dim arArEventListener2(1, 2) As Object + For i = 0 To 1 + For j = 0 To 2 + arArEventListener2(i, j) = CreateObject("VBasicEventListener.VBEventListener") + arArEventListener2(i, j).setQuiet(True) + Next + Next + 'The function calls disposing on the listeners + seq = objOleTest.methodXEventListenersMul(arArEventListener2) + For i = 0 To 1 + For j = 0 To 2 + If arArEventListener2(i, j).disposingCalled = False Then + MsgBox("Error") + End If + Next + Next + + ' SAFEARRAY of VARIANTS containing SAFEARRAYs + 'The ultimate element type is VT_DISPATCH ( XEventListener) + Dim arEventListener4(1) As Object + Dim seq1(2) As Object + Dim seq2(2) As Object + For i = 0 To 2 + seq1(i) = CreateObject("VBasicEventListener.VBEventListener") + seq2(i) = CreateObject("VBasicEventListener.VBEventListener") + seq1(i).setQuiet(True) + seq2(i).setQuiet(True) + Next + arEventListener4(0) = VB6.CopyArray(seq1) + arEventListener4(1) = VB6.CopyArray(seq2) + 'The function calls disposing on the listeners + seq = objOleTest.methodXEventListenersMul(arEventListener4) + For i = 0 To 2 + If seq1(i).disposingCalled = False Or seq2(i).disposingCalled = False Then + MsgBox("Error") + End If + Next + + End Function + + Function createHiddenDocument() As Object + 'Try to create a hidden document + Dim objPropValue As Object + objPropValue = objOleTest.Bridge_GetStruct("com.sun.star.beans.PropertyValue") + 'Set the members. If this fails then there is an Error + objPropValue.Name = "Hidden" + objPropValue.Handle = -1 + objPropValue.Value = True + + 'create a hidden document + 'Create the Desktop + Dim objDesktop As Object + objDesktop = objServiceManager.createInstance("com.sun.star.frame.Desktop") + 'Open a new empty writer document + Dim args(0) As Object + args(0) = objPropValue + createHiddenDocument = objDesktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, args) + End Function +End Module diff --git a/extensions/test/ole/VisualBasic/Project1.sln b/extensions/test/ole/VisualBasic/Project1.sln new file mode 100644 index 000000000..bea3e0edf --- /dev/null +++ b/extensions/test/ole/VisualBasic/Project1.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Project1", "Project1.vbproj", "{F62D440E-8976-4A6D-91A8-89F09701074F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F62D440E-8976-4A6D-91A8-89F09701074F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F62D440E-8976-4A6D-91A8-89F09701074F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F62D440E-8976-4A6D-91A8-89F09701074F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F62D440E-8976-4A6D-91A8-89F09701074F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/test/ole/VisualBasic/Project1.vbproj b/extensions/test/ole/VisualBasic/Project1.vbproj new file mode 100644 index 000000000..4fd617432 --- /dev/null +++ b/extensions/test/ole/VisualBasic/Project1.vbproj @@ -0,0 +1,90 @@ + + + Local + WindowsFormsWithCustomSubMain + 9.0.21022 + 2.0 + {F62D440E-8976-4A6D-91A8-89F09701074F} + Debug + AnyCPU + Project1 + WinExe + Project1.Module1 + 1 + 0 + 0 + False + StarOffice + Project1 + + + + + .\bin\ + Project1.xml + True + True + True + Win32=True + x86 + 42016,42017,42018,42019,42032 + full + + + .\bin\ + Project1.xml + False + False + True + Win32=True + x86 + 42016,42017,42018,42019,42032 + none + + + + Microsoft.VisualBasic.Compatibility + + + System + + + System.Data + + + System.Drawing + + + System.Windows.Forms + + + System.XML + + + + + + + + + + + + + + + + Code + + + + + + + + + + + + + \ No newline at end of file diff --git a/extensions/test/ole/VisualBasic/readme.txt b/extensions/test/ole/VisualBasic/readme.txt new file mode 100644 index 000000000..0b18430fc --- /dev/null +++ b/extensions/test/ole/VisualBasic/readme.txt @@ -0,0 +1,18 @@ +Runs a test written in VisualBasic. If no error message appears then the test was ok. + +Requirements: +Installed office +Component oletest.Oletest (extensions/test/ole/cpnt) +Component VBasicEventListener.VBEventListener (extensions/test/ole/EventListenerSample/VBEventListener + + +OleTest is a UNO component. It needs to be registered with the office rdb. Also there are additional +types (oletest.rdb in wntmsci7/bin/) which must be merged with the rdb. +VBEventListener is an ActiveX component. The directory contains a Visual Basic Project and also +the binary VBasicEventListener.dll. This is necessary because the dll contains the type library +which is needed by VB. Otherwise VB would generate a new CLSID on a new build. +The dll must be registered on the system. This is done by +regsvr32 VBasicEventListener.dll +or +by a rebuild of the project. + diff --git a/extensions/test/ole/callUnoToJava.htm b/extensions/test/ole/callUnoToJava.htm new file mode 100644 index 000000000..5374adbfa --- /dev/null +++ b/extensions/test/ole/callUnoToJava.htm @@ -0,0 +1,552 @@ + + + + + +Document Title + + + + + + + +

Object in JScript

+ +This test passes a XCallback to a UNO function of the UNO test control. +XCallback is implemented by the JScript class XCallback_Impl. The function +XCallback::func1 is then called from the UNO test control. +
+ +
+On the UNO object the function testInterface is called which takes +a XCallback as parameter. XCallback is implemented in a JScript object.The function +returns a XSimple Interface. Then the UNO object calls XSimple::notify. This test shall +verify the correct conversion of the return value( IDispatch JScript object) to an XSimple object.
+ +
+

out parameter

+The a JScript object of class XCallback_Impl is passed to the UNO OleTest Control as parameter. +According to the buttons the OleTest object calls a function on XCallback_Impl that has appropriate type +as out parameter.
+ + + + + + + + + + + + + +
+Other test without parameters
+ + +

in out parameter

+ + + + + + + + + + + + + +
+

Attributes

+ +
+ +Other tests with inout parameters
+ +

in parameters

+ + +

JScript object implements several interfaces

+ + + + + + + diff --git a/extensions/test/ole/cpnt/cpnt.cxx b/extensions/test/ole/cpnt/cpnt.cxx new file mode 100644 index 000000000..3369e03d6 --- /dev/null +++ b/extensions/test/ole/cpnt/cpnt.cxx @@ -0,0 +1,1955 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this 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 +#include +#include +#include +#include +#include +#include +#include +// OPTIONAL is a constant in com.sun.star.beans.PropertyAttributes but it must be +// undef'd in some header files +#define OPTIONAL OPTIONAL +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace cppu; +using namespace osl; +using namespace oletest; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::registry; +using namespace com::sun::star::script; +using namespace com::sun::star::reflection; + + +#define IMPL_NAME L"oletest.OleTestImpl" // oletest.OleTestImpl in applicat.rdb +#define SERVICE_NAME L"oletest.OleTest" +#define KEY1 L"/oletest.OleTestImpl/UNO/SERVICES" +#define KEY2 L"oletest.OleTest" + +class OComponent : public WeakImplHelper< + XTestSequence, XTestStruct, XTestOther, XTestInterfaces, + XSimple, XTestInParameters, XIdentity > +{ + Reference m_xIntIdentity; + sal_Int32 m_arrayConstructor; + Reference m_rFactory; + + Sequence m_seqByte; + Sequence m_seqFloat; + Sequence m_seqDouble; + Sequence m_seqBool; + Sequence m_seqShort; + Sequence m_seqUShort; + Sequence m_seqLong; + Sequence m_seqULong; + Sequence m_seqChar; + Sequence m_seqString; + Sequence m_seqAny; + Sequence m_seqType; + Sequence > m_seq1; + Sequence > > m_seq2; + Any m_any; + Type m_type; + Sequence > m_seqxInterface; + + sal_Int8 m_int8; + sal_uInt8 m_uint8; + sal_Int16 m_int16; + sal_uInt16 m_uint16; + sal_Int32 m_int32; + sal_uInt32 m_uint32; + sal_Int64 m_int64; + sal_uInt64 m_uint64; + float m_float; + double m_double; + OUString m_string; + sal_Unicode m_char; + sal_Bool m_bool; + Reference m_xinterface; + + sal_Int8 m_attr_int8; + sal_uInt8 m_attr_uint8; + sal_Int16 m_attr_int16; + sal_uInt16 m_attr_uint16; + sal_Int32 m_attr_int32; + sal_uInt32 m_attr_uint32; + sal_Int64 m_attr_int64; + sal_uInt64 m_attr_uint64; + float m_attr_float; + double m_attr_double; + OUString m_attr_string; + sal_Unicode m_attr_char; + sal_Bool m_attr_bool; + Any m_attr_any; + Type m_attr_type; + Reference m_attr_xinterface; + Reference m_attr_xinvocation; + +public: + OComponent( const Reference & rFactory ) : + m_rFactory( rFactory ), m_arrayConstructor(0) {} + ~OComponent(); +public: // XTestSequence + virtual Sequence SAL_CALL methodByte(const Sequence< sal_Int8 >& aSeq) throw( RuntimeException ); + virtual Sequence SAL_CALL methodFloat(const Sequence< float >& aSeq) throw( RuntimeException ); + virtual Sequence< double > SAL_CALL methodDouble(const Sequence< double >& aSeq) throw( RuntimeException); + virtual Sequence< sal_Bool > SAL_CALL methodBool(const Sequence< sal_Bool >& aSeq) throw( RuntimeException ); + virtual Sequence< sal_Int16 > SAL_CALL methodShort(const Sequence< sal_Int16 >& aSeq) throw( RuntimeException ); + virtual Sequence< sal_uInt16 > SAL_CALL methodUShort(const Sequence< sal_uInt16 >& aSeq) throw( RuntimeException ); + virtual Sequence< sal_Int32 > SAL_CALL methodLong(const Sequence< sal_Int32 >& aSeq) throw( RuntimeException) ; + virtual Sequence< sal_uInt32 > SAL_CALL methodULong(const Sequence< sal_uInt32 >& aSeq) throw( RuntimeException ); + virtual Sequence< OUString > SAL_CALL methodString(const Sequence< OUString >& aSeq) throw( RuntimeException ); + virtual Sequence< sal_Unicode > SAL_CALL methodChar(const Sequence< sal_Unicode >& aSeq) throw( RuntimeException ); + virtual Sequence< Any > SAL_CALL methodAny(const Sequence< Any >& aSeq) throw( RuntimeException ); + virtual Sequence< Type > SAL_CALL methodType(const Sequence< Type >& aSeq) throw( RuntimeException ); + virtual Sequence< Reference< XInterface > > SAL_CALL methodXInterface( const Sequence< Reference< XInterface > >& aSeq ) throw(RuntimeException) ; + virtual Sequence< Sequence< sal_Int32 > > SAL_CALL methodSequence(const Sequence< Sequence< sal_Int32 > >& aSeq) throw( RuntimeException ); + virtual Sequence< Sequence< Sequence< sal_Int32 > > > SAL_CALL methodSequence2(const Sequence< Sequence< Sequence< sal_Int32 > > >& aSeq) throw( RuntimeException ); + virtual Sequence< Reference > SAL_CALL methodXEventListeners( const Sequence >& aSeq) throw( RuntimeException); + virtual Sequence< Sequence > > SAL_CALL methodXEventListenersMul( const Sequence > >& aSeq ) throw (RuntimeException); + + virtual Sequence< sal_Int8 > SAL_CALL getAttrByte() throw( RuntimeException ); + virtual void SAL_CALL setAttrByte(const Sequence< sal_Int8 >& AttrByte_) throw( RuntimeException ); + virtual Sequence< float > SAL_CALL getAttrFloat() throw( RuntimeException) ; + virtual void SAL_CALL setAttrFloat(const Sequence< float >& AttrFloat_) throw( RuntimeException ); + virtual Sequence< double > SAL_CALL getAttrDouble() throw( RuntimeException) ; + virtual void SAL_CALL setAttrDouble(const Sequence< double >& AttrDouble_) throw( RuntimeException ); + virtual Sequence< sal_Bool > SAL_CALL getAttrBool() throw( RuntimeException ); + virtual void SAL_CALL setAttrBool(const Sequence< sal_Bool >& AttrBool_) throw( RuntimeException ); + virtual Sequence< sal_Int16 > SAL_CALL getAttrShort() throw( RuntimeException ); + virtual void SAL_CALL setAttrShort(const Sequence< sal_Int16 >& AttrShort_) throw( RuntimeException ); + virtual Sequence< sal_uInt16 > SAL_CALL getAttrUShort() throw( RuntimeException ); + virtual void SAL_CALL setAttrUShort(const Sequence< sal_uInt16 >& AttrUShort_) throw( RuntimeException ); + virtual Sequence< sal_Int32 > SAL_CALL getAttrLong() throw( RuntimeException ); + virtual void SAL_CALL setAttrLong(const Sequence< sal_Int32 >& AttrLong_) throw( RuntimeException ); + virtual Sequence< sal_uInt32 > SAL_CALL getAttrULong() throw( RuntimeException ); + virtual void SAL_CALL setAttrULong(const Sequence< sal_uInt32 >& AttrULong_) throw( RuntimeException ); + virtual Sequence< OUString > SAL_CALL getAttrString() throw(RuntimeException ); + virtual void SAL_CALL setAttrString(const Sequence< OUString >& AttrString_) throw( RuntimeException ); + virtual Sequence< sal_Unicode > SAL_CALL getAttrChar() throw( RuntimeException ); + virtual void SAL_CALL setAttrChar(const Sequence< sal_Unicode >& AttrChar_) throw( RuntimeException ); + virtual Sequence< Any > SAL_CALL getAttrAny() throw( RuntimeException ); + virtual void SAL_CALL setAttrAny(const Sequence< Any >& AttrAny_) throw( RuntimeException ); + virtual Sequence< Type > SAL_CALL getAttrType() throw( RuntimeException ); + virtual void SAL_CALL setAttrType( const Sequence< Type >& _attrtype ) throw (RuntimeException); + virtual Sequence< Sequence< sal_Int32 > > SAL_CALL getAttrSequence() throw( RuntimeException ); + virtual void SAL_CALL setAttrSequence(const Sequence< Sequence< sal_Int32 > >& AttrSequence_) throw( RuntimeException ); + virtual Sequence< Sequence< Sequence< sal_Int32 > > > SAL_CALL getAttrSequence2() throw( RuntimeException ); + virtual void SAL_CALL setAttrSequence2(const Sequence< Sequence< Sequence< sal_Int32 > > >& AttrSequence2_) throw ( RuntimeException ); + virtual Sequence< Reference< XInterface > > SAL_CALL getAttrXInterface() throw(RuntimeException); + virtual void SAL_CALL setAttrXInterface( const Sequence< Reference< XInterface > >& _attrxinterface ) throw(RuntimeException); + + virtual ::sal_Int8 SAL_CALL getAByte() throw (RuntimeException); + virtual void SAL_CALL setAByte( ::sal_Int8 _abyte ) throw (RuntimeException); + virtual float SAL_CALL getAFloat() throw (RuntimeException); + virtual void SAL_CALL setAFloat( float _afloat ) throw (RuntimeException); + virtual double SAL_CALL getADouble() throw (RuntimeException); + virtual void SAL_CALL setADouble( double _adouble ) throw (RuntimeException); + virtual sal_Bool SAL_CALL getABool() throw (RuntimeException); + virtual void SAL_CALL setABool( sal_Bool _abool ) throw (RuntimeException); + virtual ::sal_Int16 SAL_CALL getAShort() throw (RuntimeException); + virtual void SAL_CALL setAShort( ::sal_Int16 _ashort ) throw (RuntimeException); + virtual ::sal_uInt16 SAL_CALL getAUShort() throw (RuntimeException); + virtual void SAL_CALL setAUShort( ::sal_uInt16 _aushort ) throw (RuntimeException); + virtual ::sal_Int32 SAL_CALL getALong() throw (RuntimeException); + virtual void SAL_CALL setALong( ::sal_Int32 _along ) throw (RuntimeException); + virtual ::sal_uInt32 SAL_CALL getAULong() throw (RuntimeException); + virtual void SAL_CALL setAULong( ::sal_uInt32 _aulong ) throw (RuntimeException); + virtual OUString SAL_CALL getAString() throw (RuntimeException); + virtual void SAL_CALL setAString( const OUString& _astring ) throw (RuntimeException); + virtual ::sal_Unicode SAL_CALL getAChar() throw (RuntimeException); + virtual void SAL_CALL setAChar( ::sal_Unicode _achar ) throw (RuntimeException); + virtual Any SAL_CALL getAAny() throw (RuntimeException); + virtual void SAL_CALL setAAny( const Any& _aany ) throw (RuntimeException); + virtual Type SAL_CALL getAType() throw (RuntimeException); + virtual void SAL_CALL setAType( const Type& _atype ) throw (RuntimeException); + virtual Reference< XInterface > SAL_CALL getAXInterface() throw (RuntimeException); + virtual void SAL_CALL setAXInterface( const Reference& _axinterface ) throw (RuntimeException); + virtual Reference SAL_CALL getAXInvocation() throw (RuntimeException); + virtual void SAL_CALL setAXInvocation( const Reference< XInvocation >& _axinvocation ) throw (RuntimeException); + + virtual void SAL_CALL testout_methodByte(sal_Int8& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodFloat(float& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodDouble(double& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodBool(sal_Bool& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodShort(sal_Int16& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodUShort(sal_uInt16& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodLong(sal_Int32& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodULong(sal_uInt32& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodHyper(sal_Int64& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodUHyper(sal_uInt64& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodString(OUString& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodChar(sal_Unicode& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodAny(Any& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodType(Type& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodSequence(Sequence< sal_Int32 >& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodSequence2(Sequence< Sequence< sal_Int32 > >& rOut) throw( RuntimeException ); + virtual void SAL_CALL testout_methodMulParams1(sal_Int32& rout1, sal_Int32& rout2) throw( RuntimeException ); + virtual void SAL_CALL testout_methodMulParams2(sal_Int32& rout1, sal_Int32& rout2, OUString& rout3) throw( RuntimeException ); + virtual void SAL_CALL testout_methodMulParams3(const OUString& sin, OUString& sout) throw( RuntimeException ); + virtual void SAL_CALL testout_methodMulParams4( float in1, float& out1, sal_Int32 in2, sal_Int32& out2, sal_Int32 in3 ) throw(RuntimeException); + virtual void SAL_CALL testout_methodXInterface( Reference< XInterface >& rOut ) throw(RuntimeException); + + virtual void SAL_CALL testinout_methodByte(sal_Int8& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodFloat(float& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodDouble(double& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodBool(sal_Bool& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodShort(sal_Int16& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodUShort(sal_uInt16& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodLong(sal_Int32& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodULong(sal_uInt32& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodHyper(sal_Int64& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodUHyper(sal_uInt64& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodString(OUString& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodChar(sal_Unicode& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodAny(Any& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodType(Type& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodSequence(Sequence< sal_Int32 >& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodSequence2(Sequence< Sequence< sal_Int32 > >& rOut) throw( RuntimeException ); + virtual void SAL_CALL testinout_methodXInterface( Reference< XInvocation >& rOut ) throw(RuntimeException); + virtual void SAL_CALL testinout_methodXInterface2( Reference< XInterface > & rOut) throw( RuntimeException); + virtual Any SAL_CALL methodAnyTest1(const Any& rIn) throw( RuntimeException ) ; + virtual Any SAL_CALL getAttrAny2() throw( RuntimeException ) ; + virtual void SAL_CALL setAttrAny2(const Any& AttrAny2_) throw( RuntimeException ) ; + + + // XTestStruct + virtual void SAL_CALL methodStruct(const Property& aProp) throw( RuntimeException ); + + virtual Property SAL_CALL retMethodStruct() throw( RuntimeException ); + + virtual Property SAL_CALL getAttrStruct() throw( RuntimeException ); + virtual void SAL_CALL setAttrStruct(const Property& AttrStruct_) throw( RuntimeException ); + virtual Property SAL_CALL methodStruct2( const Property& aProp ) throw (RuntimeException); + + // XTestOther + virtual void SAL_CALL other_methodAnyIn(const Any& rAny) throw( RuntimeException ); + virtual void SAL_CALL other_methodAnyOut(Any& rAny) throw( RuntimeException ); + virtual Any SAL_CALL other_methodAnyRet() throw( RuntimeException ); + virtual void SAL_CALL in_float( float val) throw ( RuntimeException); + virtual Any SAL_CALL other_methodAny( const Any& rAny, const OUString& typeInAny ) + throw (RuntimeException); + + // XTestInParameters + virtual sal_Int8 SAL_CALL in_methodByte( sal_Int8 rIn ) throw (RuntimeException); + virtual float SAL_CALL in_methodFloat( float rIn ) throw (RuntimeException); + virtual double SAL_CALL in_methodDouble( double rIn ) throw (RuntimeException); + virtual sal_Bool SAL_CALL in_methodBool( sal_Bool rIn ) throw (RuntimeException); + virtual sal_Int16 SAL_CALL in_methodShort( sal_Int16 rIn ) throw (RuntimeException); + virtual sal_uInt16 SAL_CALL in_methodUShort( sal_uInt16 rIn ) throw (RuntimeException); + virtual sal_Int32 SAL_CALL in_methodLong( sal_Int32 rIn ) throw (RuntimeException); + virtual sal_uInt32 SAL_CALL in_methodULong( sal_uInt32 rIn ) throw (RuntimeException); + virtual sal_Int64 SAL_CALL in_methodHyper( sal_Int64 rIn ) throw (RuntimeException); + virtual sal_uInt64 SAL_CALL in_methodUHyper( sal_uInt64 rIn ) throw (RuntimeException); + virtual OUString SAL_CALL in_methodString( const OUString& rIn ) throw (RuntimeException); + virtual sal_Unicode SAL_CALL in_methodChar( sal_Unicode rIn ) throw (RuntimeException); + virtual Any SAL_CALL in_methodAny( const Any& rIn ) throw (RuntimeException); + virtual Type SAL_CALL in_methodType( const Type& rIn ) throw (RuntimeException); + virtual Reference SAL_CALL in_methodXInterface( const Reference< XInterface >& rIn ) throw (RuntimeException); + virtual Reference SAL_CALL in_methodInvocation( const Reference< XInvocation >& inv ) throw (RuntimeException); + virtual SimpleStruct SAL_CALL in_methodStruct( const SimpleStruct& aStruct ) throw (RuntimeException); + virtual void SAL_CALL in_methodAll( sal_Int8 b, float f, double d, sal_Bool boo, sal_Int16 sh, sal_uInt16 us, sal_Int32 l, sal_uInt32 ul, const OUString& s, sal_Unicode c, const Any& a, const Type& t, const Reference& inv ) throw (RuntimeException); + + // XTestInterfaces -------------------------------------------------------------------------- + virtual void SAL_CALL testInterface( const Reference< XCallback >& xCallback, sal_Int32 mode ) throw(RuntimeException); + virtual void SAL_CALL testInterface2( const Reference< XSimple >& xSimple, sal_Int32 mode ) throw(RuntimeException); + // XSimple -------------------------------------------------------------------------- + void SAL_CALL func( const OUString &message) throw(css::uno::RuntimeException); + OUString SAL_CALL getName() throw(css::uno::RuntimeException); + + // XIdentity + virtual void SAL_CALL setObject( const Reference< XInterface >& val ) throw (RuntimeException); + virtual sal_Bool SAL_CALL isSame( const Reference< XInterface >& val ) throw (RuntimeException); + virtual Reference< XInterface > SAL_CALL getThis( ) throw (RuntimeException); +}; + +class EventListener: public WeakImplHelper +{ +public: + EventListener(): bCalled( sal_False) + {} + virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) throw (RuntimeException); + + sal_Bool bCalled; +}; + + +OComponent::~OComponent() +{ +} + + +// functions ============================================================================== + +Reference SAL_CALL OComponent_CreateInstance( const Reference & rSMgr ) throw(RuntimeException) +{ +// Reference xService(static_cast(new OComponent( rSMgr )), UNO_QUERY); + OComponent* o= new OComponent( rSMgr ); + Reference xService(static_cast(o), UNO_QUERY); + return xService; +} + +Sequence OComponent_getSupportedServiceNames() +{ + Sequence aRet { SERVICE_NAME;//ODataInputStream_getImplementationName() }; + + return aRet; +} + + +extern "C" sal_Bool SAL_CALL component_writeInfo( void * /*pServiceManager*/, void * pRegistryKey ) +{ + if(pRegistryKey) + { + try + { + Reference xNewKey = + reinterpret_cast( pRegistryKey)->createKey(KEY1); + xNewKey->createKey( KEY2); + return sal_True; + + } + catch(InvalidRegistryException &) + { + TOOLS_WARN_EXCEPTION("extensions.olebridge", ""); + } + } + return sal_False; +} + +extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( + const char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) +{ + static void * pRet= NULL; + if( ! pRet) + { + OUString aImplName( OUString::createFromAscii( pImplName ) ); + if (pServiceManager && aImplName.equals( IMPL_NAME )) + { + Reference xMulFac( + reinterpret_cast< XMultiServiceFactory*>(pServiceManager)); + + Sequence seqServiceNames; + Reference xFactory = createOneInstanceFactory( xMulFac, SERVICE_NAME, + OComponent_CreateInstance, seqServiceNames); + + if (xFactory.is()) + { + xFactory->acquire(); + pRet = xFactory.get(); + } + } + } + return pRet; +} + + +// XTestSequence ============================================================================ +Sequence SAL_CALL OComponent::methodByte(const Sequence< sal_Int8 >& aSeq) throw( RuntimeException ) +{ + sal_Int8 _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence SAL_CALL OComponent::methodFloat(const Sequence< float>& aSeq) throw( RuntimeException ) +{ + float _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence SAL_CALL OComponent::methodDouble(const Sequence< double >& aSeq) throw( RuntimeException) +{ + double _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence< sal_Bool > SAL_CALL OComponent::methodBool(const Sequence< sal_Bool >& aSeq) throw( RuntimeException) +{ + sal_Bool _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence< sal_Int16 > SAL_CALL OComponent::methodShort(const Sequence< sal_Int16 >& aSeq) throw( RuntimeException ) +{ + sal_Int16 _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence< sal_uInt16 > SAL_CALL OComponent::methodUShort(const Sequence< sal_uInt16 >& aSeq) throw( RuntimeException ) +{ + sal_uInt16 _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence< sal_Int32 > SAL_CALL OComponent::methodLong(const Sequence< sal_Int32 >& aSeq) throw( RuntimeException) +{ + sal_Int32 _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++) { + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence< sal_uInt32 > SAL_CALL OComponent::methodULong(const Sequence< sal_uInt32 >& aSeq) throw( RuntimeException) +{ + sal_uInt32 _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence< OUString > SAL_CALL OComponent::methodString(const Sequence< OUString >& aSeq) throw( RuntimeException) +{ + OUString _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++) { + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence< sal_Unicode > SAL_CALL OComponent::methodChar(const Sequence< sal_Unicode >& aSeq) throw( RuntimeException) +{ + sal_Unicode _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} +Sequence< Any > SAL_CALL OComponent::methodAny(const Sequence< Any >& aSeq) throw( RuntimeException) +{ + Any _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + TypeClass _t= _x.getValueTypeClass(); + if( _t== TypeClass_STRING) + OUString s(* (rtl_uString**)_x.getValue()); + } + return aSeq; + +} + +Sequence< Type > SAL_CALL OComponent::methodType(const Sequence< Type >& aSeq) throw( RuntimeException ) +{ + Type _x; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + _x= aSeq.getConstArray()[i]; + } + return aSeq; +} + +Sequence< Reference< XInterface > > SAL_CALL OComponent::methodXInterface( const Sequence< Reference< XInterface > >& aSeq ) throw(RuntimeException) +{ + for( sal_Int32 i= 0; i < aSeq.getLength(); i++) + { + Reference xInt= aSeq[i]; + Reference xList( xInt, UNO_QUERY); + if( xList.is()) + xList->disposing( EventObject()); + } + return aSeq; +} + +Sequence< Sequence< sal_Int32 > > SAL_CALL OComponent::methodSequence(const Sequence< Sequence< sal_Int32 > >& aSeq) throw( RuntimeException) +{ + sal_Int32 value; + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + const Sequence& rseq2= aSeq.getConstArray()[i]; + for (sal_Int16 j= 0; j < rseq2.getLength(); j++){ + value= rseq2.getConstArray()[j]; + } + } + return aSeq; +} +Sequence< Sequence< Sequence< sal_Int32 > > > SAL_CALL OComponent::methodSequence2(const Sequence< Sequence< Sequence< sal_Int32 > > >& aSeq) + throw( RuntimeException ) +{ + sal_Int32 value; + sal_Int32 len= aSeq.getLength(); + for( sal_Int16 i= 0; i < aSeq.getLength(); i++){ + const Sequence< Sequence >& rseq2= aSeq.getConstArray()[i]; + len= rseq2.getLength(); + + for (sal_Int16 j= 0; j < rseq2.getLength(); j++){ + const Sequence & rseq3= rseq2.getConstArray()[j]; + len= rseq3.getLength(); + + for (sal_Int16 k= 0; k < rseq3.getLength(); k++) + value= rseq3.getConstArray()[k]; + } + } + return aSeq; +} + +Sequence< Reference< XEventListener> > SAL_CALL OComponent::methodXEventListeners( const Sequence< Reference >& aSeq) throw( RuntimeException) +{ + Reference listener; + for( int i= 0; i < aSeq.getLength(); i++) + { + listener= aSeq[i]; + + listener->disposing( EventObject() ); + } + + return aSeq; +} + +Sequence< Sequence > > SAL_CALL OComponent::methodXEventListenersMul( const Sequence > >& aSeq ) throw (RuntimeException) +{ + Reference listener; + for( int i= 0; i < aSeq.getLength(); i++) + { + Sequence > seqInner= aSeq[i]; + for( int j= 0; j < seqInner.getLength(); j++) + { + listener= seqInner[j]; + listener->disposing( EventObject() ); + } + } + return aSeq; +} + + +Sequence< sal_Int8 > SAL_CALL OComponent::getAttrByte() throw( RuntimeException) +{ + return m_seqByte; +} +void SAL_CALL OComponent::setAttrByte(const Sequence< sal_Int8 >& AttrByte_) throw( RuntimeException ) +{ + m_seqByte= AttrByte_; +} +Sequence< float > SAL_CALL OComponent::getAttrFloat() throw( RuntimeException ) +{ + return m_seqFloat; +} +void SAL_CALL OComponent::setAttrFloat(const Sequence< float >& AttrFloat_) throw( RuntimeException ) +{ + m_seqFloat= AttrFloat_; +} + +Sequence< double > SAL_CALL OComponent::getAttrDouble() throw( RuntimeException ) +{ + return m_seqDouble; +} +void SAL_CALL OComponent::setAttrDouble(const Sequence< double >& AttrDouble_) throw( RuntimeException ) +{ + m_seqDouble= AttrDouble_; +} + +Sequence< sal_Bool > SAL_CALL OComponent::getAttrBool() throw( RuntimeException) +{ + return m_seqBool; +} + +void SAL_CALL OComponent::setAttrBool(const Sequence< sal_Bool >& AttrBool_) throw (RuntimeException ) +{ + m_seqBool= AttrBool_; +} + +Sequence< sal_Int16 > SAL_CALL OComponent::getAttrShort() throw( RuntimeException) +{ + return m_seqShort; +} +void SAL_CALL OComponent::setAttrShort(const Sequence< sal_Int16 >& AttrShort_) throw( RuntimeException ) +{ + m_seqShort= AttrShort_; +} + +Sequence< sal_uInt16 > SAL_CALL OComponent::getAttrUShort() throw( RuntimeException ) +{ + return m_seqUShort; +} +void SAL_CALL OComponent::setAttrUShort(const Sequence< sal_uInt16 >& AttrUShort_) throw( RuntimeException ) +{ + m_seqUShort= AttrUShort_; +} + +Sequence< sal_Int32 > SAL_CALL OComponent::getAttrLong() throw( RuntimeException) +{ + return m_seqLong; +} +void SAL_CALL OComponent::setAttrLong(const Sequence< sal_Int32 >& AttrLong_) throw( RuntimeException ) +{ + m_seqLong= AttrLong_; +} + +Sequence< sal_uInt32 > SAL_CALL OComponent::getAttrULong() throw( RuntimeException ) +{ + return m_seqULong; +} +void SAL_CALL OComponent::setAttrULong(const Sequence< sal_uInt32 >& AttrULong_) throw( RuntimeException ) +{ + m_seqULong= AttrULong_; +} + +Sequence< OUString > SAL_CALL OComponent::getAttrString() throw( RuntimeException ) +{ + return m_seqString; +} +void SAL_CALL OComponent::setAttrString(const Sequence< OUString >& AttrString_) throw( RuntimeException ) +{ + m_seqString= AttrString_; +} + +Sequence< sal_Unicode > SAL_CALL OComponent::getAttrChar() throw( RuntimeException ) +{ + return m_seqChar; +} +void SAL_CALL OComponent::setAttrChar(const Sequence< sal_Unicode >& AttrChar_) throw( RuntimeException) +{ + m_seqChar= AttrChar_; +} + +Sequence< Any > SAL_CALL OComponent::getAttrAny() throw( RuntimeException) +{ + return m_seqAny; +} +void SAL_CALL OComponent::setAttrAny(const Sequence< Any >& AttrAny_) throw( RuntimeException ) +{ + m_seqAny= AttrAny_; +} + +Sequence< Type > SAL_CALL OComponent::getAttrType() throw( RuntimeException ) +{ + return m_seqType; +} + +void SAL_CALL OComponent::setAttrType( const Sequence< Type >& AttrType_) throw( RuntimeException ) +{ + m_seqType = AttrType_; +} + + +Sequence< Sequence< sal_Int32 > > SAL_CALL OComponent::getAttrSequence() throw( RuntimeException) +{ + return m_seq1; +} +void SAL_CALL OComponent::setAttrSequence(const Sequence< Sequence< sal_Int32 > >& AttrSequence) throw(RuntimeException ) +{ + sal_Int32 x= 0; + for( sal_Int32 i=0; i < AttrSequence.getLength(); i++) + { + Sequence< sal_Int32 > seq= AttrSequence[i]; + + for ( sal_Int32 j=0; j < seq.getLength(); j++) + { + x= seq[j]; + } + } + + m_seq1= AttrSequence; +} + +Sequence< Sequence< Sequence< sal_Int32 > > > SAL_CALL OComponent::getAttrSequence2() throw( RuntimeException ) +{ + return m_seq2; +} +void SAL_CALL OComponent::setAttrSequence2(const Sequence< Sequence< Sequence< sal_Int32 > > >& AttrSequence2_) + throw( RuntimeException ) +{ + m_seq2= AttrSequence2_; +} + +Sequence< Reference< XInterface > > SAL_CALL OComponent::getAttrXInterface() throw(RuntimeException) +{ + return m_seqxInterface; +} +void SAL_CALL OComponent::setAttrXInterface( const Sequence< Reference< XInterface > >& _attrxinterface ) throw(RuntimeException) +{ + m_seqxInterface= _attrxinterface; +} + + +::sal_Int8 SAL_CALL OComponent::getAByte() throw (RuntimeException) +{ + return m_attr_int8; +} + +void SAL_CALL OComponent::setAByte( ::sal_Int8 _abyte ) throw (RuntimeException) +{ + m_attr_int8 = _abyte; +} + +float SAL_CALL OComponent::getAFloat() throw (RuntimeException) +{ + return m_attr_float; +} + +void SAL_CALL OComponent::setAFloat( float _afloat ) throw (RuntimeException) +{ + m_attr_float = _afloat; +} + +double SAL_CALL OComponent::getADouble() throw (RuntimeException) +{ + return m_attr_double; +} + +void SAL_CALL OComponent::setADouble( double _adouble ) throw (RuntimeException) +{ + m_attr_double = _adouble; +} + +sal_Bool SAL_CALL OComponent::getABool() throw (RuntimeException) +{ + return m_attr_bool; +} + +void SAL_CALL OComponent::setABool( sal_Bool _abool ) throw (RuntimeException) +{ + m_attr_bool = _abool; +} + +::sal_Int16 SAL_CALL OComponent::getAShort() throw (RuntimeException) +{ + return m_attr_int16; +} + +void SAL_CALL OComponent::setAShort( ::sal_Int16 _ashort ) throw (RuntimeException) +{ + m_attr_int16 = _ashort; +} + +::sal_uInt16 SAL_CALL OComponent::getAUShort() throw (RuntimeException) +{ + return m_attr_uint16; +} + +void SAL_CALL OComponent::setAUShort( ::sal_uInt16 _aushort ) throw (RuntimeException) +{ + m_attr_uint16 = _aushort; +} + +::sal_Int32 SAL_CALL OComponent::getALong() throw (RuntimeException) +{ + return m_attr_int32; +} + +void SAL_CALL OComponent::setALong( ::sal_Int32 _along ) throw (RuntimeException) +{ + m_attr_int32 = _along; +} + +::sal_uInt32 SAL_CALL OComponent::getAULong() throw (RuntimeException) +{ + return m_attr_uint32; +} + +void SAL_CALL OComponent::setAULong( ::sal_uInt32 _aulong ) throw (RuntimeException) +{ + m_attr_uint32 = _aulong; +} + +OUString SAL_CALL OComponent::getAString() throw (RuntimeException) +{ + return m_attr_string; +} + +void SAL_CALL OComponent::setAString( const OUString& _astring ) throw (RuntimeException) +{ + m_attr_string = _astring; +} + +::sal_Unicode SAL_CALL OComponent::getAChar() throw (RuntimeException) +{ + return m_attr_char; +} + +void SAL_CALL OComponent::setAChar( ::sal_Unicode _achar ) throw (RuntimeException) +{ + m_attr_char = _achar; +} + +Any SAL_CALL OComponent::getAAny() throw (RuntimeException) +{ + return m_attr_any; +} + +void SAL_CALL OComponent::setAAny( const Any& _aany ) throw (RuntimeException) +{ + m_attr_any = _aany; +} + +Type SAL_CALL OComponent::getAType() throw (RuntimeException) +{ + return m_attr_type; +} + +void SAL_CALL OComponent::setAType( const Type& _atype ) throw (RuntimeException) +{ + m_attr_type = _atype; +} + +Reference< XInterface > SAL_CALL OComponent::getAXInterface() throw (RuntimeException) +{ + return m_attr_xinterface; +} + +void SAL_CALL OComponent::setAXInterface( const Reference& _axinterface ) throw (RuntimeException) +{ + m_attr_xinterface = _axinterface; +} + +Reference SAL_CALL OComponent::getAXInvocation() throw (RuntimeException) +{ + return m_attr_xinvocation; +} + +void SAL_CALL OComponent::setAXInvocation( const Reference< XInvocation >& _axinvocation ) throw (RuntimeException) +{ + m_attr_xinvocation = _axinvocation; +} + +void SAL_CALL OComponent::testout_methodByte(sal_Int8& rOut) throw( RuntimeException ) +{ + rOut= m_int8; +} +void SAL_CALL OComponent::testout_methodFloat(float& rOut) throw( RuntimeException ) +{ + rOut= m_float; +} +void SAL_CALL OComponent::testout_methodDouble(double& rOut) throw( RuntimeException ) +{ + rOut= m_double; +} + +void SAL_CALL OComponent::testout_methodBool(sal_Bool& rOut) throw( RuntimeException ) +{ + rOut= m_bool; +} +void SAL_CALL OComponent::testout_methodShort(sal_Int16& rOut) throw( RuntimeException ) +{ + rOut= m_int16; +} +void SAL_CALL OComponent::testout_methodUShort(sal_uInt16& rOut) throw( RuntimeException ) +{ + rOut= m_uint16; +} +void SAL_CALL OComponent::testout_methodLong(sal_Int32& rOut) throw( RuntimeException ) +{ + rOut = m_int32; +} +void SAL_CALL OComponent::testout_methodULong(sal_uInt32& rOut) throw( RuntimeException ) +{ + rOut= m_uint32; +} +void SAL_CALL OComponent::testout_methodHyper(sal_Int64& rOut) throw( RuntimeException ) +{ + rOut = m_int64; +} + +void SAL_CALL OComponent::testout_methodUHyper(sal_uInt64& rOut) throw( RuntimeException ) +{ + rOut = m_uint64; +} + +void SAL_CALL OComponent::testout_methodString(OUString& rOut) throw( RuntimeException ) +{ + rOut= m_string; +} +void SAL_CALL OComponent::testout_methodChar(sal_Unicode& rOut) throw( RuntimeException ) +{ + rOut= m_char; +} +void SAL_CALL OComponent::testout_methodAny(Any& rOut) throw( RuntimeException) +{ + rOut = m_any; +} + +void SAL_CALL OComponent::testout_methodType(Type& rOut) throw( RuntimeException ) +{ + rOut = m_type; +} + +void SAL_CALL OComponent::testout_methodSequence(Sequence< sal_Int32 >& rOut) throw( RuntimeException) +{ + rOut.realloc(10); + for( sal_Int16 i= 0; i < rOut.getLength(); i++) rOut.getArray()[i]= i; +} +void SAL_CALL OComponent::testout_methodSequence2(Sequence< Sequence< sal_Int32 > >& rOut) throw( RuntimeException ) +{ + rOut.realloc( 10); + for( sal_Int16 i= 0; i < rOut.getLength(); i++){ + Sequence& rseq2= rOut.getArray()[i]; + rseq2.realloc( 10); + for (sal_Int16 j= 0; j < rseq2.getLength(); j++){ + rseq2.getArray()[j]= j; + } + } +} +void SAL_CALL OComponent::testout_methodMulParams1(sal_Int32& rout1, sal_Int32& rout2) throw( RuntimeException ) +{ + rout1= 999; + rout2= 1111; +} +void SAL_CALL OComponent::testout_methodMulParams2(sal_Int32& rout1, sal_Int32& rout2, OUString& rout3) throw( RuntimeException ) +{ + rout1= 1111; + rout2= 1222; + rout3= L" another string"; +} +void SAL_CALL OComponent::testout_methodMulParams3(const OUString&, OUString& sout) throw( RuntimeException ) +{ + sout= L"Out Hallo!"; +} +void SAL_CALL OComponent::testout_methodMulParams4( float in1, float& out1, sal_Int32 in2, sal_Int32& out2, sal_Int32 ) throw(RuntimeException) +{ + out1= in1 + 1; + out2= in2 + 1; +} + +void SAL_CALL OComponent::testout_methodXInterface( Reference< XInterface >& rOut ) throw(RuntimeException) +{ + rOut = m_xinterface; +} + +// XTestInParameters ------------------------------------------------------------ +sal_Int8 SAL_CALL OComponent::in_methodByte( sal_Int8 rIn ) throw (RuntimeException) +{ + m_int8 = rIn; + return rIn; +} +float SAL_CALL OComponent::in_methodFloat( float rIn ) throw (RuntimeException) +{ + m_float = rIn; + return rIn; +} +double SAL_CALL OComponent::in_methodDouble( double rIn ) throw (RuntimeException) +{ + m_double = rIn; + return rIn; +} +sal_Bool SAL_CALL OComponent::in_methodBool( sal_Bool rIn ) throw (RuntimeException) +{ + m_bool = rIn; + return rIn; +} +sal_Int16 SAL_CALL OComponent::in_methodShort( sal_Int16 rIn ) throw (RuntimeException) +{ + m_int16 = rIn; + return rIn; +} +sal_uInt16 SAL_CALL OComponent::in_methodUShort( sal_uInt16 rIn ) throw (RuntimeException) +{ + m_uint16 = rIn; + return rIn; +} +sal_Int32 SAL_CALL OComponent::in_methodLong( sal_Int32 rIn ) throw (RuntimeException) +{ + m_int32 = rIn; + return rIn; +} +sal_uInt32 SAL_CALL OComponent::in_methodULong( sal_uInt32 rIn ) throw (RuntimeException) +{ + m_uint32 = rIn; + return rIn; +} +sal_Int64 SAL_CALL OComponent::in_methodHyper( sal_Int64 rIn ) throw (RuntimeException) +{ + m_int64 = rIn; + return rIn; +} + +sal_uInt64 SAL_CALL OComponent::in_methodUHyper( sal_uInt64 rIn ) throw (RuntimeException) +{ + m_uint64 = rIn; + return rIn; +} + +OUString SAL_CALL OComponent::in_methodString( const OUString& rIn ) throw (RuntimeException) +{ + m_string = rIn; + return rIn; +} +sal_Unicode SAL_CALL OComponent::in_methodChar( sal_Unicode rIn ) throw (RuntimeException) +{ + m_char = rIn; + return rIn; +} +Any SAL_CALL OComponent::in_methodAny( const Any& rIn ) throw (RuntimeException) +{ + m_any = rIn; + return rIn; +} + +Type SAL_CALL OComponent::in_methodType( const Type& rIn ) throw (RuntimeException) +{ + m_type = rIn; + return rIn; +} + +Reference SAL_CALL OComponent::in_methodInvocation( const Reference< XInvocation >& inv ) + throw (RuntimeException) +{ + //We expect the invocation results from a conversion of VBasicEventListener.VBEventListener +//which implements XEventListener + // extensions/test/ole/EventListenerSample + EventObject event( Reference(static_cast(this),UNO_QUERY)); + Any anyParam; + anyParam <<= event; + Sequence params( &anyParam, 1); + Sequence outIndex; + Sequence outParams; + try{ + inv->invoke( OUString("disposing"), + params, outIndex, outParams); + }catch(IllegalArgumentException &) { + } + catch(CannotConvertException &){ + } + catch(InvocationTargetException&) { + } + return inv; +} +Reference SAL_CALL OComponent::in_methodXInterface( const Reference& rIn ) throw (RuntimeException) +{ + m_xinterface = rIn; + return rIn; +} + +SimpleStruct SAL_CALL OComponent::in_methodStruct( const SimpleStruct& aStruct ) + throw (RuntimeException) +{ + SimpleStruct& s= const_cast(aStruct); + s.message= s.message + OUString( + "This string was set in OleTest"); + return aStruct; +} +void SAL_CALL OComponent::in_methodAll( + sal_Int8, float, double, sal_Bool, sal_Int16, sal_uInt16, + sal_Int32, sal_uInt32, const OUString&, sal_Unicode, + const Any&, const Type&, const Reference&) throw (RuntimeException) +{ +} + +// INOUT ----------------------------------------------------------------------------------- +void SAL_CALL OComponent::testinout_methodByte(sal_Int8& rOut) throw( RuntimeException ) +{ + sal_Int8 tmp = rOut; + rOut = m_int8; + m_int8 = tmp; +} +void SAL_CALL OComponent::testinout_methodFloat(float& rOut) throw( RuntimeException ) +{ + float tmp = rOut; + rOut = m_float; + m_float = tmp; +} + +void SAL_CALL OComponent::testinout_methodDouble(double& rOut) throw( RuntimeException ) +{ + double tmp = rOut; + rOut = m_double; + m_double = tmp; +} +void SAL_CALL OComponent::testinout_methodBool(sal_Bool& rOut) throw( RuntimeException ) +{ + sal_Bool tmp = rOut; + rOut = m_bool; + m_bool = tmp; +} +void SAL_CALL OComponent::testinout_methodShort(sal_Int16& rOut) throw( RuntimeException ) +{ + sal_Int16 tmp= rOut; + rOut = m_int16; + m_int16 = tmp; +} +void SAL_CALL OComponent::testinout_methodUShort(sal_uInt16& rOut) throw( RuntimeException ) +{ + sal_uInt16 tmp = rOut; + rOut = m_uint16; + m_uint16 = tmp; +} +void SAL_CALL OComponent::testinout_methodLong(sal_Int32& rOut) throw( RuntimeException ) +{ + sal_Int32 tmp = rOut; + rOut = m_int32; + m_int32 = tmp; +} +void SAL_CALL OComponent::testinout_methodULong(sal_uInt32& rOut) throw( RuntimeException ) +{ + sal_uInt32 tmp = rOut; + rOut = m_uint32; + m_uint32 = tmp; +} +void SAL_CALL OComponent::testinout_methodHyper(sal_Int64& rOut) throw( RuntimeException ) +{ + sal_Int64 tmp = rOut; + rOut = m_int64; + m_int64 = tmp; +} + +void SAL_CALL OComponent::testinout_methodUHyper(sal_uInt64& rOut) throw( RuntimeException ) +{ + sal_uInt64 tmp = rOut; + rOut = m_uint64; + m_uint64 = tmp; +} + +void SAL_CALL OComponent::testinout_methodString(OUString& rOut) throw( RuntimeException ) +{ + OUString tmp = rOut; + rOut = m_string; + m_string = tmp; +} +void SAL_CALL OComponent::testinout_methodChar(sal_Unicode& rOut) throw( RuntimeException) +{ + sal_Unicode tmp = rOut; + rOut = m_char; + m_char = tmp; +} +void SAL_CALL OComponent::testinout_methodAny(Any& rOut) throw( RuntimeException) +{ + Any tmp = rOut; + rOut = m_any; + m_any = tmp; +} +void SAL_CALL OComponent::testinout_methodType(Type& rOut) throw( RuntimeException) +{ + Type tmp = rOut; + rOut = m_type; + m_type = tmp; +} + + +void SAL_CALL OComponent::testinout_methodSequence(Sequence< sal_Int32 >& rOut) throw( RuntimeException) +{ + + sal_Int32* arr= rOut.getArray(); + for ( sal_Int32 i=0; i < rOut.getLength(); i++) + { + rOut.getArray()[i] += 1; + } +} +void SAL_CALL OComponent::testinout_methodSequence2(Sequence< Sequence< sal_Int32 > >& rOut) throw( RuntimeException ) +{ + for( sal_Int32 i=0; i < rOut.getLength(); i++) + { + Sequence< sal_Int32 >& seq= rOut.getArray()[i]; + + for ( sal_Int32 j=0; j < seq.getLength(); j++) + { + seq.getArray()[j] += seq.getArray()[j]; + } + } +} + +// The parameter should implement XInvocation and a Property "value" +void SAL_CALL OComponent::testinout_methodXInterface( Reference< XInvocation >& rOut ) throw(RuntimeException) +{ + Any any; + any= rOut->getValue( OUString( L"value")); + OUString _s; + any >>= _s; + OUString string(L"out"); + any <<= string; + rOut->setValue( OUString(L"value"), any); + + any= rOut->getValue( OUString( L"value")); + any >>= _s; + +} + +void SAL_CALL OComponent::testinout_methodXInterface2( Reference< XInterface > & rOut) throw( RuntimeException) +{ + Reference tmp = rOut; + rOut = m_xinterface; + m_xinterface = tmp; +} +Any SAL_CALL OComponent::methodAnyTest1(const Any& rIn) throw( RuntimeException ) +{ + return rIn; +} +Any SAL_CALL OComponent::getAttrAny2() throw( RuntimeException ) +{ + return m_any; +} +void SAL_CALL OComponent::setAttrAny2(const Any& AttrAny2_) throw( RuntimeException ) +{ + m_any= AttrAny2_; +} + + +// XTestStruct ======================================================================================= + +void SAL_CALL OComponent::methodStruct(const Property& aProp) throw( RuntimeException ) +{ + char buff[1024]; + buff[0]= 0; + sprintf( buff,"Property::Attribute : %d \n Property::Handle : %d \n Property::Name : %S", + aProp.Attributes, aProp.Handle, (const sal_Unicode*)aProp.Name); + MessageBox( NULL, A2T(buff), _T("OleTest: methodStruct"), MB_OK); +} + +Property SAL_CALL OComponent::retMethodStruct() throw( RuntimeException ) +{ + Property a(L"OleTest_Property", 255, cppu::UnoType::get(), PropertyAttribute::MAYBEVOID | + PropertyAttribute::BOUND | PropertyAttribute::CONSTRAINED | + PropertyAttribute::TRANSIENT | PropertyAttribute::READONLY | + PropertyAttribute::MAYBEAMBIGUOUS | PropertyAttribute::MAYBEDEFAULT ); + return a; +} + +Property SAL_CALL OComponent::getAttrStruct() throw( RuntimeException) +{ + Property a(L"OleTest_Property", 255, cppu::UnoType::get(), PropertyAttribute::MAYBEVOID | + PropertyAttribute::BOUND | PropertyAttribute::CONSTRAINED | + PropertyAttribute::TRANSIENT | PropertyAttribute::READONLY | + PropertyAttribute::MAYBEAMBIGUOUS | PropertyAttribute::MAYBEDEFAULT ); + return a; + +} + +void SAL_CALL OComponent::setAttrStruct(const Property& AttrStruct_) throw( RuntimeException ) +{ + char buff[1024]; + buff[0]= 0; + sprintf( buff,"Property::Attribute : %d \n Property::Handle : %d \n Property::Name : %S", + AttrStruct_.Attributes, AttrStruct_.Handle, (const sal_Unicode*)AttrStruct_.Name); +// MessageBox( NULL, A2T(buff), _T("OleTest: setAttrStruct"), MB_OK); +} + +Property SAL_CALL OComponent::methodStruct2( const Property& aProp ) throw (RuntimeException) +{ + return aProp; +} + +// XTestOther ================================================================================== +void SAL_CALL OComponent::other_methodAnyIn(const Any& ) throw( RuntimeException ) +{ +} +void SAL_CALL OComponent::other_methodAnyOut(Any& rAny) throw( RuntimeException ) +{ + rAny <<= OUString(L"Ein Any"); +} + +Any SAL_CALL OComponent::other_methodAnyRet() throw(RuntimeException ) +{ + Any a; + a <<= OUString(L"Ein Any"); + return a; +} +void SAL_CALL OComponent::in_float( float val) throw ( RuntimeException) +{ + USES_CONVERSION; + char buff[256]; + sprintf( buff, "parameter : %f", val); + MessageBox( NULL, A2T(buff), _T("OleTest"), MB_OK); +} +Any SAL_CALL OComponent::other_methodAny( const Any& rAny, const OUString& typeInAny ) + throw (RuntimeException) +{ + Type expectedType; + typelib_TypeDescription * pDesc= NULL; + typelib_typedescription_getByName( &pDesc, typeInAny.pData ); + if( pDesc) + { + expectedType = Type( pDesc->pWeakRef ); + typelib_typedescription_release( pDesc); + } + if (rAny.getValueType() != expectedType) + throw RuntimeException(); + + return rAny; +} + +// XTestInterfaces ------------------------------------------------------------------------------------- +void SAL_CALL OComponent::testInterface( const Reference< XCallback >& xCallback, sal_Int32 mode ) throw(RuntimeException) +{ + USES_CONVERSION; + sal_Int32 i=0; + OUString aString; + char buff[1024]; + + Reference xSimple; + SimpleStruct aSimpleStruct; + SimpleEnum aSimpleEnum; + Sequence seqAny; + Sequence< sal_Int8 > seqByte; + Any outAny; + sal_Bool aBool; + sal_Unicode aChar; + float aFloat; + double aDouble; + sal_Int8 aByte; + sal_Int16 aShort; + sal_Int32 aLong; + + switch( mode) + { + case 1: + xCallback->func1(); break; + case 2: + xSimple= xCallback->returnInterface(); + xSimple->func(L"XCallback::returnInterface"); + break; + + + case 3: + xCallback->outInterface( xSimple); + sprintf( buff, "XCallback::outInterface, value: %x", xSimple.get()); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + xSimple->func(L"XCallback::outInterface works"); + break; + case 4: + xCallback->outStruct( aSimpleStruct); + sprintf( buff,"XCallback::outStruct, SimpleStruct::message: %s", OLE2A( aSimpleStruct.message)); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 5: + xCallback->outEnum( aSimpleEnum); + sprintf( buff,"XCallback::outEnum, SimpleEnum: %d", aSimpleEnum); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 6: + xCallback->outSeqAny( seqAny); + sprintf( buff,"XCallback::outSeqAny, length: %d )", seqAny.getLength()); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + for( i=0; i < seqAny.getLength(); i++) + { + Any any= seqAny[i]; + if( any.getValueTypeClass() == TypeClass_STRING) + { + any >>= aString; + OutputDebugStringW( aString); + } + + } + break; + case 7: + xCallback->outAny( outAny); + if( outAny.getValueTypeClass() == TypeClass_STRING) + outAny >>= aString; + sprintf( buff,"XCallback::outAny, Any : %s", W2A( aString)); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 8: + xCallback->outBool( aBool); + sprintf( buff,"XCallback::outBool, value: %d", aBool); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 9: + xCallback->outChar( aChar); + sprintf( buff,"XCallback::outChar, value: %C", aChar); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 10: + xCallback->outString( aString); + sprintf( buff,"XCallback::outString, value: %s", W2A( aString)); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 11: + xCallback->outFloat( aFloat); + sprintf( buff,"XCallback::outFloat, value: %f", aFloat); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 12: + xCallback->outDouble( aDouble); + sprintf( buff,"XCallback::outDouble, value: %f", aDouble); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 13: + xCallback->outByte( aByte); + sprintf( buff,"XCallback::outByte, value: %d", aByte); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 14: + xCallback->outShort( aShort); + sprintf( buff,"XCallback::outShort, value: %d", aShort); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 15: + xCallback->outLong( aLong); + sprintf( buff,"XCallback::outLong, value: %d", aLong); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + break; + case 18: + case 19: + case 30: + { + + long outLong= 0; + xCallback->outValuesMixed( 1111, outLong, OUString( L"in string") ); + + sprintf( buff, "oletest.testInterface: outValue: %d", outLong); + MessageBox( NULL, A2T(buff), _T("OleTest"), MB_OK); + break; + } + + case 31: + { + Reference< XSimple > xSimple; + SimpleStruct aSimpleStruct; + SimpleEnum aSimpleEnum; + Sequence seqAny; + Any aAny; + sal_Bool aBool; + sal_Unicode aChar; + OUString aString; + float aFloat; + double aDouble; + sal_Int8 aByte; + sal_Int16 aShort; + sal_Int32 aLong; + xCallback->outValuesAll( xSimple, aSimpleStruct, aSimpleEnum, seqAny, aAny, aBool, + aChar, aString, + aFloat, aDouble, + aByte, + aShort, aLong); + + MessageBox( NULL, _T("XCallback::outValuesAll returned"), _T("OleTest::testInterface"), MB_OK); + break; + } + case 32: + { + + xCallback->outSeqByte( seqByte); + sprintf( buff,"XCallback::outSeqAny, length: %d )", seqAny.getLength()); + MessageBox( NULL, A2T(buff), _T("OleTest out parameter"), MB_OK); + for( i=0; i < seqAny.getLength(); i++) + { + Any any= seqAny[i]; + if( any.getValueTypeClass() == TypeClass_STRING) + { + any >>= aString; + OutputDebugStringW( aString); + } + } + break; + } + // ############################################################################ + // IN OUT parameter + // ############################################################################ + case 100: + { + Reference xSimple= static_cast(this); + xCallback->inoutInterface( xSimple); + xSimple->func(L"XSimple called from OleTest"); + break; + } + case 101: + { + Reference xRefl( theCoreReflection::get(comphelper::getComponentContext(m_rFactory)) ); + Reference xClass= xRefl->forName(L"oletest.SimpleStruct"); + Any any; + if( xClass.is()) + xClass->createObject( any); + + if( any.getValueTypeClass() == TypeClass_STRUCT) + { + SimpleStruct* pStruct= ( SimpleStruct*) any.getValue(); + pStruct->message= "This struct was created in OleTest"; + + SimpleStruct aStruct; + any >>= aStruct; + xCallback->inoutStruct( aStruct); + // a Struct should now contain a different message + MessageBox( NULL, W2T(aStruct.message), _T("OleTest in out parameter"), MB_OK); + } + + break; + } + case 102: + { + SimpleEnum aEnum= SimpleEnum_B; + xCallback->inoutEnum( aEnum); + char buff[1024]; + sprintf( buff, "Enum: %d", aEnum); + MessageBox( NULL, A2T(buff), _T("OleTest in out parameter"), MB_OK); + break; + } + case 103: + { + Any arAny[3]; + arAny[0] <<= OUString( L"string 0"); + arAny[1] <<= OUString( L"string 1"); + arAny[2] <<= OUString( L"string 2"); + + Sequence< Any >seqAny( arAny, 3); + xCallback->inoutSeqAny( seqAny); + char buff[1023]; + sprintf( buff, "Sequence length: %d", seqAny.getLength()); + MessageBox( NULL,A2T(buff) , _T("OleTest in out parameter"), MB_OK); + + for( int i=0; i < seqAny.getLength(); i++) + { + Any any; + any <<= seqAny[i]; + if(any.getValueTypeClass() == TypeClass_STRING) + { + OUString str; + any >>= str; + + } + } + + break; + } + case 104: + { + Any any; + OUString s(L" OleTest"); + any <<= s; + xCallback->inoutAny(any); + if( any.getValueTypeClass() == TypeClass_STRING) + { + OUString s= *( rtl_uString**) any.getValue(); + MessageBox( NULL, W2T( s), _T("OleTest: inout value any"), MB_OK); + } + break; + } + case 105: + { + sal_Bool b= sal_True; + xCallback->inoutBool( b); + char buff[1024]; + sprintf( buff, "out value bool: %d", b); + MessageBox( NULL, A2T( buff), _T("OleTest in out parameter"), MB_OK); + break; + } + case 106: + { + sal_Unicode uc= L'A'; + xCallback->inoutChar( uc); + char buff[1024]; + sprintf( buff, "out value sal_Unicode: %C", uc); + MessageBox( NULL, A2T( buff), _T("OleTest in out parameter"), MB_OK); + break; + } + case 107: + { + OUString s(L"OleTest"); + xCallback->inoutString( s); + char buff[1024]; + sprintf( buff, "out value string: %S", s.getStr()); + MessageBox( NULL, A2T( buff), _T("OleTest in out parameter"), MB_OK); + break; + } + case 108: + { + float f= 3.14f; + xCallback->inoutFloat(f); + char buff[1024]; + sprintf( buff, "out value float: %f", f); + MessageBox( NULL, A2T( buff), _T("OleTest in out parameter"), MB_OK); + break; + } + case 109: + { + double f= 3.145; + xCallback->inoutDouble( f); + char buff[1024]; + sprintf( buff, "out value double: %g", f); + MessageBox( NULL, A2T( buff), _T("OleTest in out parameter"), MB_OK); + break; + } + case 110: + { + sal_Int8 aByte= 0xf; + xCallback->inoutByte( aByte); + char buff[1024]; + sprintf( buff, "out value sal_Int8: %d", aByte); + MessageBox( NULL, A2T( buff), _T("OleTest in out parameter"), MB_OK); + break; + } + case 111: + { + sal_Int16 aShort= 0xff; + xCallback->inoutShort( aShort); + char buff[1024]; + sprintf( buff, "out value sal_Int16: %d", aShort); + MessageBox( NULL, A2T( buff), _T("OleTest in out parameter"), MB_OK); + break; + } + case 112: + { + sal_Int32 aLong= 0xfffe; + xCallback->inoutLong( aLong); + char buff[1024]; + sprintf( buff, "out value sal_Int32: %d", aLong); + MessageBox( NULL, A2T( buff), _T("OleTest in out parameter"), MB_OK); + break; + } + case 120: + { + Reference aXSimple= static_cast(this); + + SimpleStruct aStruct; + Reference xRefl( m_rFactory->createInstance(L"com.sun.star.reflection.CoreReflection"), UNO_QUERY); + if( xRefl.is()) + { + Reference xClass= xRefl->forName(L"oletest.SimpleStruct"); + Any any; + if( xClass.is()) + xClass->createObject( any); + + if( any.getValueTypeClass() == TypeClass_STRUCT) + { + SimpleStruct* pStruct= ( SimpleStruct*) any.getValue(); + pStruct->message= "This struct was created in OleTest"; + any >>= aStruct; + } + } + + SimpleEnum aEnum= SimpleEnum_B; + + Sequence< Any > aSeq; + Any arAny[3]; + arAny[0] <<= OUString( L"string 0"); + arAny[1] <<= OUString( L"string 1"); + arAny[2] <<= OUString( L"string 2"); + aSeq = Sequence< Any >( arAny, 3); + + Any aAny; + OUString s(L" OleTest"); + aAny <<= s; + + sal_Bool aBool= sal_True; + sal_Unicode aChar= L'A'; + OUString aString( L"OleTest"); + float aFloat=3.14f; + double aDouble= 3.145; + sal_Int8 aByte= 0xf; + sal_Int16 aShort= 0xff; + sal_Int32 aLong= 0xffe; + + xCallback->inoutValuesAll( aXSimple, aStruct, aEnum, aSeq, + aAny, aBool, aChar, aString, aFloat, aDouble, + aByte, aShort, aLong ); + + aXSimple->func(L"XSimple called from OleTest"); + MessageBox( NULL, W2T(aStruct.message), _T("OleTest"), MB_OK); + + for( int i=0; i < aSeq.getLength(); i++) + { + Any any; + any <<= aSeq[i]; + if(any.getValueTypeClass() == TypeClass_STRING) + { + OUString str; + any >>= str; + + } + } + break; + } + + // ############################################################################ + // IN parameter + // ############################################################################ + + case 200: + + xCallback->inValues( L'a', 0xffffL, OUString(L" a string from OleTest")); + break; + case 201: + { + sal_Int8 arbyte[3]= { 1,2,3}; + Sequence< sal_Int8 > seq( arbyte, 3); + xCallback->inSeqByte( seq); + break; + } + case 202: + { + const int LISTENERS= 3; + Reference arListeners[LISTENERS]; + EventObject arEvents[LISTENERS]; + + for( int i= 0; i < LISTENERS; i++) + { + Reference aList= static_cast( new EventListener()); + arListeners[i].set( aList, UNO_QUERY); + } + + xCallback->inSeqXEventListener(Sequence > (arListeners, LISTENERS), + Sequence(arEvents, LISTENERS)); + break; + } + + // ############################################################################ + // Call a COM object that has not been passed as parameter to a UNO component and + // hence no type information is available in the COM wrapper + // ############################################################################ + case 300: + { + Reference xIntFact = m_rFactory->createInstance(L"com.sun.star.bridge.oleautomation.Factory"); + + Reference oleFact(xIntFact, UNO_QUERY); + + Reference xIntCallback= oleFact->createInstance(L"XCallback_Impl.Callback"); + Reference xInv( xIntCallback, UNO_QUERY); + Sequence seqIndices; + Sequence seqOutParams; + xInv->invoke( OUString( L"outValuesAll"), Sequence(), seqIndices, seqOutParams); + + if( seqOutParams.getLength() == 12) + { + Reference xSimple= *(XSimple**)seqOutParams[0].getValue(); + xSimple->func( L"Call from OleTest on XSimple"); + SimpleStruct aStruct; + seqOutParams[1] >>= aStruct; + SimpleEnum aEnum= *(SimpleEnum*)seqOutParams[2].getValue(); + + Sequence seqAny; + seqOutParams[3] >>= seqAny; + for( int i=0; i>= _s; + } + + Any _any= *(Any*)seqOutParams[4].getValue(); + sal_Bool _bool= *(sal_Bool*)seqOutParams[5].getValue(); + sal_Unicode _char= *( sal_Unicode*) seqOutParams[6].getValue(); + OUString _str= *( rtl_uString**)seqOutParams[7].getValue(); + + float _f= *( float*)seqOutParams[8].getValue(); + double _d= *( double*) seqOutParams[9].getValue(); + sal_Int8 _byte= *( sal_Int8*) seqOutParams[10].getValue(); + sal_Int16 _short= *( sal_Int16*) seqOutParams[11].getValue(); + + sal_Int32 _long= *( sal_Int32*) seqOutParams[12].getValue(); + + } + break; + } + case 301: + // in / out parameter + { + Reference xIntFact = m_rFactory->createInstance(L"com.sun.star.bridge.oleautomation.Factory"); + + Reference oleFact(xIntFact, UNO_QUERY); + + Reference xIntCallback= oleFact->createInstance(L"XCallback_Impl.Callback"); + Reference xInv( xIntCallback, UNO_QUERY); + Sequence seqIndices; + Sequence seqOutParams; + + + Any arAny[13]; + Reference xSimple= static_cast( this); + + arAny[0] <<= xSimple; + SimpleStruct aStruct; + Reference xRefl( m_rFactory->createInstance(L"com.sun.star.reflection.CoreReflection"), UNO_QUERY); + if( xRefl.is()) + { + Reference xClass= xRefl->forName(L"oletest.SimpleStruct"); + Any any; + if( xClass.is()) + xClass->createObject( any); + + if( any.getValueTypeClass() == TypeClass_STRUCT) + { + SimpleStruct* pStruct= ( SimpleStruct*) any.getValue(); + pStruct->message = "This struct was created in OleTest"; + any >>= aStruct; + } + } + arAny[1] <<= aStruct; + arAny[2] <<= SimpleEnum_C; + + Any arSeqAny[3]; + arSeqAny[0] <<= OUString( L"string 0"); + arSeqAny[1] <<= OUString( L"string 1"); + arSeqAny[2] <<= OUString( L"string 2"); + + arAny[3] <<= Sequence< Any >( arAny, 3); + + OUString str(L" Ein Any param"); + arAny[4] <<= str; + arAny[5] <<= sal_False; + arAny[6] <<= L'B'; + OUString stringParam(L" a string parameter"); + arAny[7] <<= stringParam; + float _float= 3.14f; + arAny[8] <<= _float; + double _double= 3.145; + arAny[9] <<= _double; + sal_Int8 _byte= -1; + arAny[10] <<= _byte; + sal_Int16 _short= -1; + arAny[11] <<= _short; + sal_Int32 _long= -1; + arAny[12] <<= _long; + + Sequence params( arAny, 13); + + xInv->invoke( OUString( L"inoutValuesAll"), params, seqIndices, seqOutParams); + + if( seqOutParams.getLength() == 12) + { + Reference xSimple= *(XSimple**)seqOutParams[0].getValue(); + xSimple->func( L"Call from OleTest on XSimple"); + SimpleStruct aStruct; + seqOutParams[1] >>= aStruct; + SimpleEnum aEnum= *(SimpleEnum*)seqOutParams[2].getValue(); + + Sequence seqAny; + seqOutParams[3] >>= seqAny; + for( int i=0; i>= _s; + } + + Any _any= *(Any*)seqOutParams[4].getValue(); + sal_Bool _bool= *(sal_Bool*)seqOutParams[5].getValue(); + sal_Unicode _char= *( sal_Unicode*) seqOutParams[6].getValue(); + OUString _str= *( rtl_uString**)seqOutParams[7].getValue(); + + float _f= *( float*)seqOutParams[8].getValue(); + double _d= *( double*) seqOutParams[9].getValue(); + sal_Int8 _byte= *( sal_Int8*) seqOutParams[10].getValue(); + sal_Int16 _short= *( sal_Int16*) seqOutParams[11].getValue(); + + sal_Int32 _long= *( sal_Int32*) seqOutParams[12].getValue(); + + } + break; + } + case 303: + { + Reference xIntFact = m_rFactory->createInstance( + L"com.sun.star.bridge.oleautomation.Factory"); + + Reference oleFact(xIntFact, UNO_QUERY); + + Reference xIntCallback= oleFact->createInstance(L"XCallback_Impl.Callback"); + Reference xInv( xIntCallback, UNO_QUERY); + Sequence seqIndices; + Sequence seqOutParams; + + Any arAny[3]; + sal_Unicode aChar=L'a'; + arAny[0] <<= aChar; + sal_Int32 aLong= 0xffffffff; + arAny[1] <<= aLong; + OUString aString(L" a string parameter"); + arAny[2] <<= aString; + + xInv->invoke( OUString( L"inValues"), Sequence(arAny,3), seqIndices, seqOutParams); + + break; + } + // ############################################################################ + // Attributes + // ############################################################################ + + case 400: + Reference simple= xCallback->getsimple(); + simple->func(L"OleTest calls on XSimple"); + break; + + + } + +} + +void SAL_CALL OComponent::setObject( const Reference< XInterface >& val ) throw (RuntimeException) +{ + m_xIntIdentity= val; +} + +sal_Bool SAL_CALL OComponent::isSame( const Reference< XInterface >& val ) throw (RuntimeException) +{ + if( m_xIntIdentity == val) + return sal_True; + else + return sal_False; +} + +Reference< XInterface > SAL_CALL OComponent::getThis( ) throw (RuntimeException) +{ + Reference ret(static_cast(this), UNO_QUERY); + return ret; +} + +void SAL_CALL EventListener::disposing( const css::lang::EventObject& ) throw (RuntimeException) +{ + bCalled= sal_True; +} + +// XSimple -------------------------------------------------------------------------- +void SAL_CALL OComponent::func( const OUString &message)throw(css::uno::RuntimeException) +{ + USES_CONVERSION; + + MessageBox( NULL, W2T( message.getStr()), _T("OleTest: XSimple::func"), MB_OK); +} +// XSimple -------------------------------------------------------------------------- +OUString SAL_CALL OComponent::getName()throw(css::uno::RuntimeException) +{ + return L"XSimple"; +} +void SAL_CALL OComponent::testInterface2( const Reference< XSimple >& xSimple, sal_Int32 mode ) throw(RuntimeException) +{ + switch( mode) + { + case 0: + { + xSimple->func( L"OleTest is calling XSimple"); + Reference xSimple2( xSimple, UNO_QUERY); + if( xSimple2.is()) + xSimple2->func2( L"OleTest is calling XSimple2"); + Reference xSimple3( xSimple, UNO_QUERY); + if( xSimple3.is()) + xSimple3->func3( L"OleTest is calling XSimple3"); + + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/cpnt/exports.dxp b/extensions/test/ole/cpnt/exports.dxp new file mode 100644 index 000000000..51703a046 --- /dev/null +++ b/extensions/test/ole/cpnt/exports.dxp @@ -0,0 +1,2 @@ +component_writeInfo +component_getFactory diff --git a/extensions/test/ole/cpnt/makefile.mk b/extensions/test/ole/cpnt/makefile.mk new file mode 100644 index 000000000..ad9d07bac --- /dev/null +++ b/extensions/test/ole/cpnt/makefile.mk @@ -0,0 +1,66 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# +PRJ=..$/..$/.. + +PRJNAME= extensions +TARGET= oletest +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- Files -------------------------------------------------------- + +INCPRE+= -I$(ATL_INCLUDE) + +SLOFILES= \ + $(SLO)$/cpnt.obj + +SHL1TARGET= $(TARGET) + +SHL1STDLIBS= \ + $(SALLIB) \ + $(CPPULIB) \ + $(CPPUHELPERLIB) + +SHL1DEPN= +SHL1IMPLIB= i$(TARGET) +SHL1LIBS= $(SLB)$/$(TARGET).lib +SHL1DEF= $(MISC)$/$(SHL1TARGET).def + +DEF1NAME= $(SHL1TARGET) +DEF1EXPORTFILE= exports.dxp + + +ALLTAR : $(MISC)$/$(TARGET).cppumaker.done + + +.INCLUDE : target.mk + +ALLIDLFILES:= ..$/idl$/oletest.idl + +$(BIN)$/oletest.rdb: $(ALLIDLFILES) + idlc -I$(PRJ) -I$(SOLARIDLDIR) -O$(BIN) $? + regmerge $@ /UCR $(BIN)$/{$(?:f:s/.idl/.urd/)} + touch $@ + +$(MISC)$/$(TARGET).cppumaker.done: $(BIN)$/oletest.rdb + $(CPPUMAKER) -O$(INCCOM) -BUCR $< -X$(SOLARBINDIR)/types.rdb + $(TOUCH) $@ + diff --git a/extensions/test/ole/cpnt/readme.txt b/extensions/test/ole/cpnt/readme.txt new file mode 100644 index 000000000..ccac8066a --- /dev/null +++ b/extensions/test/ole/cpnt/readme.txt @@ -0,0 +1,21 @@ +cpnt.cxx contains a UNO component that is uses to test the olebridge within a +JavaScript context. In particular it has functions using out, in/out and +sequence parameter that have to be specifically treated in JScript because they +are represented by IDispatch objects. Other clients, such as VBScript, VB and +C++ applications can also use this component for testing. +The service name is oletest.OleTest. +The uno types are also build in this folder. The idl file is in ..\idl. The +types rdb is in wntmscixx.pro\bin\oletest.rdb + +The service is used by: +OleTest.htm +JScriptNewStyle.htm +ScriptTest.html + + +Prerequisites: + +The oletest.dll must be registered, for example in the services.rdb, using +regcomp. Then the uno types contained in oletest.rdb (wntmscixx/bin) must be merged +for example in the offapi.rdb. This is done with regmerge. + diff --git a/extensions/test/ole/cppToUno/makefile.mk b/extensions/test/ole/cppToUno/makefile.mk new file mode 100644 index 000000000..e40aa94f3 --- /dev/null +++ b/extensions/test/ole/cppToUno/makefile.mk @@ -0,0 +1,56 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +PRJ=..$/..$/.. + +PRJNAME=extensions +TARGET=testcppuno +TARGETTYPE=CUI +LIBTARGET=NO + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings --- + +.INCLUDE : settings.mk + +# --- Files --- + +INCPRE+=-I$(ATL_INCLUDE) + + + +APP1TARGET= $(TARGET) +APP1OBJS= $(OBJ)$/testcppuno.obj + +APP1STDLIBS= \ + $(SALLIB) \ + $(CPPUHELPERLIB) \ + $(CPPULIB) \ + $(USER32LIB) \ + $(KERNEL32LIB) \ + $(OLE32LIB) \ + $(OLEAUT32LIB) \ + $(UUIDLIB) \ + $(COMDLG32LIB) \ + $(GDI32LIB) + +APP1DEF= $(MISC)$/$(APP1TARGET).def + +# --- Targets --- +.INCLUDE : target.mk diff --git a/extensions/test/ole/cppToUno/readme.txt b/extensions/test/ole/cppToUno/readme.txt new file mode 100644 index 000000000..ae0189818 --- /dev/null +++ b/extensions/test/ole/cppToUno/readme.txt @@ -0,0 +1,8 @@ +testcppuno.exe currently tests the conversion of SAFEARRAYs. There is +no output from the program. Just step through the code. + +To run the test, the service oletest.OleTest ( extensions/test/ole/cpnt) +must be in the same directory as the office dlls and it must be registered +at the applicat.rdb. Also the type information must have been merged with +applicat.rdb. The program requires an office to be present. Put testcppuno +into the Office/program folder and run it there. diff --git a/extensions/test/ole/cppToUno/testcppuno.cxx b/extensions/test/ole/cppToUno/testcppuno.cxx new file mode 100644 index 000000000..e64541ed2 --- /dev/null +++ b/extensions/test/ole/cppToUno/testcppuno.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 . + */ + + +#pragma warning(disable: 4917) +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::bridge; +using namespace com::sun::star::bridge::ModelDependent; +using namespace cppu; + +HRESULT doTest(); +bool incrementMultidimensionalIndex( + sal_Int32 dimensions, + const sal_Int32 * parDimensionLengths, + sal_Int32 * parMultidimensionalIndex); + +int SAL_CALL main( int /*argc*/, char** /*argv*/ ) +{ + HRESULT hr; + if( FAILED( hr=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) + { + printf("CoInitializeEx failed \n"); + return -1; + } + + + if( FAILED(hr=doTest())) + { + _com_error err( hr); + const CHAR * errMsg= err.ErrorMessage(); + MessageBoxA( NULL, errMsg, "Test failed", MB_ICONERROR); + } + + CoUninitialize(); + return 0; +} + + +HRESULT doTest() +{ + HRESULT hr= S_OK; + long j = 0; + SAFEARRAY* par; + CComDispatchDriver disp; + CComVariant result; + CComVariant param1; + CComPtr spUnkFactory; + if( SUCCEEDED( spUnkFactory.CoCreateInstance(L"com.sun.star.ServiceManager"))) + { + disp= spUnkFactory; + param1= L"oletest.OleTest"; + disp.Invoke1( L"createInstance", ¶m1, &result); + + disp= result.pdispVal; + + // disp contains now oletest.OleTest + + // one dimensional array + par= SafeArrayCreateVector( VT_UI1, 0, 5); + unsigned char arbyte[]= { 1,2,3,4,5}; + for(long i= 0; i < 5;i++) + hr= SafeArrayPutElement( par, &i, &arbyte[i]); + + result.Clear(); + param1.vt= VT_ARRAY| VT_UI1; + param1.byref= par; + disp.Invoke1(L"methodByte", ¶m1, &result); + SafeArrayDestroy( par); + + + // two dimensional array + SAFEARRAYBOUND bounds[2]; + // least significant dimension first, Dimension 1 + bounds[0].cElements= 3; + bounds[0].lLbound= 0; + // Dimension 2 + bounds[1].cElements= 2; + bounds[1].lLbound= 0; + par= SafeArrayCreate( VT_I4, 2, bounds ); + + long uBound1; + long uBound2; + hr= SafeArrayGetUBound( par, 1, &uBound1); + hr= SafeArrayGetUBound( par, 2, &uBound2); + + long index2[2]; + memset( index2, 0, 2 * sizeof( long) ); + long dimLengths[]={3,2}; + + long data; + do + { + data= index2[1] * 3 + index2[0] +1; + hr= SafeArrayPutElement( par, index2, &data); + }while( incrementMultidimensionalIndex( 2, dimLengths, index2) ); + + long* pdata; + long (*dataL)[2][3]; + hr= SafeArrayAccessData( par, (void**)&pdata); + dataL= (long(*)[2][3])pdata; + + for (long i= 0; i < 2; i ++) + { + for(long j= 0; j < 3; j++) + data= (*dataL)[i][j]; + } + hr= SafeArrayUnaccessData(par); + + result.Clear(); + param1.vt= VT_ARRAY | VT_I4; + param1.byref= par; + disp.Invoke1(L"methodSequence", ¶m1, &result); + + SAFEARRAY* arRet= result.parray; + + for(long i= 0; i < 2 ; i++) + { + CComVariant varx; + varx.Clear(); + hr= SafeArrayGetElement( arRet, &i, &varx); + SAFEARRAY* ari= varx.parray; + + for( j= 0; j < 3; j++) + { + CComVariant varj; + varj.Clear(); + hr= SafeArrayGetElement( ari, &j, &varj); + } + + + } + SafeArrayDestroy( par); + } + + return hr; +} + +// left index is least significant +bool incrementMultidimensionalIndex( + sal_Int32 dimensions, + const sal_Int32 * parDimensionLengths, + sal_Int32 * parMultidimensionalIndex) +{ + if( dimensions < 1) + return sal_False; + + bool ret= sal_True; + bool carry= sal_True; // to get into the while loop + + sal_Int32 currentDimension= 0; //most significant is 1 + while( carry) + { + parMultidimensionalIndex[ currentDimension ]++; + // if carryover, set index to 0 and handle carry on a level above + if( parMultidimensionalIndex[ currentDimension] > (parDimensionLengths[ currentDimension] - 1)) + parMultidimensionalIndex[ currentDimension]= 0; + else + carry= sal_False; + + currentDimension ++; + // if dimensions drops below 1 and carry is set than then all indices are 0 again + // this is signalled by returning sal_False + if( currentDimension > dimensions - 1 && carry) + { + carry= sal_False; + ret= sal_False; + } + } + return ret; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/cpptest/cpptest.cxx b/extensions/test/ole/cpptest/cpptest.cxx new file mode 100644 index 000000000..ff083a052 --- /dev/null +++ b/extensions/test/ole/cpptest/cpptest.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 . + */ + +// cpptest.cpp : Defines the entry point for the console application. + +#ifdef _MSC_VER +#pragma once +#endif +#pragma warning(disable : 4917) +#include +#include +#include + +HRESULT doTest(); + +int main(int /*argc*/, char** /*argv*/) +{ + HRESULT hr; + if (FAILED(hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) + { + printf("CoInitializeEx failed \n"); + return -1; + } + + if (FAILED(hr = doTest())) + { + _com_error err(hr); + const CHAR* errMsg = err.ErrorMessage(); + MessageBoxA(NULL, errMsg, "Test failed", MB_ICONERROR); + } + + CoUninitialize(); + return 0; +} + +HRESULT doTest() +{ + HRESULT hr; + CComPtr spUnkMgr; + + if (FAILED(hr = spUnkMgr.CoCreateInstance(L"com.sun.star.ServiceManager"))) + return hr; + + IDispatchPtr starManager; + // var starManager=new ActiveXObject("com.sun.star.ServiceManager"); + if (FAILED(hr = starManager.CreateInstance(_T("com.sun.star.ServiceManager")))) + { + fprintf(stderr, "creating ServiceManager failed\n"); + return hr; + } + // var starDesktop=starManager.createInstance("com.sun.star.frame.Desktop"); + _variant_t varP1(L"com.sun.star.frame.Desktop"); + _variant_t varRet; + CComDispatchDriver dispMgr(starManager); + if (FAILED(hr = dispMgr.Invoke1(L"createInstance", &varP1, &varRet))) + { + fprintf(stderr, "createInstance of Desktop failed\n"); + return hr; + } + CComDispatchDriver dispDesk(varRet.pdispVal); + varP1.Clear(); + varRet.Clear(); + // var bOK=new Boolean(true); + + // var noArgs=new Array(); + // var oDoc=starDesktop.loadComponentFromURL("private:factory/swriter", "Test", 40, noArgs); + IDispatchPtr oDoc; + SAFEARRAY* ar = SafeArrayCreateVector(VT_DISPATCH, 0, 0); + _variant_t args[4]; + args[3] = _variant_t(L"private:factory/swriter"); + args[2] = _variant_t(L"Test"); + args[1] = _variant_t((long)40); + args[0].vt = VT_ARRAY | VT_DISPATCH; + args[0].parray = ar; + if (FAILED(hr = dispDesk.InvokeN(L"loadComponentFromURL", args, 4, &varRet))) + { + fprintf(stderr, "loadComponentFromURL failed\n"); + return hr; + } + CComDispatchDriver dispDoc(varRet.pdispVal); + varRet.Clear(); + return S_OK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/cpptest/makefile.mk b/extensions/test/ole/cpptest/makefile.mk new file mode 100644 index 000000000..984701c15 --- /dev/null +++ b/extensions/test/ole/cpptest/makefile.mk @@ -0,0 +1,55 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +PRJ=..$/..$/.. + +PRJNAME=extensions +TARGET=cppTest +TARGETTYPE=CUI +LIBTARGET=NO + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings --- + +.INCLUDE : settings.mk + +# --- Files --- + +INCPRE+=-I$(ATL_INCLUDE) + + +APP1TARGET= $(TARGET) +APP1OBJS= $(OBJ)$/cppTest.obj + +APP1STDLIBS= \ + $(SALLIB) \ + $(CPPUHELPERLIB) \ + $(CPPULIB) \ + $(USER32LIB) \ + $(KERNEL32LIB) \ + $(OLE32LIB) \ + $(OLEAUT32LIB) \ + $(UUIDLIB) \ + $(COMDLG32LIB) \ + comsupp.lib + +APP1DEF= $(MISC)\$(APP1TARGET).def + +# --- Targets --- +.INCLUDE : target.mk diff --git a/extensions/test/ole/cpptest/readme.txt b/extensions/test/ole/cpptest/readme.txt new file mode 100644 index 000000000..0fd339280 --- /dev/null +++ b/extensions/test/ole/cpptest/readme.txt @@ -0,0 +1,4 @@ +Creates the com.sun.star.ServiceManager with CoCreateInstance in a cpp program. +This little program can be used as starting point for further tests. + +It needs uwinapi.dll, which is in the program folder of OOo (URE\bin in OOo 3.0) diff --git a/extensions/test/ole/idl/oletest.idl b/extensions/test/ole/idl/oletest.idl new file mode 100644 index 000000000..b23f20b21 --- /dev/null +++ b/extensions/test/ole/idl/oletest.idl @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include + + +module oletest +{ + +interface XTestSequence: com::sun::star::uno::XInterface +{ + sequence methodByte( [in] sequence aSeq ); + sequence methodFloat( [in] sequence aSeq); + sequence methodDouble( [in] sequence aSeq); + sequence methodBool( [in] sequence aSeq); + sequence methodShort( [in] sequence aSeq); + sequence methodUShort( [in] sequence aSeq); + sequence methodLong( [in] sequence aSeq); + sequence methodULong( [in] sequence aSeq); + sequence methodString( [in] sequence aSeq); + sequence methodChar( [in] sequence aSeq); + sequence methodAny ( [in] sequence aSeq); + sequence methodType ( [in] sequence aSeq); + sequence methodXInterface ( [in] sequence aSeq); + sequence< sequence > methodSequence( [in] sequence< sequence< long > > aSeq); + sequence< sequence > > methodSequence2( [in] sequence< sequence< sequence > > aSeq); + sequence< com::sun::star::lang::XEventListener > methodXEventListeners( [in] sequence aSeq); + sequence< sequence< com::sun::star::lang::XEventListener > > methodXEventListenersMul( [in] sequence< sequence< com::sun::star::lang::XEventListener> > aSeq); + + [attribute] sequence AttrByte; + [attribute] sequence AttrFloat; + [attribute] sequence AttrDouble; + [attribute] sequence AttrBool; + [attribute] sequence AttrShort; + [attribute] sequence AttrUShort; + [attribute] sequence AttrLong; + [attribute] sequence AttrULong; + [attribute] sequence AttrString; + [attribute] sequence AttrChar; + [attribute] sequence AttrAny; + [attribute] sequence AttrType; + [attribute] sequence< sequence > AttrSequence; + [attribute] sequence< sequence< sequence > > AttrSequence2; + [attribute] sequence< com::sun::star::uno::XInterface > AttrXInterface; + + [attribute] byte AByte; + [attribute] float AFloat; + [attribute] double ADouble; + [attribute] boolean ABool; + [attribute] short AShort; + [attribute] unsigned short AUShort; + [attribute] long ALong; + [attribute] unsigned long AULong; + [attribute] string AString; + [attribute] char AChar; + [attribute] any AAny; + [attribute] type AType; + [attribute] com::sun::star::uno::XInterface AXInterface; + [attribute] com::sun::star::script::XInvocation AXInvocation; + + void testout_methodByte( [out] byte rOut ); + void testout_methodFloat( [out] float rOut); + void testout_methodDouble( [out] double rOut); + void testout_methodBool( [out] boolean rOut); + void testout_methodShort( [out] short rOut); + void testout_methodUShort( [out] unsigned short rOut); + void testout_methodLong( [out] long rOut); + void testout_methodULong( [out] unsigned long rOut); + void testout_methodHyper( [out] hyper rOut); + void testout_methodUHyper( [out] unsigned hyper rOut); + void testout_methodString( [out] string rOut); + void testout_methodChar( [out] char rOut); + void testout_methodAny ( [out] any rOut); + void testout_methodType ( [out] type rOut); + void testout_methodSequence( [out] sequence< long > rOut); + void testout_methodSequence2( [out] sequence < sequence< long > > rOut); + void testout_methodXInterface( [out] com::sun::star::uno::XInterface rOut); + + void testout_methodMulParams1( [out] long rout1, [out] long rout2); + void testout_methodMulParams2( [out] long rout1, [out] long rout2, [out] string rout3); + void testout_methodMulParams3( [in] string sin, [out] string sout); + void testout_methodMulParams4( [in] float in1, [out] float out1, [in] long in2, [out] long out2, [in] long in3); + + void testinout_methodByte( [inout] byte rOut ); + void testinout_methodFloat( [inout] float rOut); + void testinout_methodDouble( [inout] double rOut); + void testinout_methodBool( [inout] boolean rOut); + void testinout_methodShort( [inout] short rOut); + void testinout_methodUShort( [inout] unsigned short rOut); + void testinout_methodLong( [inout] long rOut); + void testinout_methodULong( [inout] unsigned long rOut); + void testinout_methodHyper( [inout] hyper rOut); + void testinout_methodUHyper( [inout] unsigned hyper rOut); + void testinout_methodString( [inout] string rOut); + void testinout_methodChar( [inout] char rOut); + void testinout_methodAny ( [inout] any rOut); + void testinout_methodType ( [inout] type rOut); + void testinout_methodSequence( [inout] sequence< long > rOut); + void testinout_methodSequence2( [inout] sequence < sequence< long > > rOut); + void testinout_methodXInterface( [inout] com::sun::star::script::XInvocation rOut); + void testinout_methodXInterface2( [inout] com::sun::star::uno::XInterface rOut); + + any methodAnyTest1( [in] any rIn); + [attribute] any AttrAny2; + +}; +interface XTestStruct: com::sun::star::uno::XInterface +{ +// Method taking structs as arguments + void methodStruct( [in] com::sun::star::beans::Property aProp); +// Methods returning structs + com::sun::star::beans::Property retMethodStruct(); +// Attributes as structs + [attribute] com::sun::star::beans::Property AttrStruct; + + com::sun::star::beans::Property methodStruct2( [in] com::sun::star::beans::Property aProp); +}; + + +struct SimpleStruct +{ + string message; +}; + +interface XTestInParameters: com::sun::star::uno::XInterface +{ + byte in_methodByte( [in] byte rIn ); + float in_methodFloat( [in] float rIn); + double in_methodDouble( [in] double rIn); + boolean in_methodBool( [in] boolean rIn); + short in_methodShort( [in] short rIn); + unsigned short in_methodUShort( [in] unsigned short rIn); + long in_methodLong( [in] long rIn); + unsigned long in_methodULong( [in] unsigned long rIn); + hyper in_methodHyper( [in] hyper rIn); + unsigned hyper in_methodUHyper( [in] unsigned hyper rIn); + string in_methodString( [in] string rIn); + char in_methodChar( [in] char rIn); + any in_methodAny ( [in] any rIn); + type in_methodType ( [in] type rIn); + com::sun::star::uno::XInterface in_methodXInterface([in] com::sun::star::uno::XInterface rIn); + com::sun::star::script::XInvocation in_methodInvocation( [in] com::sun::star::script::XInvocation inv); + SimpleStruct in_methodStruct( [in] SimpleStruct aStruct); + void in_methodAll( [in] byte b, [in] float f, [in] double d, [in] boolean abool, [in]short sh, + [in] unsigned short us, [in] long l, [in] unsigned long ul, + [in] string s, [in] char c, [in] any a, [in] type t, [in] com::sun::star::script::XInvocation inv); +}; + + +enum SimpleEnum +{ + A, + B, + C +}; + +interface XTestOther: com::sun::star::uno::XInterface +{ + // Any test + void other_methodAnyIn( [in] any rAny); + void other_methodAnyOut( [out] any rAny); + any other_methodAnyRet(); + void in_float( [in] float val); + //typeInAny determines what type must be in rAny. If rAny contains + //a different type then an exception is being thrown + any other_methodAny([in] any rAny, [in] string typeInAny); +}; + + +interface XSimple: com::sun::star::uno::XInterface +{ + void func( [in] string message); + string getName(); +}; + +interface XSimple2: com::sun::star::uno::XInterface +{ + void func2( [in] string message); + string getName2(); +}; + +interface XSimple3: com::sun::star::uno::XInterface +{ + void func3( [in] string message); + string getName3(); +}; + + +interface XCallback: com::sun::star::uno::XInterface +{ + void func1(); + oletest::XSimple returnInterface(); + void outInterface( [out] oletest::XSimple outInterface); + void outStruct( [out] oletest::SimpleStruct outStruct); + void outEnum( [out] oletest::SimpleEnum outEnum); + void outSeqAny( [out] sequence outSeqAny); + void outSeqByte( [out] sequence outVal); + void outAny( [out] any outAny); + void outBool( [out] boolean outBool); + void outChar( [out] char outChar); + void outString( [out] string outString); + void outFloat( [out] float outFloat); + void outDouble( [out] double outDouble); + void outByte( [out] byte outByte); + void outShort( [out] short outShort); + void outLong( [out] long outLong); + void outValuesMixed( [in] long lval, [out] long outval, [in] string sval); + void outValuesAll( [out] oletest::XSimple outInterface, + [out] SimpleStruct outStruct , + [out] SimpleEnum outEnum, + [out] sequence outSeqAny, + [out] any outAny, + [out] boolean outBool, + [out] char outChar, + [out] string outString, + [out] float outFloat, + [out] double outDouble, + [out] byte outByte, + [out] short outShort, + [out] long outLong); +// IN OUT parameters + void inoutInterface( [inout] oletest::XSimple inoutVal); + void inoutStruct( [inout] oletest::SimpleStruct inoutVal); + void inoutEnum( [inout] oletest::SimpleEnum inoutVal); + void inoutSeqAny( [inout] sequence inoutVal); + void inoutAny( [inout] any inoutVal); + void inoutBool( [inout] boolean inoutVal); + void inoutChar( [inout] char inoutVal); + void inoutString( [inout] string inoutVal); + void inoutFloat( [inout] float inoutVal); + void inoutDouble( [inout] double inoutVal); + void inoutByte( [inout] byte inoutVal); + void inoutShort( [inout] short inoutVal); + void inoutLong( [inout] long inoutVal); + + void inoutValuesAll( [inout] oletest::XSimple aXSimple, + [inout] oletest::SimpleStruct aStruct, + [inout] oletest::SimpleEnum aEnum, + [inout] sequence aSeq, + [inout] any aAny, + [inout] boolean aBool, + [inout] char aChar, + [inout] string aString, + [inout] float aFloat, + [inout] double aDouble, + [inout] byte aByte, + [inout] short aShort, + [inout] long aLong); + + // IN parameter + + void inValues( [in] char aChar, [in] long aLong, [in] string aString); + void inSeqByte( [in] sequence val); + void inSeqXEventListener( [in] sequence listener, [in] + sequence events); + + // Attributes + [attribute] oletest::XSimple simple; + + + + +}; + +interface XTestInterfaces: com::sun::star::uno::XInterface +{ + // Any test + void testInterface( [in] oletest::XCallback xCallback, [in] long mode); + void testInterface2( [in] oletest::XSimple xSimple, [in] long mode); +}; + +interface XIdentity: com::sun::star::uno::XInterface +{ + void setObject([in] com::sun::star::uno::XInterface val); + boolean isSame( [in] com::sun::star::uno::XInterface val); + + com::sun::star::uno::XInterface getThis(); +}; + +}; // oletest + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unloading/makefile.mk b/extensions/test/ole/unloading/makefile.mk new file mode 100644 index 000000000..53c0b3d89 --- /dev/null +++ b/extensions/test/ole/unloading/makefile.mk @@ -0,0 +1,61 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# +PRJ=..$/..$/.. + +PRJNAME= extensions +TARGET= unloadtest +TARGETTYPE=CUI +COMP1TYPELIST=$(TARGET1) + +ENABLE_EXCEPTIONS=TRUE + +USE_DEFFILE= TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# ------------------------------------------------------------------ + +APP1NOSAL=TRUE + +APP1TARGET= $(TARGET) + +APP1OBJS= $(OBJ)$/unloadTest.obj + +APP1STDLIBS= \ + $(SALLIB) \ + $(CPPUHELPERLIB) \ + $(CPPULIB) + +# all: \ +# $(BINDIR) \ +# $(BINDIR)$/test.ini \ +# ALLTAR + +# $(BINDIR) : +# @@-$(MKDIR) $(BINDIR) + +# $(BINDIR)$/test.ini : .$/unloadtest.ini +# -$(GNUCOPY) .$/unloadtest.ini $(BINDIR) + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk + + diff --git a/extensions/test/ole/unloading/readme.txt b/extensions/test/ole/unloading/readme.txt new file mode 100644 index 000000000..d8b467ddf --- /dev/null +++ b/extensions/test/ole/unloading/readme.txt @@ -0,0 +1,6 @@ +This project builds a unloadtest.exe. + +Function: Tests if the unloading mechanism works with the olebrdg.dll. +In several tests, all services are created and destroyed and rtl_unloadUnusedModules is called. + +Usage: copy into the \program directory and run there. diff --git a/extensions/test/ole/unloading/unloadTest.cxx b/extensions/test/ole/unloading/unloadTest.cxx new file mode 100644 index 000000000..b6825fad2 --- /dev/null +++ b/extensions/test/ole/unloading/unloadTest.cxx @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace ::osl; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::cppu; +using namespace ::com::sun::star::registry; + + +sal_Bool test1(); +sal_Bool test2(); +sal_Bool test3(); +sal_Bool test4(); + +int main(int, char**) +{ + sal_Bool bTest1= test1(); + sal_Bool bTest2= test2(); + sal_Bool bTest3= test3(); + sal_Bool bTest4= test4(); + + if( bTest1 && bTest2 && bTest3 && bTest4) + printf("\n#########################\n Test was successful\n#######################\n"); + + return 0; +} + +sal_Bool test1() +{ + printf("\n Test1: com.sun.star.bridge.oleautomation.BridgeSupplier\n"); + Reference xreg= createSimpleRegistry(); + xreg->open( OUString("services.rdb"), + sal_False, sal_False ); + + Reference< XComponentContext > context= bootstrap_InitialComponentContext(xreg); + Reference fac= context->getServiceManager(); + OUString sService1("com.sun.star.bridge.oleautomation.BridgeSupplier"); + Reference xint1= fac->createInstanceWithContext( sService1, context); + + OUString sModule("oleautobridge.uno" SAL_DLLEXTENSION); + oslModule hMod= osl_loadModule( sModule.pData, 0); + osl_unloadModule( hMod); + + rtl_unloadUnusedModules( NULL); + + OUString sFactoryFunc("component_getFactory"); + void* pSymbol= osl_getSymbol( hMod,sFactoryFunc.pData); + // true, instance alive + sal_Bool bTest1= pSymbol ? sal_True : sal_False; + + xint1=0; + rtl_unloadUnusedModules( NULL); + pSymbol= osl_getSymbol( hMod,sFactoryFunc.pData); + sal_Bool bTest2= pSymbol ? sal_False : sal_True; + + Reference xcomp( context, UNO_QUERY); + xcomp->dispose(); + + return bTest2 && bTest1; +} + +sal_Bool test2() +{ + printf("Test2: com.sun.star.bridge.OleBridgeSupplierVar1\n"); + Reference xreg= createSimpleRegistry(); + xreg->open( OUString("services.rdb"), + sal_False, sal_False ); + + Reference< XComponentContext > context= bootstrap_InitialComponentContext(xreg); + Reference fac= context->getServiceManager(); + OUString sService2("com.sun.star.bridge.OleBridgeSupplierVar1"); + Reference xint= fac->createInstanceWithContext( sService2, context); + + OUString sModule("oleautobridge.uno" SAL_DLLEXTENSION); + oslModule hMod= osl_loadModule( sModule.pData, 0); + osl_unloadModule( hMod); + + rtl_unloadUnusedModules( NULL); + OUString sFactoryFunc("component_getFactory"); + void* pSymbol= osl_getSymbol( hMod,sFactoryFunc.pData); + // true, instance alive + sal_Bool bTest1= pSymbol ? sal_True : sal_False; + + xint=0; + rtl_unloadUnusedModules( NULL); + pSymbol= osl_getSymbol( hMod,sFactoryFunc.pData); + sal_Bool bTest2= pSymbol ? sal_False : sal_True; + + Reference xcomp( context, UNO_QUERY); + xcomp->dispose(); + return bTest1 && bTest2; +} + +sal_Bool test3() +{ + printf("Test3: com.sun.star.bridge.oleautomation.Factory\n"); + Reference xreg= createSimpleRegistry(); + xreg->open( OUString("services.rdb"), + sal_False, sal_False ); + + Reference< XComponentContext > context= bootstrap_InitialComponentContext(xreg); + + Reference fac= context->getServiceManager(); + OUString sService("com.sun.star.bridge.oleautomation.Factory"); + Reference xint= fac->createInstanceWithContext( sService, context); + + + OUString sModule("oleautobridge.uno" SAL_DLLEXTENSION); + oslModule hMod= osl_loadModule( sModule.pData, 0); + osl_unloadModule( hMod); + + rtl_unloadUnusedModules( NULL); + OUString sFactoryFunc("component_getFactory"); + void* pSymbol= osl_getSymbol( hMod,sFactoryFunc.pData); + // true, instance alive + sal_Bool bTest1= pSymbol ? sal_True : sal_False; + + xint=0; + rtl_unloadUnusedModules( NULL); + pSymbol= osl_getSymbol( hMod,sFactoryFunc.pData); + sal_Bool bTest2= pSymbol ? sal_False : sal_True; + + Reference xcomp( context, UNO_QUERY); + xcomp->dispose(); + + return bTest1 && bTest2; +} + +sal_Bool test4() +{ + void* pSymbol= NULL; + sal_Bool bTest1= sal_False; + sal_Bool bTest2= sal_False; + oslModule hMod= NULL; + OUString sModule("oleautobridge.uno" SAL_DLLEXTENSION); + OUString sFactoryFunc("component_getFactory"); + { + printf("Test4: com.sun.star.bridge.oleautomation.ApplicationRegistration\n"); + Reference xreg= createSimpleRegistry(); + xreg->open( OUString("services.rdb"), + sal_False, sal_False ); + + Reference< XComponentContext > context= bootstrap_InitialComponentContext(xreg); + Reference fac= context->getServiceManager(); + OUString sService4("com.sun.star.bridge.oleautomation.ApplicationRegistration"); + Reference xint= fac->createInstanceWithContext( sService4, context); + + hMod= osl_loadModule( sModule.pData, 0); + osl_unloadModule( hMod); + + rtl_unloadUnusedModules( NULL); + void* pSymbol= osl_getSymbol( hMod,sFactoryFunc.pData); + // true, instance alive + bTest1= pSymbol ? sal_True : sal_False; + // ApplicationRegistration is a one-instance-service, therefore kill service manager first + Reference xcomp( context, UNO_QUERY); + xcomp->dispose(); + + } + rtl_unloadUnusedModules( NULL); + pSymbol= osl_getSymbol( hMod,sFactoryFunc.pData); + bTest2= pSymbol ? sal_False : sal_True; + + return bTest1 && bTest2; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/Test/StdAfx.cpp b/extensions/test/ole/unoTocomCalls/Test/StdAfx.cpp new file mode 100644 index 000000000..fcefb8f0c --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/Test/StdAfx.cpp @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// stdafx.cpp : source file that includes just the standard includes +// Test.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/Test/StdAfx.h b/extensions/test/ole/unoTocomCalls/Test/StdAfx.h new file mode 100644 index 000000000..0274335ce --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/Test/StdAfx.h @@ -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 . + */ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently + +#if !defined(AFX_STDAFX_H__180FF568_6F5C_11D4_8330_005004526AB4__INCLUDED_) +#define AFX_STDAFX_H__180FF568_6F5C_11D4_8330_005004526AB4__INCLUDED_ + +#ifdef _MSC_VER +#pragma once +#endif + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include +#include +#include +#include +extern CComModule _Module; +#include +#include + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__180FF568_6F5C_11D4_8330_005004526AB4__INCLUDED_) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/Test/Test.cpp b/extensions/test/ole/unoTocomCalls/Test/Test.cpp new file mode 100644 index 000000000..b10900dbc --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/Test/Test.cpp @@ -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 . + */ +// Test.cpp : Defines the entry point for the console application. + + +#include "stdafx.h" +#include "../XCallback_Impl/XCallback_Impl.h" +#include "../XCallback_Impl/XCallback_Impl_i.c" + +CComModule _Module; +BEGIN_OBJECT_MAP(ObjectMap) +END_OBJECT_MAP() + +HRESULT doTest(); + +int main(int argc, char* argv[]) +{ + HRESULT hr; + if( FAILED( hr=CoInitializeEx(NULL, COINIT_APARTMENTTHREADED))) + { + _tprintf(_T("CoInitializeEx failed \n")); + return -1; + } + + + _Module.Init( ObjectMap, GetModuleHandle( NULL)); + + if( FAILED(hr=doTest())) + { + _com_error err( hr); + const TCHAR * errMsg= err.ErrorMessage(); + MessageBox( NULL, errMsg, "Test failed", MB_ICONERROR); + } + + + _Module.Term(); + CoUninitialize(); + + + return 0; +} + + +HRESULT doTest() +{ + HRESULT hr= S_OK; + + CComPtr spUnk; + hr= spUnk.CoCreateInstance(L"com.sun.star.ServiceManager"); + if( FAILED( hr)) + return hr; + + CComDispatchDriver manager( spUnk); + CComVariant param( L"oletest.OleTest"); + CComVariant retVal; + hr= manager.Invoke1((LPCOLESTR)L"createInstance", ¶m, &retVal ); + + CComDispatchDriver oletest( retVal.punkVal); + + spUnk.Release(); + + hr= spUnk.CoCreateInstance(L"XCallback_Impl.Callback"); + if( FAILED( hr)) + return hr; + + CComQIPtr paramDisp(spUnk); + + + + // out parameters + + CComVariant param1( paramDisp); + CComVariant param2(1); + + // oletest calls XCallback::func1 + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::returnInterface + param2= 2; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outInterface + param2= 3; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outStruct + param2= 4; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outEnum + param2= 5; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outSeqAny + param2= 6; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outAny + param2= 7; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outBool + param2= 8; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outChar + param2= 9; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outString + param2= 10; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outFloat + param2= 11; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outDouble + param2= 12; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outByte + param2= 13; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outShort + param2= 14; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outLong + param2= 15; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outValuesMixed + param2= 30; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::outValuesAll + param2= 31; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + + // XCallback::outSeqByte + // Does not work currently because Sequences are always converted to + // SAFEARRAY( VARIANT) + // param2= 32; + // hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + + + // in / out parameters + + // XCallback::inoutInterface + param2= 100; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutStruct + param2= 101; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutEnum + param2= 102; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutSeqAny + param2= 103; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutAny + param2= 104; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutBool + param2= 105; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutChar + param2= 106; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutString + param2= 107; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutFloat + param2= 108; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutDouble + param2= 109; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutByte + param2= 110; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutShort + param2= 111; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutLong + param2= 112; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutValuesAll + param2=120; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + + // in parameters + + // XCallback::inValues + param2= 200; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inSeqByte + // SAFEARRAY( VARIANT) + param2= 201; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + //XCallback::inSeqXEventListener + param2= 202; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + + // The UNO test component OleTest calls on XCallback_Impl.Callback directly + // that is the COM object has not been past a parameter but rather OleTest + // creates the COM object itself + + // XCallback::outValuesAll + // does not work currently + param2= 300; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutValuesAll + param2= 301; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + // XCallback::inoutValues + param2= 302; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + + // XCallback::inValues + param2= 303; + hr= oletest.Invoke2(L"testInterface", ¶m1, ¶m2); + + // Test a COM object which implements several interfaces. + + + CComQIPtr dispSimple; + hr= dispSimple.CoCreateInstance(L"XCallback_Impl.Simple"); + CComVariant varSimple( dispSimple); + param2= 0; + hr= oletest.Invoke2(L"testInterface2", &varSimple, ¶m2); + + return hr; +} +// VARIANT CComVariant VT_UNKNOWN VT_DISPATCH V_UI1 CComDispatchDriver WINAPI + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/Test/Test.dsp b/extensions/test/ole/unoTocomCalls/Test/Test.dsp new file mode 100644 index 000000000..d9ef4e865 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/Test/Test.dsp @@ -0,0 +1,114 @@ +# Microsoft Developer Studio Project File - Name="Test" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=Test - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Test.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Test.mak" CFG="Test - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Test - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Test - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Test - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "Test - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "Test - Win32 Release" +# Name "Test - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\Test.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project + diff --git a/extensions/test/ole/unoTocomCalls/Test/Test.sln b/extensions/test/ole/unoTocomCalls/Test/Test.sln new file mode 100644 index 000000000..428b73625 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/Test/Test.sln @@ -0,0 +1,19 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test.vcproj", "{13AE4BE8-2467-4B35-800F-154379D54C24}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {13AE4BE8-2467-4B35-800F-154379D54C24}.Debug|Win32.ActiveCfg = Debug|Win32 + {13AE4BE8-2467-4B35-800F-154379D54C24}.Debug|Win32.Build.0 = Debug|Win32 + {13AE4BE8-2467-4B35-800F-154379D54C24}.Release|Win32.ActiveCfg = Release|Win32 + {13AE4BE8-2467-4B35-800F-154379D54C24}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/test/ole/unoTocomCalls/Test/Test.vcproj b/extensions/test/ole/unoTocomCalls/Test/Test.vcproj new file mode 100644 index 000000000..f31d1ffc4 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/Test/Test.vcproj @@ -0,0 +1,247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/Basic.rgs b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Basic.rgs new file mode 100644 index 000000000..bc1525d7e --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Basic.rgs @@ -0,0 +1,27 @@ +HKCR +{ + XCallback_Impl.Basic.1 = s 'Basic Class' + { + CLSID = s '{A0F04CB7-8494-11D4-8335-005004526AB4}' + } + XCallback_Impl.Basic = s 'Basic Class' + { + CLSID = s '{A0F04CB7-8494-11D4-8335-005004526AB4}' + CurVer = s 'XCallback_Impl.Basic.1' + } + NoRemove CLSID + { + ForceRemove {A0F04CB7-8494-11D4-8335-005004526AB4} = s 'Basic Class' + { + ProgID = s 'XCallback_Impl.Basic.1' + VersionIndependentProgID = s 'XCallback_Impl.Basic' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{180FF553-6F5C-11D4-8330-005004526AB4}' + } + } +} + diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/BasicTest.rgs b/extensions/test/ole/unoTocomCalls/XCallback_Impl/BasicTest.rgs new file mode 100644 index 000000000..ee718304d --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/BasicTest.rgs @@ -0,0 +1,27 @@ +HKCR +{ + XCallback_Impl.BasicTest.1 = s 'BasicTest Class' + { + CLSID = s '{A0F04CBD-8494-11D4-8335-005004526AB4}' + } + XCallback_Impl.BasicTest = s 'BasicTest Class' + { + CLSID = s '{A0F04CBD-8494-11D4-8335-005004526AB4}' + CurVer = s 'XCallback_Impl.BasicTest.1' + } + NoRemove CLSID + { + ForceRemove {A0F04CBD-8494-11D4-8335-005004526AB4} = s 'BasicTest Class' + { + ProgID = s 'XCallback_Impl.BasicTest.1' + VersionIndependentProgID = s 'XCallback_Impl.BasicTest' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{180FF553-6F5C-11D4-8330-005004526AB4}' + } + } +} + diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.cpp b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.cpp new file mode 100644 index 000000000..c60a18219 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.cpp @@ -0,0 +1,505 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// Callback.cpp : Implementation of CCallback +#include "stdafx.h" +#include "XCallback_Impl.h" +#include "Callback.h" + + +// CCallback + + +STDMETHODIMP CCallback::func1() +{ + MessageBox( NULL, _T("Callback::func1 called"),_T(""), MB_OK); + return S_OK; +} + +STDMETHODIMP CCallback::returnInterface(IDispatch **ppdisp) +{ + if( ! ppdisp) + return E_POINTER; + CComPtr spDisp; + spDisp.CoCreateInstance( L"XCallback_Impl.Simple"); + *ppdisp= spDisp; + (*ppdisp)->AddRef(); + return S_OK; +} + +STDMETHODIMP CCallback::outInterface(IDispatch **ppdisp) +{ +// return S_OK; + if( ! ppdisp) + return E_POINTER; + CComPtr spDisp; + spDisp.CoCreateInstance( L"XCallback_Impl.Simple"); + *ppdisp= spDisp; + (*ppdisp)->AddRef(); + +// MessageBox( NULL, _T("CCallback::outInterface"), _T(""), MB_OK); + return S_OK; +} + +STDMETHODIMP CCallback::outValuesMixed(long val, long *pval, BSTR string) +{ + USES_CONVERSION; + char buff[1024]; + *pval = val+1; + sprintf( buff, "param1: %d, param2 out: %d, param3: %S", val, *pval, string); + MessageBox( NULL, A2T(buff), A2T("XCallback_Impl.Callback"), MB_OK); + return S_OK; +} + + +STDMETHODIMP CCallback::outValuesAll( + /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdisp, + /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppSimpleStruct, + /* [out] */ long __RPC_FAR *aSimpleEnum, + /* [out] */ SAFEARRAY __RPC_FAR * __RPC_FAR *outSeq, + /* [out] */ VARIANT __RPC_FAR *varAny, + /* [out] */ VARIANT_BOOL __RPC_FAR *aBool, + /* [out] */ short __RPC_FAR *aChar, + /* [out] */ BSTR __RPC_FAR *aString, + /* [out] */ float __RPC_FAR *aFloat, + /* [out] */ double __RPC_FAR *aDouble, + /* [out] */ unsigned char __RPC_FAR *aByte, + /* [out] */ short __RPC_FAR *aShort, + /* [out] */ long __RPC_FAR *aLong) +//) +{ +// if( ! ppdisp || ! ppSimpleStruct || ! aSimpleEnum || +// ! outSeq || !varAny ||! aBool || ! aChar || +// ! aString || ! aFloat || ! aDouble || ! aByte || +// ! aShort || ! aLong || ! aUShort || ! aULong) +// return E_POINTER; + + HRESULT hr=S_OK; + hr= outInterface( ppdisp); + hr= outStruct( ppSimpleStruct); + hr= outEnum( aSimpleEnum); + hr= outSeqAny( outSeq); + hr= outAny( varAny); + hr= outBool( aBool); + hr= outChar( aChar); + hr= outString( aString); + hr= outFloat( aFloat); + hr= outDouble( aDouble); + hr= outByte( aByte); + hr= outShort( aShort); + hr= outLong( aLong); + return hr; +} + +STDMETHODIMP CCallback::outStruct(IDispatch **outStruct) +{ +// return S_OK; + if( !outStruct) + return E_POINTER; + HRESULT hr= E_FAIL; +// MessageBox( NULL, _T("CCallback::outStruct"), _T(""), MB_OK); + + CComPtr _dispMgr; + if( SUCCEEDED(hr= _dispMgr.CoCreateInstance(L"com.sun.star.ServiceManager"))) + { + CComDispatchDriver manager( _dispMgr); + CComVariant param1(L"com.sun.star.reflection.CoreReflection"); + CComVariant varRet; + hr= manager.Invoke1( L"createInstance", ¶m1, &varRet); + + CComDispatchDriver reflection( varRet.pdispVal); + param1= L"oletest.SimpleStruct"; + varRet.Clear(); + hr= reflection.Invoke1( L"forName", ¶m1, &varRet); + + CComDispatchDriver classSimpleStruct( varRet.pdispVal); + + CComPtr dispStruct; + param1.vt= VT_DISPATCH | VT_BYREF; + param1.ppdispVal= &dispStruct; + if( SUCCEEDED( hr= classSimpleStruct.Invoke1(L"createObject", ¶m1))) + { + // Set the value + CComDispatchDriver simpleStruct( dispStruct); + param1=L" this is a property string"; + hr= simpleStruct.PutPropertyByName(L"message", ¶m1); + *outStruct= dispStruct; + (*outStruct)->AddRef(); + hr= S_OK; + } + } + return hr; +} + +STDMETHODIMP CCallback::outEnum(long *outEnum) +{ + if( !outEnum) + return E_POINTER; + *outEnum= 1; + return S_OK; +} + +STDMETHODIMP CCallback::outSeqAny(LPSAFEARRAY* outSeq) +{ +// _CrtDbgBreak(); + SAFEARRAY* pArr= SafeArrayCreateVector( VT_VARIANT, 0, 3); + CComVariant var[3]; + var[0]=L" variant 0"; + var[1]=L" variant 1"; + var[2]=L"variant 2"; + for( long i=0; i<3; i++) + { + SafeArrayPutElement( pArr, &i, (void*)&var[i]); + } + + *outSeq= pArr; + return S_OK; +} + +// ATLASSERT //VT_EMPTY + + +STDMETHODIMP CCallback::outAny(VARIANT *outAny) +{ + if( ! outAny) + return E_POINTER; + outAny->vt= VT_BSTR; + outAny->bstrVal= SysAllocString( L"This is a string in a VARIANT"); + + return S_OK; +} + +STDMETHODIMP CCallback::outBool(VARIANT_BOOL *outBool) +{ + if( ! outBool) + return E_POINTER; + *outBool= VARIANT_TRUE; + return S_OK; +} + +STDMETHODIMP CCallback::outChar(short *outChar) +{ + if( !outChar) + return E_POINTER; + *outChar= (short)L'A'; + return S_OK; +} + +STDMETHODIMP CCallback::outString(BSTR *outString) +{ + if( !outString) + return E_POINTER; + *outString= SysAllocString(L"This is a BSTR"); + return S_OK; +} + +STDMETHODIMP CCallback::outFloat(float *outFloat) +{ + if( !outFloat) + return E_POINTER; + *outFloat= 3.14f; + return S_OK; +} + +STDMETHODIMP CCallback::outDouble(double *outDouble) +{ + if(!outDouble) + return E_POINTER; + + *outDouble= 3.145; + return S_OK; +} + + + +STDMETHODIMP CCallback::outShort(short *outShort) +{ + if(!outShort) + return E_POINTER; + *outShort= -1; + return S_OK; +} + +STDMETHODIMP CCallback::outLong(long *outLong) +{ + if(!outLong) + return E_POINTER; + *outLong= 0xffffffff; + return S_OK; +} + + + +STDMETHODIMP CCallback::outByte(unsigned char* outByte) +{ + if(!outByte) + return E_POINTER; + *outByte= 0xff; + return S_OK; +} + +STDMETHODIMP CCallback::inoutInterface(IDispatch **ppdisp) +{ + if( !ppdisp) + return E_POINTER; + CComDispatchDriver disp( *ppdisp); + CComVariant param1(L""); + disp.Invoke1(L"func", ¶m1); + + (*ppdisp)->Release(); + + CComPtr outDisp; + outDisp.CoCreateInstance( L"XCallback_Impl.Simple"); + *ppdisp= outDisp; + (*ppdisp)->AddRef(); + + return S_OK; +} + +STDMETHODIMP CCallback::inoutStruct(IDispatch **inoutVal) +{ + if( !inoutVal) + return E_POINTER; + HRESULT hr= S_OK; + USES_CONVERSION; + CComVariant var; + CComDispatchDriver disp( *inoutVal); + + hr= disp.GetPropertyByName(L"message", &var); + MessageBox( NULL, W2T(var.bstrVal), _T("XCallback_Impl.Callback"), MB_OK); + + (*inoutVal)->Release(); + + CComDispatchDriver dispStruct; + hr= outStruct( &dispStruct.p); + var.Clear(); + var= L"This struct was created in XCallback_Imp.Callback"; + hr= dispStruct.PutPropertyByName(L"message", &var); + + *inoutVal= dispStruct; + (*inoutVal)->AddRef(); + return hr; +} + +STDMETHODIMP CCallback::inoutEnum(long *inoutVal) +{ + if( !inoutVal) + return E_POINTER; + *inoutVal= *inoutVal+1; + + return S_OK; +} + +STDMETHODIMP CCallback::inoutSeqAny(LPSAFEARRAY *pArray) +{ + if( !pArray) + return E_POINTER; + HRESULT hr= S_OK; + long lbound=0; + long ubound=0; + hr= SafeArrayGetLBound( *pArray, 1, &lbound); + hr= SafeArrayGetUBound( *pArray, 1, &ubound); + long count= ubound - lbound + 1; + + // the Array is supposet to contain variants + CComVariant var; + for( long i=0; ivt= VT_BSTR) + MessageBox( NULL, W2T( inoutVal->bstrVal), _T("XCallback_Impl.Callback"), MB_OK); + + VariantClear( inoutVal); + inoutVal->vt= VT_BSTR; + inoutVal->bstrVal=SysAllocString( L" [string] XCallback_Impl.Callback inoutAny"); + return S_OK; +} + +STDMETHODIMP CCallback::inoutBool(VARIANT_BOOL *inoutVal) +{ + if( !inoutVal) + return E_POINTER; + + *inoutVal= *inoutVal == VARIANT_TRUE ? VARIANT_FALSE : VARIANT_TRUE; + return S_OK; +} + +STDMETHODIMP CCallback::inoutChar(short *inoutVal) +{ + if( !inoutVal) + return E_POINTER; + USES_CONVERSION; + char buff[256]; + sprintf( buff, "character value: %C", *inoutVal); + MessageBox( NULL, A2T(buff), _T("XCallback_Impl.Callback"), MB_OK); + *inoutVal= L'B'; + return S_OK; +} + +STDMETHODIMP CCallback::inoutString(BSTR *inoutVal) +{ + if( !inoutVal) + return E_POINTER; + USES_CONVERSION; + MessageBox( NULL, W2T(*inoutVal), _T("XCallback_Impl.Callback"), MB_OK); + SysFreeString(*inoutVal); + *inoutVal= SysAllocString(L"a string from XCallback_Impl.Callback"); + + return S_OK; +} + +STDMETHODIMP CCallback::inoutFloat(float *inoutVal) +{ + if( !inoutVal) + return E_POINTER; + *inoutVal = *inoutVal+1; + return S_OK; +} + +STDMETHODIMP CCallback::inoutDouble(double *inoutVal) +{ + if( !inoutVal) + return E_POINTER; + *inoutVal= *inoutVal+1; + return S_OK; +} + +STDMETHODIMP CCallback::inoutByte(unsigned char *inoutVal) +{ + if( !inoutVal) + return E_POINTER; + *inoutVal= 0xff; + return S_OK; +} + +STDMETHODIMP CCallback::inoutShort(short *inoutVal) +{ + if( !inoutVal) + return E_POINTER; + *inoutVal= -1; + return S_OK; +} + +STDMETHODIMP CCallback::inoutLong(long* inoutVal) +{ + if( !inoutVal) + return E_POINTER; + *inoutVal= 0xffffffff; + return S_OK; +} + +STDMETHODIMP CCallback::inoutValuesAll( + /* [out][in] */ IDispatch __RPC_FAR *__RPC_FAR *aXSimple, + /* [out][in] */ IDispatch __RPC_FAR *__RPC_FAR *aStruct, + /* [out][in] */ long __RPC_FAR *aEnum, + /* [out][in] */ SAFEARRAY __RPC_FAR * __RPC_FAR *aSeq, + /* [out][in] */ VARIANT __RPC_FAR *aAny, + /* [out][in] */ VARIANT_BOOL __RPC_FAR *aBool, + /* [out][in] */ short __RPC_FAR *aChar, + /* [out][in] */ BSTR __RPC_FAR *aString, + /* [out][in] */ float __RPC_FAR *aFloat, + /* [out][in] */ double __RPC_FAR *aDouble, + /* [out][in] */ unsigned char __RPC_FAR *aByte, + /* [out][in] */ short __RPC_FAR *aShort, + /* [out][in] */ long __RPC_FAR *aLong) +{ + inoutInterface( aXSimple); + inoutStruct( aStruct); + inoutEnum( aEnum); + inoutSeqAny( aSeq); + inoutAny( aAny); + inoutBool( aBool); + inoutChar( aChar); + inoutString( aString); + inoutFloat( aFloat); + inoutDouble( aDouble); + inoutByte( aByte); + inoutShort( aShort); + inoutLong( aLong); + + return S_OK; +} + + +STDMETHODIMP CCallback::inValues(short aChar, long aLong, BSTR aString) +{ + USES_CONVERSION; + wchar_t _char= (wchar_t) aChar; + char buff[1024]; + sprintf( buff, "Parameters: char= %C, long= %d, string= %s", _char, aLong, W2A(aString)); + MessageBox( NULL, A2T(buff), _T("XCallback_Impl.Callback"), MB_OK); + return S_OK; +} + +STDMETHODIMP CCallback::outSeqByte(LPSAFEARRAY * outVal) +{ + // TODO: Add your implementation code here + + return S_OK; +} + +STDMETHODIMP CCallback::inSeqByte( LPSAFEARRAY listeners) +{ + + return S_OK; +} + +STDMETHODIMP CCallback::inSeqXEventListener( LPSAFEARRAY listeners, LPSAFEARRAY events) +{ + HRESULT hr= S_OK; + long ubound= 0; + long lbound= 0; + long count= 0; + hr= SafeArrayGetUBound( listeners, 1, &ubound); + hr= SafeArrayGetLBound( listeners, 1, &lbound); + count= ubound - lbound +1; + + // We assume that the count of EventObjects in events is the same + for( long i = 0; i < count; i++) + { + CComVariant varListener; + CComVariant varEvent; + hr= SafeArrayGetElement( listeners, &i, &varListener); + hr= SafeArrayGetElement( events, &i, &varEvent); + if( varListener.vt == VT_DISPATCH && varEvent.vt == VT_DISPATCH) + { + CComDispatchDriver disp( varListener.pdispVal); + hr= disp.Invoke1(L"disposing", &varEvent); + } + + } + + return S_OK; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.h b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.h new file mode 100644 index 000000000..941d1202f --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.h @@ -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 . + */ +// Callback.h : Declaration of the CCallback + +#pragma once + +#include "resource.h" + + +// CCallback +class ATL_NO_VTABLE CCallback : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CCallback() + { + } + +DECLARE_REGISTRY_RESOURCEID(IDR_CALLBACK) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CCallback) + COM_INTERFACE_ENTRY(ICallback) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + +// ICallback +public: + STDMETHOD(inSeqByte)(/*[in]*/ LPSAFEARRAY val); + STDMETHOD(inSeqXEventListener)(/*[in]*/ LPSAFEARRAY listener, LPSAFEARRAY event); + STDMETHOD(outSeqByte)(/*[out]*/ LPSAFEARRAY* outVal); + STDMETHOD(inValues)(/*[in]*/short aChar, /*[in]*/ long aLong, /*[in]*/ BSTR aString); + STDMETHOD(inoutLong)(/*[in,out]*/ long* inoutVal); + STDMETHOD(inoutShort)(/*[in,out]*/ short* inoutVal); + STDMETHOD(inoutByte)(/*[in,out]*/ unsigned char* inoutVal); + STDMETHOD(inoutDouble)(/*[in,out]*/ double* inoutVal); + STDMETHOD(inoutFloat)(/*[in,out]*/ float* inoutVal); + STDMETHOD(inoutString)(/*[in,out]*/ BSTR *inoutVal); + STDMETHOD(inoutChar)(/*[in,out]*/ short* inoutVal); + STDMETHOD(inoutBool)(/*[in,out]*/ VARIANT_BOOL * inoutVal); + STDMETHOD(inoutAny)(/*[in,out]*/ VARIANT* inoutVal); + STDMETHOD(inoutSeqAny)(/*[in,out]*/ LPSAFEARRAY* pArray); + STDMETHOD(inoutEnum)(/*[in,out]*/ long * inoutVal); + STDMETHOD(inoutStruct)(/*[in,out]*/ IDispatch** inoutVal); + STDMETHOD(inoutInterface)(/*[in,out]*/ IDispatch** ppdisp); + STDMETHOD(inoutValuesAll)( + /* [out][in] */ IDispatch __RPC_FAR *__RPC_FAR *aXSimple, + /* [out][in] */ IDispatch __RPC_FAR *__RPC_FAR *aStruct, + /* [out][in] */ long __RPC_FAR *aEnum, + /* [out][in] */ SAFEARRAY __RPC_FAR * __RPC_FAR *aSeq, + /* [out][in] */ VARIANT __RPC_FAR *aAny, + /* [out][in] */ VARIANT_BOOL __RPC_FAR *aBool, + /* [out][in] */ short __RPC_FAR *aChar, + /* [out][in] */ BSTR __RPC_FAR *aString, + /* [out][in] */ float __RPC_FAR *aFloat, + /* [out][in] */ double __RPC_FAR *aDouble, + /* [out][in] */ unsigned char __RPC_FAR *aByte, + /* [out][in] */ short __RPC_FAR *aShort, + /* [out][in] */ long __RPC_FAR *aLong); + + STDMETHOD(outByte)( unsigned char* outByte); + STDMETHOD(outLong)(/*[out]*/ long* outLong); + STDMETHOD(outShort)(/*[out]*/ short *outShort); + STDMETHOD(outDouble)(/*[out]*/ double* outDouble); + STDMETHOD(outFloat)(/*[out]*/ float* outFloat); + STDMETHOD(outString)(/*[out]*/ BSTR * outString); + STDMETHOD(outChar)(short* outChar); + STDMETHOD(outBool)(VARIANT_BOOL* outBool); + STDMETHOD(outAny)(VARIANT* outAny); + STDMETHOD(outSeqAny)(/*[out]*/LPSAFEARRAY* outSeq); + STDMETHOD(outEnum)(/*[out]*/ long* outEnum); + STDMETHOD(outStruct)(/*[out]*/ IDispatch** outStruct); + virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE outValuesAll( + /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdisp, + /* [out] */ IDispatch __RPC_FAR *__RPC_FAR *ppSimpleStruct, + /* [out] */ long __RPC_FAR *aSimpleEnum, + /* [out] */ LPSAFEARRAY* outSeq, + /* [out] */ VARIANT __RPC_FAR *varAny, + /* [out] */ VARIANT_BOOL __RPC_FAR *aBool, + /* [out] */ short __RPC_FAR *aChar, + /* [out] */ BSTR __RPC_FAR *aString, + /* [out] */ float __RPC_FAR *aFloat, + /* [out] */ double __RPC_FAR *aDouble, + /* [out] */ unsigned char __RPC_FAR *aByte, + /* [out] */ short __RPC_FAR *aShort, + /* [out] */ long __RPC_FAR *aLong); +// ); + +// STDMETHOD(outValuesAll)( +// /*[out]*/ IDispatch** ppdisp, +// /*[out]*/ IUnknown** ppSimpleStruct, +// /*[out]*/ long* aSimpleEnum, +// /*[out]*/ VARIANT* ArrayAny, +// /*[out]*/ VARIANT* varAny, +// /*[out]*/ VARIANT_BOOL * aBool, +// /*[out]*/ unsigned short* aChar, +// /*[out]*/ BSTR* aString, /*[out]*/ float* aFloat, +// /*[out]*/ double* aDouble, +// /*[out]*/ signed char* aByte, /*[out]*/ short* aShort, /*[out]*/long* aLong, /*[out]*/ unsigned short* aUShort, /*[out]*/ unsigned long* aULong); + STDMETHOD(outValuesMixed)(/*[in]*/ long val, /*[out]*/ long* pval, /*[in]*/ BSTR string); + STDMETHOD(outInterface)(/*[out]*/ IDispatch** ppdisp); + STDMETHOD(returnInterface)(/*[out, retval]*/ IDispatch** ppdisp); + STDMETHOD(func1)(); +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.rgs b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.rgs new file mode 100644 index 000000000..b3f9e071b --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Callback.rgs @@ -0,0 +1,27 @@ +HKCR +{ + XCallback_Impl.Callback.1 = s 'Callback Class' + { + CLSID = s '{180FF560-6F5C-11D4-8330-005004526AB4}' + } + XCallback_Impl.Callback = s 'Callback Class' + { + CLSID = s '{180FF560-6F5C-11D4-8330-005004526AB4}' + CurVer = s 'XCallback_Impl.Callback.1' + } + NoRemove CLSID + { + ForceRemove {180FF560-6F5C-11D4-8330-005004526AB4} = s 'Callback Class' + { + ProgID = s 'XCallback_Impl.Callback.1' + VersionIndependentProgID = s 'XCallback_Impl.Callback' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{180FF553-6F5C-11D4-8330-005004526AB4}' + } + } +} + diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.cpp b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.cpp new file mode 100644 index 000000000..5b7183cdb --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.cpp @@ -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 . + */ +// Simple.cpp : Implementation of CSimple +#include "stdafx.h" +#include "XCallback_Impl.h" +#include "Simple.h" + + +// CSimple + + +STDMETHODIMP CSimple::func(BSTR message) +{ + USES_CONVERSION; + MessageBox( NULL, W2T( message), _T("XCallback_Impl.Simple"), MB_OK); + return S_OK; +} + + +STDMETHODIMP CSimple::func2(BSTR message) +{ + USES_CONVERSION; + MessageBox( NULL, W2T( message), _T("XCallback_Impl.Simple"), MB_OK); + return S_OK; +} + +STDMETHODIMP CSimple::func3(BSTR message) +{ + USES_CONVERSION; + MessageBox( NULL, W2T( message), _T("XCallback_Impl.Simple"), MB_OK); + return S_OK; +} + + +STDMETHODIMP CSimple::get__implementedInterfaces(LPSAFEARRAY *pVal) +{ + HRESULT hr= S_OK; + SAFEARRAY *pArr= SafeArrayCreateVector( VT_BSTR, 0, 3); + if( pArr) + { long index=0; + BSTR name1= SysAllocString(L"oletest.XSimple"); + BSTR name2= SysAllocString(L"oletest.XSimple2"); + BSTR name3= SysAllocString(L"oletest.XSimple3"); + + hr= SafeArrayPutElement( pArr, & index, name1); + index++; + hr|= SafeArrayPutElement( pArr, &index, name2); + index++; + hr|= SafeArrayPutElement( pArr, &index, name3); + *pVal= pArr; + + } + *pVal= pArr; + return hr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.h b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.h new file mode 100644 index 000000000..8abe56270 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.h @@ -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 . + */ +// Simple.h : Declaration of the CSimple + +#pragma once + +#include "resource.h" + + +// CSimple +class ATL_NO_VTABLE CSimple : + public CComObjectRootEx, + public CComCoClass, + public IDispatchImpl +{ +public: + CSimple() + { + } + +DECLARE_REGISTRY_RESOURCEID(IDR_SIMPLE) + +DECLARE_PROTECT_FINAL_CONSTRUCT() + +BEGIN_COM_MAP(CSimple) + COM_INTERFACE_ENTRY(ISimple) + COM_INTERFACE_ENTRY(IDispatch) +END_COM_MAP() + +// ISimple +public: + + STDMETHOD(get__implementedInterfaces)(/*[out, retval]*/ LPSAFEARRAY *pVal); + STDMETHOD(func3)(/*[in]*/ BSTR message); + STDMETHOD(func2)(/*[in]*/ BSTR message); + STDMETHOD(func)( BSTR message); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.rgs b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.rgs new file mode 100644 index 000000000..19237bf36 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/Simple.rgs @@ -0,0 +1,27 @@ +HKCR +{ + XCallback_Impl.Simple.1 = s 'Simple Class' + { + CLSID = s '{180FF565-6F5C-11D4-8330-005004526AB4}' + } + XCallback_Impl.Simple = s 'Simple Class' + { + CLSID = s '{180FF565-6F5C-11D4-8330-005004526AB4}' + CurVer = s 'XCallback_Impl.Simple.1' + } + NoRemove CLSID + { + ForceRemove {180FF565-6F5C-11D4-8330-005004526AB4} = s 'Simple Class' + { + ProgID = s 'XCallback_Impl.Simple.1' + VersionIndependentProgID = s 'XCallback_Impl.Simple' + ForceRemove 'Programmable' + InprocServer32 = s '%MODULE%' + { + val ThreadingModel = s 'Apartment' + } + 'TypeLib' = s '{180FF553-6F5C-11D4-8330-005004526AB4}' + } + } +} + diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/StdAfx.cpp b/extensions/test/ole/unoTocomCalls/XCallback_Impl/StdAfx.cpp new file mode 100644 index 000000000..da0608bfd --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/StdAfx.cpp @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +// stdafx.cpp : source file that includes just the standard includes +// stdafx.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +#ifdef _ATL_STATIC_REGISTRY +#include +#include +#endif + +#include + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/StdAfx.h b/extensions/test/ole/unoTocomCalls/XCallback_Impl/StdAfx.h new file mode 100644 index 000000000..678114bae --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/StdAfx.h @@ -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 . + */ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#if !defined(AFX_STDAFX_H__180FF556_6F5C_11D4_8330_005004526AB4__INCLUDED_) +#define AFX_STDAFX_H__180FF556_6F5C_11D4_8330_005004526AB4__INCLUDED_ + +#ifdef _MSC_VER +#pragma once +#endif + +#define STRICT +#define _ATL_APARTMENT_THREADED + +#include +#include +//You may derive a class from CComModule and use it if you want to override +//something, but do not change the name of _Module +extern CComModule _Module; +#include + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__180FF556_6F5C_11D4_8330_005004526AB4__INCLUDED) + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.cpp b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.cpp new file mode 100644 index 000000000..739695914 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.cpp @@ -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 . + */ +// XCallback_Impl.cpp : Implementation of DLL Exports. + +// Note: Proxy/Stub Information +// To build a separate proxy/stub DLL, +// run nmake -f XCallback_Implps.mk in the project directory. + +#include "stdafx.h" +#include "resource.h" +#include +#include "XCallback_Impl.h" + +#include "XCallback_Impl_i.c" +#include "Callback.h" +#include "Simple.h" + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_Callback, CCallback) +OBJECT_ENTRY(CLSID_Simple, CSimple) +END_OBJECT_MAP() + +// DLL Entry Point + +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_XCALLBACK_IMPLLib); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + return TRUE; // ok +} + +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow(void) { return (_Module.GetLockCount() == 0) ? S_OK : S_FALSE; } + +// Returns a class factory to create an object of the requested type + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + +// DllRegisterServer - Adds entries to the system registry + +STDAPI DllRegisterServer(void) +{ + // registers object, typelib and all interfaces in typelib + return _Module.RegisterServer(TRUE); +} + +// DllUnregisterServer - Removes entries from the system registry + +STDAPI DllUnregisterServer(void) { return _Module.UnregisterServer(TRUE); } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.def b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.def new file mode 100644 index 000000000..b2d5e9627 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.def @@ -0,0 +1,10 @@ +; XCallback_Impl.def : Declares the module parameters. + +LIBRARY "XCallback_Impl.DLL" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.dsp b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.dsp new file mode 100644 index 000000000..6897d0d81 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.dsp @@ -0,0 +1,337 @@ +# Microsoft Developer Studio Project File - Name="XCallback_Impl" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=XCallback_Impl - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "XCallback_Impl.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "XCallback_Impl.mak" CFG="XCallback_Impl - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "XCallback_Impl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "XCallback_Impl - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "XCallback_Impl - Win32 Release MinSize" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "XCallback_Impl - Win32 Release MinDependency" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "XCallback_Impl - Win32 Unicode Release MinSize" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "XCallback_Impl - Win32 Unicode Release MinDependency" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "XCallback_Impl - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /FR /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# Begin Custom Build - Performing registration +OutDir=.\Debug +TargetPath=.\Debug\XCallback_Impl.dll +InputPath=.\Debug\XCallback_Impl.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "XCallback_Impl - Win32 Unicode Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "DebugU" +# PROP BASE Intermediate_Dir "DebugU" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "DebugU" +# PROP Intermediate_Dir "DebugU" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# Begin Custom Build - Performing registration +OutDir=.\DebugU +TargetPath=.\DebugU\XCallback_Impl.dll +InputPath=.\DebugU\XCallback_Impl.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if "%OS%"=="" goto NOTNT + if not "%OS%"=="Windows_NT" goto NOTNT + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + goto end + :NOTNT + echo Warning : Cannot register Unicode DLL on Windows 95 + :end + +# End Custom Build + +!ELSEIF "$(CFG)" == "XCallback_Impl - Win32 Release MinSize" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseMinSize" +# PROP BASE Intermediate_Dir "ReleaseMinSize" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseMinSize" +# PROP Intermediate_Dir "ReleaseMinSize" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\ReleaseMinSize +TargetPath=.\ReleaseMinSize\XCallback_Impl.dll +InputPath=.\ReleaseMinSize\XCallback_Impl.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "XCallback_Impl - Win32 Release MinDependency" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseMinDependency" +# PROP BASE Intermediate_Dir "ReleaseMinDependency" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseMinDependency" +# PROP Intermediate_Dir "ReleaseMinDependency" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\ReleaseMinDependency +TargetPath=.\ReleaseMinDependency\XCallback_Impl.dll +InputPath=.\ReleaseMinDependency\XCallback_Impl.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + +# End Custom Build + +!ELSEIF "$(CFG)" == "XCallback_Impl - Win32 Unicode Release MinSize" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseUMinSize" +# PROP BASE Intermediate_Dir "ReleaseUMinSize" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseUMinSize" +# PROP Intermediate_Dir "ReleaseUMinSize" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\ReleaseUMinSize +TargetPath=.\ReleaseUMinSize\XCallback_Impl.dll +InputPath=.\ReleaseUMinSize\XCallback_Impl.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if "%OS%"=="" goto NOTNT + if not "%OS%"=="Windows_NT" goto NOTNT + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + goto end + :NOTNT + echo Warning : Cannot register Unicode DLL on Windows 95 + :end + +# End Custom Build + +!ELSEIF "$(CFG)" == "XCallback_Impl - Win32 Unicode Release MinDependency" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseUMinDependency" +# PROP BASE Intermediate_Dir "ReleaseUMinDependency" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseUMinDependency" +# PROP Intermediate_Dir "ReleaseUMinDependency" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_STATIC_REGISTRY" /Yu"stdafx.h" /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# Begin Custom Build - Performing registration +OutDir=.\ReleaseUMinDependency +TargetPath=.\ReleaseUMinDependency\XCallback_Impl.dll +InputPath=.\ReleaseUMinDependency\XCallback_Impl.dll +SOURCE="$(InputPath)" + +"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + if "%OS%"=="" goto NOTNT + if not "%OS%"=="Windows_NT" goto NOTNT + regsvr32 /s /c "$(TargetPath)" + echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg" + goto end + :NOTNT + echo Warning : Cannot register Unicode DLL on Windows 95 + :end + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "XCallback_Impl - Win32 Debug" +# Name "XCallback_Impl - Win32 Unicode Debug" +# Name "XCallback_Impl - Win32 Release MinSize" +# Name "XCallback_Impl - Win32 Release MinDependency" +# Name "XCallback_Impl - Win32 Unicode Release MinSize" +# Name "XCallback_Impl - Win32 Unicode Release MinDependency" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\Callback.cpp +# End Source File +# Begin Source File + +SOURCE=.\Simple.cpp +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# Begin Source File + +SOURCE=.\XCallback_Impl.cpp +# End Source File +# Begin Source File + +SOURCE=.\XCallback_Impl.def +# End Source File +# Begin Source File + +SOURCE=.\XCallback_Impl.idl +# ADD MTL /tlb ".\XCallback_Impl.tlb" /h "XCallback_Impl.h" /iid "XCallback_Impl_i.c" /Oicf +# End Source File +# Begin Source File + +SOURCE=.\XCallback_Impl.rc +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\Callback.h +# End Source File +# Begin Source File + +SOURCE=.\Resource.h +# End Source File +# Begin Source File + +SOURCE=.\Simple.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\Callback.rgs +# End Source File +# Begin Source File + +SOURCE=.\Simple.rgs +# End Source File +# End Group +# End Target +# End Project + + diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.idl b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.idl new file mode 100644 index 000000000..de56aac45 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.idl @@ -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 . + */ +// XCallback_Impl.idl : IDL source for XCallback_Impl.dll + + +// This file will be processed by the MIDL tool to +// produce the type library (XCallback_Impl.tlb) and marshalling code. + +import "oaidl.idl"; +import "ocidl.idl"; + [ + object, + uuid(180FF55F-6F5C-11D4-8330-005004526AB4), + dual, + helpstring("ICallback Interface"), + pointer_default(unique) + ] + interface ICallback : IDispatch + { + [id(1), helpstring("method func1")] HRESULT func1(); + [id(2), helpstring("method returnInterface")] HRESULT returnInterface([out, retval] IDispatch** ppdisp); + [id(3), helpstring("method outInterface")] HRESULT outInterface([out] IDispatch** ppdisp); + [id(4), helpstring("method outValuesMixed")] HRESULT outValuesMixed([in] long val, [out] long* pval, [in] BSTR string); + [id(5), helpstring("method outValuesAll")] HRESULT outValuesAll([out] IDispatch** ppdisp, [out] IDispatch** ppSimpleStruct, [out] long* aSimpleEnum, + [out] SAFEARRAY( VARIANT)* outSeq, + [out] VARIANT* varAny, + [out] VARIANT_BOOL * aBool, + [out] short* aChar, + [out] BSTR* aString , + [out] float* aFloat, + [out] double* aDouble, + [out] unsigned char* aByte, + [out] short* aShort, + [out]long* aLong); +// ); + [id(6), helpstring("method outStruct")] HRESULT outStruct([out] IDispatch** outStruct); + [id(7), helpstring("method outEnum")] HRESULT outEnum([out] long* outEnum); + [id(8), helpstring("method outSeqAny")] HRESULT outSeqAny([out] SAFEARRAY( VARIANT)* outSeq); + [id(9), helpstring("method outAny")] HRESULT outAny([out] VARIANT* outAny); + [id(10), helpstring("method outBool")] HRESULT outBool([out]VARIANT_BOOL* outBool); + [id(11), helpstring("method outChar")] HRESULT outChar([out] short* outChar); + [id(12), helpstring("method outString")] HRESULT outString([out] BSTR * outString); + [id(13), helpstring("method outFloat")] HRESULT outFloat([out] float* outFloat); + [id(14), helpstring("method outDouble")] HRESULT outDouble([out] double* outDouble); + [id(16), helpstring("method outShort")] HRESULT outShort([out] short *outShort); + [id(17), helpstring("method outLong")] HRESULT outLong([out] long* outLong); + [id(20), helpstring("method outByte")] HRESULT outByte([out] unsigned char* outByte); + [id(21), helpstring("method inoutInterface")] HRESULT inoutInterface([in,out] IDispatch** ppdisp); + [id(22), helpstring("method inoutStruct")] HRESULT inoutStruct([in,out] IDispatch** inoutVal); + [id(23), helpstring("method inoutEnum")] HRESULT inoutEnum([in,out] long * inoutVal); + [id(24), helpstring("method inoutSeqAny")] HRESULT inoutSeqAny([in,out] SAFEARRAY(VARIANT)* pArray); + [id(25), helpstring("method inoutAny")] HRESULT inoutAny([in,out] VARIANT* inoutVal); + [id(26), helpstring("method inoutBool")] HRESULT inoutBool([in,out] VARIANT_BOOL * inoutVal); + [id(27), helpstring("method inoutChar")] HRESULT inoutChar([in,out] short* inoutVal); + [id(28), helpstring("method inoutString")] HRESULT inoutString([in,out] BSTR *inoutVal); + [id(29), helpstring("method inoutFloat")] HRESULT inoutFloat([in,out] float* inoutVal); + [id(30), helpstring("method inoutDouble")] HRESULT inoutDouble([in,out] double* inoutVal); + [id(31), helpstring("method inoutByte")] HRESULT inoutByte([in,out] unsigned char* inoutVal); + [id(32), helpstring("method inoutShort")] HRESULT inoutShort([in,out] short* inoutVal); + [id(33), helpstring("method inoutLong")] HRESULT inoutLong([in,out] long* inoutVal); + [id(34), helpstring("method inoutValueAll")] HRESULT inoutValuesAll( + [in,out] IDispatch** aXSimple, + [in,out] IDispatch** aStruct, + [in,out] long* aEnum, + [in,out] SAFEARRAY( VARIANT)* aSeq, + [in,out] VARIANT* aAny, + [in,out] VARIANT_BOOL* aBool, + [in,out] short* aChar, + [in,out] BSTR* aString, + [in,out] float* aFloat, + [in,out] double* aDouble, + [in,out] unsigned char* aByte, + [in,out] short* aShort, + [in,out] long* aLong); + [id(35), helpstring("method inValues")] HRESULT inValues([in]short aChar, [in] long aLong, [in] BSTR aString); + [id(36), helpstring("method outSeqByte")] HRESULT outSeqByte([out] SAFEARRAY(unsigned char)* outVal); + [id(37), helpstring("method inSeqByte")] HRESULT inSeqByte([in] SAFEARRAY(VARIANT) val); + [id(38), helpstring("method inSeqXEventListener")] HRESULT inSeqXEventListener([in] SAFEARRAY(VARIANT) listener, + [in] SAFEARRAY(VARIANT) event); + + }; + [ + object, + uuid(180FF564-6F5C-11D4-8330-005004526AB4), + dual, + helpstring("ISimple Interface"), + pointer_default(unique) + ] + interface ISimple : IDispatch + { + [id(1), helpstring("method func")] HRESULT func( [in] BSTR message); + [id(2), helpstring("method func2")] HRESULT func2([in] BSTR message); + [id(3), helpstring("method func3")] HRESULT func3([in] BSTR message); + [propget, id(4), helpstring("property _implementedInterfaces")] HRESULT _implementedInterfaces([out, retval] SAFEARRAY(BSTR) *pVal); + }; + + + +[ + uuid(180FF553-6F5C-11D4-8330-005004526AB4), + version(1.0), + helpstring("XCallback_Impl 1.0 Type Library") +] +library XCALLBACK_IMPLLib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + + [ + uuid(180FF560-6F5C-11D4-8330-005004526AB4), + helpstring("Callback Class") + ] + coclass Callback + { + [default] interface ICallback; + }; + [ + uuid(180FF565-6F5C-11D4-8330-005004526AB4), + helpstring("Simple Class") + ] + coclass Simple + { + [default] interface ISimple; + }; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.rc b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.rc new file mode 100644 index 000000000..f544b17ca --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.rc @@ -0,0 +1,154 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS + + +// Generated from the TEXTINCLUDE 2 resource. + +#include "winres.h" + + +#undef APSTUDIO_READONLY_SYMBOLS + + +// German (Germany) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_DEU) +#ifdef _WIN32 +LANGUAGE LANG_GERMAN, SUBLANG_GERMAN +#pragma code_page(1252) +#endif //_WIN32 + + + +// REGISTRY + + +IDR_CALLBACK REGISTRY DISCARDABLE "Callback.rgs" +IDR_SIMPLE REGISTRY DISCARDABLE "Simple.rgs" +#endif // German (Germany) resources + + + + +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED + + +// TEXTINCLUDE + + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""XCallback_Impl.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC + + +// Version + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904B0" + BEGIN + VALUE "CompanyName", "\0" + VALUE "FileDescription", "XCallback_Impl Module\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "XCallback_Impl\0" + VALUE "LegalCopyright", "Copyright 2000\0" + VALUE "OriginalFilename", "XCallback_Impl.DLL\0" + VALUE "ProductName", "XCallback_Impl Module\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + VALUE "OLESelfRegister", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + + + +// String Table + + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "XCallback_Impl" +END + +#endif // English (U.S.) resources + + + + +#ifndef APSTUDIO_INVOKED + + +// Generated from the TEXTINCLUDE 3 resource. + +1 TYPELIB "XCallback_Impl.tlb" + + +#endif // not APSTUDIO_INVOKED + + diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.sln b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.sln new file mode 100644 index 000000000..62b109fe4 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.sln @@ -0,0 +1,31 @@ +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XCallback_Impl", "XCallback_Impl.vcproj", "{92A6B531-401E-4900-8217-169A96F4168D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release MinDependency|Win32 = Release MinDependency|Win32 + Release MinSize|Win32 = Release MinSize|Win32 + Unicode Debug|Win32 = Unicode Debug|Win32 + Unicode Release MinDependency|Win32 = Unicode Release MinDependency|Win32 + Unicode Release MinSize|Win32 = Unicode Release MinSize|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {92A6B531-401E-4900-8217-169A96F4168D}.Debug|Win32.ActiveCfg = Debug|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Debug|Win32.Build.0 = Debug|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Release MinDependency|Win32.ActiveCfg = Release MinDependency|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Release MinDependency|Win32.Build.0 = Release MinDependency|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Release MinSize|Win32.ActiveCfg = Release MinSize|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Release MinSize|Win32.Build.0 = Release MinSize|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Unicode Debug|Win32.ActiveCfg = Unicode Debug|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Unicode Debug|Win32.Build.0 = Unicode Debug|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Unicode Release MinDependency|Win32.ActiveCfg = Unicode Release MinDependency|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Unicode Release MinDependency|Win32.Build.0 = Unicode Release MinDependency|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Unicode Release MinSize|Win32.ActiveCfg = Unicode Release MinSize|Win32 + {92A6B531-401E-4900-8217-169A96F4168D}.Unicode Release MinSize|Win32.Build.0 = Unicode Release MinSize|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.vcproj b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.vcproj new file mode 100644 index 000000000..1a9068d31 --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/XCallback_Impl.vcproj @@ -0,0 +1,816 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/test/ole/unoTocomCalls/XCallback_Impl/resource.h b/extensions/test/ole/unoTocomCalls/XCallback_Impl/resource.h new file mode 100644 index 000000000..2864478cd --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/XCallback_Impl/resource.h @@ -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 . + */ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by XCallback_Impl.rc + +#define IDS_PROJNAME 100 +#define IDR_CALLBACK 101 +#define IDR_SIMPLE 102 +#define IDR_SIMPLESTRUCT 103 + +// Next default values for new objects + +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 201 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 104 +#endif +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/extensions/test/ole/unoTocomCalls/readme.txt b/extensions/test/ole/unoTocomCalls/readme.txt new file mode 100644 index 000000000..feb46b11e --- /dev/null +++ b/extensions/test/ole/unoTocomCalls/readme.txt @@ -0,0 +1,9 @@ +The directory XCallback_Impl contains a MSDEV project that +creates a dll containing the ActiveX components +XCallback_Impl.Simple and XCallback_Impl.Callback +Callback implements functions defined in oletest.XCallback +and Simple implements functions defined in oletest.XSimple. +These interfaces are build in extensions/test/ole/cpnt + +The projects in unoToComCalls test the functionality of COM +and JScript object which implement UNO interfaces. diff --git a/extensions/test/pgp/TestPGP.java b/extensions/test/pgp/TestPGP.java new file mode 100644 index 000000000..ce719a530 --- /dev/null +++ b/extensions/test/pgp/TestPGP.java @@ -0,0 +1,95 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +import com.sun.star.bridge.UnoUrlResolver; +import com.sun.star.bridge.XUnoUrlResolver; +import com.sun.star.comp.helper.Bootstrap; +import com.sun.star.connection.XConnection; +import com.sun.star.connection.XConnector; +import com.sun.star.container.XSet; +import com.sun.star.lang.XMultiServiceFactory; +import com.sun.star.lang.XSingleServiceFactory; +import com.sun.star.pgp.SimplePGPMailerFactoryReg; +import com.sun.star.uno.IBridge; +import com.sun.star.uno.Type; +import com.sun.star.uno.UnoRuntime; +import com.sun.star.uno.XInterface; +import com.sun.star.uno.XNamingService; + + + +public class TestPGP { + + + static void doSomething(Object r) throws com.sun.star.uno.Exception, Exception { + XNamingService rName = UnoRuntime.queryInterface(XNamingService.class, r); + + if(rName != null) { + System.err.println("got the remote naming service !"); + Object rXsmgr = rName.getRegisteredObject("StarOffice.ServiceManager"); + + XMultiServiceFactory rSmgr = UnoRuntime.queryInterface(XMultiServiceFactory.class, rXsmgr); + if(rSmgr != null) { + System.err.println("got the remote service manager !"); + } + + XSet set= UnoRuntime.queryInterface(XSet.class, rSmgr); + if( set == null) { + System.err.println(" couldn't get XSet from ServiceFactory"); + return; + } + SimplePGPMailerFactoryReg mailerReg= new SimplePGPMailerFactoryReg(); + XSingleServiceFactory factory= mailerReg.getServiceFactory( + "com.sun.star.pgp.SimplePGPMailerImpl", rSmgr, null, null); + + if( factory == null) { + System.err.println("couldn't create PGP factory !"); + return; + } + set.insert(factory ); + System.err.println("PGP factory inserted into service manager"); + + } + } + + + + public static void main(String argv[]) throws Exception { + if(argv.length != 1) { + System.err.println("usage : testoffice protocol:host:port"); + System.exit(-1); + } + + XUnoUrlResolver resolver = UnoUrlResolver.create(Bootstrap.createInitialComponentContext(null)); + + XConnector xConnector = UnoRuntime.queryInterface(XConnector.class, resolver.resolve("com.sun.star.connection.Connector")); + XConnection xConnection = xConnector.connect(argv[0]); + + String rootOid = "classic_uno"; + IBridge iBridge = UnoRuntime.getBridgeByName("java", null, "remote", null, new Object[]{"iiop", xConnection, null}); + + Object rInitialObject = iBridge.mapInterfaceFrom(rootOid, new Type(XInterface.class)); + + if(rInitialObject != null) { + System.err.println("got the remote object"); + doSomething(rInitialObject); + } + } +} + diff --git a/extensions/test/pgp/makefile.mk b/extensions/test/pgp/makefile.mk new file mode 100644 index 000000000..d5805fbe1 --- /dev/null +++ b/extensions/test/pgp/makefile.mk @@ -0,0 +1,62 @@ +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +PRJ=..$/.. + +PRJNAME := extensions +PACKAGE := +TARGET := test_com_sun_star_pgp + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# Files -------------------------------------------------------- + +APPLICATRDB := $(SOLARBINDIR)$/applicat.rdb +RDB := $(APPLICATRDB) + +JARFILES= jurt.jar + +GENJAVACLASSFILES= \ + $(CLASSDIR)$/com$/sun$/star$/beans$/PropertyValue.class \ + $(CLASSDIR)$/com$/sun$/star$/beans$/PropertyState.class \ + $(CLASSDIR)$/com$/sun$/star$/container$/XSet.class \ + +JAVACLASSFILES= \ + $(CLASSDIR)$/$(PACKAGE)$/TestPGP.class + + +TYPES={$(subst,.class, $(subst,$/,. $(subst,$(CLASSDIR)$/,-T $(GENJAVACLASSFILES))))} +GENJAVAFILES = {$(subst,.class,.java $(subst,$/class, $(GENJAVACLASSFILES)))} +JAVAFILES= $(subst,$(CLASSDIR)$/$(PACKAGE)$/, $(subst,.class,.java $(JAVACLASSFILES))) $(GENJAVAFILES) + +# --- Targets ------------------------------------------------------ + +.IF "$(depend)" == "" +ALL : $(GENJAVAFILES) ALLTAR +.ELSE +ALL: ALLDEP +.ENDIF + +.INCLUDE : target.mk + +$(GENJAVAFILES) : $(RDB) + javamaker @$(mktmp -BUCR -O$(OUT) $(TYPES) $(RDB)) + +$(JAVACLASSFILES) : $(GENJAVAFILES) diff --git a/extensions/test/pgp/readme.txt b/extensions/test/pgp/readme.txt new file mode 100644 index 000000000..8d4868770 --- /dev/null +++ b/extensions/test/pgp/readme.txt @@ -0,0 +1,33 @@ +The program TestPGP instantiates a SimplePGPMailerFactory and adds + it to the ServiceManager obtained from a running StarOffice. +Then PGP can be used from within StarOffice. + +Prerequisites: +StarOffice needs an entry in Office/user/sofficerc under the Common + section: + + Port2=socket:hamburg-11070:1111 // old style +as of 569 m +Connection=socket,hamburg-11070,port=1111;iiop; + +Please note the semicolons! + + hamburg-11070 is the host running the office and 1111 is a + freely choosable port number. + + + For the program to run make sure that the office has access + to classes.zip, libreoffice.jar, pgp.jar and swingall.jar. + + Therefore do the necessary entries in + Office/user/config/javarc + under SystemClasspath. + +There is a bug with jdk1.1.8, therefore use 1.2 instead. + +The TestPGP is called without ;iiop; : + +java TestPGP "socket,host=localhost,port=1111" + + + diff --git a/extensions/uiconfig/sabpilot/ui/contentfieldpage.ui b/extensions/uiconfig/sabpilot/ui/contentfieldpage.ui new file mode 100644 index 000000000..d28bcd105 --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/contentfieldpage.ui @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + True + False + True + True + 6 + vertical + 6 + + + True + False + True + True + 12 + True + + + True + False + True + True + vertical + 6 + + + True + False + start + Existing fields + True + selectfield + + + False + True + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore1 + False + 0 + False + + + + + + 6 + + + + 0 + + + + + + + + + True + True + 1 + + + + + True + True + 0 + + + + + True + False + True + True + vertical + 6 + + + True + False + start + start + Display field + True + True + displayfield + + + False + True + 0 + + + + + True + True + True + True + False + + + False + True + 1 + + + + + True + False + True + True + True + 35 + 35 + 0 + 0 + + + static + + + + + False + True + 2 + + + + + True + True + 1 + + + + + True + True + 0 + + + + diff --git a/extensions/uiconfig/sabpilot/ui/contenttablepage.ui b/extensions/uiconfig/sabpilot/ui/contenttablepage.ui new file mode 100644 index 000000000..01cd51f2d --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/contenttablepage.ui @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + True + 0 + none + + + True + False + True + 6 + 12 + 6 + + + + True + False + 12 + 6 + + + True + False + start + Data source + + + 0 + 0 + + + + + True + False + start + Content type + + + 0 + 1 + + + + + True + False + start + Content + + + 0 + 2 + + + + + True + False + start + + + 1 + 0 + + + + + True + False + start + + + 1 + 1 + + + + + True + False + start + + + 1 + 2 + + + + + False + True + 0 + + + + + + + True + False + Form + + + + + + + + False + True + 0 + + + + + True + False + True + True + 0 + none + + + True + False + True + True + 12 + True + 12 + 6 + + + True + False + start + start + True + On the right side, you see all the tables from the data source of the form. + + +Choose the table from which the data should be used as basis for the list content: + True + True + table + 35 + 35 + 0 + 0 + + + False + True + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore1 + False + 0 + False + + + + + + 6 + + + + 0 + + + + + + + + + False + True + 1 + + + + + + + True + False + Control + + + + + + + + True + True + 2 + + + + diff --git a/extensions/uiconfig/sabpilot/ui/datasourcepage.ui b/extensions/uiconfig/sabpilot/ui/datasourcepage.ui new file mode 100644 index 000000000..3a5ef2419 --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/datasourcepage.ui @@ -0,0 +1,235 @@ + + + + + + + True + False + 6 + 12 + + + True + False + That was all the information necessary to integrate your address data into %PRODUCTNAME. + +Now, just enter the name under which you want to register the data source in %PRODUCTNAME. + True + 70 + 70 + 0 + 0 + + + static + + + + + 0 + 0 + + + + + + True + False + True + 6 + + + Embed this address book definition into the current document. + True + True + False + True + True + + + 0 + 0 + + + + + + True + False + True + 12 + + + True + False + Location + True + location + 0 + + + 0 + 0 + + + + + Browse... + True + True + True + True + + + Specifies the location using a file dialog. + + + + + 2 + 0 + + + + + True + False + True + True + + + True + True + True + + + + + Specifies the location of the database file. + + + + + 1 + 0 + + + + + 0 + 1 + + + + + Make this address book available to all modules in %PRODUCTNAME. + True + True + False + True + True + + + Registers the newly created database file in the office suite. The database will then be listed in the Data sources pane (Ctrl+Shift+F4). If this check box is cleared, the database will be available only by opening the database file. + + + + + 0 + 2 + + + + + + True + False + True + 6 + 12 + + + + True + False + True + 12 + + + True + False + Address book name + True + name + 0 + + + 0 + 0 + + + + + True + True + True + True + True + + + Specifies the data source name. + + + + + 1 + 0 + + + + + 0 + 0 + + + + + False + True + Another data source already has this name. As data sources have to have globally unique names, you need to choose another one. + True + 70 + 70 + 0 + 0 + + + static + + + + + 0 + 1 + + + + + 0 + 3 + + + + + 0 + 1 + + + + + Specifies a location for the address book file and a name under which the data source will be listed in the data source explorer. + + + + diff --git a/extensions/uiconfig/sabpilot/ui/defaultfieldselectionpage.ui b/extensions/uiconfig/sabpilot/ui/defaultfieldselectionpage.ui new file mode 100644 index 000000000..f244af27e --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/defaultfieldselectionpage.ui @@ -0,0 +1,94 @@ + + + + + + True + False + True + True + 6 + vertical + 6 + + + True + False + start + Should one option field be selected as a default? + True + + + static + + + + + False + True + 1 + + + + + True + False + 12 + + + _Yes, the following: + True + True + False + True + True + True + + + + + + False + True + 0 + + + + + True + False + + + + + + False + True + 1 + + + + + False + True + 2 + + + + + No, one particular field is not going to be selected. + True + True + False + True + True + defaultselectionyes + + + False + True + 3 + + + + diff --git a/extensions/uiconfig/sabpilot/ui/fieldassignpage.ui b/extensions/uiconfig/sabpilot/ui/fieldassignpage.ui new file mode 100644 index 000000000..ca2c8a68e --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/fieldassignpage.ui @@ -0,0 +1,81 @@ + + + + + + + True + False + 6 + 12 + + + True + False + To incorporate the address data in your templates, %PRODUCTNAME has to know which fields contain which data. + +For instance, you could have stored the email addresses in a field named "email", or "E-mail" or "EM" - or something completely different. + +Click the button below to open another dialog where you can enter the settings for your data source. + True + 70 + 70 + 0 + 0 + + + static + + + + + 0 + 0 + + + + + Field Assignment + True + True + True + center + True + + + Opens the Templates: Address Book Assignment dialog. + + + + + 0 + 1 + + + + + True + False + True + True + 70 + 0 + 0 + + + static + + + + + 0 + 2 + + + + + Opens a dialog that allows you to specify the field assignment. + + + + diff --git a/extensions/uiconfig/sabpilot/ui/fieldlinkpage.ui b/extensions/uiconfig/sabpilot/ui/fieldlinkpage.ui new file mode 100644 index 000000000..2df466a32 --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/fieldlinkpage.ui @@ -0,0 +1,150 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + This is where you select fields with matching contents so that the value from the display field will be shown. + True + 70 + 70 + 0 + 0 + + + static + + + + + False + True + 0 + + + + + True + False + True + True + 6 + + + True + False + True + True + vertical + 6 + + + True + False + start + Field from the _Value Table + True + valuefield + + + False + True + 0 + + + + + True + False + True + True + + + True + True + True + + + + + False + True + 1 + + + + + True + True + 0 + + + + + True + False + True + True + vertical + 6 + + + True + False + start + Field from the _List Table + True + listtable + + + False + True + 0 + + + + + True + False + True + True + + + True + True + True + + + + + False + True + 1 + + + + + True + True + 1 + + + + + True + True + 1 + + + + diff --git a/extensions/uiconfig/sabpilot/ui/gridfieldsselectionpage.ui b/extensions/uiconfig/sabpilot/ui/gridfieldsselectionpage.ui new file mode 100644 index 000000000..35b764e94 --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/gridfieldsselectionpage.ui @@ -0,0 +1,403 @@ + + + + + + + + + + + + + + + + + + + + + + 200 + True + False + True + True + 6 + vertical + 12 + + + True + False + start + True + 0 + none + + + True + False + True + 12 + 12 + 6 + + + + True + False + 6 + + + True + False + start + Data source + + + 0 + 0 + + + + + True + False + start + Content type + + + 0 + 1 + + + + + True + False + start + Content + + + 0 + 2 + + + + + False + True + 0 + + + + + + True + False + True + 6 + + + True + False + start + + + 0 + 0 + + + + + True + False + start + + + 0 + 1 + + + + + True + False + start + + + 0 + 2 + + + + + False + True + 1 + + + + + + + True + False + Form + + + + + + + + False + True + 0 + + + + + True + False + True + True + 0 + none + + + + True + False + True + True + 6 + 12 + 12 + 6 + + + True + True + True + True + in + + + True + True + True + True + True + liststore1 + False + 0 + False + + + + + + 6 + + + + 0 + + + + + + + + + 2 + 1 + + + + + True + False + start + Selected fields + True + selectedfields + + + 2 + 0 + + + + + True + False + vertical + 6 + + + True + False + vertical + 6 + start + + + -> + True + True + True + + + False + True + 0 + + + + + =>> + True + True + True + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + vertical + 6 + start + + + <- + True + True + True + + + False + True + 0 + + + + + <<= + True + True + True + + + False + True + 1 + + + + + False + True + 1 + + + + + 1 + 1 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore2 + False + 0 + False + + + + + + 6 + + + + 0 + + + + + + + + + 0 + 1 + + + + + True + False + start + Existing fields + True + existingfields + + + 0 + 0 + + + + + + + + + + True + False + Table Element + + + + + + + + True + True + 2 + + + + diff --git a/extensions/uiconfig/sabpilot/ui/groupradioselectionpage.ui b/extensions/uiconfig/sabpilot/ui/groupradioselectionpage.ui new file mode 100644 index 000000000..2ab855d41 --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/groupradioselectionpage.ui @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + 200 + True + False + True + True + 6 + vertical + 12 + + + False + start + True + 0 + none + + + True + False + True + 12 + 12 + 6 + + + + True + False + 6 + 6 + + + True + False + start + Data source + + + 0 + 0 + + + + + True + False + start + Content type + + + 0 + 1 + + + + + True + False + start + Content + + + 0 + 2 + + + + + True + False + start + + + 1 + 0 + + + + + True + False + start + + + 1 + 1 + + + + + True + False + start + + + 1 + 2 + + + + + False + True + 0 + + + + + + + True + False + Form + + + + + + + + False + True + 0 + + + + + True + False + True + True + 0 + none + + + + True + False + True + True + 6 + 12 + 12 + 6 + + + True + True + True + True + in + + + True + True + True + True + True + liststore1 + False + 0 + False + + + + + + 6 + + + + 0 + + + + + + + + + 2 + 1 + + + + + True + False + start + _Option fields + True + radiobuttons + 0 + 0 + + + 2 + 0 + + + + + True + False + vertical + 6 + start + + + _>> + True + True + True + True + + + False + True + 0 + + + + + _<< + True + True + True + True + + + False + True + 1 + + + + + 1 + 1 + + + + + True + True + start + True + True + + + 0 + 1 + + + + + True + False + Which _names do you want to give the option fields? + True + True + radiolabels + 35 + 35 + 0 + 0 + + + 0 + 0 + + + + + + + + + + True + False + Table Element + + + + + + + + False + True + 2 + + + + + + + + + + + + diff --git a/extensions/uiconfig/sabpilot/ui/invokeadminpage.ui b/extensions/uiconfig/sabpilot/ui/invokeadminpage.ui new file mode 100644 index 000000000..42db6c542 --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/invokeadminpage.ui @@ -0,0 +1,80 @@ + + + + + + + True + False + 6 + 12 + + + True + False + To set up the new data source, additional information is required. + +Click the following button to open another dialog in which you then enter the necessary information. + True + 70 + 70 + 0 + 0 + + + static + + + + + 0 + 0 + + + + + Settings + True + True + True + center + + + Calls a dialog in which you can enter additional settings. + + + + + 0 + 1 + + + + + False + True + The connection to the data source could not be established. +Before you proceed, please check the settings made, or (on the previous page) choose another address data source type. + True + 70 + 70 + 0 + 0 + + + static + + + + + 0 + 2 + + + + + Allows you to enter additional settings for LDAP address data and other external data sources. + + + + diff --git a/extensions/uiconfig/sabpilot/ui/optiondbfieldpage.ui b/extensions/uiconfig/sabpilot/ui/optiondbfieldpage.ui new file mode 100644 index 000000000..e701b9827 --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/optiondbfieldpage.ui @@ -0,0 +1,113 @@ + + + + + + True + False + True + True + 6 + vertical + 12 + + + True + False + start + start + True + True + 70 + 70 + 0 + + + static + + + + + False + True + 0 + + + + + True + False + start + Do you want to save the value in a database field? + + + static + + + + + False + True + 1 + + + + + + True + False + True + True + 6 + 12 + + + _Yes, I want to save it in the following database field: + True + True + False + True + True + True + + + 0 + 0 + + + + + _No, I only want to save the value in the form. + True + True + False + True + True + yesRadiobutton + + + 0 + 1 + 2 + + + + + True + False + True + + + 1 + 0 + + + + + False + True + 2 + + + + diff --git a/extensions/uiconfig/sabpilot/ui/optionsfinalpage.ui b/extensions/uiconfig/sabpilot/ui/optionsfinalpage.ui new file mode 100644 index 000000000..49f85f66c --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/optionsfinalpage.ui @@ -0,0 +1,63 @@ + + + + + + True + False + True + True + 6 + vertical + 6 + + + True + False + start + Which _caption is to be given to your option group? + True + nameit + + + False + True + 0 + + + + + True + True + True + True + True + + + False + True + 1 + + + + + True + False + end + True + True + These were all details needed to create the option group. + + + static + + + + + True + True + 2 + + + + diff --git a/extensions/uiconfig/sabpilot/ui/optionvaluespage.ui b/extensions/uiconfig/sabpilot/ui/optionvaluespage.ui new file mode 100644 index 000000000..eb16bd41e --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/optionvaluespage.ui @@ -0,0 +1,166 @@ + + + + + + + + + + + + + + True + False + True + True + 6 + 12 + True + + + True + False + True + True + vertical + 12 + + + True + False + start + start + When you select an option, the option group is given a specific value. + True + 35 + 35 + 0 + + + static + + + + + False + True + 0 + + + + + True + False + start + start + Which _value do you want to assign to each option? + True + True + optionvalue + 35 + 35 + 0 + + + False + True + 1 + + + + + True + True + start + True + True + True + + + False + True + 2 + + + + + True + True + 0 + + + + + True + False + True + True + vertical + 6 + + + True + False + start + _Option fields + True + radiobuttons + + + False + True + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore1 + False + 0 + False + + + + + + 6 + + + + 0 + + + + + + + + + True + True + 1 + + + + + True + True + 1 + + + + diff --git a/extensions/uiconfig/sabpilot/ui/selecttablepage.ui b/extensions/uiconfig/sabpilot/ui/selecttablepage.ui new file mode 100644 index 000000000..55fbb5e9c --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/selecttablepage.ui @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + True + False + 6 + 12 + + + True + False + The external data source you have chosen contains more than one address book. +Please select the one you mainly want to work with: + True + True + table + 70 + 70 + 0 + 0 + + + static + + + + + 0 + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore1 + False + 0 + False + + + + + + 6 + + + + 0 + + + + + + + Specifies the table that is to serve as the address book for the office suite templates. + + + + + + + 0 + 1 + + + + + Specifies a table from the Seamonkey / Netscape address book source that is used as the address book in the office suite. + + + + diff --git a/extensions/uiconfig/sabpilot/ui/selecttypepage.ui b/extensions/uiconfig/sabpilot/ui/selecttypepage.ui new file mode 100644 index 000000000..d7493388c --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/selecttypepage.ui @@ -0,0 +1,211 @@ + + + + + + + True + False + 6 + 12 + + + True + False + %PRODUCTNAME lets you access address data already present in your system. To do this, a %PRODUCTNAME data source will be created in which your address data is available in tabular form. + +This wizard helps you create the data source. + True + 70 + 70 + 0 + 0 + + + static + + + + + 0 + 0 + + + + + + True + False + 6 + + + Evolution + True + True + False + True + True + True + + + Select this option if you already use an address book in Evolution. + + + + + 0 + 1 + + + + + Groupwise + True + True + False + True + True + evolution + + + Select this option if you already use an address book in Groupwise. + + + + + 0 + 2 + + + + + Evolution LDAP + True + True + False + True + True + evolution + + + Select this option if you already use an address book in Evolution LDAP. + + + + + 0 + 3 + + + + + Thunderbird + True + True + False + True + True + evolution + + + Select this option if you already use an address book in Thunderbird or Icedove. + + + + + 0 + 5 + + + + + KDE address book + True + True + False + True + True + evolution + + + Select this option if you already use an address book in KDE Address book (KAddressBook). + + + + + 0 + 6 + + + + + Mac OS X address book + True + True + False + True + True + evolution + + + Select this option if you already use an address book in macOS Address book. + + + + + 0 + 7 + + + + + Other external data source + True + True + False + True + True + evolution + + + Select this option if you want to register another data source as address book in the office suite. + + + + + 0 + 8 + + + + + True + False + Select the type of your external address book: + + + static + + + + + 0 + 0 + + + + + + + + 0 + 1 + + + + + This wizard registers an existing address book as a data source in the office suite. + + + + diff --git a/extensions/uiconfig/sabpilot/ui/tableselectionpage.ui b/extensions/uiconfig/sabpilot/ui/tableselectionpage.ui new file mode 100644 index 000000000..b9f6bbe07 --- /dev/null +++ b/extensions/uiconfig/sabpilot/ui/tableselectionpage.ui @@ -0,0 +1,261 @@ + + + + + + + + + + + + + + + + + + + + + + + + True + False + True + True + 6 + vertical + 6 + + + True + False + True + True + 0 + none + + + True + False + True + True + 6 + True + 12 + 6 + + + True + False + start + True + True + Currently, the form the control belongs to is not (or not completely) bound to a data source. + +Please choose a data source and a table. + + +Please note that the settings made on this page will take effect immediately upon leaving the page. + True + 35 + 35 + 0 + 0 + + + static + + + + + False + True + 0 + + + + + True + False + True + True + vertical + 6 + + + True + False + start + _Data source: + True + datasource + + + False + True + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore2 + False + 1 + False + + + + + + 6 + + + + 0 + + + + + + + + + True + True + 1 + + + + + _... + True + True + True + True + + + False + True + 2 + + + + + True + True + 2 + + + + + True + False + True + True + vertical + 6 + + + True + False + start + _Table / Query: + True + table + + + False + True + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore1 + False + 1 + False + + + + + + 6 + + + + 0 + + + + + + 1 + + + + + + + + + True + True + 1 + + + + + True + True + 3 + + + + + + + True + False + Data + + + + + + + + True + True + 0 + + + + diff --git a/extensions/uiconfig/sbibliography/menubar/menubar.xml b/extensions/uiconfig/sbibliography/menubar/menubar.xml new file mode 100644 index 000000000..3604c1b76 --- /dev/null +++ b/extensions/uiconfig/sbibliography/menubar/menubar.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/extensions/uiconfig/sbibliography/ui/autofiltermenu.ui b/extensions/uiconfig/sbibliography/ui/autofiltermenu.ui new file mode 100644 index 000000000..aa496513f --- /dev/null +++ b/extensions/uiconfig/sbibliography/ui/autofiltermenu.ui @@ -0,0 +1,9 @@ + + + + + + True + False + + diff --git a/extensions/uiconfig/sbibliography/ui/choosedatasourcedialog.ui b/extensions/uiconfig/sbibliography/ui/choosedatasourcedialog.ui new file mode 100644 index 000000000..ec5b09e9d --- /dev/null +++ b/extensions/uiconfig/sbibliography/ui/choosedatasourcedialog.ui @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + False + 6 + Choose Data Source + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + _OK + True + True + True + True + True + True + + + False + True + 0 + + + + + _Cancel + True + True + True + True + + + False + True + 1 + + + + + False + True + end + 0 + + + + + True + False + True + True + 0 + none + + + True + True + True + True + in + 12 + 6 + + + True + True + True + True + True + liststore2 + False + 1 + False + + + + + + True + 6 + + + + 0 + + + + + + + + + + + True + False + Entry + + + + + + + + False + True + 1 + + + + + + ok + cancel + + + diff --git a/extensions/uiconfig/sbibliography/ui/combobox.ui b/extensions/uiconfig/sbibliography/ui/combobox.ui new file mode 100644 index 000000000..9bce67069 --- /dev/null +++ b/extensions/uiconfig/sbibliography/ui/combobox.ui @@ -0,0 +1,40 @@ + + + + + + True + False + 6 + 6 + 6 + + + True + False + center + Table + True + combobox + + + False + True + 0 + + + + + True + False + center + True + + + True + True + 1 + + + + diff --git a/extensions/uiconfig/sbibliography/ui/editbox.ui b/extensions/uiconfig/sbibliography/ui/editbox.ui new file mode 100644 index 000000000..13d54230d --- /dev/null +++ b/extensions/uiconfig/sbibliography/ui/editbox.ui @@ -0,0 +1,39 @@ + + + + + + True + False + 6 + + + True + False + center + Search Key + True + entry + + + False + True + 0 + + + + + True + True + center + True + True + + + False + True + 1 + + + + diff --git a/extensions/uiconfig/sbibliography/ui/generalpage.ui b/extensions/uiconfig/sbibliography/ui/generalpage.ui new file mode 100644 index 000000000..4c0ebf76d --- /dev/null +++ b/extensions/uiconfig/sbibliography/ui/generalpage.ui @@ -0,0 +1,1019 @@ + + + + + + 55535 + 1 + 10 + + + True + False + True + True + vertical + + + True + True + True + True + in + + + True + False + 6 + + + + True + False + 6 + 12 + + + True + False + end + _Short name + True + shortnamecontrol + 1 + + + 0 + 0 + + + + + True + False + _Type + True + authtypecontrol + 1 + + + 2 + 0 + + + + + True + False + Author(s) + True + authorscontrol + 1 + + + 0 + 1 + + + + + True + False + _Publisher + True + publishercontrol + 1 + + + 0 + 2 + + + + + True + False + _Chapter + True + chaptercontrol + 1 + + + 0 + 3 + + + + + True + False + Tit_le + True + titlecontrol + 1 + + + 2 + 1 + + + + + True + False + A_ddress + True + addresscontrol + 1 + + + 2 + 2 + + + + + True + False + Pa_ge(s) + True + pagescontrol + 1 + + + 2 + 3 + + + + + True + False + _Year + True + yearcontrol + 1 + + + 4 + 0 + + + + + True + False + _ISBN + True + isbncontrol + 1 + + + 4 + 2 + + + + + True + False + Editor + True + editorcontrol + 1 + + + 0 + 5 + + + + + True + False + _Book title + True + booktitlecontrol + 1 + + + 0 + 6 + + + + + True + False + Ed_ition + True + editioncontrol + 1 + + + 2 + 5 + + + + + True + False + Volume + True + volumecontrol + 1 + + + 2 + 6 + + + + + True + False + Instit_ution + True + institutioncontrol + 1 + + + 2 + 7 + + + + + True + False + _Month + True + monthcontrol + 1 + + + 2 + 8 + + + + + True + False + Publication t_ype + True + publicationtypecontrol + 1 + + + 4 + 6 + + + + + True + False + University + True + universitycontrol + 1 + + + 4 + 7 + + + + + True + False + Type of re_port + True + reporttypecontrol + 1 + + + 0 + 8 + + + + + True + False + Organi_zation + True + organizationcontrol + 1 + + + 0 + 7 + + + + + True + False + _Journal + True + journalcontrol + 1 + + + 0 + 10 + + + + + True + False + Ann_otation + True + annotationcontrol + 1 + + + 0 + 11 + + + + + True + False + Numb_er + True + numbercontrol + 1 + + + 2 + 10 + + + + + True + False + _Note + True + notecontrol + 1 + + + 2 + 11 + + + + + True + False + Se_ries + True + seriescontrol + 1 + + + 4 + 10 + + + + + True + False + URL + True + urlcontrol + 1 + + + 4 + 11 + + + + + True + False + User-defined field _1 + True + custom1control + 1 + + + 0 + 13 + + + + + True + False + User-defined field _4 + True + custom4control + 1 + + + 0 + 14 + + + + + True + False + User-defined field _2 + True + custom2control + 1 + + + 2 + 13 + + + + + True + False + User-defined field _5 + True + custom5control + 1 + + + 2 + 14 + + + + + True + False + User-defined field _3 + True + custom3control + 1 + + + 4 + 13 + + + + + True + True + True + True + + + 1 + 0 + + + + + True + True + True + + + 3 + 1 + 3 + + + + + True + True + True + True + + + 5 + 0 + + + + + True + True + True + True + + + 1 + 1 + + + + + True + True + True + True + + + 1 + 2 + + + + + True + True + True + True + + + 3 + 2 + + + + + True + True + True + True + + + 5 + 2 + + + + + True + False + + + 3 + 0 + + + + + True + True + True + True + + + 1 + 3 + + + + + True + True + True + True + + + 3 + 3 + + + + + True + True + True + True + + + 1 + 5 + + + + + True + True + True + True + + + 3 + 5 + + + + + True + True + True + True + + + 1 + 6 + + + + + True + True + True + True + + + 3 + 6 + + + + + True + True + True + True + + + 5 + 6 + + + + + True + True + True + True + + + 1 + 7 + + + + + True + True + True + True + + + 3 + 7 + + + + + True + True + True + True + + + 5 + 7 + + + + + True + True + True + True + + + 1 + 8 + + + + + True + True + True + True + + + 3 + 8 + + + + + True + True + True + True + + + 1 + 10 + + + + + True + True + True + True + + + 1 + 11 + + + + + True + True + True + True + + + 3 + 10 + + + + + True + True + True + True + + + 3 + 11 + + + + + True + True + True + True + + + 5 + 10 + + + + + True + True + True + True + + + 5 + 11 + + + + + True + True + True + True + + + 1 + 13 + + + + + True + True + True + True + + + 1 + 14 + + + + + True + True + True + True + + + 3 + 13 + + + + + True + True + True + True + + + 3 + 14 + + + + + True + True + True + True + + + 5 + 13 + + + + + True + False + center + False + + + 0 + 4 + 6 + + + + + True + False + center + + + 0 + 12 + 6 + + + + + True + False + center + + + 0 + 9 + 6 + + + + + True + False + Local copy + True + localurlcontrol + 1 + + + 4 + 14 + + + + + True + False + vertical + + + True + False + + + True + True + True + True + + + False + True + 0 + + + + + Browse... + True + True + True + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + + + Page + True + True + False + True + + + + + + False + True + 0 + + + + + True + False + True + True + adjustment2 + + + + + + True + True + 1 + + + + + False + True + 1 + + + + + 5 + 14 + + + + + + + + + + + + + + + + + + + + + + + + + + + False + True + 0 + + + + + Insert, delete, edit, and organize records in the bibliography database. + + + + diff --git a/extensions/uiconfig/sbibliography/ui/mappingdialog.ui b/extensions/uiconfig/sbibliography/ui/mappingdialog.ui new file mode 100644 index 000000000..b4053eeb7 --- /dev/null +++ b/extensions/uiconfig/sbibliography/ui/mappingdialog.ui @@ -0,0 +1,1077 @@ + + + + + + False + 6 + Column Layout for Table “%1†+ True + 0 + 0 + dialog + + + False + True + True + vertical + 12 + + + False + end + + + _OK + True + True + True + True + True + True + + + False + True + 0 + + + + + _Cancel + True + True + True + True + + + False + True + 1 + + + + + _Help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 1 + + + + + True + False + True + True + 0 + none + + + + True + False + 12 + 6 + True + True + 6 + 12 + + + True + False + end + _Short name + True + identifierCombobox + + + 0 + 0 + + + + + True + False + end + _Author(s) + True + authorCombobox + + + 0 + 1 + + + + + True + False + end + _Publisher + True + publisherCombobox + + + 0 + 2 + + + + + True + False + end + _Chapter + True + chapterCombobox + + + 0 + 3 + + + + + True + False + end + Editor + True + editorCombobox + + + 0 + 5 + + + + + True + False + center + True + + + 1 + 1 + + + + + True + False + center + True + + + 1 + 2 + + + + + True + False + center + True + + + 1 + 3 + + + + + True + False + center + True + + + 1 + 5 + + + + + True + False + end + _Type + True + authorityTypeCombobox + + + 2 + 0 + + + + + True + False + end + _Year + True + yearCombobox + + + 4 + 0 + + + + + True + False + end + Tit_le + True + titleCombobox + + + 2 + 1 + + + + + True + False + center + True + + + 3 + 0 + + + + + True + False + center + True + + + 5 + 0 + + + + + True + False + center + True + + + 3 + 1 + + + + + True + False + end + A_ddress + True + addressCombobox + + + 2 + 2 + + + + + True + False + end + _ISBN + True + ISBNCombobox + + + 4 + 2 + + + + + True + False + end + Pa_ge(s) + True + pagesCombobox + + + 2 + 3 + + + + + True + False + center + True + + + 3 + 2 + + + + + True + False + center + True + + + 5 + 2 + + + + + True + False + center + True + + + 3 + 3 + + + + + True + False + end + Ed_ition + True + editionCombobox + + + 2 + 5 + + + + + True + False + center + True + + + 3 + 5 + + + + + True + False + end + _Book title + True + bookTitleCombobox + + + 0 + 6 + + + + + True + False + end + Volume + True + volumeCombobox + + + 2 + 6 + + + + + True + False + end + Publication t_ype + True + howPublishedCombobox + + + 4 + 6 + + + + + True + False + center + True + + + 1 + 6 + + + + + True + False + center + True + + + 3 + 6 + + + + + True + False + center + True + + + 5 + 6 + + + + + True + False + end + Organi_zation + True + organizationCombobox + + + 0 + 7 + + + + + True + False + end + Instit_ution + True + institutionCombobox + + + 2 + 7 + + + + + True + False + end + Uni_versity + True + schoolCombobox + + + 4 + 7 + + + + + True + False + center + True + + + 1 + 7 + + + + + True + False + center + True + + + 3 + 7 + + + + + True + False + center + True + + + 5 + 7 + + + + + True + False + end + Type of re_port + True + reportTypeCombobox + + + 0 + 8 + + + + + True + False + end + _Month + True + monthCombobox + + + 2 + 8 + + + + + True + False + center + True + + + 1 + 8 + + + + + True + False + center + True + + + 3 + 8 + + + + + True + False + end + _Journal + True + journalCombobox + + + 0 + 10 + + + + + True + False + end + Numb_er + True + numberCombobox + + + 2 + 10 + + + + + True + False + end + Se_ries + True + seriesCombobox + + + 4 + 10 + + + + + True + False + center + True + + + 1 + 10 + + + + + True + False + center + True + + + 3 + 10 + + + + + True + False + center + True + + + 5 + 10 + + + + + True + False + end + Ann_otation + True + annoteCombobox + + + 0 + 11 + + + + + True + False + end + _Note + True + noteCombobox + + + 2 + 11 + + + + + True + False + end + URL + True + URLCombobox + + + 4 + 11 + + + + + True + False + center + True + + + 1 + 11 + + + + + True + False + center + True + + + 3 + 11 + + + + + True + False + center + True + + + 5 + 11 + + + + + True + False + end + User-defined field _1 + True + custom1Combobox + + + 0 + 13 + + + + + True + False + end + User-defined field _2 + True + custom2Combobox + + + 2 + 13 + + + + + True + False + end + User-defined field _3 + True + custom3Combobox + + + 4 + 13 + + + + + True + False + end + User-defined field _4 + True + custom4Combobox + + + 0 + 14 + + + + + True + False + end + User-defined field _5 + True + custom5Combobox + + + 2 + 14 + + + + + True + False + center + True + + + 1 + 13 + + + + + True + False + center + True + + + 3 + 13 + + + + + True + False + center + True + + + 5 + 13 + + + + + True + False + center + True + + + 1 + 14 + + + + + True + False + center + True + + + 3 + 14 + + + + + True + False + center + True + + + 1 + 0 + + + + + 12 + 12 + True + False + vertical + + + + + + 0 + 12 + + + + + 12 + 12 + True + False + vertical + + + + + + 0 + 9 + + + + + 12 + 12 + True + False + vertical + + + + + + 0 + 4 + + + + + True + False + end + Local copy + True + LocalURLCombobox + + + 4 + 14 + + + + + True + False + center + True + + + 5 + 14 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + False + Column Names + + + + + + + + False + True + 0 + + + + + + ok + cancel + help + + + + Lets you map the column headings to data fields from a different data source. To define a different data source for your bibliography, click the Data Source button on the record's Object bar. + + + + diff --git a/extensions/uiconfig/sbibliography/ui/querydialog.ui b/extensions/uiconfig/sbibliography/ui/querydialog.ui new file mode 100644 index 000000000..121e877ee --- /dev/null +++ b/extensions/uiconfig/sbibliography/ui/querydialog.ui @@ -0,0 +1,49 @@ + + + + + + False + True + False + dialog + question + yes-no + + + False + vertical + 2 + + + False + True + + + False + False + 0 + + + + + Do not show this question again. + True + True + False + True + True + + + False + True + 2 + + + + + + + + + diff --git a/extensions/uiconfig/sbibliography/ui/toolbar.ui b/extensions/uiconfig/sbibliography/ui/toolbar.ui new file mode 100644 index 000000000..81e60b5fb --- /dev/null +++ b/extensions/uiconfig/sbibliography/ui/toolbar.ui @@ -0,0 +1,122 @@ + + + + + + True + True + False + + + True + .uno:Bib/source + True + + + False + True + + + + + True + .uno:Bib/sdbsource + Data Source + True + + + False + True + + + + + True + False + + + False + True + + + + + True + .uno:Bib/query + True + + + False + True + + + + + True + False + + + False + True + + + + + True + .uno:Bib/autoFilter + AutoFilter + True + + + False + True + + + + + True + .uno:Bib/standardFilter + Standard Filter + True + + + False + True + + + + + True + .uno:Bib/removeFilter + Reset Filter + True + + + False + True + + + + + True + .uno:Bib/Mapping + Column Arrangement + True + + + Lets you map the column headings to data fields from a different data source. To define a different data source for your bibliography, click the Data Source button on the record's Object bar. + + + + + False + True + + + + + Insert, delete, edit, and organize records in the bibliography database. + + + + diff --git a/extensions/uiconfig/scanner/ui/griddialog.ui b/extensions/uiconfig/scanner/ui/griddialog.ui new file mode 100644 index 000000000..6f8b0d2b4 --- /dev/null +++ b/extensions/uiconfig/scanner/ui/griddialog.ui @@ -0,0 +1,158 @@ + + + + + + False + 6 + True + 0 + 0 + dialog + + + + + + False + vertical + 12 + + + False + end + + + _OK + True + True + True + True + True + True + + + False + True + 0 + + + + + _Cancel + True + True + True + True + + + False + True + 1 + + + + + False + True + end + 0 + + + + + True + False + True + True + 12 + + + True + True + True + True + never + never + in + + + True + False + + + True + False + GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK + True + True + + + + + + + False + True + 0 + + + + + True + False + vertical + 6 + + + True + False + + Linear ascending + Linear descending + Original values + Exponential increasing + + + + False + True + 2 + + + + + _Set + True + True + True + True + + + False + True + 3 + + + + + False + True + 1 + + + + + False + True + 1 + + + + + + ok + cancel + + + diff --git a/extensions/uiconfig/scanner/ui/sanedialog.ui b/extensions/uiconfig/scanner/ui/sanedialog.ui new file mode 100644 index 000000000..da4cd6866 --- /dev/null +++ b/extensions/uiconfig/scanner/ui/sanedialog.ui @@ -0,0 +1,778 @@ + + + + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + 100 + 1 + 10 + + + + + + + + + + + False + 6 + Scanner + True + 0 + 0 + dialog + + + False + vertical + 12 + + + False + True + end + + + _Help + True + True + True + True + True + + + True + True + 0 + + + + + About Dev_ice + True + True + True + True + + + Displays a popup window with information obtained from the scanner driver. + + + + + False + True + 1 + + + + + Create Previe_w + True + True + True + True + + + Scans and displays the document in the preview area. + + + + + False + True + 2 + + + + + _Scan + True + True + True + True + + + Scans an image, and then inserts the result into the document and closes the dialog. + + + + + False + True + 3 + + + + + _Cancel + True + True + True + True + + + False + True + 5 + + + + + False + True + end + 1 + + + + + True + False + 12 + + + True + False + True + True + vertical + 12 + + + True + False + 0 + none + + + + True + False + 12 + 6 + 6 + 12 + + + True + False + _Left: + True + leftSpinbutton + 0 + + + 0 + 0 + + + + + True + False + To_p: + True + topSpinbutton + 0 + + + 0 + 1 + + + + + True + False + _Right: + True + rightSpinbutton + 0 + + + 0 + 2 + + + + + True + False + _Bottom: + True + bottomSpinbutton + 0 + + + 0 + 3 + + + + + True + True + True + True + True + adjustment2 + + + Set the top margin of the scan area. + + + + + 1 + 1 + + + + + True + True + True + True + True + adjustment3 + + + Set the right margin of the scan area. + + + + + 1 + 2 + + + + + True + True + True + True + True + adjustment4 + + + Set the bottom margin of the scan area. + + + + + 1 + 3 + + + + + True + True + True + True + True + adjustment1 + + + Set the left margin of the scan area. + + + + + 1 + 0 + + + + + + + True + False + Scan Area + 0 + + + + + False + True + 0 + + + + + True + False + True + True + 0 + none + + + True + True + center + start + 12 + 6 + True + True + never + never + in + + + True + False + + + True + False + GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK + True + True + + + Displays a preview of the scanned image. The preview area contains eight handles. Drag the handles to adjust the scan area or enter a value in the corresponding margin spin box. + + + + + + + + + + + True + False + Preview + + + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + vertical + 12 + + + + True + False + 6 + 12 + + + True + False + Device _used + True + deviceCombobox + 0 + + + 0 + 0 + + + + + True + False + Resolution [_DPI] + True + reslCombobox + 0 + + + 0 + 1 + + + + + True + False + True + + + Displays a list of available scanners detected in your system. + + + + + 1 + 0 + + + + + True + False + True + + + True + True + + + + + Select the resolution in dots per inch for the scan job. + + + + + 1 + 1 + + + + + False + True + 0 + + + + + True + False + True + True + vertical + 6 + + + Show advanced options + True + True + False + True + True + + + Mark this checkbox to display more configuration options for the scanner device. + + + + + False + True + 0 + + + + + True + False + vertical + 12 + True + + + + True + False + 6 + + + True + False + Options: + True + optionSvTreeListBox + 0 + + + 0 + 0 + + + + + True + True + True + True + in + + + True + True + True + True + True + liststore2 + False + 0 + + + + + + + + + 0 + + + + + + + Displays the list of available scanner driver advanced options. Double click an option to display its contents just below. + + + + + + + 0 + 1 + + + + + False + True + 0 + + + + + + True + False + 6 + + + True + False + start + 0 + + + 0 + 1 + + + + + Se_t + True + True + True + True + + + 0 + 2 + + + + + True + False + + + 0 + 3 + + + + + True + False + + + 0 + 4 + + + + + True + True + False + True + True + + + 0 + 5 + + + + + True + True + True + True + + + 0 + 6 + + + + + True + True + True + True + + + 0 + 7 + + + + + True + False + start + Vector element + True + vectorSpinbutton + 0 + + + 0 + 8 + + + + + True + True + True + True + adjustment5 + + + 0 + 9 + + + + + True + True + True + never + never + in + + + True + False + + + True + False + start + start + 0 + 0 + + + + + + + 0 + 0 + + + + + False + True + 1 + + + + + False + True + 1 + + + + + False + True + 1 + + + + + False + True + 1 + + + + + False + True + 0 + + + + + + help + deviceInfoButton + previewButton + ok + cancel + + + diff --git a/extensions/uiconfig/spropctrlr/ui/browserline.ui b/extensions/uiconfig/spropctrlr/ui/browserline.ui new file mode 100644 index 000000000..275c58aa0 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/browserline.ui @@ -0,0 +1,51 @@ + + + + + + + True + False + True + True + 6 + + + True + False + 0 + + + 0 + 0 + + + + + ... + True + True + True + + + 3 + 0 + + + + + ... + True + True + True + + + 2 + 0 + + + + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/browserpage.ui b/extensions/uiconfig/spropctrlr/ui/browserpage.ui new file mode 100644 index 000000000..171c83727 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/browserpage.ui @@ -0,0 +1,94 @@ + + + + + + + True + False + True + True + 6 + + + True + True + True + True + never + + + True + False + + + True + False + True + True + vertical + + + True + False + start + True + True + 6 + vertical + 6 + True + + + + + + False + True + 0 + + + + + + + + + 0 + 0 + + + + + True + False + 0 + none + + + True + True + False + False + 12 + 6 + + + + + True + False + Help + + + + + + + + 0 + 1 + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/colorlistbox.ui b/extensions/uiconfig/spropctrlr/ui/colorlistbox.ui new file mode 100644 index 000000000..40ae63eac --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/colorlistbox.ui @@ -0,0 +1,18 @@ + + + + + + True + True + True + True + True + True + + 0 + + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/combobox.ui b/extensions/uiconfig/spropctrlr/ui/combobox.ui new file mode 100644 index 000000000..7d3b1c698 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/combobox.ui @@ -0,0 +1,17 @@ + + + + + + True + False + True + True + + + True + True + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/controlfontdialog.ui b/extensions/uiconfig/spropctrlr/ui/controlfontdialog.ui new file mode 100644 index 000000000..3b7c1522c --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/controlfontdialog.ui @@ -0,0 +1,205 @@ + + + + + + False + 6 + Character + dialog + + + + + + False + vertical + 12 + + + False + end + + + _Reset + True + True + True + True + + + False + True + 0 + + + + + _OK + True + True + True + True + True + True + + + False + True + 1 + + + + + _Cancel + True + True + True + True + + + False + True + 2 + + + + + _Help + True + True + True + True + + + False + True + 3 + True + + + + + False + True + end + 0 + + + + + True + True + True + True + True + True + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + False + Font + + + False + + + + + + True + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + True + False + Font Effects + + + 1 + False + + + + + False + True + 1 + + + + + + reset + ok + cancel + help + + + diff --git a/extensions/uiconfig/spropctrlr/ui/datatypedialog.ui b/extensions/uiconfig/spropctrlr/ui/datatypedialog.ui new file mode 100644 index 000000000..987a8384a --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/datatypedialog.ui @@ -0,0 +1,130 @@ + + + + + + False + 6 + New Data Type + True + 0 + 0 + normal + + + + + + False + vertical + 12 + + + False + end + + + _OK + True + True + True + True + True + True + + + False + True + 0 + + + + + _Cancel + True + True + True + True + + + False + True + 1 + + + + + _Help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + + True + False + start + True + True + 6 + 12 + + + True + False + Type a name for the new data type: + True + entry + 0 + + + 0 + 0 + + + + + True + True + True + True + True + + + 0 + 1 + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/extensions/uiconfig/spropctrlr/ui/datefield.ui b/extensions/uiconfig/spropctrlr/ui/datefield.ui new file mode 100644 index 000000000..2369cd25b --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/datefield.ui @@ -0,0 +1,45 @@ + + + + + + True + False + x-office-calendar + 2 + + + True + False + True + 6 + + + True + True + True + True + + + False + True + 0 + + + + + True + True + True + image7 + 1 + True + + + False + True + 1 + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/datetimefield.ui b/extensions/uiconfig/spropctrlr/ui/datetimefield.ui new file mode 100644 index 000000000..f736a8e63 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/datetimefield.ui @@ -0,0 +1,49 @@ + + + + + + 86400000 + 1000 + 60000 + + + True + False + True + 3 + + + True + True + True + False + True + True + + + + + + + False + True + 0 + + + + + True + True + True + True + adjustment1 + + + False + True + 1 + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/formattedcontrol.ui b/extensions/uiconfig/spropctrlr/ui/formattedcontrol.ui new file mode 100644 index 000000000..be3bd8857 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/formattedcontrol.ui @@ -0,0 +1,20 @@ + + + + + + -10000 + 10000 + 1 + 10 + + + True + True + True + True + adjustmentForwardBackward + True + 2 + + diff --git a/extensions/uiconfig/spropctrlr/ui/formattedsample.ui b/extensions/uiconfig/spropctrlr/ui/formattedsample.ui new file mode 100644 index 000000000..60fb76e83 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/formattedsample.ui @@ -0,0 +1,45 @@ + + + + + + -10000 + 10000 + 1 + 10 + + + True + False + True + + + True + True + True + True + + + False + True + 0 + + + + + True + True + True + True + adjustmentForwardBackward + True + 2 + + + False + True + 1 + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/formlinksdialog.ui b/extensions/uiconfig/spropctrlr/ui/formlinksdialog.ui new file mode 100644 index 000000000..aecbfff7a --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/formlinksdialog.ui @@ -0,0 +1,384 @@ + + + + + + False + True + True + 6 + Link fields + True + 0 + 0 + dialog + + + + + + False + True + True + vertical + 12 + + + False + end + + + Suggest + True + True + True + + + False + True + 0 + + + + + _OK + True + True + True + True + True + True + + + False + True + 1 + + + + + _Cancel + True + True + True + True + + + False + True + 2 + + + + + _Help + True + True + True + True + + + False + True + 3 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + vertical + 6 + + + True + False + Sub forms can be used to display detailed data about the current record of the master form. To do this, you can specify which columns in the sub form match which columns in the master form. + True + 60 + 60 + 0 + + + False + True + 0 + + + + + True + False + True + True + + + True + False + label + + + False + True + 0 + + + + + True + False + label + + + False + True + 1 + + + + + False + True + 1 + + + + + True + False + True + 6 + + + True + False + True + True + + + True + True + True + + + + + False + True + 0 + + + + + True + False + True + True + + + True + True + True + + + + + False + True + 1 + + + + + False + True + 2 + + + + + True + False + True + 6 + + + True + False + True + True + + + True + True + True + + + + + False + True + 0 + + + + + True + False + True + True + + + True + True + True + + + + + False + True + 1 + + + + + False + True + 3 + + + + + True + False + True + 6 + + + True + False + True + True + + + True + True + True + + + + + False + True + 0 + + + + + True + False + True + True + + + True + True + True + + + + + False + True + 1 + + + + + False + True + 4 + + + + + True + False + True + 6 + + + True + False + True + True + + + True + True + True + + + + + False + True + 0 + + + + + True + False + True + True + + + True + True + True + + + + + False + True + 1 + + + + + False + True + 5 + + + + + False + True + 1 + + + + + + suggestButton + ok + cancel + help + + + diff --git a/extensions/uiconfig/spropctrlr/ui/formproperties.ui b/extensions/uiconfig/spropctrlr/ui/formproperties.ui new file mode 100644 index 000000000..ba69d3ae2 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/formproperties.ui @@ -0,0 +1,40 @@ + + + + + + True + False + True + True + vertical + + + True + True + True + True + + + False + True + 0 + + + + + False + True + vertical + + + + + + False + True + 1 + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/hyperlinkfield.ui b/extensions/uiconfig/spropctrlr/ui/hyperlinkfield.ui new file mode 100644 index 000000000..ccb2679b3 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/hyperlinkfield.ui @@ -0,0 +1,38 @@ + + + + + + True + False + True + 6 + + + True + True + True + True + + + False + True + 0 + + + + + ... + True + True + True + Activate link + + + False + True + 1 + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/labelselectiondialog.ui b/extensions/uiconfig/spropctrlr/ui/labelselectiondialog.ui new file mode 100644 index 000000000..cf4073db1 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/labelselectiondialog.ui @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + False + 6 + Label Field Selection + True + 0 + dialog + + + + + + False + True + True + vertical + 6 + + + False + end + + + _OK + True + True + True + True + True + True + + + False + True + 0 + + + + + _Cancel + True + True + True + True + + + False + True + 1 + + + + + _Help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + vertical + 6 + + + True + False + start + These are control fields that can be used as label fields for the $controlclass$ $controlname$. + True + True + control + 60 + 60 + 0 + 0 + + + False + True + 0 + + + + + True + False + True + True + in + + + True + True + True + True + liststore1 + False + 1 + True + True + + + + + + 6 + + + + 0 + + + + + + 1 + + + + + + + + + True + True + 1 + + + + + _No assignment + True + True + False + True + True + + + False + True + 2 + + + + + True + True + 1 + + + + + + ok + cancel + help + + + diff --git a/extensions/uiconfig/spropctrlr/ui/listbox.ui b/extensions/uiconfig/spropctrlr/ui/listbox.ui new file mode 100644 index 000000000..21f221d72 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/listbox.ui @@ -0,0 +1,10 @@ + + + + + + True + False + True + + diff --git a/extensions/uiconfig/spropctrlr/ui/listselectdialog.ui b/extensions/uiconfig/spropctrlr/ui/listselectdialog.ui new file mode 100644 index 000000000..1e20a1be3 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/listselectdialog.ui @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + False + 6 + True + 0 + 0 + normal + + + + + + False + vertical + 12 + + + False + end + + + _OK + True + True + True + True + True + True + + + False + True + 0 + + + + + _Cancel + True + True + True + True + + + False + True + 1 + + + + + _Help + True + True + True + True + + + False + True + 2 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + 0 + none + + + True + False + True + True + in + 12 + 6 + + + True + True + True + True + liststore2 + False + False + 0 + False + + + + + + + + + 0 + + + + + + + + + + + True + False + + + + + + + + False + True + 1 + + + + + + ok + cancel + help + + + diff --git a/extensions/uiconfig/spropctrlr/ui/multiline.ui b/extensions/uiconfig/spropctrlr/ui/multiline.ui new file mode 100644 index 000000000..d9570489a --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/multiline.ui @@ -0,0 +1,87 @@ + + + + + + False + True + none + + + True + False + vertical + 6 + + + True + True + in + + + True + True + word + + + + + False + True + 0 + + + + + _OK + True + True + True + True + + + False + True + 1 + + + + + + + True + False + True + 6 + + + True + True + True + + + False + True + 0 + + + + + True + True + True + Multiline Editing + True + + + + + + + False + True + 1 + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/numericfield.ui b/extensions/uiconfig/spropctrlr/ui/numericfield.ui new file mode 100644 index 000000000..0cd1d0645 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/numericfield.ui @@ -0,0 +1,17 @@ + + + + + + 100 + 1 + 10 + + + True + True + True + True + adjustment1 + + diff --git a/extensions/uiconfig/spropctrlr/ui/taborder.ui b/extensions/uiconfig/spropctrlr/ui/taborder.ui new file mode 100644 index 000000000..70a0d521a --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/taborder.ui @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + False + 6 + Tab Order + True + 0 + 0 + dialog + + + False + vertical + 12 + + + False + end + + + _OK + True + True + True + True + True + True + + + False + True + 3 + + + + + _Cancel + True + True + True + True + + + False + True + 4 + + + + + _Help + True + True + True + True + + + False + True + 5 + True + + + + + False + True + end + 0 + + + + + True + False + True + True + 0 + none + + + + True + False + 12 + True + True + 12 + 6 + + + True + True + True + True + in + + + True + True + True + True + liststore1 + False + False + True + 0 + False + + + + + + + + + 0 + + + + + + + + + + 1 + + + + + + + Lists all controls in the form. These controls can be selected with the tab key in the given order from top to bottom. + + + + + + + 0 + 0 + + + + + True + False + vertical + 6 + start + + + _Move Up + True + True + True + True + + + False + True + 0 + + + + + Move _Down + True + True + True + True + + + False + True + 1 + + + + + _Automatic Sort + True + True + True + True + + + False + True + 2 + + + + + 1 + 0 + + + + + + + True + False + Controls + + + + + + + + False + True + 1 + + + + + + ok + cancel + help + + + + + + diff --git a/extensions/uiconfig/spropctrlr/ui/textfield.ui b/extensions/uiconfig/spropctrlr/ui/textfield.ui new file mode 100644 index 000000000..d222cb2e7 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/textfield.ui @@ -0,0 +1,11 @@ + + + + + + True + True + True + True + + diff --git a/extensions/uiconfig/spropctrlr/ui/timefield.ui b/extensions/uiconfig/spropctrlr/ui/timefield.ui new file mode 100644 index 000000000..1203ed5e3 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/timefield.ui @@ -0,0 +1,17 @@ + + + + + + 86400000 + 1000 + 60000 + + + True + True + True + True + adjustment1 + + diff --git a/extensions/uiconfig/spropctrlr/ui/urlcontrol.ui b/extensions/uiconfig/spropctrlr/ui/urlcontrol.ui new file mode 100644 index 000000000..20db00e19 --- /dev/null +++ b/extensions/uiconfig/spropctrlr/ui/urlcontrol.ui @@ -0,0 +1,17 @@ + + + + + + True + False + True + True + + + True + True + + + + -- cgit v1.2.3