diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 05:54:39 +0000 |
commit | 267c6f2ac71f92999e969232431ba04678e7437e (patch) | |
tree | 358c9467650e1d0a1d7227a21dac2e3d08b622b2 /basctl | |
parent | Initial commit. (diff) | |
download | libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip |
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'basctl')
143 files changed, 38839 insertions, 0 deletions
diff --git a/basctl/AllLangMoTarget_basctl.mk b/basctl/AllLangMoTarget_basctl.mk new file mode 100644 index 0000000000..4c9a27bfdb --- /dev/null +++ b/basctl/AllLangMoTarget_basctl.mk @@ -0,0 +1,11 @@ +# -*- 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,basctl)) + +# vim: set noet sw=4 ts=4: diff --git a/basctl/CppunitTest_basctl_dialogs_test.mk b/basctl/CppunitTest_basctl_dialogs_test.mk new file mode 100644 index 0000000000..0e28c5a748 --- /dev/null +++ b/basctl/CppunitTest_basctl_dialogs_test.mk @@ -0,0 +1,69 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +#************************************************************************* +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +#************************************************************************* + +$(eval $(call gb_CppunitTest_CppunitScreenShot,basctl_dialogs_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,basctl_dialogs_test, \ + basctl/qa/unit/basctl-dialogs-test \ +)) + +$(eval $(call gb_CppunitTest_use_sdk_api,basctl_dialogs_test)) + +$(eval $(call gb_CppunitTest_set_include,basctl_dialogs_test,\ + -I$(SRCDIR)/basctl/source/inc \ + -I$(SRCDIR)/basctl/inc \ + $$(INCLUDE) \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,basctl_dialogs_test, \ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + drawinglayer \ + editeng \ + i18nlangtag \ + i18nutil \ + msfilter \ + oox \ + sal \ + salhelper \ + sax \ + sfx \ + sot \ + svl \ + svt \ + test \ + tl \ + tk \ + ucbhelper \ + unotest \ + utl \ + vcl \ + xo \ +)) + +$(eval $(call gb_CppunitTest_use_external,basctl_dialogs_test,boost_headers)) + +$(eval $(call gb_CppunitTest_use_sdk_api,basctl_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_ure,basctl_dialogs_test)) +$(eval $(call gb_CppunitTest_use_vcl_non_headless_with_windows,basctl_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_rdb,basctl_dialogs_test,services)) + +$(eval $(call gb_CppunitTest_use_configuration,basctl_dialogs_test)) + +$(eval $(call gb_CppunitTest_use_uiconfigs,basctl_dialogs_test,\ + modules/BasicIDE \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/basctl/IwyuFilter_basctl.yaml b/basctl/IwyuFilter_basctl.yaml new file mode 100644 index 0000000000..f72d7e7b7e --- /dev/null +++ b/basctl/IwyuFilter_basctl.yaml @@ -0,0 +1,15 @@ +--- +assumeFilename: basctl/source/basicide/baside2b.cxx +excludelist: + basctl/sdi/basslots.hrc: + # Needed for basctl/sdi/basslots.sdi + - svx/svxids.hrc + - svx/unomid.hxx + - editeng/memberids.h + basctl/source/basicide/basidesh.cxx: + # Needed for TypedWhichId defines is basslots.hxx + - sfx2/dinfdlg.hxx + - sfx2/minfitem.hxx + basctl/source/basicide/baside2b.cxx: + # Needed for implicit dtor + - com/sun/star/container/XHierarchicalNameAccess.hpp diff --git a/basctl/Library_basctl.mk b/basctl/Library_basctl.mk new file mode 100644 index 0000000000..bbd9a00475 --- /dev/null +++ b/basctl/Library_basctl.mk @@ -0,0 +1,139 @@ +# -*- 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/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Library_Library,basctl)) + +$(eval $(call gb_Library_set_componentfile,basctl,basctl/util/basctl,services)) + +$(eval $(call gb_Library_set_include,basctl,\ + -I$(SRCDIR)/basctl/inc \ + -I$(SRCDIR)/basctl/sdi \ + -I$(SRCDIR)/basctl/source/inc \ + $$(INCLUDE) \ + -I$(WORKDIR)/SdiTarget/basctl/sdi \ +)) + +$(eval $(call gb_Library_use_external,basctl,boost_headers)) + +$(eval $(call gb_Library_use_custom_headers,basctl,\ + officecfg/registry \ +)) + +$(eval $(call gb_Library_set_precompiled_header,basctl,basctl/inc/pch/precompiled_basctl)) + +$(eval $(call gb_Library_use_sdk_api,basctl)) + +$(eval $(call gb_Library_use_libraries,basctl,\ + basegfx \ + comphelper \ + cppu \ + cppuhelper \ + editeng \ + fwk \ + sal \ + i18nlangtag \ + sb \ + sfx \ + sot \ + svl \ + svt \ + svx \ + svxcore \ + tk \ + tl \ + utl \ + ucbhelper \ + vcl \ + xmlscript \ +)) + +ifneq ($(ENABLE_WASM_STRIP_ACCESSIBILITY),TRUE) +$(eval $(call gb_Library_add_exception_objects,basctl,\ + basctl/source/accessibility/accessibledialogcontrolshape \ + basctl/source/accessibility/accessibledialogwindow \ +)) +endif + +$(eval $(call gb_Library_add_exception_objects,basctl,\ + basctl/source/basicide/basdoc \ + basctl/source/basicide/IDEComboBox \ + basctl/source/basicide/basicrenderable \ + basctl/source/basicide/baside2b \ + basctl/source/basicide/baside2 \ + basctl/source/basicide/baside3 \ + basctl/source/basicide/basidectrlr \ + basctl/source/basicide/basides1 \ + basctl/source/basicide/basides2 \ + basctl/source/basicide/basides3 \ + basctl/source/basicide/basidesh \ + basctl/source/basicide/basobj2 \ + basctl/source/basicide/basobj3 \ + basctl/source/basicide/bastype2 \ + basctl/source/basicide/bastype3 \ + basctl/source/basicide/bastypes \ + basctl/source/basicide/breakpoint \ + basctl/source/basicide/brkdlg \ + basctl/source/basicide/doceventnotifier \ + basctl/source/basicide/docsignature \ + basctl/source/basicide/documentenumeration \ + basctl/source/basicide/iderdll \ + basctl/source/basicide/layout \ + basctl/source/basicide/linenumberwindow \ + basctl/source/basicide/localizationmgr \ + basctl/source/basicide/macrodlg \ + basctl/source/basicide/moduldl2 \ + basctl/source/basicide/moduldlg \ + basctl/source/basicide/ObjectCatalog \ + basctl/source/basicide/sbxitem \ + basctl/source/basicide/scriptdocument \ + basctl/source/basicide/textwindowpeer \ + basctl/source/basicide/uiobject \ + basctl/source/basicide/unomodel \ + basctl/source/dlged/dlgedclip \ + basctl/source/dlged/dlged \ + basctl/source/dlged/dlgedfac \ + basctl/source/dlged/dlgedfunc \ + basctl/source/dlged/dlgedlist \ + basctl/source/dlged/dlgedmod \ + basctl/source/dlged/dlgedobj \ + basctl/source/dlged/dlgedpage \ + basctl/source/dlged/dlgedview \ + basctl/source/dlged/managelang \ + basctl/source/dlged/propbrw \ +)) + +$(eval $(call gb_Library_add_sdi_headers,basctl,basctl/sdi/basslots)) + +$(eval $(call gb_SdiTarget_SdiTarget,basctl/sdi/basslots,basctl/sdi/baside)) + +$(eval $(call gb_SdiTarget_set_include,basctl/sdi/basslots,\ + -I$(SRCDIR)/svx/sdi \ + -I$(SRCDIR)/sfx2/sdi \ + $$(INCLUDE) \ +)) + +ifeq ($(OS),WNT) +$(eval $(call gb_Library_use_system_win32_libs,basctl,\ + advapi32 \ + gdi32 \ + shell32 \ +)) +endif + +# vim: set noet sw=4 ts=4: diff --git a/basctl/Makefile b/basctl/Makefile new file mode 100644 index 0000000000..ccb1c85a04 --- /dev/null +++ b/basctl/Makefile @@ -0,0 +1,7 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- + +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/basctl/Module_basctl.mk b/basctl/Module_basctl.mk new file mode 100644 index 0000000000..304a81dc9f --- /dev/null +++ b/basctl/Module_basctl.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/. +# +# This file incorporates work covered by the following license notice: +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed +# with this work for additional information regarding copyright +# ownership. The ASF licenses this file to you under the Apache +# License, Version 2.0 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.apache.org/licenses/LICENSE-2.0 . +# + +$(eval $(call gb_Module_Module,basctl)) + +ifneq ($(filter SCRIPTING,$(BUILD_TYPE)),) + +$(eval $(call gb_Module_add_targets,basctl,\ + Library_basctl \ + UIConfig_basicide \ +)) + +$(eval $(call gb_Module_add_l10n_targets,basctl,\ + AllLangMoTarget_basctl \ +)) + +endif + +# screenshots +$(eval $(call gb_Module_add_screenshot_targets,basctl,\ + CppunitTest_basctl_dialogs_test \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/basctl/README.md b/basctl/README.md new file mode 100644 index 0000000000..bf55060766 --- /dev/null +++ b/basctl/README.md @@ -0,0 +1,3 @@ +# BASIC IDE Controls and Dialogs + +Controls and dialogs for BASIC. Contains the BASIC IDE. diff --git a/basctl/UIConfig_basicide.mk b/basctl/UIConfig_basicide.mk new file mode 100644 index 0000000000..2c23fbfb58 --- /dev/null +++ b/basctl/UIConfig_basicide.mk @@ -0,0 +1,59 @@ +# -*- 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/BasicIDE)) + +$(eval $(call gb_UIConfig_add_popupmenufiles,modules/BasicIDE,\ + basctl/uiconfig/basicide/popupmenu/dialog \ + basctl/uiconfig/basicide/popupmenu/tabbar \ +)) + +$(eval $(call gb_UIConfig_add_menubarfiles,modules/BasicIDE,\ + basctl/uiconfig/basicide/menubar/menubar \ +)) + +$(eval $(call gb_UIConfig_add_statusbarfiles,modules/BasicIDE,\ + basctl/uiconfig/basicide/statusbar/statusbar \ +)) + +$(eval $(call gb_UIConfig_add_toolbarfiles,modules/BasicIDE,\ + basctl/uiconfig/basicide/toolbar/dialogbar \ + basctl/uiconfig/basicide/toolbar/findbar \ + basctl/uiconfig/basicide/toolbar/fullscreenbar \ + basctl/uiconfig/basicide/toolbar/insertcontrolsbar \ + basctl/uiconfig/basicide/toolbar/formcontrolsbar \ + basctl/uiconfig/basicide/toolbar/macrobar \ + basctl/uiconfig/basicide/toolbar/standardbar \ + basctl/uiconfig/basicide/toolbar/translationbar \ +)) + +$(eval $(call gb_UIConfig_add_uifiles,modules/BasicIDE,\ + basctl/uiconfig/basicide/ui/basicmacrodialog \ + basctl/uiconfig/basicide/ui/breakpointmenus \ + basctl/uiconfig/basicide/ui/codecomplete \ + basctl/uiconfig/basicide/ui/combobox \ + basctl/uiconfig/basicide/ui/defaultlanguage \ + basctl/uiconfig/basicide/ui/deletelangdialog \ + basctl/uiconfig/basicide/ui/dialogpage \ + basctl/uiconfig/basicide/ui/dockingorganizer \ + basctl/uiconfig/basicide/ui/dockingstack \ + basctl/uiconfig/basicide/ui/dockingwatch \ + basctl/uiconfig/basicide/ui/exportdialog \ + basctl/uiconfig/basicide/ui/gotolinedialog \ + basctl/uiconfig/basicide/ui/importlibdialog \ + basctl/uiconfig/basicide/ui/libpage \ + basctl/uiconfig/basicide/ui/managebreakpoints \ + basctl/uiconfig/basicide/ui/managelanguages \ + basctl/uiconfig/basicide/ui/modulepage \ + basctl/uiconfig/basicide/ui/newlibdialog \ + basctl/uiconfig/basicide/ui/organizedialog \ + basctl/uiconfig/basicide/ui/sortmenu \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/basctl/inc/bitmaps.hlst b/basctl/inc/bitmaps.hlst new file mode 100644 index 0000000000..0dc8e8d2c8 --- /dev/null +++ b/basctl/inc/bitmaps.hlst @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +inline constexpr OUString RID_BMP_BRKENABLED = u"res/im30838.png"_ustr; +inline constexpr OUString RID_BMP_BRKDISABLED = u"res/im30839.png"_ustr; +inline constexpr OUString RID_BMP_STEPMARKER = u"res/im30840.png"_ustr; +inline constexpr OUString RID_BMP_ERRORMARKER = u"res/im30841.png"_ustr; +inline constexpr OUString RID_BMP_LOCKED = u"res/lock.png"_ustr; +inline constexpr OUString RID_BMP_INSTALLATION = u"res/harddisk_16.png"_ustr; +inline constexpr OUString RID_BMP_DOCUMENT = u"res/im30826.png"_ustr; +inline constexpr OUString RID_BMP_MODLIB = u"res/im30820.png"_ustr; +inline constexpr OUString RID_BMP_MODLIBNOTLOADED = u"res/im30827.png"_ustr; +inline constexpr OUString RID_BMP_MODULE = u"res/im30821.png"_ustr; +inline constexpr OUString RID_BMP_MACRO = u"res/im30822.png"_ustr; +inline constexpr OUString RID_BMP_DLGLIB = u"res/dialogfolder_16.png"_ustr; +inline constexpr OUString RID_BMP_DLGLIBNOTLOADED = u"res/dialogfoldernot_16.png"_ustr; +inline constexpr OUString RID_BMP_DIALOG = u"res/im30823.png"_ustr; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/basctl/inc/helpids.h b/basctl/inc/helpids.h new file mode 100644 index 0000000000..2d656b96bf --- /dev/null +++ b/basctl/inc/helpids.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 . + */ +#pragma once + +#include <rtl/ustring.hxx> + +inline constexpr OUString HID_BASICIDE_OBJECTCAT = u"BASCTL_HID_BASICIDE_OBJECTCAT"_ustr; + +inline constexpr OUString HID_BASICIDE_REMOVEWATCH = u"BASCTL_HID_BASICIDE_REMOVEWATCH"_ustr; + +inline constexpr OUString HID_BASICIDE_MODULWINDOW = u"BASCTL_HID_BASICIDE_MODULWINDOW"_ustr; +inline constexpr OUString HID_BASICIDE_DIALOGWINDOW = u"BASCTL_HID_BASICIDE_DIALOGWINDOW"_ustr; + +inline constexpr OUString HID_BASICIDE_EDITORWINDOW = u"BASCTL_HID_BASICIDE_EDITORWINDOW"_ustr; +inline constexpr OUString HID_BASICIDE_BREAKPOINTWINDOW = u"BASCTL_HID_BASICIDE_BREAKPOINTWINDOW"_ustr; +inline constexpr OUString HID_BASICIDE_WATCHWINDOW = u"BASCTL_HID_BASICIDE_WATCHWINDOW"_ustr; +inline constexpr OUString HID_BASICIDE_STACKWINDOW = u"BASCTL_HID_BASICIDE_STACKWINDOW"_ustr; +inline constexpr OUString HID_BASICIDE_TABBAR = u"BASCTL_HID_BASICIDE_TABBAR"_ustr; +inline constexpr OUString HID_BASICIDE_WATCHWINDOW_EDIT = u"BASCTL_HID_BASICIDE_WATCHWINDOW_EDIT"_ustr; +inline constexpr OUString HID_BASICIDE_WATCHWINDOW_LIST = u"BASCTL_HID_BASICIDE_WATCHWINDOW_LIST"_ustr; +inline constexpr OUString HID_BASICIDE_STACKWINDOW_LIST = u"BASCTL_HID_BASICIDE_STACKWINDOW_LIST"_ustr; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/inc/iderdll.hxx b/basctl/inc/iderdll.hxx new file mode 100644 index 0000000000..6bc9bacdaf --- /dev/null +++ b/basctl/inc/iderdll.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 + +namespace basctl +{ +class Shell; +class ExtraData; + +void EnsureIde(); + +void ShellCreated(Shell* pShell); +Shell* GetShell(); +void ShellDestroyed(Shell const* pShell); + +ExtraData* GetExtraData(); + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/inc/pch/precompiled_basctl.cxx b/basctl/inc/pch/precompiled_basctl.cxx new file mode 100644 index 0000000000..c9af42afdd --- /dev/null +++ b/basctl/inc/pch/precompiled_basctl.cxx @@ -0,0 +1,12 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "precompiled_basctl.hxx" + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/inc/pch/precompiled_basctl.hxx b/basctl/inc/pch/precompiled_basctl.hxx new file mode 100644 index 0000000000..1794f96f90 --- /dev/null +++ b/basctl/inc/pch/precompiled_basctl.hxx @@ -0,0 +1,582 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + This file has been autogenerated by update_pch.sh. It is possible to edit it + manually (such as when an include file has been moved/renamed/removed). All such + manual changes will be rewritten by the next run of update_pch.sh (which presumably + also fixes all possible problems, so it's usually better to use it). + + Generated on 2023-07-19 09:19:46 using: + ./bin/update_pch basctl basctl --cutoff=3 --exclude:system --include:module --exclude:local + + If after updating build fails, use the following command to locate conflicting headers: + ./bin/update_pch_bisect ./basctl/inc/pch/precompiled_basctl.hxx "make basctl.build" --find-conflicts +*/ + +#include <sal/config.h> +#if PCH_LEVEL >= 1 +#include <algorithm> +#include <array> +#include <cassert> +#include <chrono> +#include <climits> +#include <cmath> +#include <cstddef> +#include <cstdlib> +#include <cstring> +#include <deque> +#include <float.h> +#include <functional> +#include <initializer_list> +#include <iomanip> +#include <iterator> +#include <limits.h> +#include <limits> +#include <map> +#include <math.h> +#include <memory> +#include <mutex> +#include <new> +#include <numeric> +#include <optional> +#include <ostream> +#include <span> +#include <stddef.h> +#include <stdexcept> +#include <string.h> +#include <string> +#include <string_view> +#include <type_traits> +#include <typeinfo> +#include <unordered_map> +#include <unordered_set> +#include <utility> +#include <vector> +#include <boost/property_tree/ptree_fwd.hpp> +#endif // PCH_LEVEL >= 1 +#if PCH_LEVEL >= 2 +#include <osl/diagnose.h> +#include <osl/doublecheckedlocking.h> +#include <osl/endian.h> +#include <osl/file.hxx> +#include <osl/getglobalmutex.hxx> +#include <osl/interlck.h> +#include <osl/mutex.h> +#include <osl/mutex.hxx> +#include <osl/time.h> +#include <rtl/alloc.h> +#include <rtl/character.hxx> +#include <rtl/instance.hxx> +#include <rtl/locale.h> +#include <rtl/math.h> +#include <rtl/ref.hxx> +#include <rtl/strbuf.h> +#include <rtl/strbuf.hxx> +#include <rtl/string.h> +#include <rtl/string.hxx> +#include <rtl/stringconcat.hxx> +#include <rtl/stringutils.hxx> +#include <rtl/textcvt.h> +#include <rtl/textenc.h> +#include <rtl/uri.hxx> +#include <rtl/ustrbuf.h> +#include <rtl/ustrbuf.hxx> +#include <rtl/ustring.h> +#include <rtl/ustring.hxx> +#include <rtl/uuid.h> +#include <sal/backtrace.hxx> +#include <sal/log.hxx> +#include <sal/macros.h> +#include <sal/saldllapi.h> +#include <sal/types.h> +#include <sal/typesizes.h> +#include <vcl/BinaryDataContainer.hxx> +#include <vcl/EnumContext.hxx> +#include <vcl/GraphicAttributes.hxx> +#include <vcl/GraphicExternalLink.hxx> +#include <vcl/GraphicObject.hxx> +#include <vcl/IDialogRenderable.hxx> +#include <vcl/InterimItemWindow.hxx> +#include <vcl/PrinterSupport.hxx> +#include <vcl/Scanline.hxx> +#include <vcl/WindowPosSize.hxx> +#include <vcl/alpha.hxx> +#include <vcl/animate/Animation.hxx> +#include <vcl/animate/AnimationFrame.hxx> +#include <vcl/bitmap.hxx> +#include <vcl/bitmap/BitmapTypes.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/builderpage.hxx> +#include <vcl/cairo.hxx> +#include <vcl/checksum.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/ctrl.hxx> +#include <vcl/dllapi.h> +#include <vcl/dockwin.hxx> +#include <vcl/event.hxx> +#include <vcl/fntstyle.hxx> +#include <vcl/font.hxx> +#include <vcl/formatter.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/gfxlink.hxx> +#include <vcl/gradient.hxx> +#include <vcl/graph.hxx> +#include <vcl/idle.hxx> +#include <vcl/jobset.hxx> +#include <vcl/kernarray.hxx> +#include <vcl/keycod.hxx> +#include <vcl/keycodes.hxx> +#include <vcl/mapmod.hxx> +#include <vcl/metaactiontypes.hxx> +#include <vcl/metric.hxx> +#include <vcl/outdev.hxx> +#include <vcl/prntypes.hxx> +#include <vcl/region.hxx> +#include <vcl/rendercontext/AddFontSubstituteFlags.hxx> +#include <vcl/rendercontext/AntialiasingFlags.hxx> +#include <vcl/rendercontext/DrawGridFlags.hxx> +#include <vcl/rendercontext/DrawImageFlags.hxx> +#include <vcl/rendercontext/DrawModeFlags.hxx> +#include <vcl/rendercontext/DrawTextFlags.hxx> +#include <vcl/rendercontext/GetDefaultFontFlags.hxx> +#include <vcl/rendercontext/ImplMapRes.hxx> +#include <vcl/rendercontext/InvertFlags.hxx> +#include <vcl/rendercontext/RasterOp.hxx> +#include <vcl/rendercontext/SalLayoutFlags.hxx> +#include <vcl/rendercontext/State.hxx> +#include <vcl/rendercontext/SystemTextColorFlags.hxx> +#include <vcl/salgtype.hxx> +#include <vcl/salnativewidgets.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/syswin.hxx> +#include <vcl/task.hxx> +#include <vcl/texteng.hxx> +#include <vcl/textview.hxx> +#include <vcl/timer.hxx> +#include <vcl/toolboxid.hxx> +#include <vcl/transfer.hxx> +#include <vcl/uitest/factory.hxx> +#include <vcl/vclenum.hxx> +#include <vcl/vclptr.hxx> +#include <vcl/vclreferencebase.hxx> +#include <vcl/vectorgraphicdata.hxx> +#include <vcl/virdev.hxx> +#include <vcl/wall.hxx> +#include <vcl/weld.hxx> +#include <vcl/window.hxx> +#include <vcl/windowstate.hxx> +#include <vcl/wintypes.hxx> +#include <vcl/xtextedt.hxx> +#endif // PCH_LEVEL >= 2 +#if PCH_LEVEL >= 3 +#include <basegfx/basegfxdllapi.h> +#include <basegfx/color/bcolor.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/matrix/hommatrixtemplate.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/point/b2ipoint.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/range/Range2D.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/range/b2irange.hxx> +#include <basegfx/range/b2irectangle.hxx> +#include <basegfx/range/basicrange.hxx> +#include <basegfx/tuple/Size2D.hxx> +#include <basegfx/tuple/Tuple2D.hxx> +#include <basegfx/tuple/Tuple3D.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <basegfx/tuple/b2i64tuple.hxx> +#include <basegfx/tuple/b2ituple.hxx> +#include <basegfx/tuple/b3dtuple.hxx> +#include <basegfx/utils/bgradient.hxx> +#include <basegfx/utils/common.hxx> +#include <basegfx/vector/b2dsize.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/vector/b2enums.hxx> +#include <basegfx/vector/b2isize.hxx> +#include <basegfx/vector/b2ivector.hxx> +#include <basic/basicdllapi.h> +#include <basic/basmgr.hxx> +#include <basic/sbmeth.hxx> +#include <basic/sbmod.hxx> +#include <basic/sbxcore.hxx> +#include <basic/sbxdef.hxx> +#include <basic/sbxobj.hxx> +#include <basic/sbxvar.hxx> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleContext2.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp> +#include <com/sun/star/awt/DeviceInfo.hpp> +#include <com/sun/star/awt/Gradient2.hpp> +#include <com/sun/star/awt/GradientStyle.hpp> +#include <com/sun/star/awt/Key.hpp> +#include <com/sun/star/awt/KeyGroup.hpp> +#include <com/sun/star/awt/XDevice.hpp> +#include <com/sun/star/awt/XUnitConversion.hpp> +#include <com/sun/star/awt/XUserInputInterception.hpp> +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/beans/Property.hpp> +#include <com/sun/star/beans/PropertyState.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XFastPropertySet.hpp> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetOption.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/beans/XVetoableChangeListener.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/datatransfer/DataFlavor.hpp> +#include <com/sun/star/datatransfer/XTransferable2.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp> +#include <com/sun/star/datatransfer/dnd/DNDConstants.hpp> +#include <com/sun/star/datatransfer/dnd/DropTargetDragEvent.hpp> +#include <com/sun/star/datatransfer/dnd/DropTargetDropEvent.hpp> +#include <com/sun/star/datatransfer/dnd/XDragGestureListener.hpp> +#include <com/sun/star/datatransfer/dnd/XDragSourceListener.hpp> +#include <com/sun/star/datatransfer/dnd/XDropTargetListener.hpp> +#include <com/sun/star/drawing/DashStyle.hpp> +#include <com/sun/star/drawing/HatchStyle.hpp> +#include <com/sun/star/drawing/LineCap.hpp> +#include <com/sun/star/drawing/TextFitToSizeType.hpp> +#include <com/sun/star/embed/Aspects.hpp> +#include <com/sun/star/embed/XStorage.hpp> +#include <com/sun/star/form/FormComponentType.hpp> +#include <com/sun/star/frame/XController2.hpp> +#include <com/sun/star/frame/XControllerBorder.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/frame/XDispatchInformationProvider.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XFrame.hpp> +#include <com/sun/star/frame/XInfobarProvider.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/XStatusListener.hpp> +#include <com/sun/star/frame/XStatusbarController.hpp> +#include <com/sun/star/frame/XTerminateListener.hpp> +#include <com/sun/star/frame/XTitle.hpp> +#include <com/sun/star/frame/XTitleChangeBroadcaster.hpp> +#include <com/sun/star/frame/XToolbarController.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/graphic/XPrimitive2D.hpp> +#include <com/sun/star/i18n/Calendar2.hpp> +#include <com/sun/star/i18n/DirectionProperty.hpp> +#include <com/sun/star/i18n/ForbiddenCharacters.hpp> +#include <com/sun/star/i18n/KCharacterType.hpp> +#include <com/sun/star/i18n/LanguageCountryInfo.hpp> +#include <com/sun/star/i18n/LocaleDataItem2.hpp> +#include <com/sun/star/i18n/LocaleItem.hpp> +#include <com/sun/star/i18n/NativeNumberXmlAttributes.hpp> +#include <com/sun/star/i18n/ParseResult.hpp> +#include <com/sun/star/i18n/TransliterationModules.hpp> +#include <com/sun/star/i18n/TransliterationModulesExtra.hpp> +#include <com/sun/star/i18n/UnicodeScript.hpp> +#include <com/sun/star/i18n/WordType.hpp> +#include <com/sun/star/i18n/XNumberFormatCode.hpp> +#include <com/sun/star/i18n/reservedWords.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XTruncate.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/lang/EventObject.hpp> +#include <com/sun/star/lang/Locale.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/script/XLibraryContainer2.hpp> +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <com/sun/star/security/DocumentSignatureInformation.hpp> +#include <com/sun/star/style/NumberingType.hpp> +#include <com/sun/star/style/XStyle.hpp> +#include <com/sun/star/table/BorderLineStyle.hpp> +#include <com/sun/star/task/XStatusIndicatorSupplier.hpp> +#include <com/sun/star/text/textfield/Type.hpp> +#include <com/sun/star/ui/XContextMenuInterception.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/uno/Any.h> +#include <com/sun/star/uno/Any.hxx> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/RuntimeException.hpp> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/uno/Sequence.hxx> +#include <com/sun/star/uno/Type.h> +#include <com/sun/star/uno/Type.hxx> +#include <com/sun/star/uno/TypeClass.hdl> +#include <com/sun/star/uno/XAggregation.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/uno/XCurrentContext.hpp> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/uno/XWeak.hpp> +#include <com/sun/star/uno/genfunc.h> +#include <com/sun/star/uno/genfunc.hxx> +#include <com/sun/star/util/Date.hpp> +#include <com/sun/star/util/DateTime.hpp> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/SearchAlgorithms.hpp> +#include <com/sun/star/util/SearchAlgorithms2.hpp> +#include <com/sun/star/util/SearchFlags.hpp> +#include <com/sun/star/util/SearchOptions2.hpp> +#include <com/sun/star/util/Time.hpp> +#include <com/sun/star/util/XAccounting.hpp> +#include <com/sun/star/util/XUpdatable.hpp> +#include <com/sun/star/view/PrintableState.hpp> +#include <comphelper/accessibleeventnotifier.hxx> +#include <comphelper/broadcasthelper.hxx> +#include <comphelper/compbase.hxx> +#include <comphelper/comphelperdllapi.h> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/errcode.hxx> +#include <comphelper/interfacecontainer2.hxx> +#include <comphelper/interfacecontainer4.hxx> +#include <comphelper/multicontainer2.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propagg.hxx> +#include <comphelper/proparrhlp.hxx> +#include <comphelper/propertycontainer.hxx> +#include <comphelper/propertycontainerhelper.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/propstate.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/string.hxx> +#include <comphelper/uno3.hxx> +#include <comphelper/unoimplbase.hxx> +#include <cppu/cppudllapi.h> +#include <cppu/unotype.hxx> +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/compbase_ex.hxx> +#include <cppuhelper/cppuhelperdllapi.h> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/interfacecontainer.h> +#include <cppuhelper/propshlp.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/weak.hxx> +#include <cppuhelper/weakagg.hxx> +#include <cppuhelper/weakref.hxx> +#include <docmodel/color/ComplexColor.hxx> +#include <docmodel/color/Transformation.hxx> +#include <docmodel/dllapi.h> +#include <docmodel/theme/ThemeColorType.hxx> +#include <drawinglayer/drawinglayerdllapi.h> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/primitive2d/CommonTypes.hxx> +#include <drawinglayer/primitive2d/Primitive2DContainer.hxx> +#include <drawinglayer/primitive2d/Primitive2DVisitor.hxx> +#include <drawinglayer/primitive2d/baseprimitive2d.hxx> +#include <editeng/borderline.hxx> +#include <editeng/editdata.hxx> +#include <editeng/editengdllapi.h> +#include <editeng/editstat.hxx> +#include <editeng/editview.hxx> +#include <editeng/eedata.hxx> +#include <editeng/flditem.hxx> +#include <editeng/forbiddencharacterstable.hxx> +#include <editeng/outliner.hxx> +#include <editeng/outlobj.hxx> +#include <editeng/overflowingtxt.hxx> +#include <editeng/paragraphdata.hxx> +#include <editeng/svxenum.hxx> +#include <editeng/svxfont.hxx> +#include <i18nlangtag/i18nlangtagdllapi.h> +#include <i18nlangtag/lang.h> +#include <i18nlangtag/languagetag.hxx> +#include <i18nutil/i18nutildllapi.h> +#include <i18nutil/paper.hxx> +#include <i18nutil/searchopt.hxx> +#include <i18nutil/transliteration.hxx> +#include <o3tl/cow_wrapper.hxx> +#include <o3tl/deleter.hxx> +#include <o3tl/enumarray.hxx> +#include <o3tl/hash_combine.hxx> +#include <o3tl/safeint.hxx> +#include <o3tl/sorted_vector.hxx> +#include <o3tl/string_view.hxx> +#include <o3tl/strong_int.hxx> +#include <o3tl/typed_flags_set.hxx> +#include <o3tl/underlyingenumvalue.hxx> +#include <o3tl/unit_conversion.hxx> +#include <salhelper/salhelperdllapi.h> +#include <salhelper/simplereferenceobject.hxx> +#include <sfx2/app.hxx> +#include <sfx2/basedlgs.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/chalign.hxx> +#include <sfx2/childwin.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/dllapi.h> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/frame.hxx> +#include <sfx2/groupid.hxx> +#include <sfx2/minfitem.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/request.hxx> +#include <sfx2/shell.hxx> +#include <sfx2/stbitem.hxx> +#include <sfx2/viewfrm.hxx> +#include <sot/exchange.hxx> +#include <sot/formats.hxx> +#include <sot/sotdllapi.h> +#include <svl/SfxBroadcaster.hxx> +#include <svl/cenumitm.hxx> +#include <svl/cintitem.hxx> +#include <svl/eitem.hxx> +#include <svl/hint.hxx> +#include <svl/itempool.hxx> +#include <svl/itemset.hxx> +#include <svl/languageoptions.hxx> +#include <svl/lstner.hxx> +#include <svl/nfkeytab.hxx> +#include <svl/ondemand.hxx> +#include <svl/poolitem.hxx> +#include <svl/setitem.hxx> +#include <svl/srchdefs.hxx> +#include <svl/stritem.hxx> +#include <svl/style.hxx> +#include <svl/stylesheetuser.hxx> +#include <svl/svldllapi.h> +#include <svl/typedwhich.hxx> +#include <svl/undo.hxx> +#include <svl/visitem.hxx> +#include <svl/whichranges.hxx> +#include <svl/whiter.hxx> +#include <svl/zforlist.hxx> +#include <svtools/borderline.hxx> +#include <svtools/colorcfg.hxx> +#include <svtools/statusbarcontroller.hxx> +#include <svtools/svtdllapi.h> +#include <svtools/toolbarmenu.hxx> +#include <svtools/toolboxcontroller.hxx> +#include <svx/XPropertyEntry.hxx> +#include <svx/ipolypolygoneditorcontroller.hxx> +#include <svx/itextprovider.hxx> +#include <svx/sdr/animation/scheduler.hxx> +#include <svx/sdr/overlay/overlayobject.hxx> +#include <svx/sdr/overlay/overlayobjectlist.hxx> +#include <svx/sdr/properties/defaultproperties.hxx> +#include <svx/sdr/properties/properties.hxx> +#include <svx/sdrobjectuser.hxx> +#include <svx/sdtaditm.hxx> +#include <svx/sdtaitm.hxx> +#include <svx/sdtakitm.hxx> +#include <svx/selectioncontroller.hxx> +#include <svx/svddef.hxx> +#include <svx/svddrag.hxx> +#include <svx/svddrgv.hxx> +#include <svx/svdedtv.hxx> +#include <svx/svdedxv.hxx> +#include <svx/svdglev.hxx> +#include <svx/svdglue.hxx> +#include <svx/svdhdl.hxx> +#include <svx/svdhlpln.hxx> +#include <svx/svdlayer.hxx> +#include <svx/svdmark.hxx> +#include <svx/svdmodel.hxx> +#include <svx/svdmrkv.hxx> +#include <svx/svdoattr.hxx> +#include <svx/svdobj.hxx> +#include <svx/svdobjkind.hxx> +#include <svx/svdoedge.hxx> +#include <svx/svdotext.hxx> +#include <svx/svdpntv.hxx> +#include <svx/svdpoev.hxx> +#include <svx/svdsnpv.hxx> +#include <svx/svdsob.hxx> +#include <svx/svdtext.hxx> +#include <svx/svdtrans.hxx> +#include <svx/svdtypes.hxx> +#include <svx/svdundo.hxx> +#include <svx/svdxcgv.hxx> +#include <svx/svxdllapi.h> +#include <svx/xdash.hxx> +#include <svx/xdef.hxx> +#include <svx/xhatch.hxx> +#include <svx/xpoly.hxx> +#include <svx/xtable.hxx> +#include <toolkit/dllapi.h> +#include <toolkit/helper/vclunohelper.hxx> +#include <tools/color.hxx> +#include <tools/date.hxx> +#include <tools/datetime.hxx> +#include <tools/debug.hxx> +#include <tools/degree.hxx> +#include <tools/fldunit.hxx> +#include <tools/fontenum.hxx> +#include <tools/fract.hxx> +#include <tools/gen.hxx> +#include <tools/globname.hxx> +#include <tools/helpers.hxx> +#include <tools/lineend.hxx> +#include <tools/link.hxx> +#include <tools/long.hxx> +#include <tools/mapunit.hxx> +#include <tools/poly.hxx> +#include <tools/ref.hxx> +#include <tools/solar.h> +#include <tools/stream.hxx> +#include <tools/time.hxx> +#include <tools/toolsdllapi.h> +#include <tools/urlobj.hxx> +#include <tools/weakbase.h> +#include <typelib/typeclass.h> +#include <typelib/typedescription.h> +#include <typelib/uik.h> +#include <uno/any2.h> +#include <uno/current_context.h> +#include <uno/data.h> +#include <uno/lbnames.h> +#include <uno/sequence2.h> +#include <unotools/calendarwrapper.hxx> +#include <unotools/charclass.hxx> +#include <unotools/configitem.hxx> +#include <unotools/fontdefs.hxx> +#include <unotools/localedatawrapper.hxx> +#include <unotools/nativenumberwrapper.hxx> +#include <unotools/options.hxx> +#include <unotools/resmgr.hxx> +#include <unotools/syslocale.hxx> +#include <unotools/tempfile.hxx> +#include <unotools/transliterationwrapper.hxx> +#include <unotools/unotoolsdllapi.h> +#include <unotools/weakref.hxx> +#include <xmlscript/xmldlg_imexp.hxx> +#endif // PCH_LEVEL >= 3 +#if PCH_LEVEL >= 4 +#include <baside3.hxx> +#include <basidesh.hxx> +#include <basobj.hxx> +#include <bastype2.hxx> +#include <bastypes.hxx> +#include <dlged.hxx> +#include <dlgeddef.hxx> +#include <dlgedmod.hxx> +#include <dlgedobj.hxx> +#include <dlgedpage.hxx> +#include <dlgedview.hxx> +#include <docsignature.hxx> +#include <iderid.hxx> +#include <localizationmgr.hxx> +#include <managelang.hxx> +#include <scriptdocument.hxx> +#endif // PCH_LEVEL >= 4 + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/inc/strings.hrc b/basctl/inc/strings.hrc new file mode 100644 index 0000000000..324b6ba1d4 --- /dev/null +++ b/basctl/inc/strings.hrc @@ -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 . + */ + +#ifndef BASCTL_INC_BASIDESH_HRC +#define BASCTL_INC_BASIDESH_HRC + +#define NC_(Context, String) TranslateId(Context, u8##String) + +#define RID_STR_FILTER_ALLFILES NC_("RID_STR_FILTER_ALLFILES", "<All>") +#define RID_STR_NOMODULE NC_("RID_STR_NOMODULE", "< No Module >") +#define RID_STR_WRONGPASSWORD NC_("RID_STR_WRONGPASSWORD", "Incorrect Password") +#define RID_STR_NOLIBINSTORAGE NC_("RID_STR_NOLIBINSTORAGE", "The file does not contain any BASIC libraries") +#define RID_STR_BADSBXNAME NC_("RID_STR_BADSBXNAME", "Invalid Name") +#define RID_STR_LIBNAMETOLONG NC_("RID_STR_LIBNAMETOLONG", "A library name can have up to 30 characters.") +#define RID_STR_ERRORCHOOSEMACRO NC_("RID_STR_ERRORCHOOSEMACRO", "Macros from other documents are not accessible.") +#define RID_STR_LIBISREADONLY NC_("RID_STR_LIBISREADONLY", "This library is read-only.") +#define RID_STR_REPLACELIB NC_("RID_STR_REPLACELIB", "'XX' cannot be replaced.") +#define RID_STR_IMPORTNOTPOSSIBLE NC_("RID_STR_IMPORTNOTPOSSIBLE", "'XX' cannot be added.") +#define RID_STR_NOIMPORT NC_("RID_STR_NOIMPORT", "'XX' was not added.") +#define RID_STR_ENTERPASSWORD NC_("RID_STR_ENTERPASSWORD", "Enter password for 'XX'") +#define RID_STR_SBXNAMEALLREADYUSED NC_("RID_STR_SBXNAMEALLREADYUSED", "Name already exists") +#define RID_STR_SIGNED NC_("RID_STR_SIGNED", "(Signed)") +#define RID_STR_SBXNAMEALLREADYUSED2 NC_("RID_STR_SBXNAMEALLREADYUSED2", "Object with same name already exists") +#define RID_STR_CANNOTRUNMACRO NC_("RID_STR_CANNOTRUNMACRO", "For security reasons, you cannot run this macro.\n\nFor more information, check the security settings.") +#define RID_STR_SEARCHNOTFOUND NC_("RID_STR_SEARCHNOTFOUND", "Search key not found") +#define RID_STR_SEARCHFROMSTART NC_("RID_STR_SEARCHFROMSTART", "Search to last module complete. Continue at first module?") +#define RID_STR_SEARCHREPLACES NC_("RID_STR_SEARCHREPLACES", "Search key replaced XX times") +#define RID_STR_COULDNTREAD NC_("RID_STR_COULDNTREAD", "The file could not be read") +#define RID_STR_COULDNTWRITE NC_("RID_STR_COULDNTWRITE", "The file could not be saved") +#define RID_STR_CANNOTCHANGENAMESTDLIB NC_("RID_STR_CANNOTCHANGENAMESTDLIB", "The name of the default library cannot be changed.") +#define RID_STR_GENERATESOURCE NC_("RID_STR_GENERATESOURCE", "Generating source") +#define RID_STR_FILENAME NC_("RID_STR_FILENAME", "File name:") +#define RID_STR_APPENDLIBS NC_("RID_STR_APPENDLIBS", "Import Libraries") +#define RID_STR_QUERYDELMACRO NC_("RID_STR_QUERYDELMACRO", "Do you want to delete the macro XX?") +#define RID_STR_QUERYDELDIALOG NC_("RID_STR_QUERYDELDIALOG", "Do you want to delete the XX dialog?") +#define RID_STR_QUERYDELLIB NC_("RID_STR_QUERYDELLIB", "Do you want to delete the XX library?") +#define RID_STR_QUERYDELLIBREF NC_("RID_STR_QUERYDELLIBREF", "Do you want to delete the reference to the XX library?") +#define RID_STR_QUERYDELMODULE NC_("RID_STR_QUERYDELMODULE", "Do you want to delete the XX module?") +#define RID_STR_BASIC NC_("RID_STR_BASIC", "BASIC") +// Abbreviation for 'line' +#define RID_STR_LINE NC_("RID_STR_LINE", "Ln") +// Abbreviation for 'column' +#define RID_STR_COLUMN NC_("RID_STR_COLUMN", "Col") +#define RID_STR_CANNOTCLOSE NC_("RID_STR_CANNOTCLOSE", "The window cannot be closed while BASIC is running.") +#define RID_STR_REPLACESTDLIB NC_("RID_STR_REPLACESTDLIB", "The default library cannot be replaced.") +#define RID_STR_REFNOTPOSSIBLE NC_("RID_STR_REFNOTPOSSIBLE", "Reference to 'XX' not possible.") +#define RID_STR_WATCHNAME NC_("RID_STR_WATCHNAME", "Watch") +#define RID_STR_STACKNAME NC_("RID_STR_STACKNAME", "Call Stack") +#define RID_STR_STDDIALOGNAME NC_("RID_STR_STDDIALOGNAME", "Dialog") +#define RID_STR_NEWLIB NC_("RID_STR_NEWLIB", "New Library") +#define RID_STR_NEWMOD NC_("RID_STR_NEWMOD", "New Module") +#define RID_STR_NEWDLG NC_("RID_STR_NEWDLG", "New Dialog") +#define RID_STR_ALL NC_("RID_STR_ALL", "All") +#define RID_STR_PAGE NC_("RID_STR_PAGE", "Page") +#define RID_STR_WILLSTOPPRG NC_("RID_STR_WILLSTOPPRG", "You will have to restart the program after this edit.\nContinue?") +#define RID_STR_SEARCHALLMODULES NC_("RID_STR_SEARCHALLMODULES", "Do you want to replace the text in all active modules?") +#define RID_STR_REMOVEWATCH NC_("RID_STR_REMOVEWATCH", "Watch:") +#define RID_STR_STACK NC_("RID_STR_STACK", "Calls: ") +#define RID_STR_USERMACROS NC_("RID_STR_USERMACROS", "My Macros") +#define RID_STR_USERDIALOGS NC_("RID_STR_USERDIALOGS", "My Dialogs") +#define RID_STR_USERMACROSDIALOGS NC_("RID_STR_USERMACROSDIALOGS", "My Macros & Dialogs") +#define RID_STR_SHAREMACROS NC_("RID_STR_SHAREMACROS", "Application Macros") +#define RID_STR_SHAREDIALOGS NC_("RID_STR_SHAREDIALOGS", "Application Dialogs") +#define RID_STR_SHAREMACROSDIALOGS NC_("RID_STR_SHAREMACROSDIALOGS", "Application Macros & Dialogs") +#define RID_STR_REMOVEWATCHTIP NC_("RID_STR_REMOVEWATCHTIP", "Remove Watch") +#define RID_STR_QUERYREPLACEMACRO NC_("RID_STR_QUERYREPLACEMACRO", "Do you want to overwrite the XX macro?") +#define RID_STR_TRANSLATION_NOTLOCALIZED NC_("RID_STR_TRANSLATION_NOTLOCALIZED", "<Not localized>") +#define RID_STR_TRANSLATION_DEFAULT NC_("RID_STR_TRANSLATION_DEFAULT", "[Default Language]") +#define RID_STR_DOCUMENT_OBJECTS NC_("RID_STR_DOCUMENT_OBJECTS", "Document Objects") +#define RID_STR_USERFORMS NC_("RID_STR_USERFORMS", "Forms") +#define RID_STR_NORMAL_MODULES NC_("RID_STR_NORMAL_MODULES", "Modules") +#define RID_STR_CLASS_MODULES NC_("RID_STR_CLASS_MODULES", "Class Modules") +#define RID_STR_DLGIMP_CLASH_RENAME NC_("RID_STR_DLGIMP_CLASH_RENAME", "Rename") +#define RID_STR_DLGIMP_CLASH_REPLACE NC_("RID_STR_DLGIMP_CLASH_REPLACE", "Replace") +#define RID_STR_DLGIMP_CLASH_TITLE NC_("RID_STR_DLGIMP_CLASH_TITLE", "Dialog Import - Name already used") +#define RID_STR_DLGIMP_CLASH_TEXT NC_("RID_STR_DLGIMP_CLASH_TEXT", "The library already contains a dialog with the name:\n\n$(ARG1)\n\nChoose “Rename” to give the imported dialog a new automatic name, or “Replace” to overwrite the existing dialog completely.\n ") +#define RID_STR_DLGIMP_MISMATCH_ADD NC_("RID_STR_DLGIMP_MISMATCH_ADD", "Add") +#define RID_STR_DLGIMP_MISMATCH_OMIT NC_("RID_STR_DLGIMP_MISMATCH_OMIT", "Omit") +#define RID_STR_DLGIMP_MISMATCH_TITLE NC_("RID_STR_DLGIMP_MISMATCH_TITLE", "Dialog Import - Language Mismatch") +#define RID_STR_DLGIMP_MISMATCH_TEXT NC_("RID_STR_DLGIMP_MISMATCH_TEXT", "The dialog to be imported supports other languages than the target library.\n\nAdd these languages to the library to keep additional language resources provided by the dialog or omit them to stay with the current library languages.\n\nNote: For languages not supported by the dialog the resources of the dialog's default language will be used.\n ") +#define RID_STR_PRINTDLG_PAGES NC_("RID_STR_PRINTDLG_PAGES", "Pages:") +#define RID_STR_PRINTDLG_PRINTALLPAGES NC_("RID_STR_PRINTDLG_PRINTALLPAGES", "All ~Pages") +#define RID_STR_PRINTDLG_PRINTPAGES NC_("RID_STR_PRINTDLG_PRINTPAGES", "Pa~ges:") +#define RID_STR_CHOOSE NC_("RID_STR_CHOOSE", "Choose") +#define RID_STR_RUN NC_("RID_STR_RUN", "Run") +#define RID_STR_RECORD NC_("RID_STR_RECORD", "~Save") +#define RID_BASICIDE_OBJCAT NC_("RID_BASICIDE_OBJCAT", "Object Catalog") +// Property Browser Headline ---------------------------------------------------------------- +#define RID_STR_BRWTITLE_PROPERTIES NC_("RID_STR_BRWTITLE_PROPERTIES", "Properties: ") +#define RID_STR_BRWTITLE_NO_PROPERTIES NC_("RID_STR_BRWTITLE_NO_PROPERTIES", "No Control marked") +#define RID_STR_BRWTITLE_MULTISELECT NC_("RID_STR_BRWTITLE_MULTISELECT", "Multiselection") +#define RID_STR_DEF_LANG NC_("RID_STR_DEF_LANG", "[Default Language]") +#define RID_STR_CREATE_LANG NC_("RID_STR_CREATE_LANG", "<Press 'Add' to create language resources>") +#define RID_STR_EXPORTPACKAGE NC_("RID_STR_EXPORTPACKAGE", "Export library as extension") +#define RID_STR_EXPORTBASIC NC_("RID_STR_EXPORTBASIC", "Export as BASIC library") +#define RID_STR_PACKAGE_BUNDLE NC_("RID_STR_PACKAGE_BUNDLE", "Extension") +#define RID_STR_READONLY NC_("RID_STR_READONLY", "Read-only") +#define RID_STR_MODULE_READONLY NC_("RID_STR_READONLY_WARNING", "This module is read-only and cannot be edited.") +#define RID_STR_DIALOG_READONLY NC_("RID_STR_READONLY_WARNING", "This dialog is read-only and cannot be edited.") + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/inc/strings.hxx b/basctl/inc/strings.hxx new file mode 100644 index 0000000000..5481d62de3 --- /dev/null +++ b/basctl/inc/strings.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include <rtl/ustring.hxx> + +// Dialog Controls --------------------------------------------------------------- + +inline constexpr OUString RID_STR_CLASS_CONTROL = u"Control"_ustr; +inline constexpr OUString RID_STR_CLASS_DIALOG = u"Dialog"_ustr; +inline constexpr OUString RID_STR_CLASS_BUTTON = u"CommandButton"_ustr; +inline constexpr OUString RID_STR_CLASS_RADIOBUTTON = u"OptionButton"_ustr; +inline constexpr OUString RID_STR_CLASS_CHECKBOX = u"CheckBox"_ustr; +inline constexpr OUString RID_STR_CLASS_LISTBOX = u"ListBox"_ustr; +inline constexpr OUString RID_STR_CLASS_COMBOBOX = u"ComboBox"_ustr; +inline constexpr OUString RID_STR_CLASS_GROUPBOX = u"FrameControl"_ustr; +inline constexpr OUString RID_STR_CLASS_EDIT = u"TextField"_ustr; +inline constexpr OUString RID_STR_CLASS_FIXEDTEXT = u"Label"_ustr; +inline constexpr OUString RID_STR_CLASS_IMAGECONTROL = u"ImageControl"_ustr; +inline constexpr OUString RID_STR_CLASS_PROGRESSBAR = u"ProgressBar"_ustr; +inline constexpr OUString RID_STR_CLASS_SCROLLBAR = u"ScrollBar"_ustr; +inline constexpr OUString RID_STR_CLASS_FIXEDLINE = u"FixedLine"_ustr; +inline constexpr OUString RID_STR_CLASS_DATEFIELD = u"DateField"_ustr; +inline constexpr OUString RID_STR_CLASS_TIMEFIELD = u"TimeField"_ustr; +inline constexpr OUString RID_STR_CLASS_NUMERICFIELD = u"NumericField"_ustr; +inline constexpr OUString RID_STR_CLASS_CURRENCYFIELD = u"CurrencyField"_ustr; +inline constexpr OUString RID_STR_CLASS_FORMATTEDFIELD = u"FormattedField"_ustr; +inline constexpr OUString RID_STR_CLASS_PATTERNFIELD = u"PatternField"_ustr; +inline constexpr OUString RID_STR_CLASS_FILECONTROL = u"FileControl"_ustr; +inline constexpr OUString RID_STR_CLASS_TREECONTROL = u"TreeControl"_ustr; +inline constexpr OUString RID_STR_CLASS_GRIDCONTROL = u"GridControl"_ustr; +inline constexpr OUString RID_STR_CLASS_SPINCONTROL = u"SpinButton"_ustr; +inline constexpr OUString RID_STR_CLASS_HYPERLINKCONTROL = u"HyperlinkControl"_ustr; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/basctl/qa/unit/basctl-dialogs-test.cxx b/basctl/qa/unit/basctl-dialogs-test.cxx new file mode 100644 index 0000000000..3b58757f38 --- /dev/null +++ b/basctl/qa/unit/basctl-dialogs-test.cxx @@ -0,0 +1,61 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <sal/config.h> +#include <test/screenshot_test.hxx> +#include <vcl/abstdlg.hxx> + +using namespace ::com::sun::star; + +/// Test opening a dialog in basctl +class BasctlDialogsTest : public ScreenshotTest +{ +private: + /// helper method to populate KnownDialogs, called in setUp(). Needs to be + /// written and has to add entries to KnownDialogs + virtual void registerKnownDialogsByID(mapType& rKnownDialogs) override; + + /// dialog creation for known dialogs by ID. Has to be implemented for + /// each registered known dialog + virtual VclPtr<VclAbstractDialog> createDialogByID(sal_uInt32 nID) override; + +public: + BasctlDialogsTest(); + + // try to open a dialog + void openAnyDialog(); + + CPPUNIT_TEST_SUITE(BasctlDialogsTest); + CPPUNIT_TEST(openAnyDialog); + CPPUNIT_TEST_SUITE_END(); +}; + +BasctlDialogsTest::BasctlDialogsTest() {} + +void BasctlDialogsTest::registerKnownDialogsByID(mapType& /*rKnownDialogs*/) +{ + // fill map of known dialogs +} + +VclPtr<VclAbstractDialog> BasctlDialogsTest::createDialogByID(sal_uInt32 /*nID*/) +{ + return nullptr; +} + +void BasctlDialogsTest::openAnyDialog() +{ + /// process input file containing the UXMLDescriptions of the dialogs to dump + processDialogBatchFile(u"basctl/qa/unit/data/basctl-dialogs-test.txt"); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(BasctlDialogsTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/qa/unit/data/basctl-dialogs-test.txt b/basctl/qa/unit/data/basctl-dialogs-test.txt new file mode 100644 index 0000000000..d69912386a --- /dev/null +++ b/basctl/qa/unit/data/basctl-dialogs-test.txt @@ -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 contains all dialogs that the unit tests in the module +# will work on if it is in script mode. It will read one-by-one, +# try to open it and create a screenshot that will be saved in +# workdir/screenshots using the pattern of the ui-file name. +# +# Syntax: +# - empty lines are allowed +# - lines starting with '#' are treated as comment +# - all other lines should contain a *.ui filename in the same +# notation as in the dialog constructors (see code) + +# +# The 'known' dialogs which have a hard-coded representation +# in registerKnownDialogsByID/createDialogByID +# + +# No known dialogs in basctl for now + +# +# Dialogs without a hard-coded representation. These will +# be visualized using a fallback based on weld::Builder +# + +# currently deactivated, leads to problems and the test to not work +# This is typically a hint that these should be hard-coded in the +# test case since they need some document and model data to work + +modules/BasicIDE/ui/organizedialog.ui +modules/BasicIDE/ui/libpage.ui +modules/BasicIDE/ui/managebreakpoints.ui +modules/BasicIDE/ui/basicmacrodialog.ui +modules/BasicIDE/ui/newlibdialog.ui +modules/BasicIDE/ui/gotolinedialog.ui +modules/BasicIDE/ui/exportdialog.ui +modules/BasicIDE/ui/importlibdialog.ui +modules/BasicIDE/ui/managelanguages.ui +modules/BasicIDE/ui/defaultlanguage.ui +modules/BasicIDE/ui/deletelangdialog.ui diff --git a/basctl/sdi/baside.sdi b/basctl/sdi/baside.sdi new file mode 100644 index 0000000000..9e7229ca97 --- /dev/null +++ b/basctl/sdi/baside.sdi @@ -0,0 +1,693 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +interface BasicIDEView +{ +} + +shell basctl_Shell +{ + import BasicIDEView; + + + // Current, according to current window: + + SID_SHOWLINES + [ + StateMethod = GetState; + ExecMethod = ExecuteCurrent; + ] + + SID_BASICIDE_HIDECURPAGE + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_BASICIDE_DELETECURRENT + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_BASICIDE_RENAMECURRENT + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_SELECTALL + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_CUT + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_COPY + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_PASTE + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_UNDO + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_REDO + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_DELETE + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_BACKSPACE + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + SID_GOTOLINE + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + + // Search in IDE Basic + + SID_SEARCH_OPTIONS + [ + ExecMethod = ExecuteSearch; + StateMethod = GetState; + ] + + SID_SEARCH_ITEM + [ + ExecMethod = ExecuteSearch; + StateMethod = GetState; + ] + + FID_SEARCH_NOW + [ + ExecMethod = ExecuteSearch; + StateMethod = GetState; + ] + + SID_BASICIDE_REPEAT_SEARCH + [ + ExecMethod = ExecuteSearch; + StateMethod = GetState; + ] + + FID_SEARCH_ON // status() + [ + ExecMethod = ExecuteSearch; + ] + + FID_SEARCH_OFF + [ + ExecMethod = ExecuteCurrent; + StateMethod = GetState; + ] + + + // Global: Whatever, which window is currently active: + + SID_BASICIDE_LIBSELECTOR + [ + StateMethod = GetState; + ] + + SID_BASICIDE_LIBSELECTED + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_LIBLOADED + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_LIBREMOVED + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_SBXDELETED + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_SBXINSERTED + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_SBXRENAMED + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_SHOWSBX + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_NEWWINDOW + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_DOCINFO + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_NEWDOCDIRECT + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_SAVEDOC + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_SIGNATURE + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_SAVEASDOC + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + // From here on normal ... + SID_BASICIDE_CHOOSEMACRO + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_MODULEDLG + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_OBJCAT + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_WATCH + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_STACK + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_CREATEMACRO + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_EDITMACRO + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_NAMECHANGEDONTAB + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_STOREMODULESOURCE + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_STOREALLMODULESOURCES + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_UPDATEMODULESOURCE + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_UPDATEALLMODULESOURCES + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICSTOP + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_NEWMODULE + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_NEWDIALOG + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_SHOW_PROPERTYBROWSER + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_SHOWWINDOW + [ + ExecMethod = ExecuteGlobal; + ] + + SID_BASICIDE_MANAGE_LANG + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_CURRENT_LANG + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_ATTR_ZOOMSLIDER + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_ZOOM_IN + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_ZOOM_OUT + [ + ExecMethod = ExecuteGlobal; + StateMethod = GetState; + ] + + SID_BASICIDE_CURRENT_ZOOM + [ + StateMethod = GetState; + ] + + // Only, when BasicWindow up + + SID_BASICRUN + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICCOMPILE + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICLOAD + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICSAVEAS + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICIDE_MATCHGROUP + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICSTEPINTO + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICSTEPOVER + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICSTEPOUT + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICIDE_TOGGLEBRKPNT + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICIDE_MANAGEBRKPNTS + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICIDE_TOGGLEBRKPNTENABLED + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICIDE_ADDWATCH + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICIDE_REMOVEWATCH + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + SID_BASICIDE_BRKPNTSCHANGED + [ + ExecMethod = ExecuteBasic; + StateMethod = GetState; + ] + + + // Only, when dialog window up + + SID_CHOOSE_CONTROLS + [ + StateMethod = GetState; + ] + SID_INSERT_PUSHBUTTON + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_CHECKBOX + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_RADIOBUTTON + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_SPINBUTTON + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_FIXEDTEXT + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_GROUPBOX + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_LISTBOX + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_COMBOBOX + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_EDIT + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_HSCROLLBAR + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_VSCROLLBAR + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_SELECT + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_IMAGECONTROL + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_PROGRESSBAR + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_HFIXEDLINE + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_VFIXEDLINE + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_DATEFIELD + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_TIMEFIELD + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_NUMERICFIELD + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_CURRENCYFIELD + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_FORMATTEDFIELD + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_PATTERNFIELD + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_FILECONTROL + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + SID_INSERT_TREECONTROL + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_INSERT_GRIDCONTROL + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_INSERT_HYPERLINKCONTROL + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_EXPORT_DIALOG + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_IMPORT_DIALOG + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_DIALOG_TESTMODE + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_BASICIDE_STAT_POS + [ + StateMethod = GetState; + ] + + SID_BASICIDE_STAT_DATE + [ + StateMethod = GetState; + ] + + SID_BASICIDE_STAT_TITLE + [ + StateMethod = GetState; + ] + + SID_DOC_MODIFIED + [ + StateMethod = GetState; + ] + + SID_ATTR_INSERT + [ + StateMethod = GetState; + ] + + SID_ATTR_SIZE + [ + StateMethod = GetState; + ] + + SID_INSERT_FORM_RADIO + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_INSERT_FORM_CHECK + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_INSERT_FORM_LIST + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_INSERT_FORM_COMBO + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_INSERT_FORM_VSCROLL + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_INSERT_FORM_HSCROLL + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] + + SID_INSERT_FORM_SPIN + [ + ExecMethod = ExecuteDialog; + StateMethod = GetState; + ] +} + +interface BasicIDEDocument +{ +} + +shell basctl_DocShell +{ + import BasicIDEDocument; +} diff --git a/basctl/sdi/basslots.hrc b/basctl/sdi/basslots.hrc new file mode 100644 index 0000000000..b6ec31a2cc --- /dev/null +++ b/basctl/sdi/basslots.hrc @@ -0,0 +1,24 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svx/svxids.hrc> +#include <svx/unomid.hxx> +#include <editeng/memberids.h> + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/sdi/basslots.sdi b/basctl/sdi/basslots.sdi new file mode 100644 index 0000000000..ed588f23f4 --- /dev/null +++ b/basctl/sdi/basslots.sdi @@ -0,0 +1,35 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +module +BasicIDE +[ +SlotIdFile( "basslots.hrc" ) +] +{ + + include "sfxitems.sdi" + include "sfx.sdi" + include "svxitems.sdi" + include "xoitems.sdi" + include "svx.sdi" + + include "baside.sdi" + +} + diff --git a/basctl/source/accessibility/accessibledialogcontrolshape.cxx b/basctl/source/accessibility/accessibledialogcontrolshape.cxx new file mode 100644 index 0000000000..62a260948f --- /dev/null +++ b/basctl/source/accessibility/accessibledialogcontrolshape.cxx @@ -0,0 +1,534 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <accessibledialogcontrolshape.hxx> +#include <baside3.hxx> +#include <dlgeddef.hxx> +#include <dlgedview.hxx> +#include <dlgedobj.hxx> +#include <com/sun/star/awt/XVclWindowPeer.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <cppuhelper/supportsservice.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <toolkit/awt/vclxfont.hxx> +#include <toolkit/helper/convert.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <comphelper/accessiblecontexthelper.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <i18nlangtag/languagetag.hxx> + +namespace basctl +{ + +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::accessibility; +using namespace ::comphelper; + + + + +AccessibleDialogControlShape::AccessibleDialogControlShape (DialogWindow* pDialogWindow, DlgEdObj* pDlgEdObj) + :m_pDialogWindow( pDialogWindow ) + ,m_pDlgEdObj( pDlgEdObj ) +{ + if ( m_pDlgEdObj ) + m_xControlModel.set( m_pDlgEdObj->GetUnoControlModel(), UNO_QUERY ); + + if ( m_xControlModel.is() ) + m_xControlModel->addPropertyChangeListener( OUString(), static_cast< beans::XPropertyChangeListener* >( this ) ); + + m_bFocused = IsFocused(); + m_bSelected = IsSelected(); + m_aBounds = GetBounds(); +} + + +AccessibleDialogControlShape::~AccessibleDialogControlShape() +{ + if ( m_xControlModel.is() ) + m_xControlModel->removePropertyChangeListener( OUString(), static_cast< beans::XPropertyChangeListener* >( this ) ); +} + + +bool AccessibleDialogControlShape::IsFocused() const +{ + bool bFocused = false; + if ( m_pDialogWindow ) + { + SdrView& rView = m_pDialogWindow->GetView(); + if (rView.IsObjMarked(m_pDlgEdObj) && rView.GetMarkedObjectList().GetMarkCount() == 1) + bFocused = true; + } + + return bFocused; +} + + +bool AccessibleDialogControlShape::IsSelected() const +{ + if ( m_pDialogWindow ) + return m_pDialogWindow->GetView().IsObjMarked(m_pDlgEdObj); + return false; +} + + +void AccessibleDialogControlShape::SetFocused( bool bFocused ) +{ + if ( m_bFocused != bFocused ) + { + Any aOldValue, aNewValue; + if ( m_bFocused ) + aOldValue <<= AccessibleStateType::FOCUSED; + else + aNewValue <<= AccessibleStateType::FOCUSED; + m_bFocused = bFocused; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } +} + + +void AccessibleDialogControlShape::SetSelected( bool bSelected ) +{ + if ( m_bSelected != bSelected ) + { + Any aOldValue, aNewValue; + if ( m_bSelected ) + aOldValue <<= AccessibleStateType::SELECTED; + else + aNewValue <<= AccessibleStateType::SELECTED; + m_bSelected = bSelected; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } +} + + +awt::Rectangle AccessibleDialogControlShape::GetBounds() const +{ + awt::Rectangle aBounds( 0, 0, 0, 0 ); + if ( m_pDlgEdObj ) + { + // get the bounding box of the shape in logic units + tools::Rectangle aRect = m_pDlgEdObj->GetSnapRect(); + + if ( m_pDialogWindow ) + { + // transform coordinates relative to the parent + MapMode aMap = m_pDialogWindow->GetMapMode(); + Point aOrg = aMap.GetOrigin(); + aRect.Move( aOrg.X(), aOrg.Y() ); + + // convert logic units to pixel + aRect = m_pDialogWindow->LogicToPixel( aRect, MapMode(MapUnit::Map100thMM) ); + + // clip the shape's bounding box with the bounding box of its parent + tools::Rectangle aParentRect( Point( 0, 0 ), m_pDialogWindow->GetSizePixel() ); + aRect = aRect.GetIntersection( aParentRect ); + aBounds = AWTRectangle( aRect ); + } + } + + return aBounds; +} + + +void AccessibleDialogControlShape::SetBounds( const awt::Rectangle& aBounds ) +{ + if ( m_aBounds.X != aBounds.X || m_aBounds.Y != aBounds.Y || m_aBounds.Width != aBounds.Width || m_aBounds.Height != aBounds.Height ) + { + m_aBounds = aBounds; + NotifyAccessibleEvent( AccessibleEventId::BOUNDRECT_CHANGED, Any(), Any() ); + } +} + + +vcl::Window* AccessibleDialogControlShape::GetWindow() const +{ + vcl::Window* pWindow = nullptr; + if ( m_pDlgEdObj ) + { + Reference< awt::XControl > xControl = m_pDlgEdObj->GetControl(); + if ( xControl.is() ) + pWindow = VCLUnoHelper::GetWindow( xControl->getPeer() ); + } + + return pWindow; +} + + +OUString AccessibleDialogControlShape::GetModelStringProperty( OUString const & pPropertyName ) +{ + OUString sReturn; + + try + { + if ( m_xControlModel.is() ) + { + Reference< XPropertySetInfo > xInfo = m_xControlModel->getPropertySetInfo(); + if ( xInfo.is() && xInfo->hasPropertyByName( pPropertyName ) ) + m_xControlModel->getPropertyValue( pPropertyName ) >>= sReturn; + } + } + catch ( const Exception& ) + { + TOOLS_WARN_EXCEPTION( "basctl", "AccessibleDialogControlShape::GetModelStringProperty" ); + } + + return sReturn; +} + + +void AccessibleDialogControlShape::FillAccessibleStateSet( sal_Int64& rStateSet ) +{ + rStateSet |= AccessibleStateType::ENABLED; + + rStateSet |= AccessibleStateType::VISIBLE; + + rStateSet |= AccessibleStateType::SHOWING; + + rStateSet |= AccessibleStateType::FOCUSABLE; + + if ( IsFocused() ) + rStateSet |= AccessibleStateType::FOCUSED; + + rStateSet |= AccessibleStateType::SELECTABLE; + + if ( IsSelected() ) + rStateSet |= AccessibleStateType::SELECTED; + + rStateSet |= AccessibleStateType::RESIZABLE; +} + +// OCommonAccessibleComponent +awt::Rectangle AccessibleDialogControlShape::implGetBounds() +{ + return GetBounds(); +} + +// XComponent +void AccessibleDialogControlShape::disposing() +{ + OAccessibleExtendedComponentHelper::disposing(); + + m_pDialogWindow = nullptr; + m_pDlgEdObj = nullptr; + + if ( m_xControlModel.is() ) + m_xControlModel->removePropertyChangeListener( OUString(), static_cast< beans::XPropertyChangeListener* >( this ) ); + m_xControlModel.clear(); +} + + +// XEventListener + + +void AccessibleDialogControlShape::disposing( const lang::EventObject& ) +{ + if ( m_xControlModel.is() ) + m_xControlModel->removePropertyChangeListener( OUString(), static_cast< beans::XPropertyChangeListener* >( this ) ); + m_xControlModel.clear(); +} + + +// XPropertyChangeListener + + +void AccessibleDialogControlShape::propertyChange( const beans::PropertyChangeEvent& rEvent ) +{ + if ( rEvent.PropertyName == DLGED_PROP_NAME ) + { + NotifyAccessibleEvent( AccessibleEventId::NAME_CHANGED, rEvent.OldValue, rEvent.NewValue ); + } + else if ( rEvent.PropertyName == DLGED_PROP_POSITIONX || + rEvent.PropertyName == DLGED_PROP_POSITIONY || + rEvent.PropertyName == DLGED_PROP_WIDTH || + rEvent.PropertyName == DLGED_PROP_HEIGHT ) + { + SetBounds( GetBounds() ); + } + else if ( rEvent.PropertyName == DLGED_PROP_BACKGROUNDCOLOR || + rEvent.PropertyName == DLGED_PROP_TEXTCOLOR || + rEvent.PropertyName == DLGED_PROP_TEXTLINECOLOR ) + { + NotifyAccessibleEvent( AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any() ); + } +} + +// XServiceInfo +OUString AccessibleDialogControlShape::getImplementationName() +{ + return "com.sun.star.comp.basctl.AccessibleShape"; +} + +sal_Bool AccessibleDialogControlShape::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > AccessibleDialogControlShape::getSupportedServiceNames() +{ + return { "com.sun.star.drawing.AccessibleShape" }; +} + +// XAccessible +Reference< XAccessibleContext > AccessibleDialogControlShape::getAccessibleContext( ) +{ + return this; +} + +// XAccessibleContext +sal_Int64 AccessibleDialogControlShape::getAccessibleChildCount() +{ + return 0; +} + + +Reference< XAccessible > AccessibleDialogControlShape::getAccessibleChild( sal_Int64 i ) +{ + OExternalLockGuard aGuard( this ); + + if ( i < 0 || i >= getAccessibleChildCount() ) + throw IndexOutOfBoundsException(); + + return Reference< XAccessible >(); +} + + +Reference< XAccessible > AccessibleDialogControlShape::getAccessibleParent( ) +{ + OExternalLockGuard aGuard( this ); + + Reference< XAccessible > xParent; + if ( m_pDialogWindow ) + xParent = m_pDialogWindow->GetAccessible(); + + return xParent; +} + + +sal_Int64 AccessibleDialogControlShape::getAccessibleIndexInParent( ) +{ + OExternalLockGuard aGuard( this ); + + sal_Int64 nIndexInParent = -1; + Reference< XAccessible > xParent( getAccessibleParent() ); + if ( xParent.is() ) + { + Reference< XAccessibleContext > xParentContext( xParent->getAccessibleContext() ); + if ( xParentContext.is() ) + { + for ( sal_Int64 i = 0, nCount = xParentContext->getAccessibleChildCount(); i < nCount; ++i ) + { + Reference< XAccessible > xChild( xParentContext->getAccessibleChild( i ) ); + if ( xChild.is() ) + { + Reference< XAccessibleContext > xChildContext = xChild->getAccessibleContext(); + if ( xChildContext == static_cast<XAccessibleContext*>(this) ) + { + nIndexInParent = i; + break; + } + } + } + } + } + + return nIndexInParent; +} + + +sal_Int16 AccessibleDialogControlShape::getAccessibleRole( ) +{ + OExternalLockGuard aGuard( this ); + + return AccessibleRole::SHAPE; +} + + +OUString AccessibleDialogControlShape::getAccessibleDescription( ) +{ + OExternalLockGuard aGuard( this ); + + return GetModelStringProperty( "HelpText" ); +} + + +OUString AccessibleDialogControlShape::getAccessibleName( ) +{ + OExternalLockGuard aGuard( this ); + + return GetModelStringProperty( "Name" ); +} + + +Reference< XAccessibleRelationSet > AccessibleDialogControlShape::getAccessibleRelationSet( ) +{ + OExternalLockGuard aGuard( this ); + + return new utl::AccessibleRelationSetHelper; +} + + +sal_Int64 AccessibleDialogControlShape::getAccessibleStateSet( ) +{ + OExternalLockGuard aGuard( this ); + + sal_Int64 nStateSet = 0; + + if ( !rBHelper.bDisposed && !rBHelper.bInDispose ) + { + FillAccessibleStateSet( nStateSet ); + } + else + { + nStateSet |= AccessibleStateType::DEFUNC; + } + + return nStateSet; +} + + +Locale AccessibleDialogControlShape::getLocale( ) +{ + OExternalLockGuard aGuard( this ); + + return Application::GetSettings().GetLanguageTag().getLocale(); +} + + +// XAccessibleComponent + + +Reference< XAccessible > AccessibleDialogControlShape::getAccessibleAtPoint( const awt::Point& ) +{ + OExternalLockGuard aGuard( this ); + + return Reference< XAccessible >(); +} + + +void AccessibleDialogControlShape::grabFocus( ) +{ + // no focus for shapes +} + + +sal_Int32 AccessibleDialogControlShape::getForeground( ) +{ + OExternalLockGuard aGuard( this ); + + Color nColor; + vcl::Window* pWindow = GetWindow(); + if ( pWindow ) + { + if ( pWindow->IsControlForeground() ) + nColor = pWindow->GetControlForeground(); + else + { + vcl::Font aFont; + if ( pWindow->IsControlFont() ) + aFont = pWindow->GetControlFont(); + else + aFont = pWindow->GetFont(); + nColor = aFont.GetColor(); + } + } + + return sal_Int32(nColor); +} + + +sal_Int32 AccessibleDialogControlShape::getBackground( ) +{ + OExternalLockGuard aGuard( this ); + + Color nColor; + vcl::Window* pWindow = GetWindow(); + if ( pWindow ) + { + if ( pWindow->IsControlBackground() ) + nColor = pWindow->GetControlBackground(); + else + nColor = pWindow->GetBackground().GetColor(); + } + + return sal_Int32(nColor); +} + + +// XAccessibleExtendedComponent + + +Reference< awt::XFont > AccessibleDialogControlShape::getFont( ) +{ + OExternalLockGuard aGuard( this ); + + Reference< awt::XFont > xFont; + vcl::Window* pWindow = GetWindow(); + if ( pWindow ) + { + Reference< awt::XDevice > xDev( pWindow->GetComponentInterface(), UNO_QUERY ); + if ( xDev.is() ) + { + vcl::Font aFont; + if ( pWindow->IsControlFont() ) + aFont = pWindow->GetControlFont(); + else + aFont = pWindow->GetFont(); + rtl::Reference<VCLXFont> pVCLXFont = new VCLXFont; + pVCLXFont->Init( *xDev, aFont ); + xFont = pVCLXFont; + } + } + + return xFont; +} + + +OUString AccessibleDialogControlShape::getTitledBorderText( ) +{ + OExternalLockGuard aGuard( this ); + + return OUString(); +} + + +OUString AccessibleDialogControlShape::getToolTipText( ) +{ + OExternalLockGuard aGuard( this ); + + OUString sText; + vcl::Window* pWindow = GetWindow(); + if ( pWindow ) + sText = pWindow->GetQuickHelpText(); + + return sText; +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/accessibility/accessibledialogwindow.cxx b/basctl/source/accessibility/accessibledialogwindow.cxx new file mode 100644 index 0000000000..d5c702616d --- /dev/null +++ b/basctl/source/accessibility/accessibledialogwindow.cxx @@ -0,0 +1,915 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <accessibledialogwindow.hxx> +#include <accessibledialogcontrolshape.hxx> +#include <baside3.hxx> +#include <dlged.hxx> +#include <dlgedmod.hxx> +#include <dlgedpage.hxx> +#include <dlgedview.hxx> +#include <dlgedobj.hxx> +#include <com/sun/star/awt/XVclWindowPeer.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/lang/IndexOutOfBoundsException.hpp> +#include <comphelper/accessiblecontexthelper.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <tools/debug.hxx> +#include <unotools/accessiblerelationsethelper.hxx> +#include <toolkit/awt/vclxfont.hxx> +#include <toolkit/helper/convert.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <i18nlangtag/languagetag.hxx> + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::accessibility; +using namespace ::comphelper; + +AccessibleDialogWindow::ChildDescriptor::ChildDescriptor( DlgEdObj* _pDlgEdObj ) + :pDlgEdObj( _pDlgEdObj ) +{ +} + +bool AccessibleDialogWindow::ChildDescriptor::operator==( const ChildDescriptor& rDesc ) +{ + bool bRet = false; + if ( pDlgEdObj == rDesc.pDlgEdObj ) + bRet = true; + + return bRet; +} + + +bool AccessibleDialogWindow::ChildDescriptor::operator<( const ChildDescriptor& rDesc ) const +{ + bool bRet = false; + if ( pDlgEdObj && rDesc.pDlgEdObj && pDlgEdObj->GetOrdNum() < rDesc.pDlgEdObj->GetOrdNum() ) + bRet = true; + + return bRet; +} + + + + +AccessibleDialogWindow::AccessibleDialogWindow (basctl::DialogWindow* pDialogWindow) + : m_pDialogWindow(pDialogWindow) + , m_pDlgEdModel(nullptr) +{ + if ( !m_pDialogWindow ) + return; + + SdrPage& rPage = m_pDialogWindow->GetPage(); + + for (const rtl::Reference<SdrObject>& pObj : rPage) + { + if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get())) + { + ChildDescriptor aDesc( pDlgEdObj ); + if ( IsChildVisible( aDesc ) ) + m_aAccessibleChildren.push_back( aDesc ); + } + } + + m_pDialogWindow->AddEventListener( LINK( this, AccessibleDialogWindow, WindowEventListener ) ); + + StartListening(m_pDialogWindow->GetEditor()); + + m_pDlgEdModel = &m_pDialogWindow->GetModel(); + StartListening(*m_pDlgEdModel); +} + + +AccessibleDialogWindow::~AccessibleDialogWindow() +{ + if ( m_pDialogWindow ) + m_pDialogWindow->RemoveEventListener( LINK( this, AccessibleDialogWindow, WindowEventListener ) ); + + if ( m_pDlgEdModel ) + EndListening( *m_pDlgEdModel ); +} + + +void AccessibleDialogWindow::UpdateFocused() +{ + for (const ChildDescriptor & i : m_aAccessibleChildren) + { + if ( i.mxAccessible ) + i.mxAccessible->SetFocused( i.mxAccessible->IsFocused() ); + } +} + + +void AccessibleDialogWindow::UpdateSelected() +{ + NotifyAccessibleEvent( AccessibleEventId::SELECTION_CHANGED, Any(), Any() ); + + for (const ChildDescriptor & i : m_aAccessibleChildren) + { + if ( i.mxAccessible ) + i.mxAccessible->SetSelected( i.mxAccessible->IsSelected() ); + } +} + + +void AccessibleDialogWindow::UpdateBounds() +{ + for (const ChildDescriptor & i : m_aAccessibleChildren) + { + if ( i.mxAccessible ) + i.mxAccessible->SetBounds( i.mxAccessible->GetBounds() ); + } +} + + +bool AccessibleDialogWindow::IsChildVisible( const ChildDescriptor& rDesc ) +{ + bool bVisible = false; + + if ( m_pDialogWindow ) + { + // first check, if the shape is in a visible layer + SdrLayerAdmin& rLayerAdmin = m_pDialogWindow->GetModel().GetLayerAdmin(); + DlgEdObj* pDlgEdObj = rDesc.pDlgEdObj; + if ( pDlgEdObj ) + { + SdrLayerID nLayerId = pDlgEdObj->GetLayer(); + const SdrLayer* pSdrLayer = rLayerAdmin.GetLayerPerID( nLayerId ); + if ( pSdrLayer ) + { + const OUString& aLayerName = pSdrLayer->GetName(); + SdrView& rView = m_pDialogWindow->GetView(); + if (rView.IsLayerVisible(aLayerName)) + { + // get the bounding box of the shape in logic units + tools::Rectangle aRect = pDlgEdObj->GetSnapRect(); + + // transform coordinates relative to the parent + MapMode aMap = m_pDialogWindow->GetMapMode(); + Point aOrg = aMap.GetOrigin(); + aRect.Move( aOrg.X(), aOrg.Y() ); + + // convert logic units to pixel + aRect = m_pDialogWindow->LogicToPixel( aRect, MapMode(MapUnit::Map100thMM) ); + + // check, if the shape's bounding box intersects with the bounding box of its parent + tools::Rectangle aParentRect( Point( 0, 0 ), m_pDialogWindow->GetSizePixel() ); + if ( aParentRect.Overlaps( aRect ) ) + bVisible = true; + } + } + } + } + + return bVisible; +} + + +void AccessibleDialogWindow::InsertChild( const ChildDescriptor& rDesc ) +{ + // check, if object is already in child list + AccessibleChildren::iterator aIter = std::find( m_aAccessibleChildren.begin(), m_aAccessibleChildren.end(), rDesc ); + + // if not found, insert in child list + if ( aIter != m_aAccessibleChildren.end() ) + return; + + // insert entry in child list + m_aAccessibleChildren.push_back( rDesc ); + + // get the accessible of the inserted child + Reference< XAccessible > xChild( getAccessibleChild( m_aAccessibleChildren.size() - 1 ) ); + + // sort child list + SortChildren(); + + // send accessible child event + if ( xChild.is() ) + { + Any aOldValue, aNewValue; + aNewValue <<= xChild; + NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue ); + } +} + + +void AccessibleDialogWindow::RemoveChild( const ChildDescriptor& rDesc ) +{ + // find object in child list + AccessibleChildren::iterator aIter = std::find( m_aAccessibleChildren.begin(), m_aAccessibleChildren.end(), rDesc ); + + // if found, remove from child list + if ( aIter == m_aAccessibleChildren.end() ) + return; + + // get the accessible of the removed child + rtl::Reference< AccessibleDialogControlShape > xChild( aIter->mxAccessible ); + + // remove entry from child list + m_aAccessibleChildren.erase( aIter ); + + // send accessible child event + if ( xChild.is() ) + { + Any aOldValue, aNewValue; + aOldValue <<= uno::Reference<XAccessible>(xChild); + NotifyAccessibleEvent( AccessibleEventId::CHILD, aOldValue, aNewValue ); + + if ( xChild ) + xChild->dispose(); + } +} + + +void AccessibleDialogWindow::UpdateChild( const ChildDescriptor& rDesc ) +{ + if ( IsChildVisible( rDesc ) ) + { + // if the object is not in the child list, insert child + InsertChild( rDesc ); + } + else + { + // if the object is in the child list, remove child + RemoveChild( rDesc ); + } +} + + +void AccessibleDialogWindow::UpdateChildren() +{ + if ( m_pDialogWindow ) + { + SdrPage& rPage = m_pDialogWindow->GetPage(); + for (const rtl::Reference<SdrObject>& pObj : rPage) + if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get())) + UpdateChild( ChildDescriptor( pDlgEdObj ) ); + } +} + + +void AccessibleDialogWindow::SortChildren() +{ + // sort child list + std::sort( m_aAccessibleChildren.begin(), m_aAccessibleChildren.end() ); +} + + +IMPL_LINK( AccessibleDialogWindow, WindowEventListener, VclWindowEvent&, rEvent, void ) +{ + DBG_ASSERT(rEvent.GetWindow(), "AccessibleDialogWindow::WindowEventListener: no window!"); + if (!rEvent.GetWindow()->IsAccessibilityEventsSuppressed() || rEvent.GetId() == VclEventId::ObjectDying) + ProcessWindowEvent(rEvent); +} + + +void AccessibleDialogWindow::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ) +{ + Any aOldValue, aNewValue; + + switch ( rVclWindowEvent.GetId() ) + { + case VclEventId::WindowEnabled: + { + aNewValue <<= AccessibleStateType::ENABLED; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } + break; + case VclEventId::WindowDisabled: + { + aOldValue <<= AccessibleStateType::ENABLED; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } + break; + case VclEventId::WindowActivate: + { + aNewValue <<= AccessibleStateType::ACTIVE; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } + break; + case VclEventId::WindowDeactivate: + { + aOldValue <<= AccessibleStateType::ACTIVE; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } + break; + case VclEventId::WindowGetFocus: + { + aNewValue <<= AccessibleStateType::FOCUSED; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } + break; + case VclEventId::WindowLoseFocus: + { + aOldValue <<= AccessibleStateType::FOCUSED; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } + break; + case VclEventId::WindowShow: + { + aNewValue <<= AccessibleStateType::SHOWING; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } + break; + case VclEventId::WindowHide: + { + aOldValue <<= AccessibleStateType::SHOWING; + NotifyAccessibleEvent( AccessibleEventId::STATE_CHANGED, aOldValue, aNewValue ); + } + break; + case VclEventId::WindowResize: + { + NotifyAccessibleEvent( AccessibleEventId::BOUNDRECT_CHANGED, aOldValue, aNewValue ); + UpdateChildren(); + UpdateBounds(); + } + break; + case VclEventId::ObjectDying: + { + if ( m_pDialogWindow ) + { + m_pDialogWindow->RemoveEventListener( LINK( this, AccessibleDialogWindow, WindowEventListener ) ); + m_pDialogWindow = nullptr; + + if ( m_pDlgEdModel ) + EndListening( *m_pDlgEdModel ); + m_pDlgEdModel = nullptr; + + // dispose all children + for (const ChildDescriptor & i : m_aAccessibleChildren) + { + if ( i.mxAccessible ) + i.mxAccessible->dispose(); + } + m_aAccessibleChildren.clear(); + } + } + break; + default: + { + } + break; + } +} + + +void AccessibleDialogWindow::FillAccessibleStateSet( sal_Int64& rStateSet ) +{ + if ( !m_pDialogWindow ) + return; + + if ( m_pDialogWindow->IsEnabled() ) + rStateSet |= AccessibleStateType::ENABLED; + + rStateSet |= AccessibleStateType::FOCUSABLE; + + if ( m_pDialogWindow->HasFocus() ) + rStateSet |= AccessibleStateType::FOCUSED; + + rStateSet |= AccessibleStateType::VISIBLE; + + if ( m_pDialogWindow->IsVisible() ) + rStateSet |= AccessibleStateType::SHOWING; + + rStateSet |= AccessibleStateType::OPAQUE; + + rStateSet |= AccessibleStateType::RESIZABLE; +} + + +// OCommonAccessibleComponent + + +awt::Rectangle AccessibleDialogWindow::implGetBounds() +{ + awt::Rectangle aBounds; + if ( m_pDialogWindow ) + aBounds = AWTRectangle( tools::Rectangle( m_pDialogWindow->GetPosPixel(), m_pDialogWindow->GetSizePixel() ) ); + + return aBounds; +} + + +// SfxListener + + +void AccessibleDialogWindow::Notify( SfxBroadcaster&, const SfxHint& rHint ) +{ + if (SdrHint const* pSdrHint = dynamic_cast<SdrHint const*>(&rHint)) + { + switch ( pSdrHint->GetKind() ) + { + case SdrHintKind::ObjectInserted: + { + if (DlgEdObj const* pDlgEdObj = dynamic_cast<DlgEdObj const*>(pSdrHint->GetObject())) + { + ChildDescriptor aDesc(const_cast<DlgEdObj*>(pDlgEdObj)); + if ( IsChildVisible( aDesc ) ) + InsertChild( aDesc ); + } + } + break; + case SdrHintKind::ObjectRemoved: + { + if (DlgEdObj const* pDlgEdObj = dynamic_cast<DlgEdObj const*>(pSdrHint->GetObject())) + RemoveChild( ChildDescriptor(const_cast<DlgEdObj*>(pDlgEdObj)) ); + } + break; + default: ; + } + } + else if (DlgEdHint const* pDlgEdHint = dynamic_cast<DlgEdHint const*>(&rHint)) + { + switch (pDlgEdHint->GetKind()) + { + case DlgEdHint::WINDOWSCROLLED: + { + UpdateChildren(); + UpdateBounds(); + } + break; + case DlgEdHint::LAYERCHANGED: + { + if (DlgEdObj* pDlgEdObj = pDlgEdHint->GetObject()) + UpdateChild( ChildDescriptor( pDlgEdObj ) ); + } + break; + case DlgEdHint::OBJORDERCHANGED: + { + SortChildren(); + } + break; + case DlgEdHint::SELECTIONCHANGED: + { + UpdateFocused(); + UpdateSelected(); + } + break; + default: ; + } + } +} + + +// XComponent + + +void AccessibleDialogWindow::disposing() +{ + OAccessibleExtendedComponentHelper::disposing(); + + if ( !m_pDialogWindow ) + return; + + m_pDialogWindow->RemoveEventListener( LINK( this, AccessibleDialogWindow, WindowEventListener ) ); + m_pDialogWindow = nullptr; + + if ( m_pDlgEdModel ) + EndListening( *m_pDlgEdModel ); + m_pDlgEdModel = nullptr; + + // dispose all children + for (const ChildDescriptor & i : m_aAccessibleChildren) + { + if ( i.mxAccessible ) + i.mxAccessible->dispose(); + } + m_aAccessibleChildren.clear(); +} + +// XServiceInfo +OUString AccessibleDialogWindow::getImplementationName() +{ + return "com.sun.star.comp.basctl.AccessibleWindow"; +} + +sal_Bool AccessibleDialogWindow::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +Sequence< OUString > AccessibleDialogWindow::getSupportedServiceNames() +{ + return { "com.sun.star.awt.AccessibleWindow" }; +} + +// XAccessible +Reference< XAccessibleContext > AccessibleDialogWindow::getAccessibleContext( ) +{ + return this; +} + +// XAccessibleContext +sal_Int64 AccessibleDialogWindow::getAccessibleChildCount() +{ + OExternalLockGuard aGuard( this ); + + return m_aAccessibleChildren.size(); +} + + +Reference< XAccessible > AccessibleDialogWindow::getAccessibleChild( sal_Int64 i ) +{ + OExternalLockGuard aGuard( this ); + + if ( i < 0 || i >= getAccessibleChildCount() ) + throw IndexOutOfBoundsException(); + + rtl::Reference< AccessibleDialogControlShape > xChild = m_aAccessibleChildren[i].mxAccessible; + if ( !xChild.is() ) + { + if ( m_pDialogWindow ) + { + DlgEdObj* pDlgEdObj = m_aAccessibleChildren[i].pDlgEdObj; + if ( pDlgEdObj ) + { + xChild = new AccessibleDialogControlShape( m_pDialogWindow, pDlgEdObj ); + + // insert into child list + m_aAccessibleChildren[i].mxAccessible = xChild; + } + } + } + + return xChild; +} + + +Reference< XAccessible > AccessibleDialogWindow::getAccessibleParent( ) +{ + OExternalLockGuard aGuard( this ); + + Reference< XAccessible > xParent; + if ( m_pDialogWindow ) + { + vcl::Window* pParent = m_pDialogWindow->GetAccessibleParentWindow(); + if ( pParent ) + xParent = pParent->GetAccessible(); + } + + return xParent; +} + + +sal_Int64 AccessibleDialogWindow::getAccessibleIndexInParent( ) +{ + OExternalLockGuard aGuard( this ); + + sal_Int64 nIndexInParent = -1; + if ( m_pDialogWindow ) + { + vcl::Window* pParent = m_pDialogWindow->GetAccessibleParentWindow(); + if ( pParent ) + { + for ( sal_uInt16 i = 0, nCount = pParent->GetAccessibleChildWindowCount(); i < nCount; ++i ) + { + vcl::Window* pChild = pParent->GetAccessibleChildWindow( i ); + if ( pChild == static_cast< vcl::Window* >( m_pDialogWindow ) ) + { + nIndexInParent = i; + break; + } + } + } + } + + return nIndexInParent; +} + + +sal_Int16 AccessibleDialogWindow::getAccessibleRole( ) +{ + OExternalLockGuard aGuard( this ); + + return AccessibleRole::PANEL; +} + + +OUString AccessibleDialogWindow::getAccessibleDescription( ) +{ + OExternalLockGuard aGuard( this ); + + OUString sDescription; + if ( m_pDialogWindow ) + sDescription = m_pDialogWindow->GetAccessibleDescription(); + + return sDescription; +} + + +OUString AccessibleDialogWindow::getAccessibleName( ) +{ + OExternalLockGuard aGuard( this ); + + OUString sName; + if ( m_pDialogWindow ) + sName = m_pDialogWindow->GetAccessibleName(); + + return sName; +} + + +Reference< XAccessibleRelationSet > AccessibleDialogWindow::getAccessibleRelationSet( ) +{ + OExternalLockGuard aGuard( this ); + + return new utl::AccessibleRelationSetHelper; +} + + +sal_Int64 AccessibleDialogWindow::getAccessibleStateSet( ) +{ + OExternalLockGuard aGuard( this ); + + sal_Int64 nStateSet = 0; + + if ( !rBHelper.bDisposed && !rBHelper.bInDispose ) + { + FillAccessibleStateSet( nStateSet ); + } + else + { + nStateSet |= AccessibleStateType::DEFUNC; + } + + return nStateSet; +} + + +Locale AccessibleDialogWindow::getLocale( ) +{ + OExternalLockGuard aGuard( this ); + + return Application::GetSettings().GetLanguageTag().getLocale(); +} + + +// XAccessibleComponent + + +Reference< XAccessible > AccessibleDialogWindow::getAccessibleAtPoint( const awt::Point& rPoint ) +{ + OExternalLockGuard aGuard( this ); + + Reference< XAccessible > xChild; + for ( size_t i = 0; i < m_aAccessibleChildren.size(); ++i ) + { + Reference< XAccessible > xAcc = getAccessibleChild( i ); + if ( xAcc.is() ) + { + Reference< XAccessibleComponent > xComp( xAcc->getAccessibleContext(), UNO_QUERY ); + if ( xComp.is() ) + { + tools::Rectangle aRect = VCLRectangle( xComp->getBounds() ); + Point aPos = VCLPoint( rPoint ); + if ( aRect.Contains( aPos ) ) + { + xChild = xAcc; + break; + } + } + } + } + + return xChild; +} + + +void AccessibleDialogWindow::grabFocus( ) +{ + OExternalLockGuard aGuard( this ); + + if ( m_pDialogWindow ) + m_pDialogWindow->GrabFocus(); +} + + +sal_Int32 AccessibleDialogWindow::getForeground( ) +{ + OExternalLockGuard aGuard( this ); + + Color nColor; + if ( m_pDialogWindow ) + { + if ( m_pDialogWindow->IsControlForeground() ) + nColor = m_pDialogWindow->GetControlForeground(); + else + { + vcl::Font aFont; + if ( m_pDialogWindow->IsControlFont() ) + aFont = m_pDialogWindow->GetControlFont(); + else + aFont = m_pDialogWindow->GetFont(); + nColor = aFont.GetColor(); + } + } + + return sal_Int32(nColor); +} + + +sal_Int32 AccessibleDialogWindow::getBackground( ) +{ + OExternalLockGuard aGuard( this ); + + Color nColor; + if ( m_pDialogWindow ) + { + if ( m_pDialogWindow->IsControlBackground() ) + nColor = m_pDialogWindow->GetControlBackground(); + else + nColor = m_pDialogWindow->GetBackground().GetColor(); + } + + return sal_Int32(nColor); +} + + +// XAccessibleExtendedComponent + + +Reference< awt::XFont > AccessibleDialogWindow::getFont( ) +{ + OExternalLockGuard aGuard( this ); + + Reference< awt::XFont > xFont; + if ( m_pDialogWindow ) + { + Reference< awt::XDevice > xDev( m_pDialogWindow->GetComponentInterface(), UNO_QUERY ); + if ( xDev.is() ) + { + vcl::Font aFont; + if ( m_pDialogWindow->IsControlFont() ) + aFont = m_pDialogWindow->GetControlFont(); + else + aFont = m_pDialogWindow->GetFont(); + rtl::Reference<VCLXFont> pVCLXFont = new VCLXFont; + pVCLXFont->Init( *xDev, aFont ); + xFont = pVCLXFont; + } + } + + return xFont; +} + + +OUString AccessibleDialogWindow::getTitledBorderText( ) +{ + OExternalLockGuard aGuard( this ); + + return OUString(); +} + + +OUString AccessibleDialogWindow::getToolTipText( ) +{ + OExternalLockGuard aGuard( this ); + + OUString sText; + if ( m_pDialogWindow ) + sText = m_pDialogWindow->GetQuickHelpText(); + + return sText; +} + + +// XAccessibleSelection + + +void AccessibleDialogWindow::selectAccessibleChild( sal_Int64 nChildIndex ) +{ + OExternalLockGuard aGuard( this ); + + if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() ) + throw IndexOutOfBoundsException(); + + if ( m_pDialogWindow ) + { + if (DlgEdObj* pDlgEdObj = m_aAccessibleChildren[nChildIndex].pDlgEdObj) + { + SdrView& rView = m_pDialogWindow->GetView(); + if (SdrPageView* pPgView = rView.GetSdrPageView()) + rView.MarkObj(pDlgEdObj, pPgView); + } + } +} + + +sal_Bool AccessibleDialogWindow::isAccessibleChildSelected( sal_Int64 nChildIndex ) +{ + OExternalLockGuard aGuard( this ); + + if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() ) + throw IndexOutOfBoundsException(); + + if (m_pDialogWindow) + if (DlgEdObj* pDlgEdObj = m_aAccessibleChildren[nChildIndex].pDlgEdObj) + return m_pDialogWindow->GetView().IsObjMarked(pDlgEdObj); + return false; +} + + +void AccessibleDialogWindow::clearAccessibleSelection() +{ + OExternalLockGuard aGuard( this ); + + if ( m_pDialogWindow ) + m_pDialogWindow->GetView().UnmarkAll(); +} + + +void AccessibleDialogWindow::selectAllAccessibleChildren( ) +{ + OExternalLockGuard aGuard( this ); + + if ( m_pDialogWindow ) + m_pDialogWindow->GetView().MarkAll(); +} + + +sal_Int64 AccessibleDialogWindow::getSelectedAccessibleChildCount( ) +{ + OExternalLockGuard aGuard( this ); + + sal_Int64 nRet = 0; + + for ( sal_Int64 i = 0, nCount = getAccessibleChildCount(); i < nCount; ++i ) + { + if ( isAccessibleChildSelected( i ) ) + ++nRet; + } + + return nRet; +} + + +Reference< XAccessible > AccessibleDialogWindow::getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex ) +{ + OExternalLockGuard aGuard( this ); + + if ( nSelectedChildIndex < 0 || nSelectedChildIndex >= getSelectedAccessibleChildCount() ) + throw IndexOutOfBoundsException(); + + Reference< XAccessible > xChild; + + for ( sal_Int64 i = 0, j = 0, nCount = getAccessibleChildCount(); i < nCount; ++i ) + { + if ( isAccessibleChildSelected( i ) && ( j++ == nSelectedChildIndex ) ) + { + xChild = getAccessibleChild( i ); + break; + } + } + + return xChild; +} + + +void AccessibleDialogWindow::deselectAccessibleChild( sal_Int64 nChildIndex ) +{ + OExternalLockGuard aGuard( this ); + + if ( nChildIndex < 0 || nChildIndex >= getAccessibleChildCount() ) + throw IndexOutOfBoundsException(); + + if ( m_pDialogWindow ) + { + if (DlgEdObj* pDlgEdObj = m_aAccessibleChildren[nChildIndex].pDlgEdObj) + { + SdrView& rView = m_pDialogWindow->GetView(); + SdrPageView* pPgView = rView.GetSdrPageView(); + if (pPgView) + rView.MarkObj( pDlgEdObj, pPgView, true ); + } + } +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/IDEComboBox.cxx b/basctl/source/basicide/IDEComboBox.cxx new file mode 100644 index 0000000000..d25e143d62 --- /dev/null +++ b/basctl/source/basicide/IDEComboBox.cxx @@ -0,0 +1,530 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <strings.hrc> +#include <basidesh.hxx> +#include <basobj.hxx> +#include <IDEComboBox.hxx> +#include <iderdll.hxx> +#include <iderid.hxx> +#include <localizationmgr.hxx> +#include <managelang.hxx> + +#include <sfx2/dispatch.hxx> +#include <sfx2/frame.hxx> +#include <sfx2/sfxsids.hrc> +#include <svtools/langtab.hxx> +#include <tools/debug.hxx> +#include <vcl/svapp.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/event.hxx> +#include <svl/itemset.hxx> + +namespace basctl +{ +using namespace ::com::sun::star; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; + +/*! Macro for implementation two methods for LibBoxControl Class + * + * @code + * SfxToolBoxControl* LibBoxControl::CreateImpl(sal_uInt16 nSlotId, sal_uInt16 nId, ToolBox& rTbx) + * { + * return new LibBoxControl(nSlotId, nId, rTbx); + * } + * + * void LibBoxControl::RegisterControl(sal_uInt16 nSlotId, SfxModule* pMod) + * { + * SfxToolBoxControl::RegisterToolBoxControl( + * pMod, SfxTbxCtrlFactory(* LibBoxControl::CreateImpl, typeid(nItemClass), nSlotId)); + * } + * @endcode + * @see Macro SFX_DECL_TOOLBOX_CONTROL + */ +SFX_IMPL_TOOLBOX_CONTROL(LibBoxControl, SfxStringItem); + +LibBoxControl::LibBoxControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx) + : SfxToolBoxControl(nSlotId, nId, rTbx) +{ +} + +void LibBoxControl::StateChangedAtToolBoxControl(sal_uInt16, SfxItemState eState, + const SfxPoolItem* pState) +{ + LibBox* pBox = static_cast<LibBox*>(GetToolBox().GetItemWindow(GetId())); + + DBG_ASSERT(pBox, "Box not found"); + if (!pBox) + return; + + if (eState != SfxItemState::DEFAULT) + pBox->set_sensitive(false); + else + { + pBox->set_sensitive(true); + pBox->Update(dynamic_cast<SfxStringItem const*>(pState)); + } +} + +VclPtr<InterimItemWindow> LibBoxControl::CreateItemWindow(vcl::Window* pParent) +{ + return VclPtr<LibBox>::Create(pParent); +} + +DocListenerBox::DocListenerBox(vcl::Window* pParent) + : InterimItemWindow(pParent, "modules/BasicIDE/ui/combobox.ui", "ComboBox") + , m_xWidget(m_xBuilder->weld_combo_box("combobox")) + , maNotifier(*this) +{ + InitControlBase(m_xWidget.get()); + + m_xWidget->connect_changed(LINK(this, DocListenerBox, SelectHdl)); + m_xWidget->connect_key_press(LINK(this, DocListenerBox, KeyInputHdl)); +} + +void DocListenerBox::set_sensitive(bool bSensitive) +{ + Enable(bSensitive); + m_xWidget->set_sensitive(bSensitive); +} + +IMPL_LINK(DocListenerBox, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + return HandleKeyInput(rKEvt); +} + +bool DocListenerBox::HandleKeyInput(const KeyEvent& rKEvt) { return ChildKeyInput(rKEvt); } + +IMPL_LINK_NOARG(DocListenerBox, SelectHdl, weld::ComboBox&, void) { Select(); } + +DocListenerBox::~DocListenerBox() { disposeOnce(); } + +void DocListenerBox::dispose() +{ + maNotifier.dispose(); + m_xWidget.reset(); + InterimItemWindow::dispose(); +} + +/// Only calls FillBox(). Parameter is not used. +void DocListenerBox::onDocumentCreated(const ScriptDocument& /*_rDoc*/) { FillBox(); } + +/// Only calls FillBox(). Parameter is not used. +void DocListenerBox::onDocumentOpened(const ScriptDocument& /*_rDoc*/) { FillBox(); } + +/// Only calls FillBox(). Parameter is not used. +void DocListenerBox::onDocumentSaveAsDone(const ScriptDocument& /*_rDoc*/) { FillBox(); } + +/// Only calls FillBox(). Parameter is not used. +void DocListenerBox::onDocumentClosed(const ScriptDocument& /*_rDoc*/) { FillBox(); } + +/// Not interested in. Do nothing. +void DocListenerBox::onDocumentSave(const ScriptDocument& /*_rDoc*/) {} + +/// Not interested in. Do nothing. +void DocListenerBox::onDocumentSaveDone(const ScriptDocument& /*_rDoc*/) {} + +/// Not interested in. Do nothing. +void DocListenerBox::onDocumentSaveAs(const ScriptDocument& /*_rDoc*/) {} + +/// Not interested in. Do nothing. +void DocListenerBox::onDocumentTitleChanged(const ScriptDocument& /*_rDoc*/) {} + +/// Not interested in. Do nothing. +void DocListenerBox::onDocumentModeChanged(const ScriptDocument& /*_rDoc*/) {} + +LibBox::LibBox(vcl::Window* pParent) + : DocListenerBox(pParent) +{ + FillBox(); + mbIgnoreSelect = true; // do not yet transfer select of 0 + mbFillBox = true; + m_xWidget->set_active(0); + maCurrentText = m_xWidget->get_text(0); + mbIgnoreSelect = false; + + m_xWidget->connect_focus_in(LINK(this, LibBox, FocusInHdl)); + m_xWidget->connect_focus_out(LINK(this, LibBox, FocusOutHdl)); + + SetSizePixel(m_xWidget->get_preferred_size()); +} + +LibBox::~LibBox() { disposeOnce(); } + +void LibBox::dispose() +{ + ClearBox(); + DocListenerBox::dispose(); +} + +void LibBox::Update(const SfxStringItem* pItem) +{ + // if ( !pItem || !pItem->GetValue().Len() ) + FillBox(); + + if (pItem) + { + maCurrentText = pItem->GetValue(); + if (maCurrentText.isEmpty()) + maCurrentText = IDEResId(RID_STR_ALL); + } + + if (m_xWidget->get_active_text() != maCurrentText) + m_xWidget->set_active_text(maCurrentText); +} + +void LibBox::ReleaseFocus() +{ + SfxViewShell* pCurSh = SfxViewShell::Current(); + DBG_ASSERT(pCurSh, "Current ViewShell not found!"); + + if (!pCurSh) + return; + + vcl::Window* pShellWin = pCurSh->GetWindow(); + if (pShellWin) + { + pShellWin->GrabFocus(); + return; + } + + weld::Window* pWin = Application::GetDefDialogParent(); + if (!pWin) + return; + pWin->grab_focus(); +} + +void LibBox::FillBox() +{ + m_xWidget->freeze(); + mbIgnoreSelect = true; + + maCurrentText = m_xWidget->get_active_text(); + + ClearBox(); + + // create list box entries + LibEntry* pEntry = new LibEntry(ScriptDocument::getApplicationScriptDocument(), + LIBRARY_LOCATION_UNKNOWN, OUString()); + OUString sId(weld::toId(pEntry)); + m_xWidget->append(sId, IDEResId(RID_STR_ALL)); + + InsertEntries(ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_USER); + InsertEntries(ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_SHARE); + + ScriptDocuments aDocuments( + ScriptDocument::getAllScriptDocuments(ScriptDocument::DocumentsSorted)); + for (auto const& doc : aDocuments) + { + InsertEntries(doc, LIBRARY_LOCATION_DOCUMENT); + } + + m_xWidget->thaw(); + + int nIndex = m_xWidget->find_text(maCurrentText); + if (nIndex != -1) + m_xWidget->set_active(nIndex); + else + m_xWidget->set_active(0); + maCurrentText = m_xWidget->get_active_text(); + mbIgnoreSelect = false; +} + +void LibBox::InsertEntries(const ScriptDocument& rDocument, LibraryLocation eLocation) +{ + // get a sorted list of library names + Sequence<OUString> aLibNames = rDocument.getLibraryNames(); + sal_Int32 nLibCount = aLibNames.getLength(); + const OUString* pLibNames = aLibNames.getConstArray(); + + for (sal_Int32 i = 0; i < nLibCount; ++i) + { + OUString aLibName = pLibNames[i]; + if (eLocation == rDocument.getLibraryLocation(aLibName)) + { + OUString aName(rDocument.getTitle(eLocation)); + OUString aEntryText(CreateMgrAndLibStr(aName, aLibName)); + LibEntry* pEntry = new LibEntry(rDocument, eLocation, aLibName); + m_xWidget->append(weld::toId(pEntry), aEntryText); + } + } +} + +bool LibBox::HandleKeyInput(const KeyEvent& rKEvt) +{ + bool bDone = false; + + sal_uInt16 nKeyCode = rKEvt.GetKeyCode().GetCode(); + switch (nKeyCode) + { + case KEY_RETURN: + { + NotifyIDE(); + bDone = true; + } + break; + case KEY_ESCAPE: + { + m_xWidget->set_active_text(maCurrentText); + ReleaseFocus(); + bDone = true; + } + break; + } + + return bDone || DocListenerBox::HandleKeyInput(rKEvt); +} + +IMPL_LINK_NOARG(LibBox, FocusInHdl, weld::Widget&, void) +{ + if (mbFillBox) + { + FillBox(); + mbFillBox = false; + } +} + +IMPL_LINK_NOARG(LibBox, FocusOutHdl, weld::Widget&, void) +{ + // comboboxes can be comprised of multiple widgets, ensure all have lost focus + if (m_xWidget && !m_xWidget->has_focus()) + mbFillBox = true; +} + +void LibBox::Select() +{ + if (m_xWidget->changed_by_direct_pick()) + { + if (!mbIgnoreSelect) + NotifyIDE(); + else + m_xWidget->set_active_text(maCurrentText); // (Select after Escape) + } +} + +void LibBox::NotifyIDE() +{ + LibEntry* pEntry = weld::fromId<LibEntry*>(m_xWidget->get_active_id()); + if (pEntry) + { + const ScriptDocument& aDocument(pEntry->GetDocument()); + SfxUnoAnyItem aDocumentItem(SID_BASICIDE_ARG_DOCUMENT_MODEL, + uno::Any(aDocument.getDocumentOrNull())); + const OUString& aLibName = pEntry->GetLibName(); + SfxStringItem aLibNameItem(SID_BASICIDE_ARG_LIBNAME, aLibName); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->ExecuteList(SID_BASICIDE_LIBSELECTED, SfxCallMode::SYNCHRON, + { &aDocumentItem, &aLibNameItem }); + } + ReleaseFocus(); +} + +void LibBox::ClearBox() +{ + sal_Int32 nCount = m_xWidget->get_count(); + for (sal_Int32 i = 0; i < nCount; ++i) + { + LibEntry* pEntry = weld::fromId<LibEntry*>(m_xWidget->get_id(i)); + delete pEntry; + } + m_xWidget->clear(); +} + +// class LanguageBoxControl ---------------------------------------------- + +/*! Macro for implementation two methods for LanguageBoxControl Class + * + * @code + * SfxToolBoxControl* LanguageBoxControl::CreateImpl(sal_uInt16 nSlotId, sal_uInt16 nId, ToolBox& rTbx) + * { + * return new LanguageBoxControl(nSlotId, nId, rTbx); + * } + * + * void LanguageBoxControl::RegisterControl(sal_uInt16 nSlotId, SfxModule* pMod) + * { + * SfxToolBoxControl::RegisterToolBoxControl( + * pMod, SfxTbxCtrlFactory(* LanguageBoxControl::CreateImpl, typeid(nItemClass), nSlotId)); + * } + * @endcode + * @see Macro SFX_DECL_TOOLBOX_CONTROL + */ +SFX_IMPL_TOOLBOX_CONTROL(LanguageBoxControl, SfxStringItem); + +LanguageBoxControl::LanguageBoxControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx) + : SfxToolBoxControl(nSlotId, nId, rTbx) +{ +} + +void LanguageBoxControl::StateChangedAtToolBoxControl(sal_uInt16, SfxItemState eState, + const SfxPoolItem* pItem) +{ + if (LanguageBox* pBox = static_cast<LanguageBox*>(GetToolBox().GetItemWindow(GetId()))) + { + if (eState != SfxItemState::DEFAULT) + pBox->set_sensitive(false); + else + { + pBox->set_sensitive(true); + pBox->Update(dynamic_cast<SfxStringItem const*>(pItem)); + } + } +} + +VclPtr<InterimItemWindow> LanguageBoxControl::CreateItemWindow(vcl::Window* pParent) +{ + return VclPtr<LanguageBox>::Create(pParent); +} + +// class basctl::LanguageBox ----------------------------------------------- +LanguageBox::LanguageBox(vcl::Window* pParent) + : DocListenerBox(pParent) + , msNotLocalizedStr(IDEResId(RID_STR_TRANSLATION_NOTLOCALIZED)) + , msDefaultLanguageStr(IDEResId(RID_STR_TRANSLATION_DEFAULT)) + , mbIgnoreSelect(false) +{ + FillBox(); + + SetSizePixel(m_xWidget->get_preferred_size()); +} + +LanguageBox::~LanguageBox() { disposeOnce(); } + +void LanguageBox::dispose() +{ + ClearBox(); + DocListenerBox::dispose(); +} + +void LanguageBox::FillBox() +{ + m_xWidget->freeze(); + mbIgnoreSelect = true; + msCurrentText = m_xWidget->get_active_text(); + ClearBox(); + + sal_Int32 nSelPos = -1; + + std::shared_ptr<LocalizationMgr> pCurMgr(GetShell()->GetCurLocalizationMgr()); + if (pCurMgr->isLibraryLocalized()) + { + set_sensitive(true); + Locale aDefaultLocale = pCurMgr->getStringResourceManager()->getDefaultLocale(); + Locale aCurrentLocale = pCurMgr->getStringResourceManager()->getCurrentLocale(); + Sequence<Locale> aLocaleSeq = pCurMgr->getStringResourceManager()->getLocales(); + const Locale* pLocale = aLocaleSeq.getConstArray(); + sal_Int32 i, nCount = aLocaleSeq.getLength(); + for (i = 0; i < nCount; ++i) + { + bool bIsDefault = localesAreEqual(aDefaultLocale, pLocale[i]); + bool bIsCurrent = localesAreEqual(aCurrentLocale, pLocale[i]); + LanguageType eLangType = LanguageTag::convertToLanguageType(pLocale[i]); + OUString sLanguage = SvtLanguageTable::GetLanguageString(eLangType); + if (bIsDefault) + { + sLanguage += " " + msDefaultLanguageStr; + } + LanguageEntry* pEntry = new LanguageEntry(pLocale[i], bIsDefault); + OUString sId(weld::toId(pEntry)); + m_xWidget->append(sId, sLanguage); + + if (bIsCurrent) + nSelPos = i; + } + + if (nSelPos != -1) + msCurrentText = m_xWidget->get_text(nSelPos); + } + else + { + m_xWidget->append_text(msNotLocalizedStr); + nSelPos = 0; + set_sensitive(false); + } + + m_xWidget->thaw(); + m_xWidget->set_active(nSelPos); + mbIgnoreSelect = false; +} + +void LanguageBox::ClearBox() +{ + sal_Int32 nCount = m_xWidget->get_count(); + for (sal_Int32 i = 0; i < nCount; ++i) + { + LanguageEntry* pEntry = weld::fromId<LanguageEntry*>(m_xWidget->get_id(i)); + delete pEntry; + } + m_xWidget->clear(); +} + +void LanguageBox::SetLanguage() +{ + LanguageEntry* pEntry = weld::fromId<LanguageEntry*>(m_xWidget->get_active_id()); + if (pEntry) + GetShell()->GetCurLocalizationMgr()->handleSetCurrentLocale(pEntry->m_aLocale); +} + +void LanguageBox::Select() +{ + if (!mbIgnoreSelect) + SetLanguage(); + else + m_xWidget->set_active_text(msCurrentText); // Select after Escape +} + +bool LanguageBox::HandleKeyInput(const KeyEvent& rKEvt) +{ + bool bDone = false; + + sal_uInt16 nKeyCode = rKEvt.GetKeyCode().GetCode(); + switch (nKeyCode) + { + case KEY_RETURN: + { + SetLanguage(); + bDone = true; + } + break; + case KEY_ESCAPE: + { + m_xWidget->set_active_text(msCurrentText); + bDone = true; + } + break; + } + + return bDone || DocListenerBox::HandleKeyInput(rKEvt); +} + +void LanguageBox::Update(const SfxStringItem* pItem) +{ + FillBox(); + + if (pItem && !pItem->GetValue().isEmpty()) + { + msCurrentText = pItem->GetValue(); + if (m_xWidget->get_active_text() != msCurrentText) + m_xWidget->set_active_text(msCurrentText); + } +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/ObjectCatalog.cxx b/basctl/source/basicide/ObjectCatalog.cxx new file mode 100644 index 0000000000..13069ed466 --- /dev/null +++ b/basctl/source/basicide/ObjectCatalog.cxx @@ -0,0 +1,85 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <strings.hrc> +#include <iderid.hxx> + +#include <ObjectCatalog.hxx> +#include <helpids.h> + +#include <vcl/taskpanelist.hxx> + +namespace basctl +{ +ObjectCatalog::ObjectCatalog(vcl::Window* pParent) + : DockingWindow(pParent, "modules/BasicIDE/ui/dockingorganizer.ui", "DockingOrganizer") +{ + m_xTitle = m_xBuilder->weld_label("title"); + m_xTree.reset(new SbTreeListBox(m_xBuilder->weld_tree_view("libraries"), GetFrameWeld())); + + SetHelpId("basctl:FloatingWindow:RID_BASICIDE_OBJCAT"); + SetText(IDEResId(RID_BASICIDE_OBJCAT)); + + // title + m_xTitle->set_label(IDEResId(RID_BASICIDE_OBJCAT)); + + // tree list + weld::TreeView& rWidget = m_xTree->get_widget(); + + rWidget.set_help_id(HID_BASICIDE_OBJECTCAT); + m_xTree->ScanAllEntries(); + rWidget.grab_focus(); + + // make object catalog keyboard accessible + GetParent()->GetSystemWindow()->GetTaskPaneList()->AddWindow(this); +} + +ObjectCatalog::~ObjectCatalog() { disposeOnce(); } + +void ObjectCatalog::dispose() +{ + GetParent()->GetSystemWindow()->GetTaskPaneList()->RemoveWindow(this); + m_xTitle.reset(); + m_xTree.reset(); + DockingWindow::dispose(); +} + +// ToggleFloatingMode() -- called by DockingWindow when IsFloatingMode() changes +void ObjectCatalog::ToggleFloatingMode() +{ + // base class version + DockingWindow::ToggleFloatingMode(); + + bool const bFloating = IsFloatingMode(); + // tdf#152154: m_xTitle will be null during disposing + if (m_xTitle) + m_xTitle->set_visible(!bFloating); +} + +void ObjectCatalog::SetCurrentEntry(BaseWindow* pCurWin) +{ + EntryDescriptor aDescriptor; + if (pCurWin) + aDescriptor = pCurWin->CreateEntryDescriptor(); + m_xTree->SetCurrentEntry(aDescriptor); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basdoc.cxx b/basctl/source/basicide/basdoc.cxx new file mode 100644 index 0000000000..ffd22b9063 --- /dev/null +++ b/basctl/source/basicide/basdoc.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 <sal/config.h> + +#include <sfx2/app.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/objface.hxx> + +#include "unomodel.hxx" + +#include "basdoc.hxx" +#define ShellClass_basctl_DocShell +#include <basslots.hxx> +#include <sfx2/sfxmodelfactory.hxx> +#include <svl/itemset.hxx> +#include <svx/svxids.hrc> +#include <tools/globname.hxx> +#include <tools/debug.hxx> + +namespace basctl +{ + + +SFX_IMPL_OBJECTFACTORY( DocShell, SvGlobalName(), "sbasic" ) + +SFX_IMPL_SUPERCLASS_INTERFACE(basctl_DocShell, SfxObjectShell) + +void basctl_DocShell::InitInterface_Impl() +{ + GetStaticInterface()->RegisterStatusBar(StatusBarId::BasicIdeStatusBar); +} + +DocShell::DocShell() + :SfxObjectShell( SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS | SfxModelFlags::DISABLE_DOCUMENT_RECOVERY ) +{ + SetPool( &SfxGetpApp()->GetPool() ); + SetBaseModel( new SIDEModel(this) ); +} + +DocShell::~DocShell() +{ + pPrinter.disposeAndClear(); +} + +SfxPrinter* DocShell::GetPrinter( bool bCreate ) +{ + if ( !pPrinter && bCreate ) + pPrinter.disposeAndReset(VclPtr<SfxPrinter>::Create(std::make_unique<SfxItemSetFixed + <SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN>>(GetPool()) + )); + + return pPrinter.get(); +} + +void DocShell::SetPrinter( SfxPrinter* pPr ) +{ + if (pPr != pPrinter.get()) + { + pPrinter.disposeAndReset(pPr); + } +} + +void DocShell::FillClass( SvGlobalName*, SotClipboardFormatId*, OUString*, sal_Int32, bool bTemplate) const +{ + DBG_ASSERT( !bTemplate, "No template for Basic" ); +} + +void DocShell::Draw( OutputDevice *, const JobSetup &, sal_uInt16, bool ) +{} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basdoc.hxx b/basctl/source/basicide/basdoc.hxx new file mode 100644 index 0000000000..bb847a0a9b --- /dev/null +++ b/basctl/source/basicide/basdoc.hxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sfx2/docfac.hxx> +#include <svx/ifaceids.hxx> +#include <vcl/vclptr.hxx> +#include <sfx2/printer.hxx> +#include <sfx2/objsh.hxx> + +namespace basctl +{ + +class DocShell: public SfxObjectShell +{ + ScopedVclPtr<SfxPrinter> pPrinter; + +protected: + virtual void Draw( OutputDevice *, const JobSetup & rSetup, + sal_uInt16 nAspect, bool bOutputForScreen ) override; + virtual void FillClass( SvGlobalName * pClassName, + SotClipboardFormatId * pFormat, + OUString * pFullTypeName, + sal_Int32 nVersion, + bool bTemplate = false ) const override; + +public: + + SFX_DECL_OBJECTFACTORY(); + SFX_DECL_INTERFACE( SVX_INTERFACE_BASIDE_DOCSH ) + +private: + /// SfxInterface initializer. + static void InitInterface_Impl(); + +public: + DocShell(); + virtual ~DocShell() override; + + SfxPrinter* GetPrinter( bool bCreate ); + void SetPrinter( SfxPrinter* pPrinter ); +}; + +} // namespace basctl + +// This typedef helps baside.sdi, +// because I don't know how to use nested names in it. +typedef basctl::DocShell basctl_DocShell; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basicmod.hxx b/basctl/source/basicide/basicmod.hxx new file mode 100644 index 0000000000..7a0175183d --- /dev/null +++ b/basctl/source/basicide/basicmod.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 <sfx2/module.hxx> + +namespace basctl +{ +class Module : public SfxModule +{ +public: + Module(const OString& rResName, SfxObjectFactory* pObjFact) + : SfxModule(rResName, { pObjFact }) + { + } +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basicrenderable.cxx b/basctl/source/basicide/basicrenderable.cxx new file mode 100644 index 0000000000..648f234cbd --- /dev/null +++ b/basctl/source/basicide/basicrenderable.cxx @@ -0,0 +1,221 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "basicrenderable.hxx" +#include <bastypes.hxx> +#include <iderid.hxx> +#include <strings.hrc> + +#include <toolkit/awt/vclxdevice.hxx> +#include <tools/multisel.hxx> +#include <cppuhelper/compbase.hxx> +#include <comphelper/propertysequence.hxx> + +namespace basctl +{ + +using namespace com::sun::star; +using namespace com::sun::star::uno; + +Renderable::Renderable (BaseWindow* pWin) +: cppu::WeakComponentImplHelper< css::view::XRenderable >( maMutex ) +, mpWindow( pWin ) +{ + m_aUIProperties.resize( 4 ); + + // show Subgroup for print range + vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt; + aPrintRangeOpt.maGroupHint = "PrintRange" ; + aPrintRangeOpt.mbInternalOnly = true; + + m_aUIProperties[0].Value = setSubgroupControlOpt("printrange", + IDEResId( RID_STR_PRINTDLG_PAGES ), OUString(), aPrintRangeOpt); + + // create a choice for the range to print + OUString aPrintContentName( "PrintContent" ); + const Sequence<OUString> aChoices{IDEResId(RID_STR_PRINTDLG_PRINTALLPAGES), + IDEResId(RID_STR_PRINTDLG_PRINTPAGES)}; + const Sequence<OUString> aHelpIds{".HelpID:vcl:PrintDialog:PrintContent:RadioButton:0", + ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:1"}; + const Sequence<OUString> aWidgetIds{"rbAllPages", + "rbRangePages"}; + m_aUIProperties[1].Value = setChoiceRadiosControlOpt(aWidgetIds, OUString(), + aHelpIds, aPrintContentName, + aChoices, 0); + + // create an Edit dependent on "Pages" selected + vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt(aPrintContentName, 1, true); + m_aUIProperties[2].Value = setEditControlOpt("pagerange", OUString(), + OUString(), "PageRange", + OUString(), aPageRangeOpt); + + vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintContentName, 0, true); + m_aUIProperties[3].Value = setChoiceListControlOpt("evenoddbox", + OUString(), + uno::Sequence<OUString>(), + "EvenOdd", + uno::Sequence<OUString>(), + 0, + uno::Sequence< sal_Bool >(), + aEvenOddOpt); +} + +Renderable::~Renderable() +{ +} + +VclPtr< Printer > Renderable::getPrinter() const +{ + VclPtr< Printer > pPrinter; + Any aValue( getValue( "RenderDevice" ) ); + Reference<awt::XDevice> xRenderDevice; + + if( aValue >>= xRenderDevice ) + { + VCLXDevice* pDevice = dynamic_cast<VCLXDevice*>(xRenderDevice.get()); + VclPtr< OutputDevice > pOut = pDevice ? pDevice->GetOutputDevice() : VclPtr< OutputDevice >(); + pPrinter = dynamic_cast<Printer*>(pOut.get()); + } + return pPrinter; +} + +bool Renderable::isPrintOddPages() const +{ + sal_Int64 nContent = getIntValue( "PrintContent", -1 ); + return nContent != 2; +} + +bool Renderable::isPrintEvenPages() const +{ + sal_Int64 nContent = getIntValue( "PrintContent", -1 ); + return nContent != 3; +} + +sal_Int32 SAL_CALL Renderable::getRendererCount ( + const Any&, const Sequence<beans::PropertyValue >& i_xOptions + ) +{ + processProperties( i_xOptions ); + + maValidPages.clear(); + + sal_Int32 nCount = 0; + if( mpWindow ) + { + VclPtr<Printer> pPrinter = getPrinter(); + if (!pPrinter) + throw lang::IllegalArgumentException("no printer", static_cast<cppu::OWeakObject*>(this), -1); + + nCount = mpWindow->countPages( pPrinter ); + + for (sal_Int32 nPage = 1; nPage <= nCount; nPage++) + { + if ( (isPrintEvenPages() && isOnEvenPage( nPage )) + || (isPrintOddPages() && !isOnEvenPage( nPage )) ) + { + maValidPages.push_back( nPage-1 ); + } + } + + sal_Int64 nContent = getIntValue( "PrintContent", -1 ); + sal_Int64 nEOContent = getIntValue ("EvenOdd", -1); + if( nContent == 1 ) + { + OUString aPageRange( getStringValue( "PageRange" ) ); + if( !aPageRange.isEmpty() ) + { + StringRangeEnumerator aRangeEnum( aPageRange, 0, nCount-1 ); + sal_Int32 nSelCount = aRangeEnum.size(); + if( nSelCount >= 0 ) + nCount = nSelCount; + } + } + else if ( nEOContent == 1 || nEOContent == 2 ) // even/odd pages + return static_cast<sal_Int32>( maValidPages.size() ); + } + + return nCount; +} + +Sequence<beans::PropertyValue> SAL_CALL Renderable::getRenderer ( + sal_Int32, const Any&, const Sequence<beans::PropertyValue>& i_xOptions + ) +{ + processProperties( i_xOptions ); + + Sequence< beans::PropertyValue > aVals; + // insert page size here + VclPtr<Printer> pPrinter = getPrinter(); + // no renderdevice is legal; the first call is to get our print ui options + if( pPrinter ) + { + Size aPageSize( pPrinter->PixelToLogic( pPrinter->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ) ); + + awt::Size aSize; + aSize.Width = aPageSize.Width(); + aSize.Height = aPageSize.Height(); + aVals = ::comphelper::InitPropertySequence({ + { "PageSize", Any(aSize) } + }); + } + + appendPrintUIOptions( aVals ); + + return aVals; +} + +void SAL_CALL Renderable::render ( + sal_Int32 nRenderer, const Any&, + const Sequence<beans::PropertyValue>& i_xOptions + ) +{ + processProperties( i_xOptions ); + + if( !mpWindow ) + return; + + VclPtr<Printer> pPrinter = getPrinter(); + if (!pPrinter) + throw lang::IllegalArgumentException("no printer", static_cast<cppu::OWeakObject*>(this), -1); + + sal_Int64 nContent = getIntValue( "PrintContent", -1 ); + if( nContent == 1 ) + { + OUString aPageRange( getStringValue( "PageRange" ) ); + if( !aPageRange.isEmpty() ) + { + sal_Int32 nPageCount = mpWindow->countPages( pPrinter ); + StringRangeEnumerator aRangeEnum( aPageRange, 0, nPageCount-1 ); + StringRangeEnumerator::Iterator it = aRangeEnum.begin(); + for( ; it != aRangeEnum.end() && nRenderer; --nRenderer ) + ++it; + + sal_Int32 nPage = ( it != aRangeEnum.end() ) ? *it : nRenderer; + mpWindow->printPage( nPage, pPrinter ); + } + else + mpWindow->printPage( nRenderer, pPrinter ); + } + else + mpWindow->printPage( maValidPages.at( nRenderer ), pPrinter ); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basicrenderable.hxx b/basctl/source/basicide/basicrenderable.hxx new file mode 100644 index 0000000000..638749c649 --- /dev/null +++ b/basctl/source/basicide/basicrenderable.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 <com/sun/star/view/XRenderable.hpp> +#include <cppuhelper/compbase.hxx> + +#include <vcl/print.hxx> + +namespace basctl +{ + +class BaseWindow; + +class Renderable : + public cppu::WeakComponentImplHelper< css::view::XRenderable >, + public vcl::PrinterOptionsHelper +{ + VclPtr<BaseWindow> mpWindow; + osl::Mutex maMutex; + std::vector<sal_Int32> maValidPages; + + VclPtr<Printer> getPrinter() const; + bool isPrintOddPages() const; + bool isPrintEvenPages() const; + static bool isOnEvenPage( sal_Int32 nPage ) { return nPage % 2 == 0; }; +public: + explicit Renderable (BaseWindow*); + virtual ~Renderable() override; + + // XRenderable + virtual sal_Int32 SAL_CALL getRendererCount ( + const css::uno::Any& aSelection, + const css::uno::Sequence<css::beans::PropertyValue >& xOptions) override; + + virtual css::uno::Sequence<css::beans::PropertyValue> SAL_CALL getRenderer ( + sal_Int32 nRenderer, + const css::uno::Any& rSelection, + const css::uno::Sequence<css::beans::PropertyValue>& rxOptions) override; + + virtual void SAL_CALL render ( + sal_Int32 nRenderer, + const css::uno::Any& rSelection, + const css::uno::Sequence<css::beans::PropertyValue>& rxOptions) override; + +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/baside2.cxx b/basctl/source/basicide/baside2.cxx new file mode 100644 index 0000000000..b01e5c238a --- /dev/null +++ b/basctl/source/basicide/baside2.cxx @@ -0,0 +1,1606 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "baside2.hxx" +#include <baside3.hxx> +#include <basobj.hxx> +#include <basidesh.hxx> +#include "brkdlg.hxx" +#include <iderdll.hxx> +#include <iderid.hxx> +#include "moduldlg.hxx" +#include <docsignature.hxx> +#include <officecfg/Office/BasicIDE.hxx> + +#include <helpids.h> +#include <strings.hrc> + +#include <basic/basmgr.hxx> +#include <basic/basrdll.hxx> +#include <basic/sbmeth.hxx> +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <comphelper/SetFlagContextHelper.hxx> +#include <comphelper/string.hxx> +#include <svl/srchdefs.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/docfile.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <sot/exchange.hxx> +#include <svl/eitem.hxx> +#include <svl/srchitem.hxx> +#include <svl/stritem.hxx> +#include <svl/visitem.hxx> +#include <svl/whiter.hxx> +#include <svx/svxids.hrc> +#include <tools/debug.hxx> +#include <utility> +#include <vcl/locktoplevels.hxx> +#include <vcl/errinf.hxx> +#include <vcl/event.hxx> +#include <vcl/print.hxx> +#include <vcl/svapp.hxx> +#include <vcl/textview.hxx> +#include <vcl/weld.hxx> +#include <vcl/xtextedt.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <cassert> +#include <osl/diagnose.h> +#include <officecfg/Office/Common.hxx> + +namespace basctl +{ + +namespace +{ + +namespace Print +{ + tools::Long const nLeftMargin = 1700; + tools::Long const nRightMargin = 900; + tools::Long const nTopMargin = 2000; + tools::Long const nBottomMargin = 1000; + tools::Long const nBorder = 300; +} + +short const ValidWindow = 0x1234; + +// What (who) are OW and MTF? Compare to baside3.cxx where an +// identically named variable, used in the same way, has the value +// "*.*" on Windows, "*" otherwise. Is that what should be done here, +// too? + +#if defined(OW) || defined(MTF) +char const FilterMask_All[] = "*"; +#else +constexpr OUString FilterMask_All = u"*.*"_ustr; +#endif + +} // end anonymous namespace + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ui::dialogs; +using namespace utl; +using namespace comphelper; + +namespace +{ + +void lcl_PrintHeader( Printer* pPrinter, sal_uInt16 nPages, sal_uInt16 nCurPage, const OUString& rTitle, bool bOutput ) +{ + Size const aSz = pPrinter->GetOutputSize(); + + const Color aOldLineColor( pPrinter->GetLineColor() ); + const Color aOldFillColor( pPrinter->GetFillColor() ); + const vcl::Font aOldFont( pPrinter->GetFont() ); + + pPrinter->SetLineColor( COL_BLACK ); + pPrinter->SetFillColor(); + + vcl::Font aFont( aOldFont ); + aFont.SetWeight( WEIGHT_BOLD ); + aFont.SetAlignment( ALIGN_BOTTOM ); + pPrinter->SetFont( aFont ); + + tools::Long nFontHeight = pPrinter->GetTextHeight(); + + // 1st Border => line, 2+3 Border = free space + tools::Long nYTop = Print::nTopMargin - 3*Print::nBorder - nFontHeight; + + tools::Long nXLeft = Print::nLeftMargin - Print::nBorder; + tools::Long nXRight = aSz.Width() - Print::nRightMargin + Print::nBorder; + + if( bOutput ) + pPrinter->DrawRect(tools::Rectangle( + Point(nXLeft, nYTop), + Size(nXRight - nXLeft, aSz.Height() - nYTop - Print::nBottomMargin + Print::nBorder) + )); + + + tools::Long nY = Print::nTopMargin - 2*Print::nBorder; + Point aPos(Print::nLeftMargin, nY); + if( bOutput ) + pPrinter->DrawText( aPos, rTitle ); + if ( nPages != 1 ) + { + aFont.SetWeight( WEIGHT_NORMAL ); + pPrinter->SetFont( aFont ); + aPos.AdjustX(pPrinter->GetTextWidth( rTitle ) ); + + if( bOutput ) + { + OUString aPageStr = " [" + IDEResId(RID_STR_PAGE) + " " + OUString::number( nCurPage ) + "]"; + pPrinter->DrawText( aPos, aPageStr ); + } + } + + nY = Print::nTopMargin - Print::nBorder; + + if( bOutput ) + pPrinter->DrawLine( Point( nXLeft, nY ), Point( nXRight, nY ) ); + + pPrinter->SetFont( aOldFont ); + pPrinter->SetFillColor( aOldFillColor ); + pPrinter->SetLineColor( aOldLineColor ); +} + +void lcl_ConvertTabsToSpaces( OUString& rLine ) +{ + if ( rLine.isEmpty() ) + return; + + OUStringBuffer aResult( rLine ); + sal_Int32 nPos = 0; + sal_Int32 nMax = aResult.getLength(); + while ( nPos < nMax ) + { + if ( aResult[nPos] == '\t' ) + { + // not 4 Blanks, but at 4 TabPos: + OUStringBuffer aBlanker; + string::padToLength(aBlanker, ( 4 - ( nPos % 4 ) ), ' '); + aResult.remove( nPos, 1 ); + aResult.insert( nPos, aBlanker ); + nMax = aResult.getLength(); + } + ++nPos; + } + rLine = aResult.makeStringAndClear(); +} + +} // namespace + +ModulWindow::ModulWindow (ModulWindowLayout* pParent, ScriptDocument const& rDocument, + const OUString& aLibName, const OUString& aName, OUString aModule) + : BaseWindow(pParent, rDocument, aLibName, aName) + , m_rLayout(*pParent) + , m_nValid(ValidWindow) + , m_aXEditorWindow(VclPtr<ComplexEditorWindow>::Create(this)) + , m_aModule(std::move(aModule)) +{ + m_aXEditorWindow->Show(); + SetBackground(); +} + +SbModuleRef const & ModulWindow::XModule() +{ + // ModuleWindows can now be created as a result of the + // modules getting created via the api. This is a result of an + // elementInserted event from the BasicLibrary container. + // However the SbModule is also created from a different listener to + // the same event ( in basmgr ) Therefore it is possible when we look + // for m_xModule it may not yet be available, here we keep trying to access + // the module until such time as it exists + + if ( !m_xModule.is() ) + { + BasicManager* pBasMgr = GetDocument().getBasicManager(); + if ( pBasMgr ) + { + StarBASIC* pBasic = pBasMgr->GetLib( GetLibName() ); + if ( pBasic ) + { + m_xBasic = pBasic; + m_xModule = pBasic->FindModule( GetName() ); + } + } + } + return m_xModule; +} + +ModulWindow::~ModulWindow() +{ + disposeOnce(); +} + +void ModulWindow::dispose() +{ + m_nValid = 0; + StarBASIC::Stop(); + m_aXEditorWindow.disposeAndClear(); + BaseWindow::dispose(); +} + + +void ModulWindow::GetFocus() +{ + if (m_nValid != ValidWindow) + return; + m_aXEditorWindow->GetEdtWindow().GrabFocus(); + // don't call basic calls because focus is somewhere else... +} + +void ModulWindow::DoInit() +{ + GetEditorWindow().InitScrollBars(); +} + +void ModulWindow::Paint(vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle&) +{ +} + +void ModulWindow::Resize() +{ + m_aXEditorWindow->SetPosSizePixel( Point( 0, 0 ), GetOutputSizePixel() ); +} + +void ModulWindow::CheckCompileBasic() +{ + if ( !XModule().is() ) + return; + + // never compile while running! + bool const bRunning = StarBASIC::IsRunning(); + bool const bModified = ( !m_xModule->IsCompiled() || + ( GetEditEngine() && GetEditEngine()->IsModified() ) ); + + if ( bRunning || !bModified ) + return; + + bool bDone = false; + + GetShell()->GetViewFrame().GetWindow().EnterWait(); + + AssertValidEditEngine(); + GetEditorWindow().SetSourceInBasic(); + + bool bWasModified = GetBasic()->IsModified(); + + { + // tdf#106529: only use strict compilation mode when compiling from the IDE + css::uno::ContextLayer layer(comphelper::NewFlagContext("BasicStrict")); + bDone = m_xModule->Compile(); + } + if ( !bWasModified ) + GetBasic()->SetModified(false); + + if ( bDone ) + { + GetBreakPoints().SetBreakPointsInBasic( m_xModule.get() ); + } + + GetShell()->GetViewFrame().GetWindow().LeaveWait(); + + m_aStatus.bError = !bDone; + m_aStatus.bIsRunning = false; +} + +void ModulWindow::BasicExecute() +{ + // #116444# check security settings before macro execution + ScriptDocument aDocument( GetDocument() ); + bool bMacrosDisabled = officecfg::Office::Common::Security::Scripting::DisableMacrosExecution::get(); + if (bMacrosDisabled || (aDocument.isDocument() && !aDocument.allowMacros())) + { + std::unique_ptr<weld::MessageDialog> xBox( + Application::CreateMessageDialog(GetFrameWeld(), VclMessageType::Warning, + VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO))); + xBox->run(); + return; + } + + CheckCompileBasic(); + + if ( !XModule().is() || !m_xModule->IsCompiled() || m_aStatus.bError ) + return; + + if ( GetBreakPoints().size() ) + m_aStatus.nBasicFlags = m_aStatus.nBasicFlags | BasicDebugFlags::Break; + + if ( !m_aStatus.bIsRunning ) + { + DBG_ASSERT( m_xModule.is(), "No Module!" ); + AddStatus( BASWIN_RUNNINGBASIC ); + sal_uInt16 nStart, nEnd; + TextSelection aSel = GetEditView()->GetSelection(); + // Init cursor to top + const sal_uInt32 nCurMethodStart = aSel.GetStart().GetPara() + 1; + SbMethod* pMethod = nullptr; + // first Macro, else blind "Main" (ExtSearch?) + for (sal_uInt32 nMacro = 0; nMacro < m_xModule->GetMethods()->Count(); nMacro++) + { + SbMethod* pM = static_cast<SbMethod*>(m_xModule->GetMethods()->Get(nMacro)); + assert(pM && "Method?"); + pM->GetLineRange( nStart, nEnd ); + if ( nCurMethodStart >= nStart && nCurMethodStart <= nEnd ) + { + // matched a method to the cursor position + pMethod = pM; + break; + } + } + if ( !pMethod ) + { + // If not in a method then prompt the user + ChooseMacro(GetFrameWeld(), uno::Reference<frame::XModel>()); + return; + } + pMethod->SetDebugFlags(m_aStatus.nBasicFlags); + BasicDLL::SetDebugMode(true); + RunMethod(pMethod); + BasicDLL::SetDebugMode(false); + // if cancelled during Interactive=false + BasicDLL::EnableBreak(true); + ClearStatus( BASWIN_RUNNINGBASIC ); + } + else + m_aStatus.bIsRunning = false; // cancel of Reschedule() +} + +void ModulWindow::CompileBasic() +{ + CheckCompileBasic(); + + XModule().is() && m_xModule->IsCompiled(); +} + +void ModulWindow::BasicRun() +{ + m_aStatus.nBasicFlags = BasicDebugFlags::NONE; + BasicExecute(); +} + +void ModulWindow::BasicStepOver() +{ + m_aStatus.nBasicFlags = BasicDebugFlags::StepInto | BasicDebugFlags::StepOver; + BasicExecute(); +} + + +void ModulWindow::BasicStepInto() +{ + m_aStatus.nBasicFlags = BasicDebugFlags::StepInto; + BasicExecute(); +} + +void ModulWindow::BasicStepOut() +{ + m_aStatus.nBasicFlags = BasicDebugFlags::StepOut; + BasicExecute(); +} + + +void ModulWindow::BasicStop() +{ + StarBASIC::Stop(); + m_aStatus.bIsRunning = false; +} + +void ModulWindow::LoadBasic() +{ + sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, this->GetFrameWeld()); + aDlg.SetContext(sfx2::FileDialogHelper::BasicImportSource); + Reference<XFilePicker3> xFP = aDlg.GetFilePicker(); + + xFP->appendFilter( "BASIC" , "*.bas" ); + xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All ); + xFP->setCurrentFilter( "BASIC" ); + + if( aDlg.Execute() != ERRCODE_NONE ) + return; + + Sequence< OUString > aPaths = xFP->getSelectedFiles(); + SfxMedium aMedium( aPaths[0], StreamMode::READ | StreamMode::SHARE_DENYWRITE | StreamMode::NOCREATE ); + SvStream* pStream = aMedium.GetInStream(); + if ( pStream ) + { + AssertValidEditEngine(); + sal_uInt32 nLines = CalcLineCount( *pStream ); + // nLines*4: ReadText/Formatting/Highlighting/Formatting + GetEditorWindow().CreateProgress( IDEResId(RID_STR_GENERATESOURCE), nLines*4 ); + GetEditEngine()->SetUpdateMode( false ); + // tdf#139196 - import macros using either default or utf-8 text encoding + pStream->StartReadingUnicodeText(RTL_TEXTENCODING_UTF8); + if (pStream->Tell() == 3) + pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8); + GetEditView()->Read( *pStream ); + GetEditEngine()->SetUpdateMode( true ); + GetEditorWindow().PaintImmediately(); + GetEditorWindow().ForceSyntaxTimeout(); + GetEditorWindow().DestroyProgress(); + ErrCodeMsg nError = aMedium.GetErrorIgnoreWarning(); + if ( nError ) + ErrorHandler::HandleError( nError ); + } + else + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_COULDNTREAD))); + xBox->run(); + } +} + + +void ModulWindow::SaveBasicSource() +{ + sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, this->GetFrameWeld()); + aDlg.SetContext(sfx2::FileDialogHelper::BasicExportSource); + const Reference<XFilePicker3>& xFP = aDlg.GetFilePicker(); + + xFP.queryThrow<XFilePickerControlAccess>()->setValue(ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, Any(true)); + + xFP->appendFilter( "BASIC", "*.bas" ); + xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All ); + xFP->setCurrentFilter( "BASIC" ); + + if( aDlg.Execute() != ERRCODE_NONE ) + return; + + Sequence< OUString > aPaths = xFP->getSelectedFiles(); + SfxMedium aMedium( aPaths[0], StreamMode::WRITE | StreamMode::SHARE_DENYWRITE | StreamMode::TRUNC ); + SvStream* pStream = aMedium.GetOutStream(); + if ( pStream ) + { + EnterWait(); + AssertValidEditEngine(); + // tdf#139196 - export macros using utf-8 including BOM + pStream->SetStreamCharSet(RTL_TEXTENCODING_UTF8); + pStream->WriteUChar(0xEF).WriteUChar(0xBB).WriteUChar(0xBF); + GetEditEngine()->Write( *pStream ); + aMedium.Commit(); + LeaveWait(); + ErrCodeMsg nError = aMedium.GetErrorIgnoreWarning(); + if ( nError ) + ErrorHandler::HandleError( nError ); + } + else + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_COULDNTWRITE))); + xErrorBox->run(); + } +} + +void ModulWindow::ImportDialog() +{ + const ScriptDocument& rDocument = GetDocument(); + OUString aLibName = GetLibName(); + implImportDialog(GetFrameWeld(), rDocument, aLibName); +} + +void ModulWindow::ToggleBreakPoint( sal_uInt16 nLine ) +{ + DBG_ASSERT( XModule().is(), "No Module!" ); + + if ( !XModule().is() ) + return; + + CheckCompileBasic(); + if ( m_aStatus.bError ) + { + return; + } + + BreakPoint* pBrk = GetBreakPoints().FindBreakPoint( nLine ); + if ( pBrk ) // remove + { + m_xModule->ClearBP( nLine ); + GetBreakPoints().remove( pBrk ); + } + else // create one + { + if ( m_xModule->SetBP( nLine )) + { + GetBreakPoints().InsertSorted( BreakPoint( nLine ) ); + if ( StarBASIC::IsRunning() ) + { + for (sal_uInt32 nMethod = 0; nMethod < m_xModule->GetMethods()->Count(); nMethod++) + { + SbMethod* pMethod + = static_cast<SbMethod*>(m_xModule->GetMethods()->Get(nMethod)); + assert(pMethod && "Method not found! (NULL)"); + pMethod->SetDebugFlags( pMethod->GetDebugFlags() | BasicDebugFlags::Break ); + } + } + } + } +} + +void ModulWindow::UpdateBreakPoint( const BreakPoint& rBrk ) +{ + DBG_ASSERT( XModule().is(), "No Module!" ); + + if ( XModule().is() ) + { + CheckCompileBasic(); + + if ( rBrk.bEnabled ) + m_xModule->SetBP( rBrk.nLine ); + else + m_xModule->ClearBP( rBrk.nLine ); + } +} + + +void ModulWindow::BasicToggleBreakPoint() +{ + AssertValidEditEngine(); + + TextSelection aSel = GetEditView()->GetSelection(); + aSel.GetStart().GetPara()++; // Basic lines start at 1! + aSel.GetEnd().GetPara()++; + + for ( sal_uInt32 nLine = aSel.GetStart().GetPara(); nLine <= aSel.GetEnd().GetPara(); ++nLine ) + { + ToggleBreakPoint( nLine ); + } + + m_aXEditorWindow->GetBrkWindow().Invalidate(); +} + + +void ModulWindow::BasicToggleBreakPointEnabled() +{ + AssertValidEditEngine(); + + TextView* pView = GetEditView(); + if ( !pView ) + return; + + TextSelection aSel = pView->GetSelection(); + BreakPointList& rList = GetBreakPoints(); + + for ( sal_uInt32 nLine = ++aSel.GetStart().GetPara(), nEnd = ++aSel.GetEnd().GetPara(); nLine <= nEnd; ++nLine ) + { + BreakPoint* pBrk = rList.FindBreakPoint( nLine ); + if ( pBrk ) + { + pBrk->bEnabled = !pBrk->bEnabled; + UpdateBreakPoint( *pBrk ); + } + } + + GetBreakPointWindow().Invalidate(); +} + +void ModulWindow::ManageBreakPoints() +{ + BreakPointWindow& rBrkWin = GetBreakPointWindow(); + BreakPointDialog aBrkDlg(rBrkWin.GetFrameWeld(), GetBreakPoints()); + aBrkDlg.run(); + rBrkWin.Invalidate(); +} + +void ModulWindow::BasicErrorHdl( StarBASIC const * pBasic ) +{ + GetShell()->GetViewFrame().ToTop(); + + // Return value: BOOL + // FALSE: cancel + // TRUE: go on... + sal_uInt16 nErrorLine = StarBASIC::GetLine() - 1; + sal_uInt16 nErrCol1 = StarBASIC::GetCol1(); + sal_uInt16 nErrCol2 = StarBASIC::GetCol2(); + if ( nErrCol2 != 0xFFFF ) + nErrCol2++; + + AssertValidEditEngine(); + GetEditView()->SetSelection( TextSelection( TextPaM( nErrorLine, nErrCol1 ), TextPaM( nErrorLine, nErrCol2 ) ) ); + + // if other basic, the IDE should try to display the correct module + bool const bMarkError = pBasic == GetBasic(); + if ( bMarkError ) + m_aXEditorWindow->GetBrkWindow().SetMarkerPos(nErrorLine, true); + + // #i47002# + Reference< awt::XWindow > xWindow = VCLUnoHelper::GetInterface( this ); + + // tdf#118572 make a currently running dialog, regardless of what its modal + // to, insensitive to user input until after this error dialog goes away. + TopLevelWindowLocker aBusy; + aBusy.incBusy(nullptr); + + ErrorHandler::HandleError(StarBASIC::GetErrorCode(), GetFrameWeld()); + + aBusy.decBusy(); + + // #i47002# + VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ); + if ( !pWindow ) + return; + + if ( bMarkError ) + m_aXEditorWindow->GetBrkWindow().SetNoMarker(); + return; +} + +BasicDebugFlags ModulWindow::BasicBreakHdl() +{ + // Return value: sal_uInt16 => see SB-Debug-Flags + sal_uInt16 nErrorLine = StarBASIC::GetLine(); + + + BreakPoint* pBrk = GetBreakPoints().FindBreakPoint( nErrorLine ); + if ( pBrk ) + { + pBrk->nHitCount++; + if ( pBrk->nHitCount <= pBrk->nStopAfter && GetBasic()->IsBreak() ) + return m_aStatus.nBasicFlags; // go on... + } + + nErrorLine--; // EditEngine starts at 0, Basic at 1 + + AssertValidEditEngine(); + GetEditView()->SetSelection( TextSelection( TextPaM( nErrorLine, 0 ), TextPaM( nErrorLine, 0 ) ) ); + m_aXEditorWindow->GetBrkWindow().SetMarkerPos( nErrorLine ); + + m_rLayout.UpdateDebug(false); + + m_aStatus.bIsInReschedule = true; + m_aStatus.bIsRunning = true; + + AddStatus( BASWIN_INRESCHEDULE ); + + InvalidateDebuggerSlots(); + + while( m_aStatus.bIsRunning && !Application::IsQuit()) + Application::Yield(); + + m_aStatus.bIsInReschedule = false; + m_aXEditorWindow->GetBrkWindow().SetNoMarker(); + + ClearStatus( BASWIN_INRESCHEDULE ); + + return m_aStatus.nBasicFlags; +} + +void ModulWindow::BasicAddWatch() +{ + AssertValidEditEngine(); + bool bAdd = true; + if ( !GetEditView()->HasSelection() ) + { + // tdf#57307 - expand selection to include connector punctuations + TextSelection aSel; + OUString aWord = GetEditEngine()->GetWord( GetEditView()->GetSelection().GetEnd(), &aSel.GetStart(), &aSel.GetEnd() ); + if ( !aWord.isEmpty() ) + GetEditView()->SetSelection( aSel ); + else + bAdd = false; + } + if ( bAdd ) + { + TextSelection aSel = GetEditView()->GetSelection(); + if ( aSel.GetStart().GetPara() == aSel.GetEnd().GetPara() ) // single line selection + m_rLayout.BasicAddWatch(GetEditView()->GetSelected()); + } +} + + +void ModulWindow::EditMacro( const OUString& rMacroName ) +{ + DBG_ASSERT( XModule().is(), "No Module!" ); + + if ( !XModule().is() ) + return; + + CheckCompileBasic(); + + if ( m_aStatus.bError ) + return; + + sal_uInt16 nStart, nEnd; + SbMethod* pMethod = static_cast<SbMethod*>(m_xModule->Find( rMacroName, SbxClassType::Method )); + if ( !pMethod ) + return; + + pMethod->GetLineRange( nStart, nEnd ); + if ( nStart ) + { + nStart--; + nEnd--; + } + TextSelection aSel( TextPaM( nStart, 0 ), TextPaM( nStart, 0 ) ); + AssertValidEditEngine(); + TextView * pView = GetEditView(); + // scroll if applicable so that first line is at the top + tools::Long nVisHeight = GetOutputSizePixel().Height(); + if ( pView->GetTextEngine()->GetTextHeight() > nVisHeight ) + { + tools::Long nMaxY = pView->GetTextEngine()->GetTextHeight() - nVisHeight; + tools::Long nOldStartY = pView->GetStartDocPos().Y(); + tools::Long nNewStartY = static_cast<tools::Long>(nStart) * pView->GetTextEngine()->GetCharHeight(); + nNewStartY = std::min( nNewStartY, nMaxY ); + pView->Scroll( 0, -(nNewStartY-nOldStartY) ); + pView->ShowCursor( false ); + GetEditVScrollBar().SetThumbPos( pView->GetStartDocPos().Y() ); + } + pView->SetSelection( aSel ); + pView->ShowCursor(); + pView->GetWindow()->GrabFocus(); +} + +void ModulWindow::StoreData() +{ + // StoreData is called when the BasicManager is destroyed or + // this window is closed. + // => interrupts undesired! + GetEditorWindow().SetSourceInBasic(); +} + +bool ModulWindow::AllowUndo() +{ + return GetEditorWindow().CanModify(); +} + +void ModulWindow::UpdateData() +{ + DBG_ASSERT( XModule().is(), "No Module!" ); + // UpdateData is called when the source has changed from outside + // => interrupts undesired! + + if ( !XModule().is() ) + return; + + SetModule( m_xModule->GetSource32() ); + + if ( GetEditView() ) + { + TextSelection aSel = GetEditView()->GetSelection(); + setTextEngineText(*GetEditEngine(), m_xModule->GetSource32()); + GetEditView()->SetSelection( aSel ); + GetEditEngine()->SetModified( false ); + MarkDocumentModified( GetDocument() ); + } +} + +sal_Int32 ModulWindow::countPages( Printer* pPrinter ) +{ + return FormatAndPrint( pPrinter, -1 ); +} + +void ModulWindow::printPage( sal_Int32 nPage, Printer* pPrinter ) +{ + FormatAndPrint( pPrinter, nPage ); +} + +/* implementation note: this is totally inefficient for the XRenderable interface + usage since the whole "document" will be format for every page. Should this ever + become a problem we should + - format only once for every new printer + - keep an index list for each page which is the starting paragraph +*/ +sal_Int32 ModulWindow::FormatAndPrint( Printer* pPrinter, sal_Int32 nPrintPage ) +{ + AssertValidEditEngine(); + + MapMode eOldMapMode( pPrinter->GetMapMode() ); + vcl::Font aOldFont( pPrinter->GetFont() ); + + vcl::Font aFont( GetEditEngine()->GetFont() ); + aFont.SetAlignment( ALIGN_BOTTOM ); + aFont.SetTransparent( true ); + aFont.SetFontSize( Size( 0, 360 ) ); + pPrinter->SetFont( aFont ); + pPrinter->SetMapMode(MapMode(MapUnit::Map100thMM)); + + OUString aTitle( CreateQualifiedName() ); + + sal_Int32 nLineHeight = pPrinter->GetTextHeight(); + if(nLineHeight == 0) + { + nLineHeight = 1; + } + + Size aPaperSz = pPrinter->GetOutputSize(); + aPaperSz.AdjustWidth( -(Print::nLeftMargin + Print::nRightMargin) ); + aPaperSz.AdjustHeight( -(Print::nTopMargin + Print::nBottomMargin) ); + + // nLinepPage is not correct if there's a line break + sal_Int32 nLinespPage = aPaperSz.Height()/nLineHeight; + tools::Long nXTextWidth = pPrinter->approximate_digit_width(); + + sal_Int32 nCharspLine = aPaperSz.Width() / std::max<tools::Long>(nXTextWidth, 1); + const sal_uInt32 nParas = GetEditEngine()->GetParagraphCount(); + + sal_Int32 nPages = nParas/nLinespPage+1; + sal_Int32 nCurPage = 1; + + lcl_PrintHeader( pPrinter, nPages, nCurPage, aTitle, nPrintPage == 0 ); + Point aPos( Print::nLeftMargin, Print::nTopMargin ); + for ( sal_uInt32 nPara = 0; nPara < nParas; ++nPara ) + { + OUString aLine( GetEditEngine()->GetText( nPara ) ); + lcl_ConvertTabsToSpaces( aLine ); + sal_Int32 nLines = aLine.getLength()/nCharspLine+1; + for (sal_Int32 nLine = 0; nLine < nLines; ++nLine) + { + sal_Int32 nBeginIndex = nLine*nCharspLine; + sal_Int32 nCopyCount = std::min<sal_Int32>(nCharspLine, aLine.getLength()-nBeginIndex); + OUString aTmpLine = aLine.copy(nBeginIndex, nCopyCount); + aPos.AdjustY(nLineHeight ); + if ( aPos.Y() > ( aPaperSz.Height() + Print::nTopMargin ) ) + { + nCurPage++; + lcl_PrintHeader( pPrinter, nPages, nCurPage, aTitle, nCurPage-1 == nPrintPage ); + aPos = Point(Print::nLeftMargin, Print::nTopMargin + nLineHeight); + } + if( nCurPage-1 == nPrintPage ) + pPrinter->DrawText( aPos, aTmpLine ); + } + aPos.AdjustY(10 ); // nParaSpace + } + + pPrinter->SetFont( aOldFont ); + pPrinter->SetMapMode( eOldMapMode ); + + return nCurPage; +} + +void ModulWindow::ExecuteCommand (SfxRequest& rReq) +{ + AssertValidEditEngine(); + switch (rReq.GetSlot()) + { + case SID_DELETE: + { + if (!IsReadOnly()) + { + KeyEvent aFakeDelete(0, KEY_DELETE); + (void)GetEditView()->KeyInput(aFakeDelete); + } + break; + } + case SID_SELECTALL: + { + TextSelection aSel( TextPaM( 0, 0 ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) ); + TextView * pView = GetEditView(); + pView->SetSelection( aSel ); + pView->GetWindow()->GrabFocus(); + break; + } + case SID_BASICRUN: + { + BasicRun(); + } + break; + case SID_BASICCOMPILE: + { + CompileBasic(); + } + break; + case SID_BASICSTEPOVER: + { + BasicStepOver(); + } + break; + case SID_BASICSTEPINTO: + { + BasicStepInto(); + } + break; + case SID_BASICSTEPOUT: + { + BasicStepOut(); + } + break; + case SID_BASICLOAD: + { + LoadBasic(); + } + break; + case SID_BASICSAVEAS: + { + SaveBasicSource(); + } + break; + case SID_IMPORT_DIALOG: + { + ImportDialog(); + } + break; + case SID_BASICIDE_MATCHGROUP: + { + GetEditView()->MatchGroup(); + } + break; + case SID_BASICIDE_TOGGLEBRKPNT: + { + BasicToggleBreakPoint(); + } + break; + case SID_BASICIDE_MANAGEBRKPNTS: + { + ManageBreakPoints(); + } + break; + case SID_BASICIDE_TOGGLEBRKPNTENABLED: + { + BasicToggleBreakPointEnabled(); + } + break; + case SID_BASICIDE_ADDWATCH: + { + BasicAddWatch(); + } + break; + case SID_BASICIDE_REMOVEWATCH: + { + m_rLayout.BasicRemoveWatch(); + } + break; + case SID_CUT: + { + if ( !IsReadOnly() ) + { + GetEditView()->Cut(); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_DOC_MODIFIED ); + } + } + break; + case SID_COPY: + { + GetEditView()->Copy(); + } + break; + case SID_PASTE: + { + if ( !IsReadOnly() ) + { + GetEditView()->Paste(); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_DOC_MODIFIED ); + } + } + break; + case SID_BASICIDE_BRKPNTSCHANGED: + { + GetBreakPointWindow().Invalidate(); + } + break; + case SID_SHOWLINES: + { + const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(rReq.GetSlot()); + bool bLineNumbers = pItem && pItem->GetValue(); + m_aXEditorWindow->SetLineNumberDisplay(bLineNumbers); + + std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); + officecfg::Office::BasicIDE::EditorSettings::LineNumbering::set(bLineNumbers, batch); + batch->commit(); + } + break; + case SID_BASICIDE_DELETECURRENT: + { + if (QueryDelModule(m_aName, GetFrameWeld())) + { + // tdf#134551 don't delete the window if last module is removed until this block + // is complete + VclPtr<ModulWindow> xKeepRef(this); + if (m_aDocument.removeModule(m_aLibName, m_aName)) + MarkDocumentModified(m_aDocument); + } + } + break; + case FID_SEARCH_OFF: + GrabFocus(); + break; + case SID_GOTOLINE: + { + GotoLineDialog aGotoDlg(GetFrameWeld()); + if (aGotoDlg.run() == RET_OK) + { + if (sal_Int32 const nLine = aGotoDlg.GetLineNumber()) + { + TextSelection const aSel(TextPaM(nLine - 1, 0), TextPaM(nLine - 1, 0)); + GetEditView()->SetSelection(aSel); + } + } + break; + } + } +} + +void ModulWindow::ExecuteGlobal (SfxRequest& rReq) +{ + switch (rReq.GetSlot()) + { + case SID_SIGNATURE: + { + DocumentSignature aSignature(m_aDocument); + if (aSignature.supportsSignatures()) + { + aSignature.signScriptingContent(rReq.GetFrameWeld()); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate(SID_SIGNATURE); + } + } + break; + } +} + +void ModulWindow::GetState( SfxItemSet &rSet ) +{ + SfxWhichIter aIter(rSet); + for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich() ) + { + switch ( nWh ) + { + case SID_CUT: + { + if ( !GetEditView() || !GetEditView()->HasSelection() ) + rSet.DisableItem( nWh ); + + if ( IsReadOnly() ) + rSet.DisableItem( nWh ); + } + break; + case SID_COPY: + { + if ( !GetEditView() || !GetEditView()->HasSelection() ) + rSet.DisableItem( nWh ); + } + break; + case SID_PASTE: + { + if ( !IsPasteAllowed() ) + rSet.DisableItem( nWh ); + + if ( IsReadOnly() ) + rSet.DisableItem( nWh ); + } + break; + case SID_BASICIDE_STAT_POS: + { + TextView* pView = GetEditView(); + if ( pView ) + { + TextSelection aSel = pView->GetSelection(); + OUString aPos = IDEResId( RID_STR_LINE ) + + " " + + OUString::number(aSel.GetEnd().GetPara()+1) + + ", " + + IDEResId( RID_STR_COLUMN ) + + " " + + OUString::number(aSel.GetEnd().GetIndex()+1); + SfxStringItem aItem( SID_BASICIDE_STAT_POS, aPos ); + rSet.Put( aItem ); + } + } + break; + case SID_BASICIDE_STAT_TITLE: + { + // search for current procedure name (Sub or Function) + TextView* pView = GetEditView(); + if ( pView ) + { + OUString sProcName; + + TextSelection aSel = pView->GetSelection(); + + sal_uInt32 i = aSel.GetStart().GetPara(); + do + { + OUString aCurrLine = GetEditEngine()->GetText( i ); + OUString sProcType; + if (GetEditorWindow().GetProcedureName(aCurrLine, sProcType, sProcName)) + break; + } while (i--); + + OUString aTitle = CreateQualifiedName(); + if (!sProcName.isEmpty()) + aTitle += "." + sProcName; + + if (IsReadOnly()) + aTitle += " (" + IDEResId(RID_STR_READONLY) + ")"; + + SfxStringItem aTitleItem( SID_BASICIDE_STAT_TITLE, aTitle ); + rSet.Put( aTitleItem ); + } + } + break; + case SID_ATTR_INSERT: + { + TextView* pView = GetEditView(); + if ( pView ) + { + SfxBoolItem aItem( SID_ATTR_INSERT, pView->IsInsertMode() ); + rSet.Put( aItem ); + } + } + break; + case SID_SHOWLINES: + { + bool bLineNumbers = ::officecfg::Office::BasicIDE::EditorSettings::LineNumbering::get(); + rSet.Put(SfxBoolItem(nWh, bLineNumbers)); + break; + } + case SID_SELECTALL: + { + if ( !GetEditView() ) + rSet.DisableItem( nWh ); + } + break; + } + } +} + +void ModulWindow::DoScroll( Scrollable* pCurScrollBar ) +{ + if ( ( pCurScrollBar == GetHScrollBar() ) && GetEditView() ) + { + // don't scroll with the value but rather use the Thumb-Pos for the VisArea: + tools::Long nDiff = GetEditView()->GetStartDocPos().X() - pCurScrollBar->GetThumbPos(); + GetEditView()->Scroll( nDiff, 0 ); + GetEditView()->ShowCursor( false ); + pCurScrollBar->SetThumbPos( GetEditView()->GetStartDocPos().X() ); + + } +} + +bool ModulWindow::IsModified() +{ + return GetEditEngine() && GetEditEngine()->IsModified(); +} + +OUString ModulWindow::GetSbModuleName() +{ + OUString aModuleName; + if ( XModule().is() ) + aModuleName = m_xModule->GetName(); + return aModuleName; +} + +OUString ModulWindow::GetTitle() +{ + return GetSbModuleName(); +} + +void ModulWindow::ShowCursor( bool bOn ) +{ + if ( GetEditEngine() ) + { + TextView* pView = GetEditEngine()->GetActiveView(); + if ( pView ) + { + if ( bOn ) + pView->ShowCursor(); + else + pView->HideCursor(); + } + } +} + +void ModulWindow::AssertValidEditEngine() +{ + if ( !GetEditEngine() ) + GetEditorWindow().CreateEditEngine(); +} + +void ModulWindow::Activating () +{ + bool bLineNumbers = ::officecfg::Office::BasicIDE::EditorSettings::LineNumbering::get(); + m_aXEditorWindow->SetLineNumberDisplay(bLineNumbers); + Show(); +} + +void ModulWindow::Deactivating() +{ + Hide(); +} + +sal_uInt16 ModulWindow::StartSearchAndReplace( const SvxSearchItem& rSearchItem, bool bFromStart ) +{ + if (IsSuspended()) + return 0; + + // one could also relinquish syntaxhighlighting/formatting instead of the stupid replace-everything... + AssertValidEditEngine(); + TextView* pView = GetEditView(); + TextSelection aSel; + if ( bFromStart ) + { + aSel = pView->GetSelection(); + if ( !rSearchItem.GetBackward() ) + pView->SetSelection( TextSelection() ); + else + pView->SetSelection( TextSelection( TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ), TextPaM( TEXT_PARA_ALL, TEXT_INDEX_ALL ) ) ); + } + + bool const bForward = !rSearchItem.GetBackward(); + sal_uInt16 nFound = 0; + if ( ( rSearchItem.GetCommand() == SvxSearchCmd::FIND ) || + ( rSearchItem.GetCommand() == SvxSearchCmd::FIND_ALL ) ) + { + nFound = pView->Search( rSearchItem.GetSearchOptions() , bForward ) ? 1 : 0; + } + else if ( ( rSearchItem.GetCommand() == SvxSearchCmd::REPLACE ) || + ( rSearchItem.GetCommand() == SvxSearchCmd::REPLACE_ALL ) ) + { + if ( !IsReadOnly() ) + { + bool const bAll = rSearchItem.GetCommand() == SvxSearchCmd::REPLACE_ALL; + nFound = pView->Replace( rSearchItem.GetSearchOptions() , bAll , bForward ); + } + } + + if ( bFromStart && !nFound ) + pView->SetSelection( aSel ); + + return nFound; +} + +SfxUndoManager* ModulWindow::GetUndoManager() +{ + if ( GetEditEngine() ) + return &GetEditEngine()->GetUndoManager(); + return nullptr; +} + +SearchOptionFlags ModulWindow::GetSearchOptions() +{ + SearchOptionFlags nOptions = SearchOptionFlags::SEARCH | + SearchOptionFlags::WHOLE_WORDS | + SearchOptionFlags::BACKWARDS | + SearchOptionFlags::REG_EXP | + SearchOptionFlags::EXACT | + SearchOptionFlags::SELECTION | + SearchOptionFlags::SIMILARITY; + + if ( !IsReadOnly() ) + { + nOptions |= SearchOptionFlags::REPLACE; + nOptions |= SearchOptionFlags::REPLACE_ALL; + } + + return nOptions; +} + +void ModulWindow::BasicStarted() +{ + if ( !XModule().is() ) + return; + + m_aStatus.bIsRunning = true; + BreakPointList& rList = GetBreakPoints(); + if ( rList.size() ) + { + rList.ResetHitCount(); + rList.SetBreakPointsInBasic( m_xModule.get() ); + for (sal_uInt32 nMethod = 0; nMethod < m_xModule->GetMethods()->Count(); nMethod++) + { + SbMethod* pMethod = static_cast<SbMethod*>(m_xModule->GetMethods()->Get(nMethod)); + assert(pMethod && "Method not found! (NULL)"); + pMethod->SetDebugFlags( pMethod->GetDebugFlags() | BasicDebugFlags::Break ); + } + } +} + +void ModulWindow::BasicStopped() +{ + m_aStatus.bIsRunning = false; + GetBreakPointWindow().SetNoMarker(); +} + +EntryDescriptor ModulWindow::CreateEntryDescriptor() +{ + ScriptDocument aDocument( GetDocument() ); + OUString aLibName( GetLibName() ); + LibraryLocation eLocation = aDocument.getLibraryLocation( aLibName ); + OUString aModName( GetName() ); + OUString aLibSubName; + if( m_xBasic.is() && aDocument.isInVBAMode() && XModule().is() ) + { + switch( m_xModule->GetModuleType() ) + { + case script::ModuleType::DOCUMENT: + { + aLibSubName = IDEResId( RID_STR_DOCUMENT_OBJECTS ); + uno::Reference< container::XNameContainer > xLib = aDocument.getOrCreateLibrary( E_SCRIPTS, aLibName ); + if( xLib.is() ) + { + OUString sObjName; + ModuleInfoHelper::getObjectName( xLib, aModName, sObjName ); + if( !sObjName.isEmpty() ) + { + aModName += " (" + sObjName + ")"; + } + } + break; + } + case script::ModuleType::FORM: + aLibSubName = IDEResId( RID_STR_USERFORMS ); + break; + case script::ModuleType::NORMAL: + aLibSubName = IDEResId( RID_STR_NORMAL_MODULES ); + break; + case script::ModuleType::CLASS: + aLibSubName = IDEResId( RID_STR_CLASS_MODULES ); + break; + } + } + return EntryDescriptor( aDocument, eLocation, aLibName, aLibSubName, aModName, OBJ_TYPE_MODULE ); +} + +void ModulWindow::SetReadOnly (bool b) +{ + if ( GetEditView() ) + GetEditView()->SetReadOnly( b ); +} + +bool ModulWindow::IsReadOnly() +{ + return GetEditView() && GetEditView()->IsReadOnly(); +} + +bool ModulWindow::IsPasteAllowed() +{ + bool bPaste = false; + + // get clipboard + Reference< datatransfer::clipboard::XClipboard > xClipboard = GetClipboard(); + if ( xClipboard.is() ) + { + + Reference< datatransfer::XTransferable > xTransf = xClipboard->getContents(); + if ( xTransf.is() ) + { + datatransfer::DataFlavor aFlavor; + SotExchange::GetFormatDataFlavor( SotClipboardFormatId::STRING, aFlavor ); + if ( xTransf->isDataFlavorSupported( aFlavor ) ) + bPaste = true; + } + } + + return bPaste; +} + +void ModulWindow::OnNewDocument () +{ + bool bLineNumbers = ::officecfg::Office::BasicIDE::EditorSettings::LineNumbering::get(); + m_aXEditorWindow->SetLineNumberDisplay(bLineNumbers); +} + +OUString ModulWindow::GetHid () const +{ + return HID_BASICIDE_MODULWINDOW; +} +ItemType ModulWindow::GetType () const +{ + return TYPE_MODULE; +} + +bool ModulWindow::HasActiveEditor () const +{ + return !IsSuspended(); +} + + +void ModulWindow::UpdateModule () +{ + OUString const aModule = getTextEngineText(*GetEditEngine()); + + // update module in basic + assert(m_xModule.is()); + + // update module in module window + SetModule(aModule); + + // update module in library + OSL_VERIFY(m_aDocument.updateModule(m_aLibName, m_aName, aModule)); + + GetEditEngine()->SetModified(false); + MarkDocumentModified(m_aDocument); +} + +ModulWindowLayout::ModulWindowLayout (vcl::Window* pParent, ObjectCatalog& rObjectCatalog_) : + Layout(pParent), + pChild(nullptr), + aWatchWindow(VclPtr<WatchWindow>::Create(this)), + aStackWindow(VclPtr<StackWindow>::Create(this)), + rObjectCatalog(rObjectCatalog_) +{ } + +ModulWindowLayout::~ModulWindowLayout() +{ + disposeOnce(); +} + +void ModulWindowLayout::dispose() +{ + aWatchWindow.disposeAndClear(); + aStackWindow.disposeAndClear(); + pChild.clear(); + Layout::dispose(); +} + +void ModulWindowLayout::UpdateDebug (bool bBasicStopped) +{ + aWatchWindow->UpdateWatches(bBasicStopped); + aStackWindow->UpdateCalls(); +} + +void ModulWindowLayout::Paint (vcl::RenderContext& rRenderContext, tools::Rectangle const&) +{ + rRenderContext.DrawText(Point(), IDEResId(RID_STR_NOMODULE)); +} + +void ModulWindowLayout::Activating (BaseWindow& rChild) +{ + assert(dynamic_cast<ModulWindow*>(&rChild)); + pChild = &static_cast<ModulWindow&>(rChild); + aWatchWindow->Show(); + aStackWindow->Show(); + rObjectCatalog.Show(); + rObjectCatalog.SetLayoutWindow(this); + rObjectCatalog.UpdateEntries(); + Layout::Activating(rChild); + aSyntaxColors.SetActiveEditor(&pChild->GetEditorWindow()); +} + +void ModulWindowLayout::Deactivating () +{ + aSyntaxColors.SetActiveEditor(nullptr); + Layout::Deactivating(); + aWatchWindow->Hide(); + aStackWindow->Hide(); + rObjectCatalog.Hide(); + pChild = nullptr; +} + +void ModulWindowLayout::GetState (SfxItemSet &rSet, unsigned nWhich) +{ + switch (nWhich) + { + case SID_SHOW_PROPERTYBROWSER: + rSet.Put(SfxVisibilityItem(nWhich, false)); + break; + + case SID_BASICIDE_CHOOSEMACRO: + rSet.Put(SfxVisibilityItem(nWhich, true)); + break; + } +} + +void ModulWindowLayout::BasicAddWatch (OUString const& rWatchStr) +{ + aWatchWindow->AddWatch(rWatchStr); +} + +void ModulWindowLayout::BasicRemoveWatch () +{ + aWatchWindow->RemoveSelectedWatch(); +} + +void ModulWindowLayout::ShowWatchWindow(bool bVisible) +{ + aWatchWindow->Show(bVisible); + ArrangeWindows(); +} + +void ModulWindowLayout::ShowStackWindow(bool bVisible) +{ + aStackWindow->Show(bVisible); + ArrangeWindows(); +} + +void ModulWindowLayout::OnFirstSize (tools::Long const nWidth, tools::Long const nHeight) +{ + AddToLeft(&rObjectCatalog, Size(nWidth * 0.20, nHeight * 0.75)); + AddToBottom(aWatchWindow.get(), Size(nWidth * 0.67, nHeight * 0.25)); + AddToBottom(aStackWindow.get(), Size(nWidth * 0.33, nHeight * 0.25)); +} + +ModulWindowLayout::SyntaxColors::SyntaxColors () : + pEditor(nullptr) +{ + aConfig.AddListener(this); + + NewConfig(true); +} + +ModulWindowLayout::SyntaxColors::~SyntaxColors () +{ + aConfig.RemoveListener(this); +} + +// virtual +void ModulWindowLayout::SyntaxColors::ConfigurationChanged (utl::ConfigurationBroadcaster*, ConfigurationHints) +{ + NewConfig(false); +} + +// when a new configuration has to be set +void ModulWindowLayout::SyntaxColors::NewConfig (bool bFirst) +{ + static struct + { + TokenType eTokenType; + svtools::ColorConfigEntry eEntry; + } + const vIds[] = + { + { TokenType::Unknown, svtools::FONTCOLOR }, + { TokenType::Identifier, svtools::BASICIDENTIFIER }, + { TokenType::Whitespace, svtools::FONTCOLOR }, + { TokenType::Number, svtools::BASICNUMBER }, + { TokenType::String, svtools::BASICSTRING }, + { TokenType::EOL, svtools::FONTCOLOR }, + { TokenType::Comment, svtools::BASICCOMMENT }, + { TokenType::Error, svtools::BASICERROR }, + { TokenType::Operator, svtools::BASICOPERATOR }, + { TokenType::Keywords, svtools::BASICKEYWORD }, + }; + + Color aDocColor = aConfig.GetColorValue(svtools::BASICEDITOR).nColor; + if (bFirst || aDocColor != m_aBackgroundColor) + { + m_aBackgroundColor = aDocColor; + if (!bFirst && pEditor) + { + pEditor->SetBackground(Wallpaper(m_aBackgroundColor)); + pEditor->Invalidate(); + } + } + + Color aFontColor = aConfig.GetColorValue(svtools::FONTCOLOR).nColor; + if (bFirst || aFontColor != m_aFontColor) + { + m_aFontColor = aFontColor; + if (!bFirst && pEditor) + pEditor->ChangeFontColor(m_aFontColor); + } + + bool bChanged = false; + for (const auto& vId: vIds) + { + Color const aColor = aConfig.GetColorValue(vId.eEntry).nColor; + Color& rMyColor = aColors[vId.eTokenType]; + if (bFirst || aColor != rMyColor) + { + rMyColor = aColor; + bChanged = true; + } + } + if (bChanged && !bFirst && pEditor) + pEditor->UpdateSyntaxHighlighting(); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/baside2.hxx b/basctl/source/basicide/baside2.hxx new file mode 100644 index 0000000000..116dab2bb9 --- /dev/null +++ b/basctl/source/basicide/baside2.hxx @@ -0,0 +1,526 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <memory> +#include <mutex> +#include <layout.hxx> +#include "breakpoint.hxx" +#include "linenumberwindow.hxx" + +#include <basic/sbmod.hxx> +#include <basic/sbstar.hxx> +#include <vcl/InterimItemWindow.hxx> +#include <vcl/idle.hxx> +#include <vcl/weld.hxx> + +#include <svtools/colorcfg.hxx> +#include <svtools/scrolladaptor.hxx> +#include <o3tl/enumarray.hxx> +#include <rtl/ustrbuf.hxx> + +#include <set> +#include <string_view> + +#include <vcl/textdata.hxx> +#include <basic/codecompletecache.hxx> +#include <com/sun/star/reflection/XIdlClass.hpp> +#include <comphelper/syntaxhighlight.hxx> + +class ExtTextEngine; +class TextView; +class SvxSearchItem; +namespace com::sun::star::beans { class XMultiPropertySet; } + +namespace basctl +{ + +class ObjectCatalog; +class CodeCompleteWindow; +class ModulWindowLayout; + +// #108672 Helper functions to get/set text in TextEngine +// using the stream interface (get/setText() only supports +// tools Strings limited to 64K). +// defined in baside2b.cxx +OUString getTextEngineText (ExtTextEngine&); +void setTextEngineText (ExtTextEngine&, std::u16string_view); + +class EditorWindow final : public vcl::Window, public SfxListener +{ +friend class CodeCompleteWindow; +friend class EditorWindowUIObject; +private: + class ChangesListener; + + std::unique_ptr<TextView> pEditView; + std::unique_ptr<ExtTextEngine> pEditEngine; + ModulWindow& rModulWindow; + + rtl::Reference< ChangesListener > listener_; + std::mutex mutex_; + css::uno::Reference< css::beans::XMultiPropertySet > + notifier_; + + tools::Long nCurTextWidth; + + ImplSVEvent* m_nSetSourceInBasicId; + + SyntaxHighlighter aHighlighter; + Idle aSyntaxIdle; + std::set<sal_uInt16> aSyntaxLineTable; + DECL_LINK(SyntaxTimerHdl, Timer *, void); + DECL_LINK(SetSourceInBasicHdl, void*, void); + + // progress bar + class ProgressInfo; + std::unique_ptr<ProgressInfo> pProgress; + + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; + + void ImpDoHighlight( sal_uInt32 nLineOff ); + void ImplSetFont(); + sal_uInt16 nCurrentZoomLevel; + + bool bHighlighting; + bool bDoSyntaxHighlight; + bool bDelayHighlight; + + virtual css::uno::Reference< css::awt::XVclWindowPeer > GetComponentInterface(bool bCreate = true) override; + CodeCompleteDataCache aCodeCompleteCache; + VclPtr<CodeCompleteWindow> pCodeCompleteWnd; + OUString GetActualSubName( sal_uInt32 nLine ); // gets the actual subroutine name according to line number + void SetupAndShowCodeCompleteWnd(const std::vector< OUString >& aEntryVect, TextSelection aSel ); + void HandleAutoCorrect(); + void HandleAutoCloseParen(); + void HandleAutoCloseDoubleQuotes(); + void HandleCodeCompletion(); + void HandleProcedureCompletion(); + TextSelection GetLastHighlightPortionTextSelection() const; + + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& ) override; + virtual void Resize() override; + virtual void KeyInput( const KeyEvent& rKeyEvt ) override; + virtual void MouseMove( const MouseEvent& rMEvt ) override; + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void MouseButtonUp( const MouseEvent& rMEvt ) override; + virtual void Command( const CommandEvent& rCEvt ) override; + virtual void LoseFocus() override; + virtual void RequestHelp( const HelpEvent& rHEvt ) override; + + void DoSyntaxHighlight( sal_uInt32 nPara ); + OUString GetWordAtCursor(); + bool ImpCanModify(); + +public: + EditorWindow (vcl::Window* pParent, ModulWindow*); + virtual ~EditorWindow() override; + virtual void dispose() override; + + ExtTextEngine* GetEditEngine() const { return pEditEngine.get(); } + TextView* GetEditView() const { return pEditView.get(); } + + void CreateProgress( const OUString& rText, sal_uInt32 nRange ); + void DestroyProgress(); + + void ParagraphInsertedDeleted( sal_uInt32 nNewPara, bool bInserted ); + void DoDelayedSyntaxHighlight( sal_uInt32 nPara ); + + void CreateEditEngine(); + void SetScrollBarRanges(); + void InitScrollBars(); + + void ForceSyntaxTimeout(); + void SetSourceInBasic(); + + bool CanModify() { return ImpCanModify(); } + + void ChangeFontColor( Color aColor ); + void UpdateSyntaxHighlighting (); + + void SetEditorZoomLevel(sal_uInt16 nNewZoomLevel); + sal_uInt16 GetCurrentZoom() { return nCurrentZoomLevel; } + + bool GetProcedureName(std::u16string_view rLine, OUString& rProcType, OUString& rProcName) const; + + FactoryFunction GetUITestFactory() const override; +}; + +class BreakPointWindow final : public vcl::Window +{ + ModulWindow& rModulWindow; + tools::Long nCurYOffset; + sal_uInt16 nMarkerPos; + BreakPointList aBreakPointList; + bool bErrorMarker; + + virtual void DataChanged(DataChangedEvent const & rDCEvt) override; + + void setBackgroundColor(Color aColor); + + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) override; + BreakPoint* FindBreakPoint( const Point& rMousePos ); + void ShowMarker(vcl::RenderContext& rRenderContext); + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void Command( const CommandEvent& rCEvt ) override; + + bool SyncYOffset(); + +public: + BreakPointWindow (vcl::Window* pParent, ModulWindow*); + + void SetMarkerPos( sal_uInt16 nLine, bool bErrorMarker = false ); + void SetNoMarker (); + + void DoScroll( tools::Long nVertScroll ); + tools::Long& GetCurYOffset() { return nCurYOffset; } + BreakPointList& GetBreakPoints() { return aBreakPointList; } +}; + +class WatchWindow final : public DockingWindow +{ +private: + std::unique_ptr<weld::Container> m_xTitleArea; + std::unique_ptr<weld::Label> m_xTitle; + std::unique_ptr<weld::Entry> m_xEdit; + std::unique_ptr<weld::Button> m_xRemoveWatchButton; + std::unique_ptr<weld::TreeView> m_xTreeListBox; + + ImplSVEvent* m_nUpdateWatchesId; + OUString aEditingRes; + + virtual void Resize() override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + + SbxBase* ImplGetSBXForEntry(const weld::TreeIter& rEntry, bool& rbArrayElement); + + void implEnableChildren(const weld::TreeIter& rEntry, bool bEnable); + + DECL_STATIC_LINK(WatchWindow, ButtonHdl, weld::Button&, void); + DECL_LINK(TreeListHdl, weld::TreeView&, void); + DECL_LINK(RequestingChildrenHdl, const weld::TreeIter&, bool); + DECL_LINK(ActivateHdl, weld::Entry&, bool); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + DECL_LINK(EditingEntryHdl, const weld::TreeIter&, bool); + typedef std::pair<const weld::TreeIter&, OUString> IterString; + DECL_LINK(EditedEntryHdl, const IterString&, bool); + DECL_LINK(ExecuteUpdateWatches, void*, void); + +public: + explicit WatchWindow (Layout* pParent); + virtual ~WatchWindow() override; + virtual void dispose() override; + + void AddWatch( const OUString& rVName ); + void RemoveSelectedWatch(); + void UpdateWatches(bool bBasicStopped = false); +}; + +class StackWindow : public DockingWindow +{ +private: + std::unique_ptr<weld::Label> m_xTitle; + std::unique_ptr<weld::TreeView> m_xTreeListBox; + +protected: + virtual void Resize() override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override; + +public: + explicit StackWindow (Layout* pParent); + virtual ~StackWindow() override; + virtual void dispose() override; + + void UpdateCalls(); +}; + + +class ComplexEditorWindow final : public vcl::Window +{ +private: + VclPtr<BreakPointWindow> aBrkWindow; + VclPtr<LineNumberWindow> aLineNumberWindow; + VclPtr<EditorWindow> aEdtWindow; + VclPtr<ScrollAdaptor> aEWVScrollBar; + VclPtr<ScrollAdaptor> aEWHScrollBar; + + virtual void DataChanged(DataChangedEvent const & rDCEvt) override; + + virtual void Resize() override; + DECL_LINK(ScrollHdl, weld::Scrollbar&, void); + +public: + explicit ComplexEditorWindow( ModulWindow* pParent ); + virtual ~ComplexEditorWindow() override; + virtual void dispose() override; + BreakPointWindow& GetBrkWindow() { return *aBrkWindow; } + LineNumberWindow& GetLineNumberWindow() { return *aLineNumberWindow; } + EditorWindow& GetEdtWindow() { return *aEdtWindow; } + ScrollAdaptor& GetEWVScrollBar() { return *aEWVScrollBar; } + ScrollAdaptor& GetEWHScrollBar() { return *aEWHScrollBar; } + + void SetLineNumberDisplay(bool b); +}; + + +class ModulWindow: public BaseWindow +{ +private: + ModulWindowLayout& m_rLayout; + StarBASICRef m_xBasic; + short m_nValid; + VclPtr<ComplexEditorWindow> m_aXEditorWindow; + BasicStatus m_aStatus; + SbModuleRef m_xModule; + OUString m_aModule; + + void CheckCompileBasic(); + void BasicExecute(); + + sal_Int32 FormatAndPrint( Printer* pPrinter, sal_Int32 nPage ); + SbModuleRef const & XModule(); +protected: + virtual void Resize() override; + virtual void GetFocus() override; + virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& ) override; + virtual void DoInit() override; + virtual void DoScroll(Scrollable* pCurScrollBar) override; + +public: + ModulWindow( ModulWindowLayout* pParent, const ScriptDocument& rDocument, const OUString& aLibName, const OUString& aName, OUString aModule ); + + virtual ~ModulWindow() override; + virtual void dispose() override; + + virtual void ExecuteCommand (SfxRequest& rReq) override; + virtual void ExecuteGlobal (SfxRequest& rReq) override; + virtual void GetState( SfxItemSet& ) override; + virtual void StoreData() override; + virtual void UpdateData() override; + // return number of pages to be printed + virtual sal_Int32 countPages( Printer* pPrinter ) override; + // print page + virtual void printPage( sal_Int32 nPage, Printer* pPrinter ) override; + virtual OUString GetTitle() override; + virtual EntryDescriptor CreateEntryDescriptor() override; + virtual bool AllowUndo() override; + virtual void SetReadOnly (bool bReadOnly) override; + virtual bool IsReadOnly() override; + + StarBASIC* GetBasic() { XModule(); return m_xBasic.get(); } + + SbModule* GetSbModule() { return m_xModule.get(); } + void SetSbModule( SbModule* pModule ) { m_xModule = pModule; } + OUString GetSbModuleName(); + + void CompileBasic(); + void BasicRun(); + void BasicStepOver(); + void BasicStepInto(); + void BasicStepOut(); + void BasicStop(); + void BasicToggleBreakPoint(); + void BasicToggleBreakPointEnabled(); + void ManageBreakPoints(); + void UpdateBreakPoint( const BreakPoint& rBrk ); + void BasicAddWatch(); + + void BasicErrorHdl( StarBASIC const * pBasic ); + BasicDebugFlags BasicBreakHdl(); + void AssertValidEditEngine(); + + void LoadBasic(); + void SaveBasicSource(); + void ImportDialog(); + + void EditMacro( const OUString& rMacroName ); + + void ToggleBreakPoint( sal_uInt16 nLine ); + + BasicStatus& GetBasicStatus() { return m_aStatus; } + + virtual bool IsModified () override; + bool IsPasteAllowed (); + + void ShowCursor( bool bOn ); + + virtual SearchOptionFlags GetSearchOptions() override; + virtual sal_uInt16 StartSearchAndReplace (SvxSearchItem const&, bool bFromStart = false) override; + + EditorWindow& GetEditorWindow() { return m_aXEditorWindow->GetEdtWindow(); } + BreakPointWindow& GetBreakPointWindow() { return m_aXEditorWindow->GetBrkWindow(); } + LineNumberWindow& GetLineNumberWindow() { return m_aXEditorWindow->GetLineNumberWindow(); } + ScrollAdaptor& GetEditVScrollBar() { return m_aXEditorWindow->GetEWVScrollBar(); } + ScrollAdaptor& GetEditHScrollBar() { return m_aXEditorWindow->GetEWHScrollBar(); } + ExtTextEngine* GetEditEngine() { return GetEditorWindow().GetEditEngine(); } + TextView* GetEditView() { return GetEditorWindow().GetEditView(); } + BreakPointList& GetBreakPoints() { return GetBreakPointWindow().GetBreakPoints(); } + ModulWindowLayout& GetLayout () { return m_rLayout; } + + virtual void BasicStarted() override; + virtual void BasicStopped() override; + + virtual SfxUndoManager* + GetUndoManager() override; + + const OUString& GetModule() const { return m_aModule; } + void SetModule( const OUString& aModule ) { m_aModule = aModule; } + + virtual void Activating () override; + virtual void Deactivating () override; + + virtual void OnNewDocument () override; + virtual OUString GetHid () const override; + virtual ItemType GetType () const override; + virtual bool HasActiveEditor () const override; + + void UpdateModule (); +}; + +class ModulWindowLayout: public Layout +{ +public: + ModulWindowLayout (vcl::Window* pParent, ObjectCatalog&); + virtual ~ModulWindowLayout() override; + virtual void dispose() override; +public: + // Layout: + virtual void Activating (BaseWindow&) override; + virtual void Deactivating () override; + virtual void GetState (SfxItemSet&, unsigned nWhich) override; + virtual void UpdateDebug (bool bBasicStopped) override; +public: + void BasicAddWatch (OUString const&); + void BasicRemoveWatch (); + void ShowWatchWindow(bool bVisible); + void ShowStackWindow(bool bVisible); + bool IsWatchWindowVisible() { return aWatchWindow->IsVisible(); } + bool IsStackWindowVisible() { return aStackWindow->IsVisible(); } + Color const & GetSyntaxBackgroundColor () const { return aSyntaxColors.GetBackgroundColor(); } + Color const & GetFontColor () const { return aSyntaxColors.GetFontColor(); } + Color const & GetSyntaxColor (TokenType eType) const { return aSyntaxColors.GetColor(eType); } + +protected: + // Window: + virtual void Paint (vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + // Layout: + virtual void OnFirstSize (tools::Long nWidth, tools::Long nHeight) override; + +private: + // main child window + VclPtr<ModulWindow> pChild; + // dockable windows + VclPtr<WatchWindow> aWatchWindow; + VclPtr<StackWindow> aStackWindow; + ObjectCatalog& rObjectCatalog; + + // SyntaxColors -- stores Basic syntax highlighting colors + class SyntaxColors : public utl::ConfigurationListener + { + public: + SyntaxColors (); + virtual ~SyntaxColors () override; + public: + void SetActiveEditor (EditorWindow* pEditor_) { pEditor = pEditor_; } + public: + Color const & GetBackgroundColor () const { return m_aBackgroundColor; }; + Color const & GetFontColor () const { return m_aFontColor; } + Color const & GetColor(TokenType eType) const { return aColors[eType]; } + + private: + virtual void ConfigurationChanged (utl::ConfigurationBroadcaster*, ConfigurationHints) override; + void NewConfig (bool bFirst); + + private: + Color m_aBackgroundColor; + Color m_aFontColor; + // the color values (the indexes are TokenType, see comphelper/syntaxhighlight.hxx) + o3tl::enumarray<TokenType, Color> aColors; + // the configuration + svtools::ColorConfig aConfig; + // the active editor + VclPtr<EditorWindow> pEditor; + + } aSyntaxColors; +}; + +class CodeCompleteWindow final : public InterimItemWindow +{ +private: + VclPtr<EditorWindow> pParent; // parent window + TextSelection m_aTextSelection; + std::unique_ptr<weld::TreeView> m_xListBox; + + /* a buffer to build up function name when typing + * a function name, used for showing/hiding listbox values + * */ + OUStringBuffer aFuncBuffer; + + void InsertSelectedEntry(); // insert the selected entry + void SetMatchingEntries(); // sets the visible entries based on aFuncBuffer variable + TextView* GetParentEditView(); + + DECL_LINK(ImplDoubleClickHdl, weld::TreeView&, bool); + DECL_LINK(ImplSelectHdl, weld::TreeView&, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + +public: + explicit CodeCompleteWindow( EditorWindow* pPar ); + virtual ~CodeCompleteWindow() override; + virtual void dispose() override; + + void InsertEntry( const OUString& aStr ); + void ClearListBox(); + void SetTextSelection( const TextSelection& aSel ); + const TextSelection& GetTextSelection() const { return m_aTextSelection;} + void ResizeAndPositionListBox(); + void SelectFirstEntry(); //selects first entry in ListBox + + /* + * clears if typed anything, then hides + * the window, clear internal variables + * */ + void ClearAndHide(); + void HideAndRestoreFocus(); + + bool HandleKeyInput(const KeyEvent& rKeyEvt); +}; + +class UnoTypeCodeCompletetor +{ +private: + css::uno::Reference< css::reflection::XIdlClass > xClass; + bool bCanComplete; + + bool CheckField( const OUString& sFieldName ); + bool CheckMethod( const OUString& sMethName ); + +public: + UnoTypeCodeCompletetor( const std::vector< OUString >& aVect, const OUString& sVarType ); + + std::vector< OUString > GetXIdlClassMethods() const; + std::vector< OUString > GetXIdlClassFields() const; + + bool CanCodeComplete() const { return bCanComplete;} +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/baside2b.cxx b/basctl/source/basicide/baside2b.cxx new file mode 100644 index 0000000000..0cb1316117 --- /dev/null +++ b/basctl/source/basicide/baside2b.cxx @@ -0,0 +1,2985 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <cassert> +#include <string_view> + +#include <helpids.h> +#include <iderid.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> + +#include "baside2.hxx" +#include "brkdlg.hxx" +#include <basidesh.hxx> +#include <basobj.hxx> +#include <iderdll.hxx> + +#include <basic/sbmeth.hxx> +#include <basic/sbuno.hxx> +#include <com/sun/star/beans/XMultiPropertySet.hpp> +#include <com/sun/star/beans/XPropertiesChangeListener.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> +#include <com/sun/star/script/XLibraryContainer2.hpp> +#include <comphelper/string.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <o3tl/string_view.hxx> +#include <officecfg/Office/Common.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/progress.hxx> +#include <sfx2/viewfrm.hxx> +#include <tools/debug.hxx> +#include <utility> +#include <vcl/image.hxx> +#include <vcl/weld.hxx> +#include <vcl/weldutils.hxx> +#include <svl/urihelper.hxx> +#include <svx/svxids.hrc> +#include <vcl/commandevent.hxx> +#include <vcl/xtextedt.hxx> +#include <vcl/textview.hxx> +#include <vcl/txtattr.hxx> +#include <vcl/settings.hxx> +#include <vcl/ptrstyle.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/taskpanelist.hxx> +#include <vcl/help.hxx> +#include <cppuhelper/implbase.hxx> +#include <vector> +#include <com/sun/star/reflection/theCoreReflection.hpp> +#include <unotools/charclass.hxx> +#include "textwindowpeer.hxx" +#include "uiobject.hxx" +#include <basegfx/utils/zoomtools.hxx> +#include <svl/itemset.hxx> + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace +{ + +sal_uInt16 const NoMarker = 0xFFFF; +tools::Long const nBasePad = 2; +tools::Long const nCursorPad = 5; + +tools::Long nVirtToolBoxHeight; // inited in WatchWindow, used in Stackwindow + +// Returns pBase converted to SbxVariable if valid and is not an SbxMethod. +SbxVariable* IsSbxVariable (SbxBase* pBase) +{ + if (SbxVariable* pVar = dynamic_cast<SbxVariable*>(pBase)) + if (!dynamic_cast<SbxMethod*>(pVar)) + return pVar; + return nullptr; +} + +Image GetImage(const OUString& rId) +{ + return Image(StockImage::Yes, rId); +} + +int const nScrollLine = 12; +int const nScrollPage = 60; +int const DWBORDER = 3; + +std::u16string_view const cSuffixes = u"%&!#@$"; + +} // namespace + + +/** + * Helper functions to get/set text in TextEngine using + * the stream interface. + * + * get/setText() only supports tools Strings limited to 64K). + */ +OUString getTextEngineText (ExtTextEngine& rEngine) +{ + SvMemoryStream aMemStream; + aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); + aMemStream.SetLineDelimiter( LINEEND_LF ); + rEngine.Write( aMemStream ); + std::size_t nSize = aMemStream.Tell(); + OUString aText( static_cast<const char*>(aMemStream.GetData()), + nSize, RTL_TEXTENCODING_UTF8 ); + return aText; +} + +void setTextEngineText (ExtTextEngine& rEngine, std::u16string_view aStr) +{ + rEngine.SetText(OUString()); + OString aUTF8Str = OUStringToOString( aStr, RTL_TEXTENCODING_UTF8 ); + SvMemoryStream aMemStream( const_cast<char *>(aUTF8Str.getStr()), aUTF8Str.getLength(), + StreamMode::READ ); + aMemStream.SetStreamCharSet( RTL_TEXTENCODING_UTF8 ); + aMemStream.SetLineDelimiter( LINEEND_LF ); + rEngine.Read(aMemStream); +} + +namespace +{ + +void lcl_DrawIDEWindowFrame(DockingWindow const * pWin, vcl::RenderContext& rRenderContext) +{ + if (pWin->IsFloatingMode()) + return; + + Size aSz(pWin->GetOutputSizePixel()); + const Color aOldLineColor(rRenderContext.GetLineColor()); + rRenderContext.SetLineColor(COL_WHITE); + // White line on top + rRenderContext.DrawLine(Point(0, 0), Point(aSz.Width(), 0)); + // Black line at bottom + rRenderContext.SetLineColor(COL_BLACK); + rRenderContext.DrawLine(Point(0, aSz.Height() - 1), + Point(aSz.Width(), aSz.Height() - 1)); + rRenderContext.SetLineColor(aOldLineColor); +} + +void lcl_SeparateNameAndIndex( const OUString& rVName, OUString& rVar, OUString& rIndex ) +{ + rVar = rVName; + rIndex.clear(); + sal_Int32 nIndexStart = rVar.indexOf( '(' ); + if ( nIndexStart != -1 ) + { + sal_Int32 nIndexEnd = rVar.indexOf( ')', nIndexStart ); + if (nIndexEnd != -1) + { + rIndex = rVar.copy(nIndexStart + 1, nIndexEnd - nIndexStart - 1); + rVar = rVar.copy(0, nIndexStart); + rVar = comphelper::string::stripEnd(rVar, ' '); + rIndex = comphelper::string::strip(rIndex, ' '); + } + } + + if ( !rVar.isEmpty() ) + { + sal_uInt16 nLastChar = rVar.getLength()-1; + if ( cSuffixes.find(rVar[ nLastChar ] ) != std::u16string_view::npos ) + rVar = rVar.replaceAt( nLastChar, 1, u"" ); + } + if ( !rIndex.isEmpty() ) + { + sal_uInt16 nLastChar = rIndex.getLength()-1; + if ( cSuffixes.find(rIndex[ nLastChar ] ) != std::u16string_view::npos ) + rIndex = rIndex.replaceAt( nLastChar, 1, u"" ); + } +} + +} // namespace + + +// EditorWindow + + +class EditorWindow::ChangesListener: + public cppu::WeakImplHelper< beans::XPropertiesChangeListener > +{ +public: + explicit ChangesListener(EditorWindow & editor): editor_(editor) {} + +private: + virtual ~ChangesListener() override {} + + virtual void SAL_CALL disposing(lang::EventObject const &) override + { + std::unique_lock g(editor_.mutex_); + editor_.notifier_.clear(); + } + + virtual void SAL_CALL propertiesChange( + Sequence< beans::PropertyChangeEvent > const &) override + { + SolarMutexGuard g; + editor_.ImplSetFont(); + } + + EditorWindow & editor_; +}; + +class EditorWindow::ProgressInfo : public SfxProgress +{ +public: + ProgressInfo (SfxObjectShell* pObjSh, OUString const& rText, sal_uInt32 nRange) : + SfxProgress(pObjSh, rText, nRange), + nCurState(0) + { } + + void StepProgress () + { + SetState(++nCurState); + } + +private: + sal_uInt32 nCurState; +}; + +EditorWindow::EditorWindow (vcl::Window* pParent, ModulWindow* pModulWindow) : + Window(pParent, WB_BORDER), + rModulWindow(*pModulWindow), + nCurTextWidth(0), + m_nSetSourceInBasicId(nullptr), + aHighlighter(HighlighterLanguage::Basic), + aSyntaxIdle( "basctl EditorWindow aSyntaxIdle" ), + bHighlighting(false), + bDoSyntaxHighlight(true), + bDelayHighlight(true), + pCodeCompleteWnd(VclPtr<CodeCompleteWindow>::Create(this)) +{ + set_id("EditorWindow"); + const Wallpaper aBackground(rModulWindow.GetLayout().GetSyntaxBackgroundColor()); + SetBackground(aBackground); + GetWindow(GetWindowType::Border)->SetBackground(aBackground); + SetPointer( PointerStyle::Text ); + SetHelpId( HID_BASICIDE_EDITORWINDOW ); + + listener_ = new ChangesListener(*this); + Reference< beans::XMultiPropertySet > n( + officecfg::Office::Common::Font::SourceViewFont::get(), + UNO_QUERY_THROW); + { + std::unique_lock g(mutex_); + notifier_ = n; + } + + // The zoom level applied to the editor window is the zoom slider value in the shell + nCurrentZoomLevel = GetShell()->GetCurrentZoomSliderValue(); + + const Sequence<OUString> aPropertyNames{"FontHeight", "FontName"}; + n->addPropertiesChangeListener(aPropertyNames, listener_); +} + + +EditorWindow::~EditorWindow() +{ + disposeOnce(); +} + +void EditorWindow::dispose() +{ + if (m_nSetSourceInBasicId) + { + Application::RemoveUserEvent(m_nSetSourceInBasicId); + m_nSetSourceInBasicId = nullptr; + } + + Reference< beans::XMultiPropertySet > n; + { + std::unique_lock g(mutex_); + n = notifier_; + } + if (n.is()) { + n->removePropertiesChangeListener(listener_); + } + + aSyntaxIdle.Stop(); + + if ( pEditEngine ) + { + EndListening( *pEditEngine ); + pEditEngine->RemoveView(pEditView.get()); + } + pCodeCompleteWnd.disposeAndClear(); + vcl::Window::dispose(); +} + +OUString EditorWindow::GetWordAtCursor() +{ + OUString aWord; + + if ( pEditView ) + { + TextEngine* pTextEngine = pEditView->GetTextEngine(); + if ( pTextEngine ) + { + // check first, if the cursor is at a help URL + const TextSelection& rSelection = pEditView->GetSelection(); + const TextPaM& rSelStart = rSelection.GetStart(); + const TextPaM& rSelEnd = rSelection.GetEnd(); + OUString aText = pTextEngine->GetText( rSelEnd.GetPara() ); + CharClass aClass( ::comphelper::getProcessComponentContext() , Application::GetSettings().GetLanguageTag() ); + sal_Int32 nSelStart = rSelStart.GetIndex(); + sal_Int32 nSelEnd = rSelEnd.GetIndex(); + sal_Int32 nLength = aText.getLength(); + sal_Int32 nStart = 0; + sal_Int32 nEnd = nLength; + while ( nStart < nLength ) + { + OUString aURL( URIHelper::FindFirstURLInText( aText, nStart, nEnd, aClass ) ); + INetURLObject aURLObj( aURL ); + if ( aURLObj.GetProtocol() == INetProtocol::VndSunStarHelp + && nSelStart >= nStart && nSelStart <= nEnd && nSelEnd >= nStart && nSelEnd <= nEnd ) + { + aWord = aURL; + break; + } + nStart = nEnd; + nEnd = nLength; + } + + // Not the selected range, but at the CursorPosition, + // if a word is partially selected. + if ( aWord.isEmpty() ) + aWord = pTextEngine->GetWord( rSelEnd ); + + // Can be empty when full word selected, as Cursor behind it + if ( aWord.isEmpty() && pEditView->HasSelection() ) + aWord = pTextEngine->GetWord( rSelStart ); + } + } + + return aWord; +} + +void EditorWindow::RequestHelp( const HelpEvent& rHEvt ) +{ + bool bDone = false; + + // Should have been activated at some point + if ( pEditEngine ) + { + if ( rHEvt.GetMode() & HelpEventMode::CONTEXT ) + { + OUString aKeyword = GetWordAtCursor(); + Application::GetHelp()->SearchKeyword( aKeyword ); + bDone = true; + } + else if ( rHEvt.GetMode() & HelpEventMode::QUICK ) + { + OUString aHelpText; + tools::Rectangle aHelpRect; + if ( StarBASIC::IsRunning() ) + { + Point aWindowPos = rHEvt.GetMousePosPixel(); + aWindowPos = ScreenToOutputPixel( aWindowPos ); + Point aDocPos = GetEditView()->GetDocPos( aWindowPos ); + TextPaM aCursor = GetEditView()->GetTextEngine()->GetPaM(aDocPos); + TextPaM aStartOfWord; + OUString aWord = GetEditView()->GetTextEngine()->GetWord( aCursor, &aStartOfWord ); + if ( !aWord.isEmpty() && !comphelper::string::isdigitAsciiString(aWord) ) + { + sal_uInt16 nLastChar = aWord.getLength() - 1; + if ( cSuffixes.find(aWord[ nLastChar ] ) != std::u16string_view::npos ) + aWord = aWord.replaceAt( nLastChar, 1, u"" ); + SbxBase* pSBX = StarBASIC::FindSBXInCurrentScope( aWord ); + if (SbxVariable const* pVar = IsSbxVariable(pSBX)) + { + SbxDataType eType = pVar->GetType(); + if ( static_cast<sal_uInt8>(eType) == sal_uInt8(SbxOBJECT) ) + // might cause a crash e. g. at the selections-object + // Type == Object does not mean pVar == Object! + ; // aHelpText = ((SbxObject*)pVar)->GetClassName(); + else if ( eType & SbxARRAY ) + ; // aHelpText = "{...}"; + else if ( static_cast<sal_uInt8>(eType) != sal_uInt8(SbxEMPTY) ) + { + aHelpText = pVar->GetName(); + if ( aHelpText.isEmpty() ) // name is not copied with the passed parameters + aHelpText = aWord; + aHelpText += "=" + pVar->GetOUString(); + } + } + if ( !aHelpText.isEmpty() ) + { + tools::Rectangle aStartWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aStartOfWord)); + TextPaM aEndOfWord(aStartOfWord.GetPara(), aStartOfWord.GetIndex() + aWord.getLength()); + tools::Rectangle aEndWordRect(GetEditView()->GetTextEngine()->PaMtoEditCursor(aEndOfWord)); + aHelpRect = aStartWordRect.GetUnion(aEndWordRect); + + Point aTopLeft = GetEditView()->GetWindowPos(aHelpRect.TopLeft()); + aTopLeft = GetEditView()->GetWindow()->OutputToScreenPixel(aTopLeft); + + aHelpRect.SetPos(aTopLeft); + } + } + } + Help::ShowQuickHelp( this, aHelpRect, aHelpText, QuickHelpFlags::NONE); + bDone = true; + } + } + + if ( !bDone ) + Window::RequestHelp( rHEvt ); +} + + +void EditorWindow::Resize() +{ + // ScrollBars, etc. happens in Adjust... + if ( !pEditView ) + return; + + tools::Long nVisY = pEditView->GetStartDocPos().Y(); + + pEditView->ShowCursor(); + Size aOutSz( GetOutputSizePixel() ); + tools::Long nMaxVisAreaStart = pEditView->GetTextEngine()->GetTextHeight() - aOutSz.Height(); + if ( nMaxVisAreaStart < 0 ) + nMaxVisAreaStart = 0; + if ( pEditView->GetStartDocPos().Y() > nMaxVisAreaStart ) + { + Point aStartDocPos( pEditView->GetStartDocPos() ); + aStartDocPos.setY( nMaxVisAreaStart ); + pEditView->SetStartDocPos( aStartDocPos ); + pEditView->ShowCursor(); + rModulWindow.GetBreakPointWindow().GetCurYOffset() = aStartDocPos.Y(); + rModulWindow.GetLineNumberWindow().GetCurYOffset() = aStartDocPos.Y(); + } + InitScrollBars(); + if ( nVisY != pEditView->GetStartDocPos().Y() ) + Invalidate(); +} + + +void EditorWindow::MouseMove( const MouseEvent &rEvt ) +{ + if ( pEditView ) + pEditView->MouseMove( rEvt ); +} + + +void EditorWindow::MouseButtonUp( const MouseEvent &rEvt ) +{ + if ( pEditView ) + { + pEditView->MouseButtonUp( rEvt ); + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_BASICIDE_STAT_POS ); + pBindings->Invalidate( SID_BASICIDE_STAT_TITLE ); + } + } +} + +void EditorWindow::MouseButtonDown( const MouseEvent &rEvt ) +{ + GrabFocus(); + if (!pEditView) + return; + pEditView->MouseButtonDown(rEvt); + if( pCodeCompleteWnd->IsVisible() ) + { + if (pEditView->GetSelection() != pCodeCompleteWnd->GetTextSelection()) + { + //selection changed, code complete window should be hidden + pCodeCompleteWnd->HideAndRestoreFocus(); + } + } +} + +void EditorWindow::Command( const CommandEvent& rCEvt ) +{ + if ( !pEditView ) + return; + + pEditView->Command( rCEvt ); + if ( ( rCEvt.GetCommand() == CommandEventId::Wheel ) || + ( rCEvt.GetCommand() == CommandEventId::StartAutoScroll ) || + ( rCEvt.GetCommand() == CommandEventId::AutoScroll ) ) + { + const CommandWheelData* pData = rCEvt.GetWheelData(); + + // Check if it is a Ctrl+Wheel zoom command + if (pData && pData->IsMod1()) + { + const sal_uInt16 nOldZoom = GetCurrentZoom(); + sal_uInt16 nNewZoom; + if( pData->GetDelta() < 0 ) + nNewZoom = std::max<sal_uInt16>(basctl::Shell::GetMinZoom(), + basegfx::zoomtools::zoomOut(nOldZoom)); + else + nNewZoom = std::min<sal_uInt16>(basctl::Shell::GetMaxZoom(), + basegfx::zoomtools::zoomIn(nOldZoom)); + GetShell()->SetGlobalEditorZoomLevel(nNewZoom); + } + else + HandleScrollCommand(rCEvt, &rModulWindow.GetEditHScrollBar(), &rModulWindow.GetEditVScrollBar()); + } + else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) { + SfxDispatcher* pDispatcher = GetDispatcher(); + if ( pDispatcher ) + { + SfxDispatcher::ExecutePopup(); + } + if( pCodeCompleteWnd->IsVisible() ) // hide the code complete window + pCodeCompleteWnd->ClearAndHide(); + } +} + +bool EditorWindow::ImpCanModify() +{ + bool bCanModify = true; + if ( StarBASIC::IsRunning() && rModulWindow.GetBasicStatus().bIsRunning ) + { + // If in Trace-mode, abort the trace or refuse input + // Remove markers in the modules in Notify at Basic::Stopped + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr, + VclMessageType::Question, VclButtonsType::OkCancel, + IDEResId(RID_STR_WILLSTOPPRG))); + if (xQueryBox->run() == RET_OK) + { + rModulWindow.GetBasicStatus().bIsRunning = false; + StopBasic(); + } + else + bCanModify = false; + } + return bCanModify; +} + +void EditorWindow::KeyInput( const KeyEvent& rKEvt ) +{ + if ( !pEditView ) // Happens in Win95 + return; + + bool const bWasModified = pEditEngine->IsModified(); + // see if there is an accelerator to be processed first + SfxViewShell *pVS( SfxViewShell::Current()); + bool bDone = pVS && pVS->KeyInput( rKEvt ); + + if (pCodeCompleteWnd->IsVisible() && CodeCompleteOptions::IsCodeCompleteOn()) + { + pCodeCompleteWnd->HandleKeyInput(rKEvt); + if( rKEvt.GetKeyCode().GetCode() == KEY_UP + || rKEvt.GetKeyCode().GetCode() == KEY_DOWN + || rKEvt.GetKeyCode().GetCode() == KEY_TAB + || rKEvt.GetKeyCode().GetCode() == KEY_POINT) + return; + } + + if( (rKEvt.GetKeyCode().GetCode() == KEY_SPACE || + rKEvt.GetKeyCode().GetCode() == KEY_TAB || + rKEvt.GetKeyCode().GetCode() == KEY_RETURN ) && CodeCompleteOptions::IsAutoCorrectOn() ) + { + HandleAutoCorrect(); + } + + if( rKEvt.GetCharCode() == '"' && CodeCompleteOptions::IsAutoCloseQuotesOn() ) + {//autoclose double quotes + HandleAutoCloseDoubleQuotes(); + } + + if( rKEvt.GetCharCode() == '(' && CodeCompleteOptions::IsAutoCloseParenthesisOn() ) + {//autoclose parenthesis + HandleAutoCloseParen(); + } + + if( rKEvt.GetKeyCode().GetCode() == KEY_RETURN && CodeCompleteOptions::IsProcedureAutoCompleteOn() ) + {//autoclose implementation + HandleProcedureCompletion(); + } + + if( rKEvt.GetKeyCode().GetCode() == KEY_POINT && CodeCompleteOptions::IsCodeCompleteOn() ) + { + HandleCodeCompletion(); + } + if ( !bDone && ( !TextEngine::DoesKeyChangeText( rKEvt ) || ImpCanModify() ) ) + { + if ( ( rKEvt.GetKeyCode().GetCode() == KEY_TAB ) && !rKEvt.GetKeyCode().IsMod1() && + !rKEvt.GetKeyCode().IsMod2() && !GetEditView()->IsReadOnly() ) + { + TextSelection aSel( pEditView->GetSelection() ); + if ( aSel.GetStart().GetPara() != aSel.GetEnd().GetPara() ) + { + bDelayHighlight = false; + if ( !rKEvt.GetKeyCode().IsShift() ) + pEditView->IndentBlock(); + else + pEditView->UnindentBlock(); + bDelayHighlight = true; + bDone = true; + } + } + if ( !bDone ) + bDone = pEditView->KeyInput( rKEvt ); + } + if ( !bDone ) + { + Window::KeyInput( rKEvt ); + } + else + { + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_BASICIDE_STAT_POS ); + pBindings->Invalidate( SID_BASICIDE_STAT_TITLE ); + if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_CURSOR ) + { + pBindings->Update( SID_BASICIDE_STAT_POS ); + pBindings->Update( SID_BASICIDE_STAT_TITLE ); + } + if ( rKEvt.GetKeyCode().GetGroup() == KEYGROUP_ALPHA || + rKEvt.GetKeyCode().GetGroup() == KEYGROUP_NUM ) + { + // If the module is read-only, warn that it can't be edited + if ( rModulWindow.IsReadOnly() ) + rModulWindow.ShowReadOnlyInfoBar(); + } + if ( !bWasModified && pEditEngine->IsModified() ) + { + pBindings->Invalidate( SID_SAVEDOC ); + pBindings->Invalidate( SID_DOC_MODIFIED ); + pBindings->Invalidate( SID_UNDO ); + } + if ( rKEvt.GetKeyCode().GetCode() == KEY_INSERT ) + pBindings->Invalidate( SID_ATTR_INSERT ); + } + } +} + +void EditorWindow::HandleAutoCorrect() +{ + TextSelection aSel = GetEditView()->GetSelection(); + const sal_uInt32 nLine = aSel.GetStart().GetPara(); + const sal_Int32 nIndex = aSel.GetStart().GetIndex(); + OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified + const OUString& sActSubName = GetActualSubName( nLine ); // the actual procedure + + std::vector<HighlightPortion> aPortions; + aHighlighter.getHighlightPortions( aLine, aPortions ); + + if( aPortions.empty() ) + return; + + HighlightPortion& r = aPortions.back(); + if( static_cast<size_t>(nIndex) != aPortions.size()-1 ) + {//cursor is not standing at the end of the line + for (auto const& portion : aPortions) + { + if( portion.nEnd == nIndex ) + { + r = portion; + break; + } + } + } + + OUString sStr = aLine.copy( r.nBegin, r.nEnd - r.nBegin ); + //if WS or empty string: stop, nothing to do + if( ( r.tokenType == TokenType::Whitespace ) || sStr.isEmpty() ) + return; + //create the appropriate TextSelection, and update the cache + TextPaM aStart( nLine, r.nBegin ); + TextPaM aEnd( nLine, r.nBegin + sStr.getLength() ); + TextSelection sTextSelection( aStart, aEnd ); + rModulWindow.UpdateModule(); + rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse( aCodeCompleteCache ); + // correct the last entered keyword + if( r.tokenType == TokenType::Keywords ) + { + sStr = sStr.toAsciiLowerCase(); + if( !SbModule::GetKeywordCase(sStr).isEmpty() ) + // if it is a keyword, get its correct case + sStr = SbModule::GetKeywordCase(sStr); + else + // else capitalize first letter/select the correct one, and replace + sStr = sStr.replaceAt( 0, 1, OUString(sStr[0]).toAsciiUpperCase() ); + + pEditEngine->ReplaceText( sTextSelection, sStr ); + pEditView->SetSelection( aSel ); + } + if( r.tokenType != TokenType::Identifier ) + return; + +// correct variables + if( !aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName ).isEmpty() ) + { + sStr = aCodeCompleteCache.GetCorrectCaseVarName( sStr, sActSubName ); + pEditEngine->ReplaceText( sTextSelection, sStr ); + pEditView->SetSelection( aSel ); + } + else + { + //autocorrect procedures + SbxArray* pArr = rModulWindow.GetSbModule()->GetMethods().get(); + for (sal_uInt32 i = 0; i < pArr->Count(); ++i) + { + if (pArr->Get(i)->GetName().equalsIgnoreAsciiCase(sStr)) + { + sStr = pArr->Get(i)->GetName(); //if found, get the correct case + pEditEngine->ReplaceText( sTextSelection, sStr ); + pEditView->SetSelection( aSel ); + return; + } + } + } +} + +TextSelection EditorWindow::GetLastHighlightPortionTextSelection() const +{//creates a text selection from the highlight portion on the cursor + const sal_uInt32 nLine = GetEditView()->GetSelection().GetStart().GetPara(); + const sal_Int32 nIndex = GetEditView()->GetSelection().GetStart().GetIndex(); + OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified + std::vector<HighlightPortion> aPortions; + aHighlighter.getHighlightPortions( aLine, aPortions ); + + assert(!aPortions.empty()); + HighlightPortion& r = aPortions.back(); + if( static_cast<size_t>(nIndex) != aPortions.size()-1 ) + {//cursor is not standing at the end of the line + for (auto const& portion : aPortions) + { + if( portion.nEnd == nIndex ) + { + r = portion; + break; + } + } + } + + if( aPortions.empty() ) + return TextSelection(); + + std::u16string_view sStr = aLine.subView( r.nBegin, r.nEnd - r.nBegin ); + TextPaM aStart( nLine, r.nBegin ); + TextPaM aEnd( nLine, r.nBegin + sStr.size() ); + return TextSelection( aStart, aEnd ); +} + +void EditorWindow::HandleAutoCloseParen() +{ + TextSelection aSel = GetEditView()->GetSelection(); + const sal_uInt32 nLine = aSel.GetStart().GetPara(); + OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified + + if( aLine.getLength() > 0 && aLine[aSel.GetEnd().GetIndex()-1] != '(' ) + { + GetEditView()->InsertText(")"); + //leave the cursor on its place: inside the parenthesis + TextPaM aEnd(nLine, aSel.GetEnd().GetIndex()); + GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) ); + } +} + +void EditorWindow::HandleAutoCloseDoubleQuotes() +{ + TextSelection aSel = GetEditView()->GetSelection(); + const sal_uInt32 nLine = aSel.GetStart().GetPara(); + OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified + + std::vector<HighlightPortion> aPortions; + aHighlighter.getHighlightPortions( aLine, aPortions ); + + if( aPortions.empty() ) + return; + + if( aLine.getLength() > 0 && !aLine.endsWith("\"") && (aPortions.back().tokenType != TokenType::String) ) + { + GetEditView()->InsertText("\""); + //leave the cursor on its place: inside the two double quotes + TextPaM aEnd(nLine, aSel.GetEnd().GetIndex()); + GetEditView()->SetSelection( TextSelection( aEnd, aEnd ) ); + } +} + +void EditorWindow::HandleProcedureCompletion() +{ + + TextSelection aSel = GetEditView()->GetSelection(); + const sal_uInt32 nLine = aSel.GetStart().GetPara(); + OUString aLine( pEditEngine->GetText( nLine ) ); + + OUString sProcType; + OUString sProcName; + bool bFoundName = GetProcedureName(aLine, sProcType, sProcName); + if (!bFoundName) + return; + + OUString sText("\nEnd "); + aSel = GetEditView()->GetSelection(); + if( sProcType.equalsIgnoreAsciiCase("function") ) + sText += "Function\n"; + if( sProcType.equalsIgnoreAsciiCase("sub") ) + sText += "Sub\n"; + + if( nLine+1 == pEditEngine->GetParagraphCount() ) + { + pEditView->InsertText( sText );//append to the end + GetEditView()->SetSelection(aSel); + } + else + { + for( sal_uInt32 i = nLine+1; i < pEditEngine->GetParagraphCount(); ++i ) + {//searching forward for end token, or another sub/function definition + OUString aCurrLine = pEditEngine->GetText( i ); + std::vector<HighlightPortion> aCurrPortions; + aHighlighter.getHighlightPortions( aCurrLine, aCurrPortions ); + + if( aCurrPortions.size() >= 3 ) + {//at least 3 tokens: (sub|function) whitespace identifier... + HighlightPortion& r = aCurrPortions.front(); + std::u16string_view sStr = aCurrLine.subView(r.nBegin, r.nEnd - r.nBegin); + + if( r.tokenType == TokenType::Keywords ) + { + if( o3tl::equalsIgnoreAsciiCase(sStr, u"sub") || o3tl::equalsIgnoreAsciiCase(sStr, u"function") ) + { + pEditView->InsertText( sText );//append to the end + GetEditView()->SetSelection(aSel); + break; + } + if( o3tl::equalsIgnoreAsciiCase(sStr, u"end") ) + break; + } + } + } + } +} + +bool EditorWindow::GetProcedureName(std::u16string_view rLine, OUString& rProcType, OUString& rProcName) const +{ + std::vector<HighlightPortion> aPortions; + aHighlighter.getHighlightPortions(rLine, aPortions); + + if( aPortions.empty() ) + return false; + + bool bFoundType = false; + bool bFoundName = false; + + for (auto const& portion : aPortions) + { + std::u16string_view sTokStr = rLine.substr(portion.nBegin, portion.nEnd - portion.nBegin); + + if( portion.tokenType == TokenType::Keywords && ( o3tl::equalsIgnoreAsciiCase(sTokStr, u"sub") + || o3tl::equalsIgnoreAsciiCase(sTokStr, u"function")) ) + { + rProcType = sTokStr; + bFoundType = true; + } + if( portion.tokenType == TokenType::Identifier && bFoundType ) + { + rProcName = sTokStr; + bFoundName = true; + break; + } + } + + if( !bFoundType || !bFoundName ) + return false;// no sub/function keyword or there is no identifier + + return true; + +} + +void EditorWindow::HandleCodeCompletion() +{ + rModulWindow.UpdateModule(); + rModulWindow.GetSbModule()->GetCodeCompleteDataFromParse(aCodeCompleteCache); + TextSelection aSel = GetEditView()->GetSelection(); + const sal_uInt32 nLine = aSel.GetStart().GetPara(); + OUString aLine( pEditEngine->GetText( nLine ) ); // the line being modified + std::vector< OUString > aVect; //vector to hold the base variable+methods for the nested reflection + + std::vector<HighlightPortion> aPortions; + aLine = aLine.copy(0, aSel.GetEnd().GetIndex()); + aHighlighter.getHighlightPortions( aLine, aPortions ); + if( aPortions.empty() ) + return; + + //use the syntax highlighter to grab out nested reflection calls, eg. aVar.aMethod("aa").aOtherMethod .. + for( std::vector<HighlightPortion>::reverse_iterator i( + aPortions.rbegin()); + i != aPortions.rend(); ++i) + { + if( i->tokenType == TokenType::Whitespace ) // a whitespace: stop; if there is no ws, it goes to the beginning of the line + break; + if( i->tokenType == TokenType::Identifier || i->tokenType == TokenType::Keywords ) // extract the identifiers(methods, base variable) + /* an example: Dim aLocVar2 as com.sun.star.beans.PropertyValue + * here, aLocVar2.Name, and PropertyValue's Name field is treated as a keyword(?!) + * */ + aVect.insert( aVect.begin(), aLine.copy(i->nBegin, i->nEnd - i->nBegin) ); + } + + if( aVect.empty() )//nothing to do + return; + + OUString sBaseName = aVect[aVect.size()-1];//variable name + OUString sVarType = aCodeCompleteCache.GetVarType( sBaseName ); + + if( !sVarType.isEmpty() && CodeCompleteOptions::IsAutoCorrectOn() ) + {//correct variable name, if autocorrection on + const OUString& sStr = aCodeCompleteCache.GetCorrectCaseVarName( sBaseName, GetActualSubName(nLine) ); + if( !sStr.isEmpty() ) + { + TextPaM aStart(nLine, aSel.GetStart().GetIndex() - sStr.getLength() ); + TextSelection sTextSelection(aStart, TextPaM(nLine, aSel.GetStart().GetIndex())); + pEditEngine->ReplaceText( sTextSelection, sStr ); + pEditView->SetSelection( aSel ); + } + } + + UnoTypeCodeCompletetor aTypeCompletor( aVect, sVarType ); + + if( !aTypeCompletor.CanCodeComplete() ) + return; + + std::vector< OUString > aEntryVect;//entries to be inserted into the list + std::vector< OUString > aFieldVect = aTypeCompletor.GetXIdlClassFields();//fields + aEntryVect.insert(aEntryVect.end(), aFieldVect.begin(), aFieldVect.end() ); + if( CodeCompleteOptions::IsExtendedTypeDeclaration() ) + {// if extended types on, reflect classes, else just the structs (XIdlClass without methods) + std::vector< OUString > aMethVect = aTypeCompletor.GetXIdlClassMethods();//methods + aEntryVect.insert(aEntryVect.end(), aMethVect.begin(), aMethVect.end() ); + } + if( !aEntryVect.empty() ) + SetupAndShowCodeCompleteWnd( aEntryVect, aSel ); +} + +void EditorWindow::SetupAndShowCodeCompleteWnd( const std::vector< OUString >& aEntryVect, TextSelection aSel ) +{ + // clear the listbox + pCodeCompleteWnd->ClearListBox(); + // fill the listbox + for(const auto & l : aEntryVect) + { + pCodeCompleteWnd->InsertEntry( l ); + } + // show it + pCodeCompleteWnd->Show(); + pCodeCompleteWnd->ResizeAndPositionListBox(); + pCodeCompleteWnd->SelectFirstEntry(); + // correct text selection, and set it + ++aSel.GetStart().GetIndex(); + ++aSel.GetEnd().GetIndex(); + pCodeCompleteWnd->SetTextSelection( aSel ); + //give the focus to the EditView + pEditView->GetWindow()->GrabFocus(); +} + +void EditorWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + if (!pEditEngine) // We need it now at latest + CreateEditEngine(); + + pEditView->Paint(rRenderContext, rRect); +} + +void EditorWindow::LoseFocus() +{ + // tdf#114258 wait until the next event loop cycle to do this so it doesn't + // happen during a mouse down/up selection in the treeview whose contents + // this may update + if (!m_nSetSourceInBasicId) + m_nSetSourceInBasicId = Application::PostUserEvent(LINK(this, EditorWindow, SetSourceInBasicHdl)); + Window::LoseFocus(); +} + +IMPL_LINK_NOARG(EditorWindow, SetSourceInBasicHdl, void*, void) +{ + m_nSetSourceInBasicId = nullptr; + SetSourceInBasic(); +} + +void EditorWindow::SetSourceInBasic() +{ + if ( pEditEngine && pEditEngine->IsModified() + && !GetEditView()->IsReadOnly() ) // Added for #i60626, otherwise + // any read only bug in the text engine could lead to a crash later + { + if ( !StarBASIC::IsRunning() ) // Not at runtime! + { + rModulWindow.UpdateModule(); + } + } +} + +// Returns the position of the last character of any of the following +// EOL char combinations: CR, CR/LF, LF, return -1 if no EOL is found +sal_Int32 searchEOL( std::u16string_view rStr, sal_Int32 fromIndex ) +{ + size_t iLF = rStr.find( LINE_SEP, fromIndex ); + if( iLF != std::u16string_view::npos ) + return iLF; + + size_t iCR = rStr.find( LINE_SEP_CR, fromIndex ); + return iCR == std::u16string_view::npos ? -1 : iCR; +} + +void EditorWindow::CreateEditEngine() +{ + if (pEditEngine) + return; + + pEditEngine.reset(new ExtTextEngine); + pEditView.reset(new TextView(pEditEngine.get(), this)); + pEditView->SetAutoIndentMode(true); + pEditEngine->SetUpdateMode(false); + pEditEngine->InsertView(pEditView.get()); + + ImplSetFont(); + + aSyntaxIdle.SetInvokeHandler( LINK( this, EditorWindow, SyntaxTimerHdl ) ); + + bool bWasDoSyntaxHighlight = bDoSyntaxHighlight; + bDoSyntaxHighlight = false; // too slow for large texts... + OUString aOUSource(rModulWindow.GetModule()); + sal_Int32 nLines = 0; + sal_Int32 nIndex = -1; + do + { + nLines++; + nIndex = searchEOL( aOUSource, nIndex+1 ); + } + while (nIndex >= 0); + + // nLines*4: SetText+Formatting+DoHighlight+Formatting + // it could be cut down on one formatting but you would wait even longer + // for the text then if the source code is long... + pProgress.reset(new ProgressInfo(GetShell()->GetViewFrame().GetObjectShell(), + IDEResId(RID_STR_GENERATESOURCE), + nLines * 4)); + setTextEngineText(*pEditEngine, aOUSource); + + pEditView->SetStartDocPos(Point(0, 0)); + pEditView->SetSelection(TextSelection()); + rModulWindow.GetBreakPointWindow().GetCurYOffset() = 0; + rModulWindow.GetLineNumberWindow().GetCurYOffset() = 0; + pEditEngine->SetUpdateMode(true); + rModulWindow.PaintImmediately(); // has only been invalidated at UpdateMode = true + + pEditView->ShowCursor(); + + StartListening(*pEditEngine); + + aSyntaxIdle.Stop(); + bDoSyntaxHighlight = bWasDoSyntaxHighlight; + + for (sal_Int32 nLine = 0; nLine < nLines; nLine++) + aSyntaxLineTable.insert(nLine); + ForceSyntaxTimeout(); + + pProgress.reset(); + + pEditEngine->SetModified( false ); + pEditEngine->EnableUndo( true ); + + InitScrollBars(); + + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate(SID_BASICIDE_STAT_POS); + pBindings->Invalidate(SID_BASICIDE_STAT_TITLE); + } + + DBG_ASSERT(rModulWindow.GetBreakPointWindow().GetCurYOffset() == 0, "CreateEditEngine: breakpoints moved?"); + + // set readonly mode for readonly libraries + ScriptDocument aDocument(rModulWindow.GetDocument()); + OUString aOULibName(rModulWindow.GetLibName()); + Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + if (xModLibContainer.is() + && xModLibContainer->hasByName(aOULibName) + && xModLibContainer->isLibraryReadOnly(aOULibName)) + { + rModulWindow.SetReadOnly(true); + } + + if (aDocument.isDocument() && aDocument.isReadOnly()) + rModulWindow.SetReadOnly(true); +} + +void EditorWindow::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint ) +{ + TextHint const* pTextHint = dynamic_cast<TextHint const*>(&rHint); + if (!pTextHint) + return; + + TextHint const& rTextHint = *pTextHint; + if( rTextHint.GetId() == SfxHintId::TextViewScrolled ) + { + rModulWindow.GetEditVScrollBar().SetThumbPos( pEditView->GetStartDocPos().Y() ); + rModulWindow.GetEditHScrollBar().SetThumbPos( pEditView->GetStartDocPos().X() ); + rModulWindow.GetBreakPointWindow().DoScroll + ( rModulWindow.GetBreakPointWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() ); + rModulWindow.GetLineNumberWindow().DoScroll + ( rModulWindow.GetLineNumberWindow().GetCurYOffset() - pEditView->GetStartDocPos().Y() ); + } + else if( rTextHint.GetId() == SfxHintId::TextHeightChanged ) + { + if ( pEditView->GetStartDocPos().Y() ) + { + tools::Long nOutHeight = GetOutputSizePixel().Height(); + tools::Long nTextHeight = pEditEngine->GetTextHeight(); + if ( nTextHeight < nOutHeight ) + pEditView->Scroll( 0, pEditView->GetStartDocPos().Y() ); + + rModulWindow.GetLineNumberWindow().Invalidate(); + } + + SetScrollBarRanges(); + } + else if( rTextHint.GetId() == SfxHintId::TextFormatted ) + { + + const tools::Long nWidth = pEditEngine->CalcTextWidth(); + if ( nWidth != nCurTextWidth ) + { + nCurTextWidth = nWidth; + rModulWindow.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth-1) ); + rModulWindow.GetEditHScrollBar().SetThumbPos( pEditView->GetStartDocPos().X() ); + } + tools::Long nPrevTextWidth = nCurTextWidth; + nCurTextWidth = pEditEngine->CalcTextWidth(); + if ( nCurTextWidth != nPrevTextWidth ) + SetScrollBarRanges(); + } + else if( rTextHint.GetId() == SfxHintId::TextParaInserted ) + { + ParagraphInsertedDeleted( rTextHint.GetValue(), true ); + DoDelayedSyntaxHighlight( rTextHint.GetValue() ); + } + else if( rTextHint.GetId() == SfxHintId::TextParaRemoved ) + { + ParagraphInsertedDeleted( rTextHint.GetValue(), false ); + } + else if( rTextHint.GetId() == SfxHintId::TextParaContentChanged ) + { + DoDelayedSyntaxHighlight( rTextHint.GetValue() ); + } + else if( rTextHint.GetId() == SfxHintId::TextViewSelectionChanged ) + { + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_CUT ); + pBindings->Invalidate( SID_COPY ); + } + } +} + +OUString EditorWindow::GetActualSubName( sal_uInt32 nLine ) +{ + SbxArrayRef pMethods = rModulWindow.GetSbModule()->GetMethods(); + for (sal_uInt32 i = 0; i < pMethods->Count(); i++) + { + SbMethod* pMeth = dynamic_cast<SbMethod*>(pMethods->Get(i)); + if( pMeth ) + { + sal_uInt16 l1,l2; + pMeth->GetLineRange(l1,l2); + if( (l1 <= nLine+1) && (nLine+1 <= l2) ) + { + return pMeth->GetName(); + } + } + } + return OUString(); +} + +void EditorWindow::SetScrollBarRanges() +{ + // extra method, not InitScrollBars, because for EditEngine events too + if ( !pEditEngine ) + return; + + rModulWindow.GetEditVScrollBar().SetRange( Range( 0, pEditEngine->GetTextHeight()-1 ) ); + rModulWindow.GetEditHScrollBar().SetRange( Range( 0, nCurTextWidth-1 ) ); +} + +void EditorWindow::InitScrollBars() +{ + if (!pEditEngine) + return; + + SetScrollBarRanges(); + Size aOutSz(GetOutputSizePixel()); + rModulWindow.GetEditVScrollBar().SetVisibleSize(aOutSz.Height()); + rModulWindow.GetEditVScrollBar().SetPageSize(aOutSz.Height() * 8 / 10); + rModulWindow.GetEditVScrollBar().SetLineSize(GetTextHeight()); + rModulWindow.GetEditVScrollBar().SetThumbPos(pEditView->GetStartDocPos().Y()); + rModulWindow.GetEditVScrollBar().Show(); + + rModulWindow.GetEditHScrollBar().SetVisibleSize(aOutSz.Width()); + rModulWindow.GetEditHScrollBar().SetPageSize(aOutSz.Width() * 8 / 10); + rModulWindow.GetEditHScrollBar().SetLineSize(GetTextWidth( "x" )); + rModulWindow.GetEditHScrollBar().SetThumbPos(pEditView->GetStartDocPos().X()); + rModulWindow.GetEditHScrollBar().Show(); +} + +void EditorWindow::ImpDoHighlight( sal_uInt32 nLine ) +{ + if ( !bDoSyntaxHighlight ) + return; + + OUString aLine( pEditEngine->GetText( nLine ) ); + bool const bWasModified = pEditEngine->IsModified(); + pEditEngine->RemoveAttribs( nLine ); + std::vector<HighlightPortion> aPortions; + aHighlighter.getHighlightPortions( aLine, aPortions ); + + for (auto const& portion : aPortions) + { + Color const aColor = rModulWindow.GetLayout().GetSyntaxColor(portion.tokenType); + pEditEngine->SetAttrib(TextAttribFontColor(aColor), nLine, portion.nBegin, portion.nEnd); + } + + pEditEngine->SetModified(bWasModified); +} + +void EditorWindow::ChangeFontColor( Color aColor ) +{ + if (pEditEngine) + { + vcl::Font aFont(pEditEngine->GetFont()); + aFont.SetColor(aColor); + pEditEngine->SetFont(aFont); + } +} + +void EditorWindow::UpdateSyntaxHighlighting () +{ + const sal_uInt32 nCount = pEditEngine->GetParagraphCount(); + for (sal_uInt32 i = 0; i < nCount; ++i) + DoDelayedSyntaxHighlight(i); +} + +void EditorWindow::ImplSetFont() +{ + // Get default font name and height defined in the Options dialog + OUString sFontName(officecfg::Office::Common::Font::SourceViewFont::FontName::get().value_or(OUString())); + if (sFontName.isEmpty()) + { + vcl::Font aTmpFont(OutputDevice::GetDefaultFont(DefaultFontType::FIXED, + Application::GetSettings().GetUILanguageTag().getLanguageType(), + GetDefaultFontFlags::NONE, GetOutDev())); + sFontName = aTmpFont.GetFamilyName(); + } + sal_uInt16 nDefaultFontHeight = officecfg::Office::Common::Font::SourceViewFont::FontHeight::get(); + + // Calculate font size considering zoom level + sal_uInt16 nNewFontHeight = nDefaultFontHeight * (static_cast<float>(nCurrentZoomLevel) / 100); + Size aFontSize(0, nNewFontHeight); + + vcl::Font aFont(sFontName, aFontSize); + aFont.SetColor(rModulWindow.GetLayout().GetFontColor()); + SetPointFont(*GetOutDev(), aFont); // FIXME RenderContext + aFont = GetFont(); + + rModulWindow.GetBreakPointWindow().SetFont(aFont); + rModulWindow.GetLineNumberWindow().SetFont(aFont); + rModulWindow.Invalidate(); + + if (pEditEngine) + { + bool const bModified = pEditEngine->IsModified(); + pEditEngine->SetFont(aFont); + pEditEngine->SetModified(bModified); + } + + // Update controls + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_BASICIDE_CURRENT_ZOOM ); + pBindings->Invalidate( SID_ATTR_ZOOMSLIDER ); + } +} + +void EditorWindow::SetEditorZoomLevel(sal_uInt16 nNewZoomLevel) +{ + if (nCurrentZoomLevel == nNewZoomLevel) + return; + + if (nNewZoomLevel < MIN_ZOOM_LEVEL || nNewZoomLevel > MAX_ZOOM_LEVEL) + return; + + nCurrentZoomLevel = nNewZoomLevel; + ImplSetFont(); +} + +void EditorWindow::DoSyntaxHighlight( sal_uInt32 nPara ) +{ + // because of the DelayedSyntaxHighlight it's possible + // that this line does not exist anymore! + if ( nPara < pEditEngine->GetParagraphCount() ) + { + // unfortunately I'm not sure that exactly this line does Modified()... + if ( pProgress ) + pProgress->StepProgress(); + ImpDoHighlight( nPara ); + } +} + +void EditorWindow::DoDelayedSyntaxHighlight( sal_uInt32 nPara ) +{ + // line is only added to list, processed in TimerHdl + // => don't manipulate breaks while EditEngine is formatting + if ( pProgress ) + pProgress->StepProgress(); + + if ( !bHighlighting && bDoSyntaxHighlight ) + { + if ( bDelayHighlight ) + { + aSyntaxLineTable.insert( nPara ); + aSyntaxIdle.Start(); + } + else + DoSyntaxHighlight( nPara ); + } +} + +IMPL_LINK_NOARG(EditorWindow, SyntaxTimerHdl, Timer *, void) +{ + DBG_ASSERT( pEditView, "Not yet a View, but Syntax-Highlight?!" ); + + bool const bWasModified = pEditEngine->IsModified(); + //pEditEngine->SetUpdateMode(false); + + bHighlighting = true; + for (auto const& syntaxLine : aSyntaxLineTable) + { + DoSyntaxHighlight(syntaxLine); + } + + // #i45572# + if ( pEditView ) + pEditView->ShowCursor( false ); + + pEditEngine->SetModified( bWasModified ); + + aSyntaxLineTable.clear(); + bHighlighting = false; +} + +void EditorWindow::ParagraphInsertedDeleted( sal_uInt32 nPara, bool bInserted ) +{ + if ( pProgress ) + pProgress->StepProgress(); + + if ( !bInserted && ( nPara == TEXT_PARA_ALL ) ) + { + rModulWindow.GetBreakPoints().reset(); + rModulWindow.GetBreakPointWindow().Invalidate(); + rModulWindow.GetLineNumberWindow().Invalidate(); + } + else + { + rModulWindow.GetBreakPoints().AdjustBreakPoints( static_cast<sal_uInt16>(nPara)+1, bInserted ); + + tools::Long nLineHeight = GetTextHeight(); + Size aSz = rModulWindow.GetBreakPointWindow().GetOutDev()->GetOutputSize(); + tools::Rectangle aInvRect( Point( 0, 0 ), aSz ); + tools::Long nY = nPara*nLineHeight - rModulWindow.GetBreakPointWindow().GetCurYOffset(); + aInvRect.SetTop( nY ); + rModulWindow.GetBreakPointWindow().Invalidate( aInvRect ); + + Size aLnSz(rModulWindow.GetLineNumberWindow().GetWidth(), + GetOutputSizePixel().Height() - 2 * DWBORDER); + rModulWindow.GetLineNumberWindow().SetPosSizePixel(Point(DWBORDER + 19, DWBORDER), aLnSz); + rModulWindow.GetLineNumberWindow().Invalidate(); + } +} + +void EditorWindow::CreateProgress( const OUString& rText, sal_uInt32 nRange ) +{ + DBG_ASSERT( !pProgress, "ProgressInfo exists already" ); + pProgress.reset(new ProgressInfo( + GetShell()->GetViewFrame().GetObjectShell(), + rText, + nRange + )); +} + +void EditorWindow::DestroyProgress() +{ + pProgress.reset(); +} + +void EditorWindow::ForceSyntaxTimeout() +{ + aSyntaxIdle.Stop(); + aSyntaxIdle.Invoke(); +} + +FactoryFunction EditorWindow::GetUITestFactory() const +{ + return EditorWindowUIObject::create; +} + + +// BreakPointWindow + +BreakPointWindow::BreakPointWindow (vcl::Window* pParent, ModulWindow* pModulWindow) + : Window(pParent, WB_BORDER) + , rModulWindow(*pModulWindow) + , nCurYOffset(0) // memorize nCurYOffset and not take it from EditEngine + , nMarkerPos(NoMarker) + , bErrorMarker(false) +{ + setBackgroundColor(GetSettings().GetStyleSettings().GetFieldColor()); + SetHelpId(HID_BASICIDE_BREAKPOINTWINDOW); +} + +void BreakPointWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + if (SyncYOffset()) + return; + + Size const aOutSz = rRenderContext.GetOutputSize(); + tools::Long const nLineHeight = rRenderContext.GetTextHeight(); + + Image const aBrk[2] = + { + GetImage(RID_BMP_BRKDISABLED), + GetImage(RID_BMP_BRKENABLED) + }; + + Size const aBmpSz = rRenderContext.PixelToLogic(aBrk[1].GetSizePixel()); + Point const aBmpOff((aOutSz.Width() - aBmpSz.Width()) / 2, + (nLineHeight - aBmpSz.Height()) / 2); + + for (size_t i = 0, n = GetBreakPoints().size(); i < n; ++i) + { + BreakPoint& rBrk = GetBreakPoints().at(i); + sal_uInt16 const nLine = rBrk.nLine - 1; + size_t const nY = nLine*nLineHeight - nCurYOffset; + rRenderContext.DrawImage(Point(0, nY) + aBmpOff, aBrk[rBrk.bEnabled]); + } + + ShowMarker(rRenderContext); +} + +void BreakPointWindow::ShowMarker(vcl::RenderContext& rRenderContext) +{ + if (nMarkerPos == NoMarker) + return; + + Size const aOutSz = GetOutDev()->GetOutputSize(); + tools::Long const nLineHeight = GetTextHeight(); + + Image aMarker = GetImage(bErrorMarker ? RID_BMP_ERRORMARKER : RID_BMP_STEPMARKER); + + Size aMarkerSz(aMarker.GetSizePixel()); + aMarkerSz = rRenderContext.PixelToLogic(aMarkerSz); + Point aMarkerOff(0, 0); + aMarkerOff.setX( (aOutSz.Width() - aMarkerSz.Width()) / 2 ); + aMarkerOff.setY( (nLineHeight - aMarkerSz.Height()) / 2 ); + + tools::Long nY = nMarkerPos * nLineHeight - nCurYOffset; + Point aPos(0, nY); + aPos += aMarkerOff; + + rRenderContext.DrawImage(aPos, aMarker); +} + +void BreakPointWindow::DoScroll( tools::Long nVertScroll ) +{ + nCurYOffset -= nVertScroll; + Window::Scroll( 0, nVertScroll ); +} + +void BreakPointWindow::SetMarkerPos( sal_uInt16 nLine, bool bError ) +{ + if ( SyncYOffset() ) + PaintImmediately(); + + nMarkerPos = nLine; + bErrorMarker = bError; + Invalidate(); +} + +void BreakPointWindow::SetNoMarker () +{ + SetMarkerPos(NoMarker); +} + +BreakPoint* BreakPointWindow::FindBreakPoint( const Point& rMousePos ) +{ + size_t nLineHeight = GetTextHeight(); + nLineHeight = nLineHeight > 0 ? nLineHeight : 1; + size_t nYPos = rMousePos.Y() + nCurYOffset; + + for ( size_t i = 0, n = GetBreakPoints().size(); i < n ; ++i ) + { + BreakPoint& rBrk = GetBreakPoints().at( i ); + sal_uInt16 nLine = rBrk.nLine-1; + size_t nY = nLine*nLineHeight; + if ( ( nYPos > nY ) && ( nYPos < ( nY + nLineHeight ) ) ) + return &rBrk; + } + return nullptr; +} + +void BreakPointWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( rMEvt.GetClicks() == 2 ) + { + Point aMousePos( PixelToLogic( rMEvt.GetPosPixel() ) ); + tools::Long nLineHeight = GetTextHeight(); + if(nLineHeight) + { + tools::Long nYPos = aMousePos.Y() + nCurYOffset; + tools::Long nLine = nYPos / nLineHeight + 1; + rModulWindow.ToggleBreakPoint( static_cast<sal_uInt16>(nLine) ); + Invalidate(); + } + } +} + +void BreakPointWindow::Command( const CommandEvent& rCEvt ) +{ + if ( rCEvt.GetCommand() != CommandEventId::ContextMenu ) + return; + + Point aPos( rCEvt.IsMouseEvent() ? rCEvt.GetMousePosPixel() : Point(1,1) ); + tools::Rectangle aRect(aPos, Size(1, 1)); + weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect); + + std::unique_ptr<weld::Builder> xUIBuilder(Application::CreateBuilder(pPopupParent, "modules/BasicIDE/ui/breakpointmenus.ui")); + + Point aEventPos( PixelToLogic( aPos ) ); + BreakPoint* pBrk = rCEvt.IsMouseEvent() ? FindBreakPoint( aEventPos ) : nullptr; + if ( pBrk ) + { + // test if break point is enabled... + std::unique_ptr<weld::Menu> xBrkPropMenu = xUIBuilder->weld_menu("breakmenu"); + xBrkPropMenu->set_active("active", pBrk->bEnabled); + OUString sCommand = xBrkPropMenu->popup_at_rect(pPopupParent, aRect); + if (sCommand == "active") + { + pBrk->bEnabled = !pBrk->bEnabled; + rModulWindow.UpdateBreakPoint( *pBrk ); + Invalidate(); + } + else if (sCommand == "properties") + { + BreakPointDialog aBrkDlg(pPopupParent, GetBreakPoints()); + aBrkDlg.SetCurrentBreakPoint( *pBrk ); + aBrkDlg.run(); + Invalidate(); + } + } + else + { + std::unique_ptr<weld::Menu> xBrkListMenu = xUIBuilder->weld_menu("breaklistmenu"); + OUString sCommand = xBrkListMenu->popup_at_rect(pPopupParent, aRect); + if (sCommand == "manage") + { + BreakPointDialog aBrkDlg(pPopupParent, GetBreakPoints()); + aBrkDlg.run(); + Invalidate(); + } + } +} + +bool BreakPointWindow::SyncYOffset() +{ + TextView* pView = rModulWindow.GetEditView(); + if ( pView ) + { + tools::Long nViewYOffset = pView->GetStartDocPos().Y(); + if ( nCurYOffset != nViewYOffset ) + { + nCurYOffset = nViewYOffset; + Invalidate(); + return true; + } + } + return false; +} + +// virtual +void BreakPointWindow::DataChanged(DataChangedEvent const & rDCEvt) +{ + Window::DataChanged(rDCEvt); + if (rDCEvt.GetType() == DataChangedEventType::SETTINGS + && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) + { + Color aColor(GetSettings().GetStyleSettings().GetFieldColor()); + const AllSettings* pOldSettings = rDCEvt.GetOldSettings(); + if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFieldColor()) + { + setBackgroundColor(aColor); + Invalidate(); + } + } +} + +void BreakPointWindow::setBackgroundColor(Color aColor) +{ + SetBackground(Wallpaper(aColor)); +} + +namespace { + +struct WatchItem +{ + OUString maName; + OUString maDisplayName; + SbxObjectRef mpObject; + std::vector<OUString> maMemberList; + + SbxDimArrayRef mpArray; + int nDimLevel; // 0 = Root + int nDimCount; + std::vector<sal_Int32> vIndices; + + WatchItem* mpArrayParentItem; + + explicit WatchItem (OUString aName): + maName(std::move(aName)), + nDimLevel(0), + nDimCount(0), + mpArrayParentItem(nullptr) + { } + + void clearWatchItem () + { + maMemberList.clear(); + } + + WatchItem* GetRootItem(); + SbxDimArray* GetRootArray(); +}; + +} + +WatchWindow::WatchWindow(Layout* pParent) + : DockingWindow(pParent, "modules/BasicIDE/ui/dockingwatch.ui", "DockingWatch") + , m_nUpdateWatchesId(nullptr) +{ + m_xTitleArea = m_xBuilder->weld_container("titlearea"); + + nVirtToolBoxHeight = m_xTitleArea->get_preferred_size().Height(); + + m_xTitle = m_xBuilder->weld_label("title"); + m_xTitle->set_label(IDEResId(RID_STR_REMOVEWATCH)); + + m_xEdit = m_xBuilder->weld_entry("edit"); + m_xRemoveWatchButton = m_xBuilder->weld_button("remove"); + m_xTreeListBox = m_xBuilder->weld_tree_view("treeview"); + + m_xEdit->set_accessible_name(IDEResId(RID_STR_WATCHNAME)); + m_xEdit->set_help_id(HID_BASICIDE_WATCHWINDOW_EDIT); + m_xEdit->set_size_request(LogicToPixel(Size(80, 0), MapMode(MapUnit::MapAppFont)).Width(), -1); + m_xEdit->connect_activate(LINK( this, WatchWindow, ActivateHdl)); + m_xEdit->connect_key_press(LINK( this, WatchWindow, KeyInputHdl)); + m_xTreeListBox->set_accessible_name(IDEResId(RID_STR_WATCHNAME)); + + m_xRemoveWatchButton->set_sensitive(false); + m_xRemoveWatchButton->connect_clicked(LINK( this, WatchWindow, ButtonHdl)); + m_xRemoveWatchButton->set_help_id(HID_BASICIDE_REMOVEWATCH); + m_xRemoveWatchButton->set_tooltip_text(IDEResId(RID_STR_REMOVEWATCHTIP)); + + m_xTreeListBox->set_help_id(HID_BASICIDE_WATCHWINDOW_LIST); + m_xTreeListBox->connect_editing(LINK(this, WatchWindow, EditingEntryHdl), + LINK(this, WatchWindow, EditedEntryHdl)); + m_xTreeListBox->connect_changed( LINK( this, WatchWindow, TreeListHdl ) ); + m_xTreeListBox->connect_expanding(LINK(this, WatchWindow, RequestingChildrenHdl)); + + // VarTabWidth, ValueTabWidth, TypeTabWidth + std::vector<int> aWidths { 220, 100, 1250 }; + std::vector<bool> aEditables { false, true, false }; + m_xTreeListBox->set_column_fixed_widths(aWidths); + m_xTreeListBox->set_column_editables(aEditables); + + SetText(IDEResId(RID_STR_WATCHNAME)); + + SetHelpId( HID_BASICIDE_WATCHWINDOW ); + + // make watch window keyboard accessible + GetSystemWindow()->GetTaskPaneList()->AddWindow( this ); +} + +WatchWindow::~WatchWindow() +{ + disposeOnce(); +} + +void WatchWindow::dispose() +{ + if (m_nUpdateWatchesId) + { + Application::RemoveUserEvent(m_nUpdateWatchesId); + m_nUpdateWatchesId = nullptr; + } + + // Destroy user data + m_xTreeListBox->all_foreach([this](weld::TreeIter& rEntry){ + WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rEntry)); + delete pItem; + return false; + }); + + m_xTitle.reset(); + m_xEdit.reset(); + m_xRemoveWatchButton.reset(); + m_xTitleArea.reset(); + m_xTreeListBox.reset(); + GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this ); + DockingWindow::dispose(); +} + +void WatchWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + lcl_DrawIDEWindowFrame(this, rRenderContext); +} + +void WatchWindow::Resize() +{ + Size aSz = GetOutputSizePixel(); + Size aBoxSz(aSz.Width() - 2*DWBORDER, aSz.Height() - 2*DWBORDER); + + if ( aBoxSz.Width() < 4 ) + aBoxSz.setWidth( 0 ); + if ( aBoxSz.Height() < 4 ) + aBoxSz.setHeight( 0 ); + + m_xBox->SetPosSizePixel(Point(DWBORDER, DWBORDER), aBoxSz); + + Invalidate(); +} + +WatchItem* WatchItem::GetRootItem() +{ + WatchItem* pItem = mpArrayParentItem; + while( pItem ) + { + if( pItem->mpArray.is() ) + break; + pItem = pItem->mpArrayParentItem; + } + return pItem; +} + +SbxDimArray* WatchItem::GetRootArray() +{ + WatchItem* pRootItem = GetRootItem(); + SbxDimArray* pRet = nullptr; + if( pRootItem ) + pRet = pRootItem->mpArray.get(); + return pRet; +} + +void WatchWindow::AddWatch( const OUString& rVName ) +{ + OUString aVar, aIndex; + lcl_SeparateNameAndIndex( rVName, aVar, aIndex ); + WatchItem* pWatchItem = new WatchItem(aVar); + + OUString sId(weld::toId(pWatchItem)); + std::unique_ptr<weld::TreeIter> xRet = m_xTreeListBox->make_iterator(); + m_xTreeListBox->insert(nullptr, -1, &aVar, &sId, nullptr, nullptr, false, xRet.get()); + m_xTreeListBox->set_text(*xRet, "", 1); + m_xTreeListBox->set_text(*xRet, "", 2); + + m_xTreeListBox->set_cursor(*xRet); + m_xTreeListBox->select(*xRet); + m_xTreeListBox->scroll_to_row(*xRet); + m_xRemoveWatchButton->set_sensitive(true); + + UpdateWatches(false); +} + +void WatchWindow::RemoveSelectedWatch() +{ + std::unique_ptr<weld::TreeIter> xEntry = m_xTreeListBox->make_iterator(); + bool bEntry = m_xTreeListBox->get_cursor(xEntry.get()); + if (bEntry) + { + m_xTreeListBox->remove(*xEntry); + bEntry = m_xTreeListBox->get_cursor(xEntry.get()); + if (bEntry) + m_xEdit->set_text(weld::fromId<WatchItem*>(m_xTreeListBox->get_id(*xEntry))->maName); + else + m_xEdit->set_text(OUString()); + if ( !m_xTreeListBox->n_children() ) + m_xRemoveWatchButton->set_sensitive(false); + } +} + +IMPL_STATIC_LINK_NOARG(WatchWindow, ButtonHdl, weld::Button&, void) +{ + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->Execute(SID_BASICIDE_REMOVEWATCH); +} + +IMPL_LINK_NOARG(WatchWindow, TreeListHdl, weld::TreeView&, void) +{ + std::unique_ptr<weld::TreeIter> xCurEntry = m_xTreeListBox->make_iterator(); + bool bCurEntry = m_xTreeListBox->get_cursor(xCurEntry.get()); + if (!bCurEntry) + return; + WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(*xCurEntry)); + if (!pItem) + return; + m_xEdit->set_text(pItem->maName); +} + +IMPL_LINK_NOARG(WatchWindow, ActivateHdl, weld::Entry&, bool) +{ + OUString aCurText(m_xEdit->get_text()); + if (!aCurText.isEmpty()) + { + AddWatch(aCurText); + m_xEdit->select_region(0, -1); + } + return true; +} + +IMPL_LINK(WatchWindow, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bHandled = false; + + sal_uInt16 nKeyCode = rKEvt.GetKeyCode().GetCode(); + if (nKeyCode == KEY_ESCAPE) + { + m_xEdit->set_text(OUString()); + bHandled = true; + } + + return bHandled; +} + +// StackWindow +StackWindow::StackWindow(Layout* pParent) + : DockingWindow(pParent, "modules/BasicIDE/ui/dockingstack.ui", "DockingStack") +{ + m_xTitle = m_xBuilder->weld_label("title"); + m_xTitle->set_label(IDEResId(RID_STR_STACK)); + + m_xTitle->set_size_request(-1, nVirtToolBoxHeight); // so the two title areas are the same height + + m_xTreeListBox = m_xBuilder->weld_tree_view("stack"); + + m_xTreeListBox->set_help_id(HID_BASICIDE_STACKWINDOW_LIST); + m_xTreeListBox->set_accessible_name(IDEResId(RID_STR_STACKNAME)); + m_xTreeListBox->set_selection_mode(SelectionMode::NONE); + m_xTreeListBox->append_text(OUString()); + + SetText(IDEResId(RID_STR_STACKNAME)); + + SetHelpId( HID_BASICIDE_STACKWINDOW ); + + // make stack window keyboard accessible + GetSystemWindow()->GetTaskPaneList()->AddWindow( this ); +} + +StackWindow::~StackWindow() +{ + disposeOnce(); +} + +void StackWindow::dispose() +{ + GetSystemWindow()->GetTaskPaneList()->RemoveWindow( this ); + m_xTitle.reset(); + m_xTreeListBox.reset(); + DockingWindow::dispose(); +} + +void StackWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + lcl_DrawIDEWindowFrame(this, rRenderContext); +} + +void StackWindow::Resize() +{ + Size aSz = GetOutputSizePixel(); + Size aBoxSz(aSz.Width() - 2*DWBORDER, aSz.Height() - 2*DWBORDER); + + if ( aBoxSz.Width() < 4 ) + aBoxSz.setWidth( 0 ); + if ( aBoxSz.Height() < 4 ) + aBoxSz.setHeight( 0 ); + + m_xBox->SetPosSizePixel(Point(DWBORDER, DWBORDER), aBoxSz); + + Invalidate(); +} + +void StackWindow::UpdateCalls() +{ + m_xTreeListBox->freeze(); + m_xTreeListBox->clear(); + + if (StarBASIC::IsRunning()) + { + ErrCode eOld = SbxBase::GetError(); + m_xTreeListBox->set_selection_mode(SelectionMode::Single); + + sal_Int32 nScope = 0; + SbMethod* pMethod = StarBASIC::GetActiveMethod( nScope ); + while ( pMethod ) + { + OUStringBuffer aEntry( OUString::number(nScope )); + if ( aEntry.getLength() < 2 ) + aEntry.insert(0, " "); + aEntry.append(": " + pMethod->GetName()); + SbxArray* pParams = pMethod->GetParameters(); + SbxInfo* pInfo = pMethod->GetInfo(); + if ( pParams ) + { + aEntry.append("("); + // 0 is the sub's name... + for (sal_uInt32 nParam = 1; nParam < pParams->Count(); nParam++) + { + SbxVariable* pVar = pParams->Get(nParam); + assert(pVar && "Parameter?!"); + if ( !pVar->GetName().isEmpty() ) + { + aEntry.append(pVar->GetName()); + } + else if ( pInfo ) + { + assert(nParam <= std::numeric_limits<sal_uInt16>::max()); + const SbxParamInfo* pParam = pInfo->GetParam( sal::static_int_cast<sal_uInt16>(nParam) ); + if ( pParam ) + { + aEntry.append(pParam->aName); + } + } + aEntry.append("="); + SbxDataType eType = pVar->GetType(); + if( eType & SbxARRAY ) + { + aEntry.append("..."); + } + else if( eType != SbxOBJECT ) + { + aEntry.append(pVar->GetOUString()); + } + if (nParam < (pParams->Count() - 1)) + { + aEntry.append(", "); + } + } + aEntry.append(")"); + } + m_xTreeListBox->append_text(aEntry.makeStringAndClear()); + nScope++; + pMethod = StarBASIC::GetActiveMethod( nScope ); + } + + SbxBase::ResetError(); + if( eOld != ERRCODE_NONE ) + SbxBase::SetError( eOld ); + } + else + { + m_xTreeListBox->set_selection_mode(SelectionMode::NONE); + m_xTreeListBox->append_text(OUString()); + } + + m_xTreeListBox->thaw(); +} + +ComplexEditorWindow::ComplexEditorWindow( ModulWindow* pParent ) : + Window( pParent, WB_3DLOOK | WB_CLIPCHILDREN ), + aBrkWindow(VclPtr<BreakPointWindow>::Create(this, pParent)), + aLineNumberWindow(VclPtr<LineNumberWindow>::Create(this, pParent)), + aEdtWindow(VclPtr<EditorWindow>::Create(this, pParent)), + aEWVScrollBar(VclPtr<ScrollAdaptor>::Create(this, false)), + aEWHScrollBar(VclPtr<ScrollAdaptor>::Create(this, true)) +{ + aEdtWindow->Show(); + aBrkWindow->Show(); + + aEWVScrollBar->SetLineSize(nScrollLine); + aEWVScrollBar->SetPageSize(nScrollPage); + aEWVScrollBar->SetScrollHdl( LINK( this, ComplexEditorWindow, ScrollHdl ) ); + aEWVScrollBar->Show(); + + aEWHScrollBar->SetLineSize(nScrollLine); + aEWHScrollBar->SetPageSize(nScrollPage); + aEWHScrollBar->SetScrollHdl( LINK( this, ComplexEditorWindow, ScrollHdl ) ); + aEWHScrollBar->Show(); +} + +ComplexEditorWindow::~ComplexEditorWindow() +{ + disposeOnce(); +} + +void ComplexEditorWindow::dispose() +{ + aBrkWindow.disposeAndClear(); + aLineNumberWindow.disposeAndClear(); + aEdtWindow.disposeAndClear(); + aEWVScrollBar.disposeAndClear(); + aEWHScrollBar.disposeAndClear(); + vcl::Window::dispose(); +} + +void ComplexEditorWindow::Resize() +{ + Size aOutSz = GetOutputSizePixel(); + Size aSz(aOutSz); + aSz.AdjustWidth( -(2*DWBORDER) ); + aSz.AdjustHeight( -(2*DWBORDER) ); + tools::Long nBrkWidth = 20; + tools::Long nSBWidth = aEWVScrollBar->GetSizePixel().Width(); + tools::Long nSBHeight = aEWHScrollBar->GetSizePixel().Height(); + + Size aBrkSz(nBrkWidth, aSz.Height() - nSBHeight); + + if (aLineNumberWindow->IsVisible()) + { + Size aLnSz(aLineNumberWindow->GetWidth(), aSz.Height() - nSBHeight); + Size aEWSz(aSz.Width() - nBrkWidth - aLineNumberWindow->GetWidth() - nSBWidth, aSz.Height() - nSBHeight); + aBrkWindow->SetPosSizePixel(Point(DWBORDER, DWBORDER), aBrkSz); + aLineNumberWindow->SetPosSizePixel(Point(DWBORDER + nBrkWidth, DWBORDER), aLnSz); + aEdtWindow->SetPosSizePixel(Point(DWBORDER + nBrkWidth + aLnSz.Width(), DWBORDER), aEWSz); + } + else + { + Size aEWSz(aSz.Width() - nBrkWidth - nSBWidth, aSz.Height() - nSBHeight); + aBrkWindow->SetPosSizePixel( Point( DWBORDER, DWBORDER ), aBrkSz ); + aEdtWindow->SetPosSizePixel(Point(DWBORDER + nBrkWidth, DWBORDER), aEWSz); + } + + aEWVScrollBar->SetPosSizePixel(Point(aOutSz.Width() - DWBORDER - nSBWidth, DWBORDER), + Size(nSBWidth, aSz.Height() - nSBHeight)); + aEWHScrollBar->SetPosSizePixel(Point(DWBORDER, aOutSz.Height() - DWBORDER - nSBHeight), + Size(aSz.Width() - nSBWidth, nSBHeight)); +} + +IMPL_LINK_NOARG(ComplexEditorWindow, ScrollHdl, weld::Scrollbar&, void) +{ + if (aEdtWindow->GetEditView()) + { + tools::Long nXDiff = aEdtWindow->GetEditView()->GetStartDocPos().X() - aEWHScrollBar->GetThumbPos(); + tools::Long nYDiff = aEdtWindow->GetEditView()->GetStartDocPos().Y() - aEWVScrollBar->GetThumbPos(); + aEdtWindow->GetEditView()->Scroll(nXDiff, nYDiff); + aBrkWindow->DoScroll( nYDiff ); + aLineNumberWindow->DoScroll( nYDiff ); + aEdtWindow->GetEditView()->ShowCursor(false); + aEWVScrollBar->SetThumbPos( aEdtWindow->GetEditView()->GetStartDocPos().Y() ); + } +} + +void ComplexEditorWindow::DataChanged(DataChangedEvent const & rDCEvt) +{ + Window::DataChanged(rDCEvt); + if (rDCEvt.GetType() == DataChangedEventType::SETTINGS + && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) + { + Color aColor(GetSettings().GetStyleSettings().GetFaceColor()); + const AllSettings* pOldSettings = rDCEvt.GetOldSettings(); + if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFaceColor()) + { + SetBackground(Wallpaper(aColor)); + Invalidate(); + } + } +} + +void ComplexEditorWindow::SetLineNumberDisplay(bool b) +{ + aLineNumberWindow->Show(b); + Resize(); +} + +uno::Reference< awt::XVclWindowPeer > +EditorWindow::GetComponentInterface(bool bCreate) +{ + uno::Reference< awt::XVclWindowPeer > xPeer( + Window::GetComponentInterface(false)); + if (!xPeer.is() && bCreate) + { + // Make sure edit engine and view are available: + if (!pEditEngine) + CreateEditEngine(); + + xPeer = createTextWindowPeer(*GetEditView()); + SetComponentInterface(xPeer); + } + return xPeer; +} + +static sal_uInt32 getCorrectedPropCount(SbxArray* p) +{ + sal_uInt32 nPropCount = p->Count(); + if (nPropCount >= 3 && p->Get(nPropCount - 1)->GetName().equalsIgnoreAsciiCase("Dbg_Methods") + && p->Get(nPropCount - 2)->GetName().equalsIgnoreAsciiCase("Dbg_Properties") + && p->Get(nPropCount - 3)->GetName().equalsIgnoreAsciiCase("Dbg_SupportedInterfaces")) + { + nPropCount -= 3; + } + return nPropCount; +} + +IMPL_LINK(WatchWindow, RequestingChildrenHdl, const weld::TreeIter&, rParent, bool) +{ + if( !StarBASIC::IsRunning() ) + return true; + + if (m_xTreeListBox->iter_has_child(rParent)) + return true; + + WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rParent)); + std::unique_ptr<weld::TreeIter> xRet = m_xTreeListBox->make_iterator(); + + SbxDimArray* pArray = pItem->mpArray.get(); + SbxDimArray* pRootArray = pItem->GetRootArray(); + bool bArrayIsRootArray = false; + if( !pArray && pRootArray ) + { + pArray = pRootArray; + bArrayIsRootArray = true; + } + + SbxObject* pObj = pItem->mpObject.get(); + if( pObj ) + { + createAllObjectProperties( pObj ); + SbxArray* pProps = pObj->GetProperties(); + const sal_uInt32 nPropCount = getCorrectedPropCount(pProps); + pItem->maMemberList.reserve(nPropCount); + + for( sal_uInt32 i = 0 ; i < nPropCount ; ++i ) + { + SbxVariable* pVar = pProps->Get(i); + + pItem->maMemberList.push_back(pVar->GetName()); + OUString const& rName = pItem->maMemberList.back(); + + WatchItem* pWatchItem = new WatchItem(rName); + OUString sId(weld::toId(pWatchItem)); + + m_xTreeListBox->insert(&rParent, -1, &rName, &sId, nullptr, nullptr, false, xRet.get()); + m_xTreeListBox->set_text(*xRet, "", 1); + m_xTreeListBox->set_text(*xRet, "", 2); + } + + if (nPropCount > 0 && !m_nUpdateWatchesId) + { + m_nUpdateWatchesId = Application::PostUserEvent(LINK(this, WatchWindow, ExecuteUpdateWatches)); + } + } + else if( pArray ) + { + sal_uInt16 nElementCount = 0; + + // Loop through indices of current level + int nParentLevel = bArrayIsRootArray ? pItem->nDimLevel : 0; + int nThisLevel = nParentLevel + 1; + sal_Int32 nMin, nMax; + if (pArray->GetDim(nThisLevel, nMin, nMax)) + { + for (sal_Int32 i = nMin; i <= nMax; i++) + { + WatchItem* pChildItem = new WatchItem(pItem->maName); + + // Copy data and create name + + OUStringBuffer aIndexStr = "("; + pChildItem->mpArrayParentItem = pItem; + pChildItem->nDimLevel = nThisLevel; + pChildItem->nDimCount = pItem->nDimCount; + pChildItem->vIndices.resize(pChildItem->nDimCount); + sal_Int32 j; + for (j = 0; j < nParentLevel; j++) + { + sal_Int32 n = pChildItem->vIndices[j] = pItem->vIndices[j]; + aIndexStr.append( OUString::number(n) + "," ); + } + pChildItem->vIndices[nParentLevel] = i; + aIndexStr.append( OUString::number(i) + ")" ); + + OUString aDisplayName; + WatchItem* pArrayRootItem = pChildItem->GetRootItem(); + if (pArrayRootItem && pArrayRootItem->mpArrayParentItem) + aDisplayName = pItem->maDisplayName; + else + aDisplayName = pItem->maName; + aDisplayName += aIndexStr; + pChildItem->maDisplayName = aDisplayName; + + OUString sId(weld::toId(pChildItem)); + + m_xTreeListBox->insert(&rParent, -1, &aDisplayName, &sId, nullptr, nullptr, false, + xRet.get()); + m_xTreeListBox->set_text(*xRet, "", 1); + m_xTreeListBox->set_text(*xRet, "", 2); + + nElementCount++; + } + } + if (nElementCount > 0 && !m_nUpdateWatchesId) + { + m_nUpdateWatchesId = Application::PostUserEvent(LINK(this, WatchWindow, ExecuteUpdateWatches)); + } + } + + return true; +} + +IMPL_LINK_NOARG(WatchWindow, ExecuteUpdateWatches, void*, void) +{ + m_nUpdateWatchesId = nullptr; + UpdateWatches(); +} + +SbxBase* WatchWindow::ImplGetSBXForEntry(const weld::TreeIter& rEntry, bool& rbArrayElement) +{ + SbxBase* pSBX = nullptr; + rbArrayElement = false; + + WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rEntry)); + OUString aVName( pItem->maName ); + + std::unique_ptr<weld::TreeIter> xParentEntry = m_xTreeListBox->make_iterator(&rEntry); + bool bParentEntry = m_xTreeListBox->iter_parent(*xParentEntry); + WatchItem* pParentItem = bParentEntry ? weld::fromId<WatchItem*>(m_xTreeListBox->get_id(*xParentEntry)) : nullptr; + if( pParentItem ) + { + SbxObject* pObj = pParentItem->mpObject.get(); + SbxDimArray* pArray; + if( pObj ) + { + pSBX = pObj->Find( aVName, SbxClassType::DontCare ); + if (SbxVariable const* pVar = IsSbxVariable(pSBX)) + { + // Force getting value + SbxValues aRes; + aRes.eType = SbxVOID; + pVar->Get( aRes ); + } + } + // Array? + else if( (pArray = pItem->GetRootArray()) != nullptr ) + { + rbArrayElement = true; + if( pParentItem->nDimLevel + 1 == pParentItem->nDimCount ) + pSBX = pArray->Get(pItem->vIndices.empty() ? nullptr : &*pItem->vIndices.begin()); + } + } + else + { + pSBX = StarBASIC::FindSBXInCurrentScope( aVName ); + } + return pSBX; +} + +IMPL_LINK(WatchWindow, EditingEntryHdl, const weld::TreeIter&, rIter, bool) +{ + WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rIter)); + + bool bEdit = false; + if (StarBASIC::IsRunning() && StarBASIC::GetActiveMethod() && !SbxBase::IsError()) + { + // No out of scope entries + bool bArrayElement; + SbxBase* pSbx = ImplGetSBXForEntry(rIter, bArrayElement); + if (IsSbxVariable(pSbx) || bArrayElement) + { + // Accept no objects and only end nodes of arrays for editing + if( !pItem->mpObject.is() && ( !pItem->mpArray.is() || pItem->nDimLevel == pItem->nDimCount ) ) + { + aEditingRes = m_xTreeListBox->get_text(rIter, 1); + aEditingRes = comphelper::string::strip(aEditingRes, ' '); + bEdit = true; + } + } + } + + return bEdit; +} + +IMPL_LINK(WatchWindow, EditedEntryHdl, const IterString&, rIterString, bool) +{ + const weld::TreeIter& rIter = rIterString.first; + OUString aResult = comphelper::string::strip(rIterString.second, ' '); + + sal_uInt16 nResultLen = aResult.getLength(); + sal_Unicode cFirst = aResult[0]; + sal_Unicode cLast = aResult[ nResultLen - 1 ]; + if( cFirst == '\"' && cLast == '\"' ) + aResult = aResult.copy( 1, nResultLen - 2 ); + + if (aResult == aEditingRes) + return false; + + bool bArrayElement; + SbxBase* pSBX = ImplGetSBXForEntry(rIter, bArrayElement); + + if (SbxVariable* pVar = IsSbxVariable(pSBX)) + { + SbxDataType eType = pVar->GetType(); + if ( static_cast<sal_uInt8>(eType) != sal_uInt8(SbxOBJECT) + && ( eType & SbxARRAY ) == 0 ) + { + // If the type is variable, the conversion of the SBX does not matter, + // else the string is converted. + pVar->PutStringExt( aResult ); + } + } + + if ( SbxBase::IsError() ) + { + SbxBase::ResetError(); + } + + UpdateWatches(); + + // The text should never be taken/copied 1:1, + // as the UpdateWatches will be lost + return false; +} + +namespace +{ + +void implCollapseModifiedObjectEntry(const weld::TreeIter& rParent, weld::TreeView& rTree) +{ + rTree.collapse_row(rParent); + + std::unique_ptr<weld::TreeIter> xDeleteEntry = rTree.make_iterator(&rParent); + + while (rTree.iter_children(*xDeleteEntry)) + { + implCollapseModifiedObjectEntry(*xDeleteEntry, rTree); + + WatchItem* pItem = weld::fromId<WatchItem*>(rTree.get_id(*xDeleteEntry)); + delete pItem; + rTree.remove(*xDeleteEntry); + rTree.copy_iterator(rParent, *xDeleteEntry); + } +} + +OUString implCreateTypeStringForDimArray( WatchItem* pItem, SbxDataType eType ) +{ + OUString aRetStr = getBasicTypeName( eType ); + + SbxDimArray* pArray = pItem->mpArray.get(); + if( !pArray ) + pArray = pItem->GetRootArray(); + if( pArray ) + { + int nDimLevel = pItem->nDimLevel; + int nDims = pItem->nDimCount; + if( nDimLevel < nDims ) + { + aRetStr += "("; + for( int i = nDimLevel ; i < nDims ; i++ ) + { + sal_Int32 nMin, nMax; + pArray->GetDim(sal::static_int_cast<sal_Int32>(i + 1), nMin, nMax); + aRetStr += OUString::number(nMin) + " to " + OUString::number(nMax); + if( i < nDims - 1 ) + aRetStr += ", "; + } + aRetStr += ")"; + } + } + return aRetStr; +} + +} // namespace + +void WatchWindow::implEnableChildren(const weld::TreeIter& rEntry, bool bEnable) +{ + if (bEnable) + { + if (!m_xTreeListBox->get_row_expanded(rEntry)) + m_xTreeListBox->set_children_on_demand(rEntry, true); + } + else + { + assert(!m_xTreeListBox->get_row_expanded(rEntry)); + m_xTreeListBox->set_children_on_demand(rEntry, false); + } +} + +void WatchWindow::UpdateWatches(bool bBasicStopped) +{ + SbMethod* pCurMethod = StarBASIC::GetActiveMethod(); + + ErrCode eOld = SbxBase::GetError(); + setBasicWatchMode( true ); + + m_xTreeListBox->all_foreach([this, pCurMethod, bBasicStopped](weld::TreeIter& rEntry){ + WatchItem* pItem = weld::fromId<WatchItem*>(m_xTreeListBox->get_id(rEntry)); + DBG_ASSERT( !pItem->maName.isEmpty(), "Var? - Must not be empty!" ); + OUString aWatchStr; + OUString aTypeStr; + if ( pCurMethod ) + { + bool bCollapse = false; + TriState eEnableChildren = TRISTATE_INDET; + + bool bArrayElement; + SbxBase* pSBX = ImplGetSBXForEntry(rEntry, bArrayElement); + + // Array? If no end node create type string + if( bArrayElement && pItem->nDimLevel < pItem->nDimCount ) + { + SbxDimArray* pRootArray = pItem->GetRootArray(); + SbxDataType eType = pRootArray->GetType(); + aTypeStr = implCreateTypeStringForDimArray( pItem, eType ); + eEnableChildren = TRISTATE_TRUE; + } + + if (SbxVariable* pVar = dynamic_cast<SbxVariable*>(pSBX)) + { + // extra treatment of arrays + SbxDataType eType = pVar->GetType(); + if ( eType & SbxARRAY ) + { + // consider multidimensional arrays! + if (SbxDimArray* pNewArray = dynamic_cast<SbxDimArray*>(pVar->GetObject())) + { + SbxDimArray* pOldArray = pItem->mpArray.get(); + + bool bArrayChanged = false; + if (pOldArray != nullptr) + { + // Compare Array dimensions to see if array has changed + // Can be a copy, so comparing pointers does not work + sal_Int32 nOldDims = pOldArray->GetDims(); + sal_Int32 nNewDims = pNewArray->GetDims(); + if( nOldDims != nNewDims ) + { + bArrayChanged = true; + } + else + { + for( sal_Int32 i = 0 ; i < nOldDims ; i++ ) + { + sal_Int32 nOldMin, nOldMax; + sal_Int32 nNewMin, nNewMax; + + pOldArray->GetDim(i + 1, nOldMin, nOldMax); + pNewArray->GetDim(i + 1, nNewMin, nNewMax); + if( nOldMin != nNewMin || nOldMax != nNewMax ) + { + bArrayChanged = true; + break; + } + } + } + } + else + { + bArrayChanged = true; + } + eEnableChildren = TRISTATE_TRUE; + // #i37227 Clear always and replace array + if( pNewArray != pOldArray ) + { + pItem->clearWatchItem(); + eEnableChildren = TRISTATE_TRUE; + + pItem->mpArray = pNewArray; + sal_Int32 nDims = pNewArray->GetDims(); + pItem->nDimLevel = 0; + pItem->nDimCount = nDims; + } + if( bArrayChanged && pOldArray != nullptr ) + { + bCollapse = true; + } + aTypeStr = implCreateTypeStringForDimArray( pItem, eType ); + } + else + { + aWatchStr += "<?>"; + } + } + else if ( static_cast<sal_uInt8>(eType) == sal_uInt8(SbxOBJECT) ) + { + if (SbxObject* pObj = dynamic_cast<SbxObject*>(pVar->GetObject())) + { + if ( pItem->mpObject.is() && !pItem->maMemberList.empty() ) + { + createAllObjectProperties(pObj); + SbxArray* pProps = pObj->GetProperties(); + const sal_uInt32 nPropCount = getCorrectedPropCount(pProps); + // Check if member list has changed + bCollapse = pItem->maMemberList.size() != nPropCount; + for( sal_uInt32 i = 0 ; !bCollapse && i < nPropCount ; i++ ) + { + SbxVariable* pVar_ = pProps->Get(i); + if( pItem->maMemberList[i] != pVar_->GetName() ) + bCollapse = true; + } + } + + pItem->mpObject = pObj; + eEnableChildren = TRISTATE_TRUE; + aTypeStr = getBasicObjectTypeName( pObj ); + } + else + { + aWatchStr = "Null"; + if( pItem->mpObject.is() ) + { + bCollapse = true; + eEnableChildren = TRISTATE_FALSE; + } + } + } + else + { + if( pItem->mpObject.is() ) + { + bCollapse = true; + eEnableChildren = TRISTATE_FALSE; + } + + bool bString = (static_cast<sal_uInt8>(eType) == sal_uInt8(SbxSTRING)); + OUString aStrStr( "\"" ); + if( bString ) + { + aWatchStr += aStrStr; + } + // tdf#57308 - avoid a second call to retrieve the data + const SbxFlagBits nFlags = pVar->GetFlags(); + pVar->SetFlag(SbxFlagBits::NoBroadcast); + aWatchStr += pVar->GetOUString(); + pVar->SetFlags(nFlags); + if( bString ) + { + aWatchStr += aStrStr; + } + } + if( aTypeStr.isEmpty() ) + { + if( !pVar->IsFixed() ) + { + aTypeStr = "Variant/"; + } + aTypeStr += getBasicTypeName( pVar->GetType() ); + } + } + else if( !bArrayElement ) + { + aWatchStr += "<Out of Scope>"; + } + + if( bCollapse ) + { + implCollapseModifiedObjectEntry(rEntry, *m_xTreeListBox); + pItem->clearWatchItem(); + } + + if (eEnableChildren != TRISTATE_INDET) + implEnableChildren(rEntry, eEnableChildren == TRISTATE_TRUE); + } + else if( bBasicStopped ) + { + if( pItem->mpObject.is() || pItem->mpArray.is() ) + { + implCollapseModifiedObjectEntry(rEntry, *m_xTreeListBox); + pItem->mpObject.clear(); + pItem->mpArray.clear(); + } + pItem->clearWatchItem(); + } + + m_xTreeListBox->set_text(rEntry, aWatchStr, 1); + m_xTreeListBox->set_text(rEntry, aTypeStr, 2); + + return false; + }); + + SbxBase::ResetError(); + if( eOld != ERRCODE_NONE ) + SbxBase::SetError( eOld ); + setBasicWatchMode( false ); +} + +IMPL_LINK_NOARG(CodeCompleteWindow, ImplDoubleClickHdl, weld::TreeView&, bool) +{ + InsertSelectedEntry(); + return true; +} + +IMPL_LINK_NOARG(CodeCompleteWindow, ImplSelectHdl, weld::TreeView&, void) +{ + //give back the focus to the parent + pParent->GrabFocus(); +} + +TextView* CodeCompleteWindow::GetParentEditView() +{ + return pParent->GetEditView(); +} + +void CodeCompleteWindow::InsertSelectedEntry() +{ + OUString sSelectedEntry = m_xListBox->get_selected_text(); + + if( !aFuncBuffer.isEmpty() ) + { + // if the user typed in something: remove, and insert + GetParentEditView()->SetSelection(pParent->GetLastHighlightPortionTextSelection()); + GetParentEditView()->DeleteSelected(); + + if (!sSelectedEntry.isEmpty()) + { + // if the user selected something + GetParentEditView()->InsertText(sSelectedEntry); + } + } + else + { + if (!sSelectedEntry.isEmpty()) + { + // if the user selected something + GetParentEditView()->InsertText(sSelectedEntry); + } + } + HideAndRestoreFocus(); +} + +void CodeCompleteWindow::SetMatchingEntries() +{ + for (sal_Int32 i = 0, nEntryCount = m_xListBox->n_children(); i< nEntryCount; ++i) + { + OUString sEntry = m_xListBox->get_text(i); + if (sEntry.startsWithIgnoreAsciiCase(aFuncBuffer)) + { + m_xListBox->select(i); + break; + } + } +} + +IMPL_LINK(CodeCompleteWindow, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + return HandleKeyInput(rKEvt); +} + +bool CodeCompleteWindow::HandleKeyInput( const KeyEvent& rKeyEvt ) +{ + bool bHandled = true; + + sal_Unicode aChar = rKeyEvt.GetKeyCode().GetCode(); + if( (( aChar >= KEY_A ) && ( aChar <= KEY_Z )) + || ((aChar >= KEY_0) && (aChar <= KEY_9)) ) + { + aFuncBuffer.append(rKeyEvt.GetCharCode()); + SetMatchingEntries(); + } + else + { + switch( aChar ) + { + case KEY_POINT: + break; + case KEY_ESCAPE: // hide, do nothing + HideAndRestoreFocus(); + break; + case KEY_RIGHT: + { + TextSelection aTextSelection( GetParentEditView()->GetSelection() ); + if( aTextSelection.GetEnd().GetPara() != GetTextSelection().GetEnd().GetPara()-1 ) + { + HideAndRestoreFocus(); + } + break; + } + case KEY_LEFT: + { + TextSelection aTextSelection( GetParentEditView()->GetSelection() ); + if( aTextSelection.GetStart().GetIndex()-1 < GetTextSelection().GetStart().GetIndex() ) + {//leave the cursor where it is + HideAndRestoreFocus(); + } + break; + } + case KEY_TAB: + { + TextSelection aTextSelection = pParent->GetLastHighlightPortionTextSelection(); + OUString sTypedText = pParent->GetEditEngine()->GetText(aTextSelection); + if( !aFuncBuffer.isEmpty() ) + { + sal_Int32 nInd = m_xListBox->get_selected_index(); + if (nInd != -1) + { + int nEntryCount = m_xListBox->n_children(); + //if there is something selected + bool bFound = false; + for (sal_Int32 i = nInd; i != nEntryCount; ++i) + { + OUString sEntry = m_xListBox->get_text(i); + if( sEntry.startsWithIgnoreAsciiCase( aFuncBuffer ) + && (std::u16string_view(aFuncBuffer) != sTypedText) && (i != nInd) ) + { + m_xListBox->select(i); + bFound = true; + break; + } + } + if( !bFound ) + SetMatchingEntries(); + + GetParentEditView()->SetSelection( aTextSelection ); + GetParentEditView()->DeleteSelected(); + GetParentEditView()->InsertText(m_xListBox->get_selected_text()); + } + } + break; + } + case KEY_SPACE: + HideAndRestoreFocus(); + break; + case KEY_BACKSPACE: case KEY_DELETE: + if( !aFuncBuffer.isEmpty() ) + { + //if there was something inserted by tab: add it to aFuncBuffer + TextSelection aSel( GetParentEditView()->GetSelection() ); + TextPaM aEnd( GetParentEditView()->CursorEndOfLine(GetTextSelection().GetEnd()) ); + GetParentEditView()->SetSelection(TextSelection(GetTextSelection().GetStart(), aEnd ) ); + OUString aTabInsertedStr( GetParentEditView()->GetSelected() ); + GetParentEditView()->SetSelection( aSel ); + + if( !aTabInsertedStr.isEmpty() && aTabInsertedStr != std::u16string_view(aFuncBuffer) ) + { + aFuncBuffer = aTabInsertedStr; + } + aFuncBuffer.remove(aFuncBuffer.getLength()-1, 1); + SetMatchingEntries(); + } + else + { + ClearAndHide(); + bHandled = false; + } + break; + case KEY_RETURN: + InsertSelectedEntry(); + break; + case KEY_UP: + { + int nInd = m_xListBox->get_selected_index(); + if (nInd) + m_xListBox->select(nInd - 1); + break; + } + case KEY_DOWN: + { + int nInd = m_xListBox->get_selected_index(); + if (nInd + 1 < m_xListBox->n_children()) + m_xListBox->select(nInd + 1); + break; + } + default: + bHandled = false; + break; + } + } + + return bHandled; +} + +void CodeCompleteWindow::HideAndRestoreFocus() +{ + Hide(); + pParent->GrabFocus(); +} + +CodeCompleteWindow::CodeCompleteWindow(EditorWindow* pPar) + : InterimItemWindow(pPar, "modules/BasicIDE/ui/codecomplete.ui", "CodeComplete") + , pParent(pPar) + , m_xListBox(m_xBuilder->weld_tree_view("treeview")) +{ + m_xListBox->connect_row_activated(LINK(this, CodeCompleteWindow, ImplDoubleClickHdl)); + m_xListBox->connect_changed(LINK(this, CodeCompleteWindow, ImplSelectHdl)); + m_xListBox->connect_key_press(LINK(this, CodeCompleteWindow, KeyInputHdl)); + m_xListBox->make_sorted(); + + m_xListBox->set_size_request(150, 150); // default, this will adopt the line length + SetSizePixel(m_xContainer->get_preferred_size()); +} + +CodeCompleteWindow::~CodeCompleteWindow() +{ + disposeOnce(); +} + +void CodeCompleteWindow::dispose() +{ + m_xListBox.reset(); + pParent.clear(); + InterimItemWindow::dispose(); +} + +void CodeCompleteWindow::InsertEntry( const OUString& aStr ) +{ + m_xListBox->append_text(aStr); +} + +void CodeCompleteWindow::ClearListBox() +{ + m_xListBox->clear(); + aFuncBuffer.setLength(0); +} + +void CodeCompleteWindow::SetTextSelection( const TextSelection& aSel ) +{ + m_aTextSelection = aSel; +} + +void CodeCompleteWindow::ResizeAndPositionListBox() +{ + if (m_xListBox->n_children() < 1) + return; + + // if there is at least one element inside + // calculate basic position: under the current line + tools::Rectangle aRect = static_cast<TextEngine*>(pParent->GetEditEngine())->PaMtoEditCursor( pParent->GetEditView()->GetSelection().GetEnd() ); + tools::Long nViewYOffset = pParent->GetEditView()->GetStartDocPos().Y(); + Point aPos = aRect.BottomRight();// this variable will be used later (if needed) + aPos.setY( (aPos.Y() - nViewYOffset) + nBasePad ); + + // get line count + const sal_uInt16 nLines = static_cast<sal_uInt16>(std::min(6, m_xListBox->n_children())); + + m_xListBox->set_size_request(-1, m_xListBox->get_height_rows(nLines)); + + Size aSize = m_xContainer->get_preferred_size(); + //set the size + SetSizePixel( aSize ); + + //calculate position + const tools::Rectangle aVisArea( pParent->GetEditView()->GetStartDocPos(), pParent->GetOutputSizePixel() ); //the visible area + const Point& aBottomPoint = aVisArea.BottomRight(); + + if( aVisArea.TopRight().getY() + aPos.getY() + aSize.getHeight() > aBottomPoint.getY() ) + {//clipped at the bottom: move it up + const tools::Long& nParentFontHeight = pParent->GetEditEngine()->GetFont().GetFontHeight(); //parent's font (in the IDE): needed for height + aPos.AdjustY( -(aSize.getHeight() + nParentFontHeight + nCursorPad) ); + } + + if( aVisArea.TopLeft().getX() + aPos.getX() + aSize.getWidth() > aBottomPoint.getX() ) + {//clipped at the right side, move it a bit left + aPos.AdjustX( -(aSize.getWidth() + aVisArea.TopLeft().getX()) ); + } + //set the position + SetPosPixel( aPos ); +} + +void CodeCompleteWindow::SelectFirstEntry() +{ + if (m_xListBox->n_children() > 0) + m_xListBox->select(0); +} + +void CodeCompleteWindow::ClearAndHide() +{ + ClearListBox(); + HideAndRestoreFocus(); +} + +UnoTypeCodeCompletetor::UnoTypeCodeCompletetor( const std::vector< OUString >& aVect, const OUString& sVarType ) +: bCanComplete( true ) +{ + if( aVect.empty() || sVarType.isEmpty() ) + { + bCanComplete = false;//invalid parameters, nothing to code complete + return; + } + + try + { + // Get the base class for reflection: + xClass = css::reflection::theCoreReflection::get( + comphelper::getProcessComponentContext())->forName(sVarType); + } + catch( const Exception& ) + { + bCanComplete = false; + return; + } + + //start from aVect[1]: aVect[0] is the variable name + bCanComplete = std::none_of(aVect.begin() + 1, aVect.end(), [this](const OUString& rMethName) { + return (!CodeCompleteOptions::IsExtendedTypeDeclaration() || !CheckMethod(rMethName)) && !CheckField(rMethName); }); +} + +std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassMethods() const +{ + std::vector< OUString > aRetVect; + if( bCanComplete && ( xClass != nullptr ) ) + { + const Sequence< Reference< reflection::XIdlMethod > > aMethods = xClass->getMethods(); + for(Reference< reflection::XIdlMethod > const & rMethod : aMethods) + { + aRetVect.push_back( rMethod->getName() ); + } + } + return aRetVect;//this is empty when cannot code complete +} + +std::vector< OUString > UnoTypeCodeCompletetor::GetXIdlClassFields() const +{ + std::vector< OUString > aRetVect; + if( bCanComplete && ( xClass != nullptr ) ) + { + const Sequence< Reference< reflection::XIdlField > > aFields = xClass->getFields(); + for(Reference< reflection::XIdlField > const & rxField : aFields) + { + aRetVect.push_back( rxField->getName() ); + } + } + return aRetVect;//this is empty when cannot code complete +} + + +bool UnoTypeCodeCompletetor::CheckField( const OUString& sFieldName ) +{// modifies xClass!!! + + if ( xClass == nullptr ) + return false; + + Reference< reflection::XIdlField> xField = xClass->getField( sFieldName ); + if( xField != nullptr ) + { + xClass = xField->getType(); + if( xClass != nullptr ) + { + return true; + } + } + return false; +} + +bool UnoTypeCodeCompletetor::CheckMethod( const OUString& sMethName ) +{// modifies xClass!!! + + + if ( xClass == nullptr ) + return false; + + Reference< reflection::XIdlMethod> xMethod = xClass->getMethod( sMethName ); + if( xMethod != nullptr ) //method OK, check return type + { + xClass = xMethod->getReturnType(); + if( xClass != nullptr ) + { + return true; + } + } + return false; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/baside3.cxx b/basctl/source/basicide/baside3.cxx new file mode 100644 index 0000000000..4a6b1dfbfb --- /dev/null +++ b/basctl/source/basicide/baside3.cxx @@ -0,0 +1,1325 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <strings.hrc> +#include <helpids.h> +#include <iderid.hxx> + +#include <accessibledialogwindow.hxx> +#include <baside3.hxx> +#include <basidesh.hxx> +#include <bastype2.hxx> +#include <basobj.hxx> +#include <dlged.hxx> +#include <dlgeddef.hxx> +#include <dlgedmod.hxx> +#include <dlgedview.hxx> +#include <iderdll.hxx> +#include <localizationmgr.hxx> +#include <managelang.hxx> + +#include <com/sun/star/script/XLibraryContainer2.hpp> +#include <com/sun/star/resource/StringResourceWithLocation.hpp> +#include <com/sun/star/ucb/SimpleFileAccess.hpp> +#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> +#include <comphelper/processfactory.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/visitem.hxx> +#include <svl/whiter.hxx> +#include <svx/svdundo.hxx> +#include <svx/svxids.hrc> +#include <comphelper/diagnose_ex.hxx> +#include <tools/urlobj.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/weld.hxx> +#include <vcl/settings.hxx> +#include <vcl/stdtext.hxx> +#include <vcl/svapp.hxx> +#include <xmlscript/xmldlg_imexp.hxx> + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::resource; +using namespace ::com::sun::star::ui::dialogs; + +#ifdef _WIN32 +constexpr OUString FilterMask_All = u"*.*"_ustr; +#else +constexpr OUString FilterMask_All = u"*"_ustr; +#endif + +DialogWindow::DialogWindow(DialogWindowLayout* pParent, ScriptDocument const& rDocument, + const OUString& aLibName, const OUString& aName, + css::uno::Reference<css::container::XNameContainer> const& xDialogModel) + : BaseWindow(pParent, rDocument, aLibName, aName) + ,m_rLayout(*pParent) + ,m_pEditor(new DlgEditor(*this, m_rLayout, rDocument.isDocument() + ? rDocument.getDocument() + : Reference<frame::XModel>(), xDialogModel)) + ,m_pUndoMgr(new SfxUndoManager) + ,m_nControlSlotId(SID_INSERT_SELECT) +{ + InitSettings(); + + m_pEditor->GetModel().SetNotifyUndoActionHdl( + &DialogWindow::NotifyUndoActionHdl + ); + + SetHelpId( HID_BASICIDE_DIALOGWINDOW ); + + // set readonly mode for readonly libraries + Reference< script::XLibraryContainer2 > xDlgLibContainer( GetDocument().getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) + SetReadOnly(true); + + if ( rDocument.isDocument() && rDocument.isReadOnly() ) + SetReadOnly(true); +} + +void DialogWindow::dispose() +{ + m_pEditor.reset(); + BaseWindow::dispose(); +} + +void DialogWindow::LoseFocus() +{ + if ( IsModified() ) + StoreData(); + + Window::LoseFocus(); +} + +void DialogWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + m_pEditor->Paint(rRenderContext, rRect); +} + +void DialogWindow::Resize() +{ + if (GetHScrollBar() && GetVScrollBar()) + { + m_pEditor->SetScrollBars( GetHScrollBar(), GetVScrollBar() ); + } +} + +void DialogWindow::MouseButtonDown( const MouseEvent& rMEvt ) +{ + m_pEditor->MouseButtonDown( rMEvt ); + + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_SHOW_PROPERTYBROWSER ); +} + +void DialogWindow::MouseButtonUp( const MouseEvent& rMEvt ) +{ + m_pEditor->MouseButtonUp( rMEvt ); + if( (m_pEditor->GetMode() == DlgEditor::INSERT) && !m_pEditor->IsCreateOK() ) + { + m_nControlSlotId = SID_INSERT_SELECT; + m_pEditor->SetMode( DlgEditor::SELECT ); + Shell::InvalidateControlSlots(); + } + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_SHOW_PROPERTYBROWSER ); + pBindings->Invalidate( SID_DOC_MODIFIED ); + pBindings->Invalidate( SID_SAVEDOC ); + pBindings->Invalidate( SID_COPY ); + pBindings->Invalidate( SID_CUT ); + } +} + +void DialogWindow::MouseMove( const MouseEvent& rMEvt ) +{ + m_pEditor->MouseMove( rMEvt ); +} + +void DialogWindow::KeyInput( const KeyEvent& rKEvt ) +{ + SfxBindings* pBindings = GetBindingsPtr(); + + if( rKEvt.GetKeyCode() == KEY_BACKSPACE ) + { + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->Execute( SID_BACKSPACE ); + } + else + { + if( pBindings && rKEvt.GetKeyCode() == KEY_TAB ) + pBindings->Invalidate( SID_SHOW_PROPERTYBROWSER ); + + if( !m_pEditor->KeyInput( rKEvt ) ) + { + if( !SfxViewShell::Current()->KeyInput( rKEvt ) ) + Window::KeyInput( rKEvt ); + } + } + + // may be KEY_TAB, KEY_BACKSPACE, KEY_ESCAPE + if( pBindings ) + { + pBindings->Invalidate( SID_COPY ); + pBindings->Invalidate( SID_CUT ); + } +} + +void DialogWindow::Command( const CommandEvent& rCEvt ) +{ + if ( ( rCEvt.GetCommand() == CommandEventId::Wheel ) || + ( rCEvt.GetCommand() == CommandEventId::StartAutoScroll ) || + ( rCEvt.GetCommand() == CommandEventId::AutoScroll ) ) + { + HandleScrollCommand( rCEvt, GetHScrollBar(), GetVScrollBar() ); + } + else if ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) + { + if (GetDispatcher()) + { + SdrView& rView = GetView(); + if( !rCEvt.IsMouseEvent() && rView.AreObjectsMarked() ) + { + tools::Rectangle aMarkedRect( rView.GetMarkedRect() ); + Point MarkedCenter( aMarkedRect.Center() ); + Point PosPixel( LogicToPixel( MarkedCenter ) ); + SfxDispatcher::ExecutePopup( this, &PosPixel ); + } + else + { + SfxDispatcher::ExecutePopup(); + } + + } + } + else + BaseWindow::Command( rCEvt ); +} + + +void DialogWindow::NotifyUndoActionHdl( std::unique_ptr<SdrUndoAction> ) +{ + // #i120515# pUndoAction needs to be deleted, this hand over is an ownership + // change. As long as it does not get added to the undo manager, it needs at + // least to be deleted. +} + +void DialogWindow::DoInit() +{ + m_pEditor->SetScrollBars( GetHScrollBar(), GetVScrollBar() ); +} + +void DialogWindow::DoScroll( Scrollable* ) +{ + m_pEditor->DoScroll(); +} + +void DialogWindow::GetState( SfxItemSet& rSet ) +{ + SfxWhichIter aIter(rSet); + bool bIsCalc = false; + if ( GetDocument().isDocument() ) + { + Reference< frame::XModel > xModel= GetDocument().getDocument(); + if ( xModel.is() ) + { + Reference< lang::XServiceInfo > xServiceInfo ( xModel, UNO_QUERY ); + if ( xServiceInfo.is() && xServiceInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) ) + bIsCalc = true; + } + } + + for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich() ) + { + switch ( nWh ) + { + case SID_PASTE: + { + if ( !IsPasteAllowed() ) + rSet.DisableItem( nWh ); + + if ( IsReadOnly() ) + rSet.DisableItem( nWh ); + } + break; + case SID_COPY: + { + // any object selected? + if ( !m_pEditor->GetView().AreObjectsMarked() ) + rSet.DisableItem( nWh ); + } + break; + case SID_CUT: + case SID_DELETE: + case SID_BACKSPACE: + { + // any object selected? + if ( !m_pEditor->GetView().AreObjectsMarked() ) + rSet.DisableItem( nWh ); + + if ( IsReadOnly() ) + rSet.DisableItem( nWh ); + } + break; + case SID_REDO: + { + if ( !m_pUndoMgr->GetUndoActionCount() ) + rSet.DisableItem( nWh ); + } + break; + + case SID_DIALOG_TESTMODE: + { + // is the IDE still active? + bool const bBool = GetShell()->GetFrame() && + m_pEditor->GetMode() == DlgEditor::TEST; + rSet.Put(SfxBoolItem(SID_DIALOG_TESTMODE, bBool)); + } + break; + + case SID_CHOOSE_CONTROLS: + { + if ( IsReadOnly() ) + rSet.DisableItem( nWh ); + } + break; + + case SID_SHOW_PROPERTYBROWSER: + { + Shell* pShell = GetShell(); + SfxViewFrame* pViewFrame = pShell ? &pShell->GetViewFrame() : nullptr; + if ( pViewFrame && !pViewFrame->HasChildWindow( SID_SHOW_PROPERTYBROWSER ) && !m_pEditor->GetView().AreObjectsMarked() ) + rSet.DisableItem( nWh ); + + if ( IsReadOnly() ) + rSet.DisableItem( nWh ); + } + break; + case SID_INSERT_FORM_RADIO: + case SID_INSERT_FORM_CHECK: + case SID_INSERT_FORM_LIST: + case SID_INSERT_FORM_COMBO: + case SID_INSERT_FORM_VSCROLL: + case SID_INSERT_FORM_HSCROLL: + case SID_INSERT_FORM_SPIN: + { + if ( !bIsCalc || IsReadOnly() ) + rSet.DisableItem( nWh ); + else + rSet.Put( SfxBoolItem( nWh, m_nControlSlotId == nWh ) ); + } + break; + + case SID_INSERT_SELECT: + case SID_INSERT_PUSHBUTTON: + case SID_INSERT_RADIOBUTTON: + case SID_INSERT_CHECKBOX: + case SID_INSERT_LISTBOX: + case SID_INSERT_COMBOBOX: + case SID_INSERT_GROUPBOX: + case SID_INSERT_EDIT: + case SID_INSERT_FIXEDTEXT: + case SID_INSERT_IMAGECONTROL: + case SID_INSERT_PROGRESSBAR: + case SID_INSERT_HSCROLLBAR: + case SID_INSERT_VSCROLLBAR: + case SID_INSERT_HFIXEDLINE: + case SID_INSERT_VFIXEDLINE: + case SID_INSERT_DATEFIELD: + case SID_INSERT_TIMEFIELD: + case SID_INSERT_NUMERICFIELD: + case SID_INSERT_CURRENCYFIELD: + case SID_INSERT_FORMATTEDFIELD: + case SID_INSERT_PATTERNFIELD: + case SID_INSERT_FILECONTROL: + case SID_INSERT_SPINBUTTON: + case SID_INSERT_GRIDCONTROL: + case SID_INSERT_HYPERLINKCONTROL: + case SID_INSERT_TREECONTROL: + { + if ( IsReadOnly() ) + rSet.DisableItem( nWh ); + else + rSet.Put( SfxBoolItem( nWh, m_nControlSlotId == nWh ) ); + } + break; + case SID_SHOWLINES: + { + // if this is not a module window hide the + // setting, doesn't make sense for example if the + // dialog editor is open + rSet.DisableItem(nWh); + rSet.Put(SfxVisibilityItem(nWh, false)); + break; + } + case SID_SELECTALL: + { + rSet.DisableItem( nWh ); + } + break; + } + } +} + +void DialogWindow::ExecuteCommand( SfxRequest& rReq ) +{ + const sal_uInt16 nSlotId(rReq.GetSlot()); + SdrObjKind nInsertObj(SdrObjKind::NONE); + + switch ( nSlotId ) + { + case SID_CUT: + if ( !IsReadOnly() ) + { + GetEditor().Cut(); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_DOC_MODIFIED ); + } + break; + case SID_DELETE: + if ( !IsReadOnly() ) + { + GetEditor().Delete(); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_DOC_MODIFIED ); + } + break; + case SID_COPY: + GetEditor().Copy(); + break; + case SID_PASTE: + if ( !IsReadOnly() ) + { + GetEditor().Paste(); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_DOC_MODIFIED ); + } + break; + + case SID_INSERT_FORM_RADIO: + nInsertObj = SdrObjKind::BasicDialogFormRadio; + break; + case SID_INSERT_FORM_CHECK: + nInsertObj = SdrObjKind::BasicDialogFormCheck; + break; + case SID_INSERT_FORM_LIST: + nInsertObj = SdrObjKind::BasicDialogFormList; + break; + case SID_INSERT_FORM_COMBO: + nInsertObj = SdrObjKind::BasicDialogFormCombo; + break; + case SID_INSERT_FORM_SPIN: + nInsertObj = SdrObjKind::BasicDialogFormSpin; + break; + case SID_INSERT_FORM_VSCROLL: + nInsertObj = SdrObjKind::BasicDialogFormVerticalScroll; + break; + case SID_INSERT_FORM_HSCROLL: + nInsertObj = SdrObjKind::BasicDialogFormHorizontalScroll; + break; + case SID_INSERT_PUSHBUTTON: + nInsertObj = SdrObjKind::BasicDialogPushButton; + break; + case SID_INSERT_RADIOBUTTON: + nInsertObj = SdrObjKind::BasicDialogRadioButton; + break; + case SID_INSERT_CHECKBOX: + nInsertObj = SdrObjKind::BasicDialogCheckbox; + break; + case SID_INSERT_LISTBOX: + nInsertObj = SdrObjKind::BasicDialogListbox; + break; + case SID_INSERT_COMBOBOX: + nInsertObj = SdrObjKind::BasicDialogCombobox; + break; + case SID_INSERT_GROUPBOX: + nInsertObj = SdrObjKind::BasicDialogGroupBox; + break; + case SID_INSERT_EDIT: + nInsertObj = SdrObjKind::BasicDialogEdit; + break; + case SID_INSERT_FIXEDTEXT: + nInsertObj = SdrObjKind::BasicDialogFixedText; + break; + case SID_INSERT_IMAGECONTROL: + nInsertObj = SdrObjKind::BasicDialogImageControl; + break; + case SID_INSERT_PROGRESSBAR: + nInsertObj = SdrObjKind::BasicDialogProgressbar; + break; + case SID_INSERT_HSCROLLBAR: + nInsertObj = SdrObjKind::BasicDialogHorizontalScrollbar; + break; + case SID_INSERT_VSCROLLBAR: + nInsertObj = SdrObjKind::BasicDialogVerticalScrollbar; + break; + case SID_INSERT_HFIXEDLINE: + nInsertObj = SdrObjKind::BasicDialogHorizontalFixedLine; + break; + case SID_INSERT_VFIXEDLINE: + nInsertObj = SdrObjKind::BasicDialogVerticalFixedLine; + break; + case SID_INSERT_DATEFIELD: + nInsertObj = SdrObjKind::BasicDialogDateField; + break; + case SID_INSERT_TIMEFIELD: + nInsertObj = SdrObjKind::BasicDialogTimeField; + break; + case SID_INSERT_NUMERICFIELD: + nInsertObj = SdrObjKind::BasicDialogNumericField; + break; + case SID_INSERT_CURRENCYFIELD: + nInsertObj = SdrObjKind::BasicDialogCurencyField; + break; + case SID_INSERT_FORMATTEDFIELD: + nInsertObj = SdrObjKind::BasicDialogFormattedField; + break; + case SID_INSERT_PATTERNFIELD: + nInsertObj = SdrObjKind::BasicDialogPatternField; + break; + case SID_INSERT_FILECONTROL: + nInsertObj = SdrObjKind::BasicDialogFileControl; + break; + case SID_INSERT_SPINBUTTON: + nInsertObj = SdrObjKind::BasicDialogSpinButton; + break; + case SID_INSERT_GRIDCONTROL: + nInsertObj = SdrObjKind::BasicDialogGridControl; + break; + case SID_INSERT_HYPERLINKCONTROL: + nInsertObj = SdrObjKind::BasicDialogHyperlinkControl; + break; + case SID_INSERT_TREECONTROL: + nInsertObj = SdrObjKind::BasicDialogTreeControl; + break; + case SID_INSERT_SELECT: + m_nControlSlotId = nSlotId; + GetEditor().SetMode( DlgEditor::SELECT ); + Shell::InvalidateControlSlots(); + break; + + case SID_DIALOG_TESTMODE: + { + DlgEditor::Mode eOldMode = GetEditor().GetMode(); + GetEditor().SetMode( DlgEditor::TEST ); + GetEditor().SetMode( eOldMode ); + rReq.Done(); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_DIALOG_TESTMODE ); + return; + } + case SID_EXPORT_DIALOG: + SaveDialog(); + break; + + case SID_IMPORT_DIALOG: + ImportDialog(); + break; + + case SID_BASICIDE_DELETECURRENT: + if (QueryDelDialog(m_aName, GetFrameWeld())) + { + if (RemoveDialog(m_aDocument, m_aLibName, m_aName)) + { + MarkDocumentModified(m_aDocument); + GetShell()->RemoveWindow(this, true); + } + } + break; + } + + if ( nInsertObj != SdrObjKind::NONE ) + { + m_nControlSlotId = nSlotId; + GetEditor().SetMode( DlgEditor::INSERT ); + GetEditor().SetInsertObj( nInsertObj ); + + if ( rReq.GetModifier() & KEY_MOD1 ) + { + GetEditor().CreateDefaultObject(); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_DOC_MODIFIED ); + } + + Shell::InvalidateControlSlots(); + } + + rReq.Done(); +} + +Reference< container::XNameContainer > const & DialogWindow::GetDialog() const +{ + return m_pEditor->GetDialog(); +} + +bool DialogWindow::RenameDialog( const OUString& rNewName ) +{ + if (!basctl::RenameDialog(GetFrameWeld(), GetDocument(), GetLibName(), GetName(), rNewName)) + return false; + + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_DOC_MODIFIED ); + + return true; +} + +void DialogWindow::DisableBrowser() +{ + m_rLayout.DisablePropertyBrowser(); +} + +void DialogWindow::UpdateBrowser() +{ + m_rLayout.UpdatePropertyBrowser(); +} + +void DialogWindow::SaveDialog() +{ + sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION, + FileDialogFlags::NONE, this->GetFrameWeld()); + aDlg.SetContext(sfx2::FileDialogHelper::BasicExportDialog); + Reference<XFilePicker3> xFP = aDlg.GetFilePicker(); + + xFP.queryThrow<XFilePickerControlAccess>()->setValue(ExtendedFilePickerElementIds::CHECKBOX_AUTOEXTENSION, 0, Any(true)); + xFP->setDefaultName( GetName() ); + + OUString aDialogStr(IDEResId(RID_STR_STDDIALOGNAME)); + xFP->appendFilter( aDialogStr, "*.xdl" ); + xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All ); + xFP->setCurrentFilter( aDialogStr ); + + if( aDlg.Execute() != ERRCODE_NONE ) + return; + + OUString aSelectedFileURL = xFP->getSelectedFiles()[0]; + + Reference<uno::XComponentContext> xContext(comphelper::getProcessComponentContext()); + Reference< XSimpleFileAccess3 > xSFI( SimpleFileAccess::create(xContext) ); + + Reference< XOutputStream > xOutput; + try + { + if( xSFI->exists(aSelectedFileURL) ) + xSFI->kill(aSelectedFileURL); + xOutput = xSFI->openFileWrite(aSelectedFileURL); + } + catch(const Exception& ) + {} + + if (!xOutput) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_COULDNTWRITE))); + xBox->run(); + return; + } + + // export dialog model to xml + auto xInput(xmlscript::exportDialogModel(GetDialog(), xContext, GetDocument().getDocumentOrNull())->createInputStream()); + + for (Sequence<sal_Int8> bytes; xInput->readBytes(bytes, xInput->available());) + xOutput->writeBytes(bytes); + + // With resource? + Reference< resource::XStringResourceResolver > xStringResourceResolver; + if (auto xDialogModelPropSet = GetDialog().query<beans::XPropertySet>()) + { + try + { + Any aResourceResolver = xDialogModelPropSet->getPropertyValue( "ResourceResolver" ); + aResourceResolver >>= xStringResourceResolver; + } + catch(const beans::UnknownPropertyException& ) + {} + } + + Sequence<lang::Locale> aLocaleSeq; + if (xStringResourceResolver) + aLocaleSeq = xStringResourceResolver->getLocales(); + if (aLocaleSeq.hasElements()) + { + INetURLObject aURLObj(aSelectedFileURL); + aURLObj.removeExtension(); + OUString aDialogName( aURLObj.getName() ); + aURLObj.removeSegment(); + OUString aURL( aURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + OUString aComment = "# " + aDialogName + " strings" ; + Reference< task::XInteractionHandler > xDummyHandler; + + // Remove old properties files in case of overwriting Dialog files + if( xSFI->isFolder( aURL ) ) + { + Sequence< OUString > aContentSeq = xSFI->getFolderContents( aURL, false ); + + OUString aDialogName_ = aDialogName + "_" ; + for( const OUString& rCompleteName : aContentSeq ) + { + OUString aPureName; + OUString aExtension; + sal_Int32 iDot = rCompleteName.lastIndexOf( '.' ); + if( iDot != -1 ) + { + sal_Int32 iSlash = rCompleteName.lastIndexOf( '/' ); + sal_Int32 iCopyFrom = (iSlash != -1) ? iSlash + 1 : 0; + aPureName = rCompleteName.copy( iCopyFrom, iDot-iCopyFrom ); + aExtension = rCompleteName.copy( iDot + 1 ); + } + + if( aExtension == "properties" || aExtension == "default" ) + { + if( aPureName.startsWith( aDialogName_ ) ) + { + try + { + xSFI->kill( rCompleteName ); + } + catch(const uno::Exception& ) + {} + } + } + } + } + + Reference< XStringResourceWithLocation > xStringResourceWithLocation = + StringResourceWithLocation::create( xContext, aURL, false/*bReadOnly*/, + xStringResourceResolver->getDefaultLocale(), aDialogName, aComment, xDummyHandler ); + + // Add locales + for( const lang::Locale& rLocale : aLocaleSeq ) + { + xStringResourceWithLocation->newLocale( rLocale ); + } + + LocalizationMgr::copyResourceForDialog( GetDialog(), + xStringResourceResolver, xStringResourceWithLocation ); + + xStringResourceWithLocation->store(); + } +} + +static std::vector< lang::Locale > implGetLanguagesOnlyContainedInFirstSeq + ( const Sequence< lang::Locale >& aFirstSeq, const Sequence< lang::Locale >& aSecondSeq ) +{ + std::vector< lang::Locale > avRet; + + std::copy_if(aFirstSeq.begin(), aFirstSeq.end(), + std::back_inserter(avRet), + [&aSecondSeq](const lang::Locale& rFirstLocale) { + return std::none_of( + aSecondSeq.begin(), aSecondSeq.end(), + [&rFirstLocale](const lang::Locale& rSecondLocale) { + return localesAreEqual(rFirstLocale, rSecondLocale); + }); + }); + return avRet; +} + +namespace { + +class NameClashQueryBox +{ +private: + std::unique_ptr<weld::MessageDialog> m_xQueryBox; +public: + NameClashQueryBox(weld::Window* pParent, const OUString& rTitle, const OUString& rMessage) + : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Question, VclButtonsType::NONE, rMessage)) + { + if (!rTitle.isEmpty()) + m_xQueryBox->set_title(rTitle); + m_xQueryBox->add_button(IDEResId(RID_STR_DLGIMP_CLASH_RENAME), RET_YES); + m_xQueryBox->add_button(IDEResId(RID_STR_DLGIMP_CLASH_REPLACE), RET_NO); + m_xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); + m_xQueryBox->set_default_response(RET_YES); + } + short run() { return m_xQueryBox->run(); } +}; + +class LanguageMismatchQueryBox +{ +private: + std::unique_ptr<weld::MessageDialog> m_xQueryBox; +public: + LanguageMismatchQueryBox(weld::Window* pParent, const OUString& rTitle, const OUString& rMessage) + : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Question, VclButtonsType::NONE, rMessage)) + { + if (!rTitle.isEmpty()) + m_xQueryBox->set_title(rTitle); + m_xQueryBox->add_button(IDEResId(RID_STR_DLGIMP_MISMATCH_ADD), RET_YES); + m_xQueryBox->add_button(IDEResId(RID_STR_DLGIMP_MISMATCH_OMIT), RET_NO); + m_xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL); + m_xQueryBox->add_button(GetStandardText(StandardButtonType::Help), RET_HELP); + m_xQueryBox->set_default_response(RET_YES); + } + short run() { return m_xQueryBox->run(); } +}; + +} + +bool implImportDialog(weld::Window* pWin, const ScriptDocument& rDocument, const OUString& aLibName) +{ + bool bDone = false; + + Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext()); + sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, + FileDialogFlags::NONE, pWin); + aDlg.SetContext(sfx2::FileDialogHelper::BasicImportDialog); + Reference<XFilePicker3> xFP = aDlg.GetFilePicker(); + + OUString aDialogStr(IDEResId(RID_STR_STDDIALOGNAME)); + xFP->appendFilter( aDialogStr, "*.xdl" ); + xFP->appendFilter( IDEResId(RID_STR_FILTER_ALLFILES), FilterMask_All ); + xFP->setCurrentFilter( aDialogStr ); + + if( aDlg.Execute() == ERRCODE_NONE ) + { + Sequence< OUString > aPaths = xFP->getSelectedFiles(); + + OUString aBasePath; + OUString aOUCurPath( aPaths[0] ); + sal_Int32 iSlash = aOUCurPath.lastIndexOf( '/' ); + if( iSlash != -1 ) + aBasePath = aOUCurPath.copy( 0, iSlash + 1 ); + + try + { + // create dialog model + Reference< container::XNameContainer > xDialogModel( + xContext->getServiceManager()->createInstanceWithContext("com.sun.star.awt.UnoControlDialogModel", xContext), + UNO_QUERY_THROW ); + + Reference< XSimpleFileAccess3 > xSFI( SimpleFileAccess::create(xContext) ); + + Reference< XInputStream > xInput; + if( xSFI->exists( aOUCurPath ) ) + xInput = xSFI->openFileRead( aOUCurPath ); + + ::xmlscript::importDialogModel( xInput, xDialogModel, xContext, rDocument.isDocument() ? rDocument.getDocument() : Reference< frame::XModel >() ); + + OUString aXmlDlgName; + Reference< beans::XPropertySet > xDialogModelPropSet( xDialogModel, UNO_QUERY ); + assert(xDialogModelPropSet.is()); + try + { + Any aXmlDialogNameAny = xDialogModelPropSet->getPropertyValue( DLGED_PROP_NAME ); + aXmlDialogNameAny >>= aXmlDlgName; + } + catch(const beans::UnknownPropertyException& ) + { + TOOLS_WARN_EXCEPTION("basctl", ""); + } + assert( !aXmlDlgName.isEmpty() ); + + bool bDialogAlreadyExists = rDocument.hasDialog( aLibName, aXmlDlgName ); + + OUString aNewDlgName = aXmlDlgName; + enum NameClashMode + { + NO_CLASH, + CLASH_OVERWRITE_DIALOG, + CLASH_RENAME_DIALOG, + }; + NameClashMode eNameClashMode = NO_CLASH; + if( bDialogAlreadyExists ) + { + OUString aQueryBoxTitle(IDEResId(RID_STR_DLGIMP_CLASH_TITLE)); + OUString aQueryBoxText(IDEResId(RID_STR_DLGIMP_CLASH_TEXT)); + aQueryBoxText = aQueryBoxText.replaceAll("$(ARG1)", aXmlDlgName); + + NameClashQueryBox aQueryBox(pWin, aQueryBoxTitle, aQueryBoxText); + sal_uInt16 nRet = aQueryBox.run(); + if( nRet == RET_YES ) + { + // RET_YES == Rename, see NameClashQueryBox::NameClashQueryBox + eNameClashMode = CLASH_RENAME_DIALOG; + + aNewDlgName = rDocument.createObjectName( E_DIALOGS, aLibName ); + } + else if( nRet == RET_NO ) + { + // RET_NO == Replace, see NameClashQueryBox::NameClashQueryBox + eNameClashMode = CLASH_OVERWRITE_DIALOG; + } + else if( nRet == RET_CANCEL ) + { + return bDone; + } + } + + Shell* pShell = GetShell(); + assert(pShell); + + // Resource? + css::lang::Locale aLocale = Application::GetSettings().GetUILanguageTag().getLocale(); + Reference< task::XInteractionHandler > xDummyHandler; + Reference< XStringResourceWithLocation > xImportStringResource = + StringResourceWithLocation::create( xContext, aBasePath, true/*bReadOnly*/, + aLocale, aXmlDlgName, OUString(), xDummyHandler ); + + Sequence< lang::Locale > aImportLocaleSeq = xImportStringResource->getLocales(); + sal_Int32 nImportLocaleCount = aImportLocaleSeq.getLength(); + + Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) ); + Reference< resource::XStringResourceManager > xLibStringResourceManager = LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + sal_Int32 nLibLocaleCount = 0; + Sequence< lang::Locale > aLibLocaleSeq; + if( xLibStringResourceManager.is() ) + { + aLibLocaleSeq = xLibStringResourceManager->getLocales(); + nLibLocaleCount = aLibLocaleSeq.getLength(); + } + + // Check language matches + std::vector< lang::Locale > aOnlyInImportLanguages = + implGetLanguagesOnlyContainedInFirstSeq( aImportLocaleSeq, aLibLocaleSeq ); + int nOnlyInImportLanguageCount = aOnlyInImportLanguages.size(); + + // For now: Keep languages from lib + bool bLibLocalized = (nLibLocaleCount > 0); + bool bImportLocalized = (nImportLocaleCount > 0); + + bool bAddDialogLanguagesToLib = false; + if( nOnlyInImportLanguageCount > 0 ) + { + OUString aQueryBoxTitle(IDEResId(RID_STR_DLGIMP_MISMATCH_TITLE)); + OUString aQueryBoxText(IDEResId(RID_STR_DLGIMP_MISMATCH_TEXT)); + LanguageMismatchQueryBox aQueryBox(pWin, aQueryBoxTitle, aQueryBoxText); + sal_uInt16 nRet = aQueryBox.run(); + if( nRet == RET_YES ) + { + // RET_YES == Add, see LanguageMismatchQueryBox::LanguageMismatchQueryBox + bAddDialogLanguagesToLib = true; + } + // RET_NO == Omit, see LanguageMismatchQueryBox::LanguageMismatchQueryBox + // -> nothing to do here + //else if( RET_NO == nRet ) + //{ + //} + else if( nRet == RET_CANCEL ) + { + return bDone; + } + } + + if( bImportLocalized ) + { + bool bCopyResourcesForDialog = true; + if( bAddDialogLanguagesToLib ) + { + const std::shared_ptr<LocalizationMgr>& pCurMgr = pShell->GetCurLocalizationMgr(); + + lang::Locale aFirstLocale = aOnlyInImportLanguages[0]; + if( nOnlyInImportLanguageCount > 1 ) + { + // Check if import default belongs to only import languages and use it then + lang::Locale aImportDefaultLocale = xImportStringResource->getDefaultLocale(); + + if (std::any_of(aOnlyInImportLanguages.begin(), aOnlyInImportLanguages.end(), + [&aImportDefaultLocale](const lang::Locale& aTmpLocale) { + return localesAreEqual(aImportDefaultLocale, aTmpLocale); + })) + { + aFirstLocale = aImportDefaultLocale; + } + } + + pCurMgr->handleAddLocales( {aFirstLocale} ); + + if( nOnlyInImportLanguageCount > 1 ) + { + Sequence< lang::Locale > aRemainingLocaleSeq( nOnlyInImportLanguageCount - 1 ); + auto pRemainingLocaleSeq = aRemainingLocaleSeq.getArray(); + int iSeq = 0; + for( const lang::Locale& rLocale : aOnlyInImportLanguages ) + { + if( !localesAreEqual( aFirstLocale, rLocale ) ) + pRemainingLocaleSeq[iSeq++] = rLocale; + } + pCurMgr->handleAddLocales( aRemainingLocaleSeq ); + } + } + else if( !bLibLocalized ) + { + LocalizationMgr::resetResourceForDialog( xDialogModel, xImportStringResource ); + bCopyResourcesForDialog = false; + } + + if( bCopyResourcesForDialog ) + { + LocalizationMgr::copyResourceForDroppedDialog( xDialogModel, aXmlDlgName, + xLibStringResourceManager, xImportStringResource ); + } + } + else if( bLibLocalized ) + { + LocalizationMgr::setResourceIDsForDialog( xDialogModel, xLibStringResourceManager ); + } + + + LocalizationMgr::setStringResourceAtDialog( rDocument, aLibName, aNewDlgName, xDialogModel ); + + if( eNameClashMode == CLASH_OVERWRITE_DIALOG ) + { + if (basctl::RemoveDialog( rDocument, aLibName, aNewDlgName ) ) + { + BaseWindow* pDlgWin = pShell->FindDlgWin( rDocument, aLibName, aNewDlgName, false, true ); + if( pDlgWin != nullptr ) + pShell->RemoveWindow( pDlgWin, false ); + MarkDocumentModified( rDocument ); + } + else + { + // TODO: Assertion? + return bDone; + } + } + + if( eNameClashMode == CLASH_RENAME_DIALOG ) + { + bool bRenamed = false; + if( xDialogModelPropSet.is() ) + { + try + { + xDialogModelPropSet->setPropertyValue( DLGED_PROP_NAME, Any(aNewDlgName) ); + bRenamed = true; + } + catch(const beans::UnknownPropertyException& ) + {} + } + + + if( bRenamed ) + { + LocalizationMgr::renameStringResourceIDs( rDocument, aLibName, aNewDlgName, xDialogModel ); + } + else + { + // TODO: Assertion? + return bDone; + } + } + + Reference< XInputStreamProvider > xISP = ::xmlscript::exportDialogModel( xDialogModel, xContext, rDocument.isDocument() ? rDocument.getDocument() : Reference< frame::XModel >() ); + bool bSuccess = rDocument.insertDialog( aLibName, aNewDlgName, xISP ); + if( bSuccess ) + { + VclPtr<DialogWindow> pNewDlgWin = pShell->CreateDlgWin( rDocument, aLibName, aNewDlgName ); + pShell->SetCurWindow( pNewDlgWin, true ); + } + + bDone = true; + } + catch(const Exception& ) + {} + } + + return bDone; +} + +void DialogWindow::ImportDialog() +{ + const ScriptDocument& rDocument = GetDocument(); + OUString aLibName = GetLibName(); + implImportDialog(GetFrameWeld(), rDocument, aLibName); +} + +DlgEdModel& DialogWindow::GetModel() const +{ + return m_pEditor->GetModel(); +} + +DlgEdPage& DialogWindow::GetPage() const +{ + return m_pEditor->GetPage(); +} + +DlgEdView& DialogWindow::GetView() const +{ + return m_pEditor->GetView(); +} + +bool DialogWindow::IsModified() +{ + return m_pEditor->IsModified(); +} + +SfxUndoManager* DialogWindow::GetUndoManager() +{ + return m_pUndoMgr.get(); +} + +OUString DialogWindow::GetTitle() +{ + return GetName(); +} + +EntryDescriptor DialogWindow::CreateEntryDescriptor() +{ + ScriptDocument aDocument( GetDocument() ); + OUString aLibName( GetLibName() ); + LibraryLocation eLocation = aDocument.getLibraryLocation( aLibName ); + return EntryDescriptor( aDocument, eLocation, aLibName, OUString(), GetName(), OBJ_TYPE_DIALOG ); +} + +void DialogWindow::SetReadOnly (bool bReadOnly) +{ + m_pEditor->SetMode(bReadOnly ? DlgEditor::READONLY : DlgEditor::SELECT); +} + +bool DialogWindow::IsReadOnly () +{ + return m_pEditor->GetMode() == DlgEditor::READONLY; +} + +bool DialogWindow::IsPasteAllowed() +{ + return m_pEditor->IsPasteAllowed(); +} + +void DialogWindow::StoreData() +{ + if ( !IsModified() ) + return; + + try + { + Reference< container::XNameContainer > xLib = GetDocument().getLibrary( E_DIALOGS, GetLibName(), true ); + + if( xLib.is() ) + { + Reference< container::XNameContainer > xDialogModel = m_pEditor->GetDialog(); + + if( xDialogModel.is() ) + { + Reference< XComponentContext > xContext( + comphelper::getProcessComponentContext() ); + Reference< XInputStreamProvider > xISP = ::xmlscript::exportDialogModel( xDialogModel, xContext, GetDocument().isDocument() ? GetDocument().getDocument() : Reference< frame::XModel >() ); + xLib->replaceByName( GetName(), Any( xISP ) ); + } + } + } + catch (const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + MarkDocumentModified( GetDocument() ); + m_pEditor->ClearModifyFlag(); +} + +void DialogWindow::Activating () +{ + UpdateBrowser(); + Show(); +} + +void DialogWindow::Deactivating() +{ + Hide(); + if ( IsModified() ) + MarkDocumentModified( GetDocument() ); + DisableBrowser(); +} + +sal_Int32 DialogWindow::countPages( Printer* ) +{ + return 1; +} + +void DialogWindow::printPage( sal_Int32 nPage, Printer* pPrinter ) +{ + DlgEditor::printPage( nPage, pPrinter, CreateQualifiedName() ); +} + +void DialogWindow::DataChanged( const DataChangedEvent& rDCEvt ) +{ + if( (rDCEvt.GetType()==DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) ) + { + InitSettings(); + Invalidate(); + } + else + BaseWindow::DataChanged( rDCEvt ); +} + +void DialogWindow::InitSettings() +{ + // FIXME RenderContext + const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); + vcl::Font aFont = rStyleSettings.GetFieldFont(); + SetPointFont(*GetOutDev(), aFont); + + SetTextColor( rStyleSettings.GetFieldTextColor() ); + SetTextFillColor(); + + SetBackground(rStyleSettings.GetFaceColor()); +} + +css::uno::Reference< css::accessibility::XAccessible > DialogWindow::CreateAccessible() +{ + return new AccessibleDialogWindow(this); +} + +OUString DialogWindow::GetHid () const +{ + return HID_BASICIDE_DIALOGWINDOW; +} + +ItemType DialogWindow::GetType () const +{ + return TYPE_DIALOG; +} + + +// DialogWindowLayout + + +DialogWindowLayout::DialogWindowLayout (vcl::Window* pParent, ObjectCatalog& rObjectCatalog_) : + Layout(pParent), + rObjectCatalog(rObjectCatalog_), + pPropertyBrowser(nullptr) +{ + ShowPropertyBrowser(); +} + +DialogWindowLayout::~DialogWindowLayout() +{ + disposeOnce(); +} + +void DialogWindowLayout::dispose() +{ + if (pPropertyBrowser) + Remove(pPropertyBrowser); + pPropertyBrowser.disposeAndClear(); + Layout::dispose(); +} + +// shows the property browser (and creates if necessary) +void DialogWindowLayout::ShowPropertyBrowser () +{ + // not exists? + if (!pPropertyBrowser) + { + // creating + pPropertyBrowser = VclPtr<PropBrw>::Create(*this); + pPropertyBrowser->Show(); + // after OnFirstSize(): + if (HasSize()) + AddPropertyBrowser(); + // updating if necessary + UpdatePropertyBrowser(); + } + else + pPropertyBrowser->Show(); + // refreshing the button state + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate(SID_SHOW_PROPERTYBROWSER); +} + +// disables the property browser +void DialogWindowLayout::DisablePropertyBrowser () +{ + if (pPropertyBrowser) + pPropertyBrowser->Update(nullptr); +} + +// updates the property browser +void DialogWindowLayout::UpdatePropertyBrowser () +{ + if (pPropertyBrowser) + pPropertyBrowser->Update(GetShell()); +} + +void DialogWindowLayout::Activating (BaseWindow& rChild) +{ + assert(dynamic_cast<DialogWindow*>(&rChild)); + rObjectCatalog.SetLayoutWindow(this); + rObjectCatalog.UpdateEntries(); + rObjectCatalog.Show(); + if (pPropertyBrowser) + pPropertyBrowser->Show(); + Layout::Activating(rChild); +} + +void DialogWindowLayout::Deactivating () +{ + Layout::Deactivating(); + rObjectCatalog.Hide(); + if (pPropertyBrowser) + pPropertyBrowser->Hide(); +} + +void DialogWindowLayout::ExecuteGlobal (SfxRequest& rReq) +{ + switch (rReq.GetSlot()) + { + case SID_SHOW_PROPERTYBROWSER: + // toggling property browser + if (pPropertyBrowser && pPropertyBrowser->IsVisible()) + pPropertyBrowser->Hide(); + else + ShowPropertyBrowser(); + ArrangeWindows(); + // refreshing the button state + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate(SID_SHOW_PROPERTYBROWSER); + break; + } +} + +void DialogWindowLayout::GetState (SfxItemSet& rSet, unsigned nWhich) +{ + switch (nWhich) + { + case SID_SHOW_PROPERTYBROWSER: + rSet.Put(SfxBoolItem(nWhich, pPropertyBrowser && pPropertyBrowser->IsVisible())); + break; + + case SID_BASICIDE_CHOOSEMACRO: + rSet.Put(SfxVisibilityItem(nWhich, false)); + break; + } +} + +void DialogWindowLayout::OnFirstSize (tools::Long const nWidth, tools::Long const nHeight) +{ + AddToLeft(&rObjectCatalog, Size(nWidth * 0.25, nHeight * 0.35)); + if (pPropertyBrowser) + AddPropertyBrowser(); +} + +void DialogWindowLayout::AddPropertyBrowser () { + Size const aSize = GetOutputSizePixel(); + AddToLeft(pPropertyBrowser, Size(aSize.Width() * 0.25, aSize.Height() * 0.65)); +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basidectrlr.cxx b/basctl/source/basicide/basidectrlr.cxx new file mode 100644 index 0000000000..849bff30cb --- /dev/null +++ b/basctl/source/basicide/basidectrlr.cxx @@ -0,0 +1,113 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <basidectrlr.hxx> +#include <basidesh.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> + +namespace basctl +{ + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::beans; + +namespace +{ + +int const nPropertyIconId = 1; +constexpr OUStringLiteral sPropertyIconId(u"IconId"); + +} + +Controller::Controller (Shell* pViewShell) + :OPropertyContainer( m_aBHelper ) + ,SfxBaseController( pViewShell ) + ,m_nIconId( ICON_MACROLIBRARY ) +{ + registerProperty( + sPropertyIconId, nPropertyIconId, + PropertyAttribute::READONLY, + &m_nIconId, cppu::UnoType<decltype(m_nIconId)>::get() + ); +} + +Controller::~Controller() +{ } + +// XInterface +Any SAL_CALL Controller::queryInterface( const Type & rType ) +{ + Any aReturn = SfxBaseController::queryInterface( rType ); + if ( !aReturn.hasValue() ) + aReturn = OPropertyContainer::queryInterface( rType ); + + return aReturn; +} + +void SAL_CALL Controller::acquire() noexcept +{ + SfxBaseController::acquire(); +} + +void SAL_CALL Controller::release() noexcept +{ + SfxBaseController::release(); +} + +// XTypeProvider ( ::SfxBaseController ) +Sequence< Type > SAL_CALL Controller::getTypes() +{ + Sequence< Type > aTypes = ::comphelper::concatSequences( + SfxBaseController::getTypes(), + getBaseTypes() + ); + + return aTypes; +} + +Sequence< sal_Int8 > SAL_CALL Controller::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + +// XPropertySet +Reference< beans::XPropertySetInfo > SAL_CALL Controller::getPropertySetInfo() +{ + Reference< beans::XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +// OPropertySetHelper +::cppu::IPropertyArrayHelper& Controller::getInfoHelper() +{ + return *getArrayHelper(); +} + +// OPropertyArrayUsageHelper +::cppu::IPropertyArrayHelper* Controller::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties( aProps ); + return new ::cppu::OPropertyArrayHelper( aProps ); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basides1.cxx b/basctl/source/basicide/basides1.cxx new file mode 100644 index 0000000000..9ef9f75e3f --- /dev/null +++ b/basctl/source/basicide/basides1.cxx @@ -0,0 +1,1551 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <iderid.hxx> +#include <strings.hrc> +#include <helpids.h> + +#include "baside2.hxx" +#include <baside3.hxx> +#include <basidesh.hxx> +#include <basobj.hxx> +#include <docsignature.hxx> +#include <iderdll.hxx> +#include "iderdll2.hxx" +#include <localizationmgr.hxx> +#include <managelang.hxx> + +#include <basic/basmgr.hxx> +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <com/sun/star/script/XLibraryContainer2.hpp> +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <svl/srchdefs.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <sfx2/app.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/childwin.hxx> +#include <sfx2/dinfdlg.hxx> +#include <sfx2/minfitem.hxx> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <svx/svxids.hrc> +#include <svl/eitem.hxx> +#include <svl/intitem.hxx> +#include <svl/visitem.hxx> +#include <svl/whiter.hxx> +#include <vcl/texteng.hxx> +#include <vcl/textview.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <svx/zoomsliderctrl.hxx> +#include <svx/zoomslideritem.hxx> +#include <basegfx/utils/zoomtools.hxx> + +constexpr sal_Int32 TAB_HEIGHT_MARGIN = 10; + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::frame; + +static void lcl_InvalidateZoomSlots(SfxBindings* pBindings) +{ + if (!pBindings) + return; + + static sal_uInt16 const aInval[] = { + SID_ZOOM_OUT, SID_ZOOM_IN, SID_ATTR_ZOOMSLIDER, 0 + }; + pBindings->Invalidate(aInval); +} + +void Shell::ExecuteSearch( SfxRequest& rReq ) +{ + if ( !pCurWin ) + return; + + const SfxItemSet* pArgs = rReq.GetArgs(); + sal_uInt16 nSlot = rReq.GetSlot(); + + // if searching has not been done before this time + if (nSlot == SID_BASICIDE_REPEAT_SEARCH && !mpSearchItem) + { + rReq.SetReturnValue(SfxBoolItem(nSlot, false)); + nSlot = 0; + } + + switch ( nSlot ) + { + case SID_SEARCH_OPTIONS: + break; + case SID_SEARCH_ITEM: + mpSearchItem.reset(pArgs->Get(SID_SEARCH_ITEM).Clone()); + break; + case FID_SEARCH_ON: + mbJustOpened = true; + GetViewFrame().GetBindings().Invalidate(SID_SEARCH_ITEM); + break; + case SID_BASICIDE_REPEAT_SEARCH: + case FID_SEARCH_NOW: + { + if (!pCurWin->HasActiveEditor()) + break; + + // If it is a repeat searching + if ( nSlot == SID_BASICIDE_REPEAT_SEARCH ) + { + if( !mpSearchItem ) + mpSearchItem.reset( new SvxSearchItem( SID_SEARCH_ITEM )); + } + else + { + // Get SearchItem from request if it is the first searching + if ( pArgs ) + { + mpSearchItem.reset(pArgs->Get(SID_SEARCH_ITEM).Clone()); + } + } + + sal_Int32 nFound = 0; + + if ( mpSearchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL ) + { + sal_uInt16 nActModWindows = 0; + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + if (pWin->HasActiveEditor()) + nActModWindows++; + } + + bool bAllModules = nActModWindows <= 1; + if (!bAllModules) + { + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pCurWin ? pCurWin->GetFrameWeld() : nullptr, + VclMessageType::Question, VclButtonsType::YesNo, + IDEResId(RID_STR_SEARCHALLMODULES))); + xQueryBox->set_default_response(RET_YES); + bAllModules = xQueryBox->run() == RET_YES; + } + + if (bAllModules) + { + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + nFound += pWin->StartSearchAndReplace( *mpSearchItem ); + } + } + else + nFound = pCurWin->StartSearchAndReplace( *mpSearchItem ); + + OUString aReplStr(IDEResId(RID_STR_SEARCHREPLACES)); + aReplStr = aReplStr.replaceAll("XX", OUString::number(nFound)); + + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pCurWin->GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + aReplStr)); + xInfoBox->run(); + } + else + { + bool bCanceled = false; + nFound = pCurWin->StartSearchAndReplace( *mpSearchItem ); + if ( !nFound && !mpSearchItem->GetSelection() ) + { + // search other modules... + bool bChangeCurWindow = false; + auto it = std::find_if(aWindowTable.cbegin(), aWindowTable.cend(), + [this](const WindowTable::value_type& item) { return item.second == pCurWin; }); + if (it != aWindowTable.cend()) + ++it; + BaseWindow* pWin = it != aWindowTable.cend() ? it->second.get() : nullptr; + + bool bSearchedFromStart = false; + while ( !nFound && !bCanceled && ( pWin || !bSearchedFromStart ) ) + { + if ( !pWin ) + { + SfxViewFrame& rViewFrame = GetViewFrame(); + SfxChildWindow* pChildWin = rViewFrame.GetChildWindow(SID_SEARCH_DLG); + auto xParent = pChildWin ? pChildWin->GetController() : nullptr; + + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(xParent ? xParent->getDialog() : nullptr, + VclMessageType::Question, VclButtonsType::YesNo, + IDEResId(RID_STR_SEARCHFROMSTART))); + xQueryBox->set_default_response(RET_YES); + if (xQueryBox->run() == RET_YES) + { + it = aWindowTable.cbegin(); + if ( it != aWindowTable.cend() ) + pWin = it->second; + bSearchedFromStart = true; + } + else + bCanceled = true; + } + + if (pWin && pWin->HasActiveEditor()) + { + if ( pWin != pCurWin ) + { + if ( pCurWin ) + pWin->SetSizePixel( pCurWin->GetSizePixel() ); + nFound = pWin->StartSearchAndReplace( *mpSearchItem, true ); + } + if ( nFound ) + { + bChangeCurWindow = true; + break; + } + } + if ( pWin && ( pWin != pCurWin ) ) + { + if ( it != aWindowTable.cend() ) + ++it; + pWin = it != aWindowTable.cend() ? it->second.get() : nullptr; + } + else + pWin = nullptr; + } + if ( !nFound && bSearchedFromStart ) + nFound = pCurWin->StartSearchAndReplace( *mpSearchItem, true ); + if ( bChangeCurWindow ) + SetCurWindow( pWin, true ); + } + if ( !nFound && !bCanceled ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pCurWin->GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + IDEResId(RID_STR_SEARCHNOTFOUND))); + xInfoBox->run(); + } + } + + rReq.Done(); + break; + } + default: + pCurWin->ExecuteCommand( rReq ); + } +} + +void Shell::ExecuteCurrent( SfxRequest& rReq ) +{ + if ( !pCurWin ) + return; + + switch ( rReq.GetSlot() ) + { + case SID_BASICIDE_HIDECURPAGE: + { + pCurWin->StoreData(); + RemoveWindow( pCurWin, false ); + } + break; + case SID_BASICIDE_RENAMECURRENT: + { + pTabBar->StartEditMode( pTabBar->GetCurPageId() ); + } + break; + case SID_UNDO: + case SID_REDO: + if ( GetUndoManager() && pCurWin->AllowUndo() ) + GetViewFrame().ExecuteSlot( rReq ); + break; + default: + pCurWin->ExecuteCommand( rReq ); + } +} + +// no matter who's at the top, influence on the shell: +void Shell::ExecuteGlobal( SfxRequest& rReq ) +{ + sal_uInt16 nSlot = rReq.GetSlot(); + switch ( nSlot ) + { + case SID_NEWDOCDIRECT: + { + // we do not have a new document factory, + // so just forward to a fallback method. + SfxGetpApp()->ExecuteSlot(rReq); + } + break; + + case SID_BASICSTOP: + { + // maybe do not simply stop if on breakpoint! + if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get())) + pMCurWin->BasicStop(); + StopBasic(); + } + break; + + case SID_SAVEDOC: + { + if ( pCurWin ) + { + // rewrite date into the BASIC + StoreAllWindowData(); + + // document basic + ScriptDocument aDocument( pCurWin->GetDocument() ); + if ( aDocument.isDocument() ) + { + uno::Reference< task::XStatusIndicator > xStatusIndicator; + + const SfxUnoAnyItem* pStatusIndicatorItem = rReq.GetArg<SfxUnoAnyItem>(SID_PROGRESS_STATUSBAR_CONTROL); + if ( pStatusIndicatorItem ) + OSL_VERIFY( pStatusIndicatorItem->GetValue() >>= xStatusIndicator ); + else + { + // get statusindicator + SfxViewFrame *pFrame_ = GetFrame(); + if ( pFrame_ ) + { + uno::Reference< task::XStatusIndicatorFactory > xStatFactory( + pFrame_->GetFrame().GetFrameInterface(), + uno::UNO_QUERY ); + if( xStatFactory.is() ) + xStatusIndicator = xStatFactory->createStatusIndicator(); + } + + if ( xStatusIndicator.is() ) + rReq.AppendItem( SfxUnoAnyItem( SID_PROGRESS_STATUSBAR_CONTROL, uno::Any( xStatusIndicator ) ) ); + } + + aDocument.saveDocument( xStatusIndicator ); + } + + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_DOC_MODIFIED ); + pBindings->Invalidate( SID_SAVEDOC ); + pBindings->Invalidate( SID_SIGNATURE ); + } + } + } + break; + case SID_BASICIDE_MODULEDLG: + { + if ( rReq.GetArgs() ) + { + const SfxUInt16Item &rTabId = rReq.GetArgs()->Get(SID_BASICIDE_ARG_TABID ); + Organize(rReq.GetFrameWeld(), nullptr, rTabId.GetValue()); + } + else + Organize(rReq.GetFrameWeld(), nullptr, 0); + } + break; + case SID_BASICIDE_CHOOSEMACRO: + { + ChooseMacro(rReq.GetFrameWeld(), nullptr); + } + break; + case SID_BASICIDE_CREATEMACRO: + case SID_BASICIDE_EDITMACRO: + { + DBG_ASSERT( rReq.GetArgs(), "arguments expected" ); + const SfxMacroInfoItem& rInfo = rReq.GetArgs()->Get(SID_BASICIDE_ARG_MACROINFO ); + BasicManager* pBasMgr = const_cast<BasicManager*>(rInfo.GetBasicManager()); + DBG_ASSERT( pBasMgr, "Nothing selected in basic tree?" ); + + ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) ); + + StartListening(*pBasMgr, DuplicateHandling::Prevent /* log on only once */); + OUString aLibName( rInfo.GetLib() ); + if ( aLibName.isEmpty() ) + aLibName = "Standard" ; + StarBASIC* pBasic = pBasMgr->GetLib( aLibName ); + if ( !pBasic ) + { + // load module and dialog library (if not loaded) + aDocument.loadLibraryIfExists( E_SCRIPTS, aLibName ); + aDocument.loadLibraryIfExists( E_DIALOGS, aLibName ); + + // get Basic + pBasic = pBasMgr->GetLib( aLibName ); + } + DBG_ASSERT( pBasic, "No Basic!" ); + + SetCurLib( aDocument, aLibName ); + + if ( pBasic && rReq.GetSlot() == SID_BASICIDE_CREATEMACRO ) + { + SbModule* pModule = pBasic->FindModule( rInfo.GetModule() ); + if ( !pModule ) + { + if ( !rInfo.GetModule().isEmpty() || pBasic->GetModules().empty() ) + { + const OUString& aModName = rInfo.GetModule(); + + OUString sModuleCode; + if ( aDocument.createModule( aLibName, aModName, false, sModuleCode ) ) + pModule = pBasic->FindModule( aModName ); + } + else + pModule = pBasic->GetModules().front().get(); + } + DBG_ASSERT( pModule, "No Module!" ); + if ( pModule && !pModule->GetMethods()->Find( rInfo.GetMethod(), SbxClassType::Method ) ) + CreateMacro( pModule, rInfo.GetMethod() ); + } + SfxViewFrame& rViewFrame = GetViewFrame(); + rViewFrame.ToTop(); + VclPtr<ModulWindow> pWin = FindBasWin( aDocument, aLibName, rInfo.GetModule(), true ); + DBG_ASSERT( pWin, "Edit/Create Macro: Window was not created/found!" ); + SetCurWindow( pWin, true ); + pWin->EditMacro( rInfo.GetMethod() ); + } + break; + + case SID_BASICIDE_OBJCAT: + // toggling object catalog + aObjectCatalog->Show(!aObjectCatalog->IsVisible()); + if (pLayout) + pLayout->ArrangeWindows(); + // refresh the button state + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate(SID_BASICIDE_OBJCAT); + break; + + case SID_BASICIDE_WATCH: + { + // Toggling the watch window can only be done from a ModulWindow + if (!dynamic_cast<ModulWindowLayout*>(pLayout.get())) + return; + + pModulLayout->ShowWatchWindow(!pModulLayout->IsWatchWindowVisible()); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate(SID_BASICIDE_WATCH); + } + break; + + case SID_BASICIDE_STACK: + { + // Toggling the stack window can only be done from a ModulWindow + if (!dynamic_cast<ModulWindowLayout*>(pLayout.get())) + return; + + pModulLayout->ShowStackWindow(!pModulLayout->IsStackWindowVisible()); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate(SID_BASICIDE_STACK); + } + break; + + case SID_BASICIDE_NAMECHANGEDONTAB: + { + DBG_ASSERT( rReq.GetArgs(), "arguments expected" ); + const SfxUInt16Item &rTabId = rReq.GetArgs()->Get(SID_BASICIDE_ARG_TABID ); + const SfxStringItem &rModName = rReq.GetArgs()->Get(SID_BASICIDE_ARG_MODULENAME ); + if ( aWindowTable.find( rTabId.GetValue() ) != aWindowTable.end() ) + { + VclPtr<BaseWindow> pWin = aWindowTable[ rTabId.GetValue() ]; + const OUString& aNewName( rModName.GetValue() ); + OUString aOldName( pWin->GetName() ); + if ( aNewName != aOldName ) + { + bool bRenameOk = false; + if (ModulWindow* pModWin = dynamic_cast<ModulWindow*>(pWin.get())) + { + const OUString& aLibName = pModWin->GetLibName(); + ScriptDocument aDocument( pWin->GetDocument() ); + + if (RenameModule(pModWin->GetFrameWeld(), aDocument, aLibName, aOldName, aNewName)) + { + bRenameOk = true; + // Because we listen for container events for script + // modules, rename will delete the 'old' window + // pWin has been invalidated, restore now + pWin = FindBasWin( aDocument, aLibName, aNewName, true ); + } + + } + else if (DialogWindow* pDlgWin = dynamic_cast<DialogWindow*>(pWin.get())) + { + bRenameOk = pDlgWin->RenameDialog( aNewName ); + } + if ( bRenameOk ) + { + MarkDocumentModified( pWin->GetDocument() ); + } + else + { + // set old name in TabWriter + sal_uInt16 nId = GetWindowId( pWin ); + DBG_ASSERT( nId, "No entry in Tabbar!" ); + if ( nId ) + pTabBar->SetPageText( nId, aOldName ); + } + } + + // set focus to current window + pWin->GrabFocus(); + } + } + break; + case SID_BASICIDE_STOREMODULESOURCE: + case SID_BASICIDE_UPDATEMODULESOURCE: + { + DBG_ASSERT( rReq.GetArgs(), "arguments expected" ); + const SfxMacroInfoItem& rInfo = rReq.GetArgs()->Get(SID_BASICIDE_ARG_MACROINFO ); + BasicManager* pBasMgr = const_cast<BasicManager*>(rInfo.GetBasicManager()); + DBG_ASSERT( pBasMgr, "Store source: No BasMgr?" ); + ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) ); + VclPtr<ModulWindow> pWin = FindBasWin( aDocument, rInfo.GetLib(), rInfo.GetModule(), false, true ); + if ( pWin ) + { + if ( rReq.GetSlot() == SID_BASICIDE_STOREMODULESOURCE ) + pWin->StoreData(); + else + pWin->UpdateData(); + } + } + break; + case SID_BASICIDE_STOREALLMODULESOURCES: + case SID_BASICIDE_UPDATEALLMODULESOURCES: + { + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + if (!pWin->IsSuspended() && dynamic_cast<ModulWindow*>(pWin)) + { + if ( rReq.GetSlot() == SID_BASICIDE_STOREALLMODULESOURCES ) + pWin->StoreData(); + else + pWin->UpdateData(); + } + } + } + break; + case SID_BASICIDE_LIBSELECTED: + case SID_BASICIDE_LIBREMOVED: + case SID_BASICIDE_LIBLOADED: + { + DBG_ASSERT( rReq.GetArgs(), "arguments expected" ); + const SfxUnoAnyItem& rShellItem = rReq.GetArgs()->Get( SID_BASICIDE_ARG_DOCUMENT_MODEL ); + uno::Reference< frame::XModel > xModel( rShellItem.GetValue(), UNO_QUERY ); + ScriptDocument aDocument( xModel.is() ? ScriptDocument( xModel ) : ScriptDocument::getApplicationScriptDocument() ); + const SfxStringItem& rLibNameItem = rReq.GetArgs()->Get( SID_BASICIDE_ARG_LIBNAME ); + const OUString& aLibName( rLibNameItem.GetValue() ); + + if ( nSlot == SID_BASICIDE_LIBSELECTED ) + { + // load module and dialog library (if not loaded) + aDocument.loadLibraryIfExists( E_SCRIPTS, aLibName ); + aDocument.loadLibraryIfExists( E_DIALOGS, aLibName ); + + // check password, if library is password protected and not verified + bool bOK = true; + Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) ) + { + OUString aPassword; + bOK = QueryPassword(rReq.GetFrameWeld(), xModLibContainer, aLibName, aPassword); + } + } + + if ( bOK ) + { + SetCurLib( aDocument, aLibName, true, false ); + } + else + { + // adjust old value... + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate(SID_BASICIDE_LIBSELECTOR, true); + } + } + else if ( nSlot == SID_BASICIDE_LIBREMOVED ) + { + if ( m_aCurLibName.isEmpty() || ( aDocument == m_aCurDocument && aLibName == m_aCurLibName ) ) + { + RemoveWindows( aDocument, aLibName ); + if ( aDocument == m_aCurDocument && aLibName == m_aCurLibName ) + { + m_aCurDocument = ScriptDocument::getApplicationScriptDocument(); + m_aCurLibName.clear(); + // no UpdateWindows! + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_BASICIDE_LIBSELECTOR ); + } + } + } + else // Loaded... + UpdateWindows(); + } + break; + case SID_BASICIDE_NEWMODULE: + { + VclPtr<ModulWindow> pWin = CreateBasWin( m_aCurDocument, m_aCurLibName, OUString() ); + DBG_ASSERT( pWin, "New Module: Could not create window!" ); + SetCurWindow( pWin, true ); + } + break; + case SID_BASICIDE_NEWDIALOG: + { + VclPtr<DialogWindow> pWin = CreateDlgWin( m_aCurDocument, m_aCurLibName, OUString() ); + DBG_ASSERT( pWin, "New Module: Could not create window!" ); + SetCurWindow( pWin, true ); + } + break; + case SID_BASICIDE_SBXRENAMED: + { + DBG_ASSERT( rReq.GetArgs(), "arguments expected" ); + } + break; + case SID_BASICIDE_SBXINSERTED: + { + DBG_ASSERT( rReq.GetArgs(), "arguments expected" ); + const SbxItem& rSbxItem = rReq.GetArgs()->Get(SID_BASICIDE_ARG_SBX ); + const ScriptDocument& aDocument( rSbxItem.GetDocument() ); + const OUString& aLibName( rSbxItem.GetLibName() ); + const OUString& aName( rSbxItem.GetName() ); + if ( m_aCurLibName.isEmpty() || ( aDocument == m_aCurDocument && aLibName == m_aCurLibName ) ) + { + if ( rSbxItem.GetType() == TYPE_MODULE ) + FindBasWin( aDocument, aLibName, aName, true ); + else if ( rSbxItem.GetType() == TYPE_DIALOG ) + FindDlgWin( aDocument, aLibName, aName, true ); + } + } + break; + case SID_BASICIDE_SBXDELETED: + { + DBG_ASSERT( rReq.GetArgs(), "arguments expected" ); + const SbxItem& rSbxItem = rReq.GetArgs()->Get(SID_BASICIDE_ARG_SBX ); + const ScriptDocument& aDocument( rSbxItem.GetDocument() ); + VclPtr<BaseWindow> pWin = FindWindow( aDocument, rSbxItem.GetLibName(), rSbxItem.GetName(), rSbxItem.GetType(), true ); + if ( pWin ) + RemoveWindow( pWin, true ); + } + break; + case SID_BASICIDE_SHOWSBX: + { + DBG_ASSERT( rReq.GetArgs(), "arguments expected" ); + const SbxItem& rSbxItem = rReq.GetArgs()->Get(SID_BASICIDE_ARG_SBX ); + const ScriptDocument& aDocument( rSbxItem.GetDocument() ); + const OUString& aLibName( rSbxItem.GetLibName() ); + const OUString& aName( rSbxItem.GetName() ); + SetCurLib( aDocument, aLibName ); + BaseWindow* pWin = nullptr; + if ( rSbxItem.GetType() == TYPE_DIALOG ) + { + pWin = FindDlgWin( aDocument, aLibName, aName, true ); + } + else if ( rSbxItem.GetType() == TYPE_MODULE ) + { + pWin = FindBasWin( aDocument, aLibName, aName, true ); + } + else if ( rSbxItem.GetType() == TYPE_METHOD ) + { + pWin = FindBasWin( aDocument, aLibName, aName, true ); + static_cast<ModulWindow*>(pWin)->EditMacro( rSbxItem.GetMethodName() ); + } + DBG_ASSERT( pWin, "Window was not created!" ); + SetCurWindow( pWin, true ); + pTabBar->MakeVisible( pTabBar->GetCurPageId() ); + } + break; + case SID_BASICIDE_SHOWWINDOW: + { + std::unique_ptr< ScriptDocument > pDocument; + + const SfxStringItem* pDocumentItem = rReq.GetArg<SfxStringItem>(SID_BASICIDE_ARG_DOCUMENT); + if ( pDocumentItem ) + { + const OUString& sDocumentCaption = pDocumentItem->GetValue(); + if ( !sDocumentCaption.isEmpty() ) + pDocument.reset( new ScriptDocument( ScriptDocument::getDocumentWithURLOrCaption( sDocumentCaption ) ) ); + } + + const SfxUnoAnyItem* pDocModelItem = rReq.GetArg<SfxUnoAnyItem>(SID_BASICIDE_ARG_DOCUMENT_MODEL); + if (!pDocument && pDocModelItem) + { + uno::Reference< frame::XModel > xModel( pDocModelItem->GetValue(), UNO_QUERY ); + if ( xModel.is() ) + pDocument.reset( new ScriptDocument( xModel ) ); + } + + if (!pDocument) + break; + + const SfxStringItem* pLibNameItem = rReq.GetArg<SfxStringItem>(SID_BASICIDE_ARG_LIBNAME); + if ( !pLibNameItem ) + break; + + OUString aLibName( pLibNameItem->GetValue() ); + pDocument->loadLibraryIfExists( E_SCRIPTS, aLibName ); + SetCurLib( *pDocument, aLibName ); + const SfxStringItem* pNameItem = rReq.GetArg<SfxStringItem>(SID_BASICIDE_ARG_NAME); + if ( pNameItem ) + { + const OUString& aName( pNameItem->GetValue() ); + OUString aModType( "Module" ); + OUString aType( aModType ); + const SfxStringItem* pTypeItem = rReq.GetArg<SfxStringItem>(SID_BASICIDE_ARG_TYPE); + if ( pTypeItem ) + aType = pTypeItem->GetValue(); + + BaseWindow* pWin = nullptr; + if ( aType == aModType ) + pWin = FindBasWin( *pDocument, aLibName, aName ); + else if ( aType == "Dialog" ) + pWin = FindDlgWin( *pDocument, aLibName, aName ); + + if ( pWin ) + { + SetCurWindow( pWin, true ); + if ( pTabBar ) + pTabBar->MakeVisible( pTabBar->GetCurPageId() ); + + if (ModulWindow* pModWin = dynamic_cast<ModulWindow*>(pWin)) + { + const SfxUInt32Item* pLineItem = rReq.GetArg<SfxUInt32Item>(SID_BASICIDE_ARG_LINE); + if ( pLineItem ) + { + pModWin->AssertValidEditEngine(); + TextView* pTextView = pModWin->GetEditView(); + if ( pTextView ) + { + TextEngine* pTextEngine = pTextView->GetTextEngine(); + if ( pTextEngine ) + { + sal_uInt32 nLine = pLineItem->GetValue(); + sal_uInt32 nLineCount = 0; + for ( sal_uInt32 i = 0, nCount = pTextEngine->GetParagraphCount(); i < nCount; ++i ) + nLineCount += pTextEngine->GetLineCount( i ); + if ( nLine > nLineCount ) + nLine = nLineCount; + if ( nLine > 0 ) + --nLine; + + // scroll window and set selection + tools::Long nVisHeight = pModWin->GetOutputSizePixel().Height(); + tools::Long nTextHeight = pTextEngine->GetTextHeight(); + if ( nTextHeight > nVisHeight ) + { + tools::Long nMaxY = nTextHeight - nVisHeight; + tools::Long nOldY = pTextView->GetStartDocPos().Y(); + tools::Long nNewY = nLine * pTextEngine->GetCharHeight() - nVisHeight / 2; + nNewY = std::min( nNewY, nMaxY ); + pTextView->Scroll( 0, -( nNewY - nOldY ) ); + pTextView->ShowCursor( false ); + pModWin->GetEditVScrollBar().SetThumbPos( pTextView->GetStartDocPos().Y() ); + } + sal_uInt16 nCol1 = 0, nCol2 = 0; + const SfxUInt16Item* pCol1Item = rReq.GetArg<SfxUInt16Item>(SID_BASICIDE_ARG_COLUMN1); + if ( pCol1Item ) + { + nCol1 = pCol1Item->GetValue(); + if ( nCol1 > 0 ) + --nCol1; + nCol2 = nCol1; + } + const SfxUInt16Item* pCol2Item = rReq.GetArg<SfxUInt16Item>(SID_BASICIDE_ARG_COLUMN2); + if ( pCol2Item ) + { + nCol2 = pCol2Item->GetValue(); + if ( nCol2 > 0 ) + --nCol2; + } + TextSelection aSel( TextPaM( nLine, nCol1 ), TextPaM( nLine, nCol2 ) ); + pTextView->SetSelection( aSel ); + pTextView->ShowCursor(); + vcl::Window* pWindow_ = pTextView->GetWindow(); + if ( pWindow_ ) + pWindow_->GrabFocus(); + } + } + } + } + } + } + rReq.Done(); + } + break; + + case SID_BASICIDE_MANAGE_LANG: + { + auto pRequest = std::make_shared<SfxRequest>(rReq); + rReq.Ignore(); // the 'old' request is not relevant any more + auto xDlg = std::make_shared<ManageLanguageDialog>(pCurWin ? pCurWin->GetFrameWeld() : nullptr, m_pCurLocalizationMgr); + weld::DialogController::runAsync(xDlg, [=](sal_Int32 /*nResult*/){ + pRequest->Done(); + }); + } + break; + + case SID_ATTR_ZOOMSLIDER: + { + const SfxItemSet *pArgs = rReq.GetArgs(); + const SfxPoolItem* pItem; + + if (pArgs && pArgs->GetItemState(SID_ATTR_ZOOMSLIDER, true, &pItem ) == SfxItemState::SET) + SetGlobalEditorZoomLevel(static_cast<const SvxZoomSliderItem*>(pItem)->GetValue()); + + lcl_InvalidateZoomSlots(GetBindingsPtr()); + } + break; + + case SID_ZOOM_IN: + case SID_ZOOM_OUT: + { + const sal_uInt16 nOldZoom = GetCurrentZoomSliderValue(); + sal_uInt16 nNewZoom; + if (nSlot == SID_ZOOM_IN) + nNewZoom = std::min<sal_uInt16>(GetMaxZoom(), basegfx::zoomtools::zoomIn(nOldZoom)); + else + nNewZoom = std::max<sal_uInt16>(GetMinZoom(), basegfx::zoomtools::zoomOut(nOldZoom)); + SetGlobalEditorZoomLevel(nNewZoom); + lcl_InvalidateZoomSlots(GetBindingsPtr()); + } + break; + + default: + if (pLayout) + pLayout->ExecuteGlobal(rReq); + if (pCurWin) + pCurWin->ExecuteGlobal(rReq); + break; + } +} + +void Shell::GetState(SfxItemSet &rSet) +{ + SfxWhichIter aIter(rSet); + for ( sal_uInt16 nWh = aIter.FirstWhich(); nWh != 0; nWh = aIter.NextWhich() ) + { + switch ( nWh ) + { + case SID_NEWDOCDIRECT: + { + // we do not have a new document factory, + // so just forward to a fallback method. + SfxGetpApp()->GetSlotState(nWh, nullptr, &rSet); + } + break; + case SID_DOCINFO: + { + rSet.DisableItem( nWh ); + } + break; + case SID_SAVEDOC: + { + bool bDisable = false; + + if ( pCurWin ) + { + if ( !pCurWin->IsModified() ) + { + ScriptDocument aDocument( pCurWin->GetDocument() ); + bDisable = ( !aDocument.isAlive() ) + || ( aDocument.isDocument() ? !aDocument.isDocumentModified() : !IsAppBasicModified() ); + } + } + else + { + bDisable = true; + } + + if ( bDisable ) + rSet.DisableItem( nWh ); + } + break; + case SID_NEWWINDOW: + case SID_SAVEASDOC: + { + rSet.DisableItem( nWh ); + } + break; + case SID_SIGNATURE: + { + SignatureState nState = SignatureState::NOSIGNATURES; + if ( pCurWin ) + { + DocumentSignature aSignature( pCurWin->GetDocument() ); + nState = aSignature.getScriptingSignatureState(); + } + rSet.Put( SfxUInt16Item( SID_SIGNATURE, static_cast<sal_uInt16>(nState) ) ); + } + break; + case SID_BASICIDE_MODULEDLG: + { + if ( StarBASIC::IsRunning() ) + rSet.DisableItem( nWh ); + } + break; + + case SID_BASICIDE_OBJCAT: + { + if (pLayout) + rSet.Put(SfxBoolItem(nWh, aObjectCatalog->IsVisible())); + else + rSet.Put(SfxVisibilityItem(nWh, false)); + } + break; + + case SID_BASICIDE_WATCH: + { + if (pLayout) + { + rSet.Put(SfxBoolItem(nWh, pModulLayout->IsWatchWindowVisible())); + // Disable command if the visible window is not a ModulWindow + if (!dynamic_cast<ModulWindowLayout*>(pLayout.get())) + rSet.DisableItem(nWh); + } + else + rSet.Put(SfxVisibilityItem(nWh, false)); + } + break; + + case SID_BASICIDE_STACK: + { + if (pLayout) + { + rSet.Put(SfxBoolItem(nWh, pModulLayout->IsStackWindowVisible())); + // Disable command if the visible window is not a ModulWindow + if (!dynamic_cast<ModulWindowLayout*>(pLayout.get())) + rSet.DisableItem(nWh); + } + else + rSet.Put(SfxVisibilityItem(nWh, false)); + } + break; + + case SID_BASICIDE_SHOWSBX: + case SID_BASICIDE_CREATEMACRO: + case SID_BASICIDE_EDITMACRO: + case SID_BASICIDE_NAMECHANGEDONTAB: + { + ; + } + break; + + case SID_BASICIDE_ADDWATCH: + case SID_BASICIDE_REMOVEWATCH: + case SID_BASICLOAD: + case SID_BASICSAVEAS: + case SID_BASICIDE_MATCHGROUP: + { + if (!dynamic_cast<ModulWindow*>(pCurWin.get())) + rSet.DisableItem( nWh ); + else if ( ( nWh == SID_BASICLOAD ) && ( StarBASIC::IsRunning() || ( pCurWin && pCurWin->IsReadOnly() ) ) ) + rSet.DisableItem( nWh ); + } + break; + case SID_BASICRUN: + case SID_BASICSTEPINTO: + case SID_BASICSTEPOVER: + case SID_BASICSTEPOUT: + case SID_BASICIDE_TOGGLEBRKPNT: + case SID_BASICIDE_MANAGEBRKPNTS: + { + if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get())) + { + if (StarBASIC::IsRunning() && !pMCurWin->GetBasicStatus().bIsInReschedule) + rSet.DisableItem(nWh); + } + else + rSet.DisableItem( nWh ); + } + break; + case SID_BASICCOMPILE: + { + if (StarBASIC::IsRunning() || !dynamic_cast<ModulWindow*>(pCurWin.get())) + rSet.DisableItem( nWh ); + } + break; + case SID_BASICSTOP: + { + // stop is always possible when some Basic is running... + if (!StarBASIC::IsRunning()) + rSet.DisableItem( nWh ); + } + break; + case SID_CHOOSE_CONTROLS: + case SID_DIALOG_TESTMODE: + case SID_INSERT_SELECT: + case SID_INSERT_PUSHBUTTON: + case SID_INSERT_RADIOBUTTON: + case SID_INSERT_CHECKBOX: + case SID_INSERT_LISTBOX: + case SID_INSERT_COMBOBOX: + case SID_INSERT_GROUPBOX: + case SID_INSERT_EDIT: + case SID_INSERT_FIXEDTEXT: + case SID_INSERT_IMAGECONTROL: + case SID_INSERT_PROGRESSBAR: + case SID_INSERT_HSCROLLBAR: + case SID_INSERT_VSCROLLBAR: + case SID_INSERT_HFIXEDLINE: + case SID_INSERT_VFIXEDLINE: + case SID_INSERT_DATEFIELD: + case SID_INSERT_TIMEFIELD: + case SID_INSERT_NUMERICFIELD: + case SID_INSERT_CURRENCYFIELD: + case SID_INSERT_FORMATTEDFIELD: + case SID_INSERT_PATTERNFIELD: + case SID_INSERT_FILECONTROL: + case SID_INSERT_SPINBUTTON: + case SID_INSERT_GRIDCONTROL: + case SID_INSERT_HYPERLINKCONTROL: + case SID_INSERT_TREECONTROL: + case SID_INSERT_FORM_RADIO: + case SID_INSERT_FORM_CHECK: + case SID_INSERT_FORM_LIST: + case SID_INSERT_FORM_COMBO: + case SID_INSERT_FORM_VSCROLL: + case SID_INSERT_FORM_HSCROLL: + case SID_INSERT_FORM_SPIN: + { + if (!dynamic_cast<DialogWindow*>(pCurWin.get())) + rSet.DisableItem( nWh ); + } + break; + case SID_SEARCH_OPTIONS: + { + SearchOptionFlags nOptions = SearchOptionFlags::NONE; + if( pCurWin ) + nOptions = pCurWin->GetSearchOptions(); + rSet.Put( SfxUInt16Item( SID_SEARCH_OPTIONS, static_cast<sal_uInt16>(nOptions) ) ); + } + break; + case SID_BASICIDE_LIBSELECTOR: + { + OUString aName; + if ( !m_aCurLibName.isEmpty() ) + { + LibraryLocation eLocation = m_aCurDocument.getLibraryLocation( m_aCurLibName ); + aName = CreateMgrAndLibStr( m_aCurDocument.getTitle( eLocation ), m_aCurLibName ); + } + SfxStringItem aItem( SID_BASICIDE_LIBSELECTOR, aName ); + rSet.Put( aItem ); + } + break; + case SID_SEARCH_ITEM: + { + if ( !mpSearchItem ) + { + mpSearchItem.reset( new SvxSearchItem( SID_SEARCH_ITEM )); + mpSearchItem->SetSearchString( GetSelectionText( true )); + } + + if ( mbJustOpened && HasSelection() ) + { + OUString aText = GetSelectionText( true ); + + if ( !aText.isEmpty() ) + { + mpSearchItem->SetSearchString( aText ); + mpSearchItem->SetSelection( false ); + } + else + mpSearchItem->SetSelection( true ); + } + + mbJustOpened = false; + rSet.Put( *mpSearchItem ); + } + break; + case SID_BASICIDE_STAT_DATE: + { + SfxStringItem aItem( SID_BASICIDE_STAT_DATE, "Datum?!" ); + rSet.Put( aItem ); + } + break; + case SID_DOC_MODIFIED: + { + bool bModified = false; + + if ( pCurWin ) + { + if ( pCurWin->IsModified() ) + bModified = true; + else + { + ScriptDocument aDocument( pCurWin->GetDocument() ); + bModified = aDocument.isDocument() ? aDocument.isDocumentModified() : IsAppBasicModified(); + } + } + + SfxBoolItem aItem(SID_DOC_MODIFIED, bModified); + rSet.Put( aItem ); + } + break; + case SID_BASICIDE_STAT_TITLE: + { + if ( pCurWin ) + { + OUString aTitle = pCurWin->CreateQualifiedName(); + if (pCurWin->IsReadOnly()) + aTitle += " (" + IDEResId(RID_STR_READONLY) + ")"; + SfxStringItem aItem( SID_BASICIDE_STAT_TITLE, aTitle ); + rSet.Put( aItem ); + } + } + break; + case SID_BASICIDE_CURRENT_ZOOM: + { + // The current zoom value is only visible in a module window + ModulWindow* pModuleWindow = dynamic_cast<ModulWindow*>(pCurWin.get()); + if (pModuleWindow) + { + OUString sZoom; + sZoom = OUString::number(m_nCurrentZoomSliderValue) + "%"; + SfxStringItem aItem( SID_BASICIDE_CURRENT_ZOOM, sZoom ); + rSet.Put( aItem ); + } + } + break; + // are interpreted by the controller: + case SID_ATTR_SIZE: + case SID_ATTR_INSERT: + break; + case SID_UNDO: + case SID_REDO: + { + if( GetUndoManager() ) // recursive GetState else + GetViewFrame().GetSlotState( nWh, nullptr, &rSet ); + } + break; + case SID_BASICIDE_CURRENT_LANG: + { + if( (pCurWin && pCurWin->IsReadOnly()) || GetCurLibName().isEmpty() ) + rSet.DisableItem( nWh ); + else + { + OUString aItemStr; + std::shared_ptr<LocalizationMgr> pCurMgr(GetCurLocalizationMgr()); + if ( pCurMgr->isLibraryLocalized() ) + { + Sequence< lang::Locale > aLocaleSeq = pCurMgr->getStringResourceManager()->getLocales(); + const lang::Locale* pLocale = aLocaleSeq.getConstArray(); + sal_Int32 i, nCount = aLocaleSeq.getLength(); + + // Force different results for any combination of locales and default locale + OUString aLangStr; + for ( i = 0; i <= nCount; ++i ) + { + lang::Locale aLocale; + if( i < nCount ) + aLocale = pLocale[i]; + else + aLocale = pCurMgr->getStringResourceManager()->getDefaultLocale(); + + aLangStr += aLocale.Language + aLocale.Country + aLocale.Variant; + } + aItemStr = aLangStr; + } + rSet.Put( SfxStringItem( nWh, aItemStr ) ); + } + } + break; + + case SID_BASICIDE_MANAGE_LANG: + { + if( (pCurWin && pCurWin->IsReadOnly()) || GetCurLibName().isEmpty() ) + rSet.DisableItem( nWh ); + } + break; + case SID_GOTOLINE: + { + // if this is not a module window hide the + // setting, doesn't make sense for example if the + // dialog editor is open + if (pCurWin && !dynamic_cast<ModulWindow*>(pCurWin.get())) + { + rSet.DisableItem( nWh ); + rSet.Put(SfxVisibilityItem(nWh, false)); + } + break; + } + case SID_BASICIDE_HIDECURPAGE: + { + if (pTabBar->GetPageCount() == 0) + rSet.DisableItem(nWh); + } + break; + case SID_BASICIDE_DELETECURRENT: + case SID_BASICIDE_RENAMECURRENT: + { + if (pTabBar->GetPageCount() == 0 || StarBASIC::IsRunning()) + rSet.DisableItem(nWh); + else if (m_aCurDocument.isInVBAMode()) + { + // disable to delete or rename object modules in IDE + BasicManager* pBasMgr = m_aCurDocument.getBasicManager(); + StarBASIC* pBasic = pBasMgr ? pBasMgr->GetLib(m_aCurLibName) : nullptr; + if (pBasic && dynamic_cast<ModulWindow*>(pCurWin.get())) + { + SbModule* pActiveModule = pBasic->FindModule( pCurWin->GetName() ); + if ( pActiveModule && ( pActiveModule->GetModuleType() == script::ModuleType::DOCUMENT ) ) + rSet.DisableItem(nWh); + } + } + } + [[fallthrough]]; + + case SID_BASICIDE_NEWMODULE: + case SID_BASICIDE_NEWDIALOG: + { + Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( ( xModLibContainer.is() && xModLibContainer->hasByName( m_aCurLibName ) && xModLibContainer->isLibraryReadOnly( m_aCurLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( m_aCurLibName ) && xDlgLibContainer->isLibraryReadOnly( m_aCurLibName ) ) ) + rSet.DisableItem(nWh); + } + break; + + case SID_ZOOM_IN: + case SID_ZOOM_OUT: + { + const sal_uInt16 nCurrentZoom = GetCurrentZoomSliderValue(); + if ((nWh == SID_ZOOM_IN && nCurrentZoom >= GetMaxZoom()) || + (nWh == SID_ZOOM_OUT && nCurrentZoom <= GetMinZoom())) + rSet.DisableItem(nWh); + } + break; + + case SID_ATTR_ZOOMSLIDER: + { + // The zoom slider is only visible in a module window + ModulWindow* pModuleWindow = dynamic_cast<ModulWindow*>(pCurWin.get()); + if (pModuleWindow) + { + SvxZoomSliderItem aZoomSliderItem(GetCurrentZoomSliderValue(), GetMinZoom(), GetMaxZoom()); + aZoomSliderItem.AddSnappingPoint(100); + rSet.Put( aZoomSliderItem ); + } + } + break; + + default: + if (pLayout) + pLayout->GetState(rSet, nWh); + } + } + if ( pCurWin ) + pCurWin->GetState( rSet ); +} + +bool Shell::HasUIFeature(SfxShellFeature nFeature) const +{ + assert((nFeature & ~SfxShellFeature::BasicMask) == SfxShellFeature::NONE); + bool bResult = false; + + if (nFeature & SfxShellFeature::BasicShowBrowser) + { + // fade out (in) property browser in module (dialog) windows + if (dynamic_cast<DialogWindow*>(pCurWin.get()) && !pCurWin->IsReadOnly()) + bResult = true; + } + + return bResult; +} + +void Shell::SetCurWindow( BaseWindow* pNewWin, bool bUpdateTabBar, bool bRememberAsCurrent ) +{ + if ( pNewWin == pCurWin ) + return; + + pCurWin = pNewWin; + if (pLayout) + pLayout->Deactivating(); + if (pCurWin) + { + if (pCurWin->GetType() == TYPE_MODULE) + pLayout = pModulLayout.get(); + else + pLayout = pDialogLayout.get(); + AdjustPosSizePixel(Point(0, 0), GetViewFrame().GetWindow().GetOutputSizePixel()); + pLayout->Activating(*pCurWin); + GetViewFrame().GetWindow().SetHelpId(pCurWin->GetHid()); + if (bRememberAsCurrent) + pCurWin->InsertLibInfo(); + if (GetViewFrame().GetWindow().IsVisible()) // SFX will do it later otherwise + pCurWin->Show(); + pCurWin->Init(); + if (!GetExtraData()->ShellInCriticalSection()) + { + vcl::Window* pFrameWindow = &GetViewFrame().GetWindow(); + vcl::Window* pFocusWindow = Application::GetFocusWindow(); + while ( pFocusWindow && ( pFocusWindow != pFrameWindow ) ) + pFocusWindow = pFocusWindow->GetParent(); + if ( pFocusWindow ) // Focus in BasicIDE + pCurWin->GrabFocus(); + } + } + else + { + SetWindow(pLayout); + pLayout = nullptr; + } + if ( bUpdateTabBar ) + { + sal_uInt16 nKey = GetWindowId( pCurWin ); + if ( pCurWin && ( pTabBar->GetPagePos( nKey ) == TabBar::PAGE_NOT_FOUND ) ) + pTabBar->InsertPage( nKey, pCurWin->GetTitle() ); // has just been faded in + pTabBar->SetCurPageId( nKey ); + } + if ( pCurWin && pCurWin->IsSuspended() ) // if the window is shown in the case of an error... + pCurWin->SetStatus( pCurWin->GetStatus() & ~BASWIN_SUSPENDED ); + if ( pCurWin ) + { + SetWindow( pCurWin ); + if ( pCurWin->GetDocument().isDocument() ) + SfxObjectShell::SetCurrentComponent( pCurWin->GetDocument().getDocument() ); + } + else if (pLayout) + { + SetWindow(pLayout); + GetViewFrame().GetWindow().SetHelpId( HID_BASICIDE_MODULWINDOW ); + SfxObjectShell::SetCurrentComponent(nullptr); + } + aObjectCatalog->SetCurrentEntry(pCurWin); + SetUndoManager( pCurWin ? pCurWin->GetUndoManager() : nullptr ); + InvalidateBasicIDESlots(); + InvalidateControlSlots(); + + if ( m_pCurLocalizationMgr ) + m_pCurLocalizationMgr->handleTranslationbar(); + + ManageToolbars(); + + // fade out (in) property browser in module (dialog) windows + UIFeatureChanged(); +} + +void Shell::ManageToolbars() +{ + static constexpr OUString aMacroBarResName = u"private:resource/toolbar/macrobar"_ustr; + static constexpr OUString aDialogBarResName = u"private:resource/toolbar/dialogbar"_ustr; + static constexpr OUString aInsertControlsBarResName + = u"private:resource/toolbar/insertcontrolsbar"_ustr; + static constexpr OUString aFormControlsBarResName + = u"private:resource/toolbar/formcontrolsbar"_ustr; + + if( !pCurWin ) + return; + + Reference< beans::XPropertySet > xFrameProps + ( GetViewFrame().GetFrame().GetFrameInterface(), uno::UNO_QUERY ); + if ( !xFrameProps.is() ) + return; + + Reference< css::frame::XLayoutManager > xLayoutManager; + uno::Any a = xFrameProps->getPropertyValue( "LayoutManager" ); + a >>= xLayoutManager; + if ( !xLayoutManager.is() ) + return; + + xLayoutManager->lock(); + if (dynamic_cast<DialogWindow*>(pCurWin.get())) + { + xLayoutManager->destroyElement( aMacroBarResName ); + + xLayoutManager->requestElement( aDialogBarResName ); + xLayoutManager->requestElement( aInsertControlsBarResName ); + xLayoutManager->requestElement( aFormControlsBarResName ); + } + else + { + xLayoutManager->destroyElement( aDialogBarResName ); + xLayoutManager->destroyElement( aInsertControlsBarResName ); + xLayoutManager->destroyElement( aFormControlsBarResName ); + + xLayoutManager->requestElement( aMacroBarResName ); + } + xLayoutManager->unlock(); +} + +VclPtr<BaseWindow> Shell::FindApplicationWindow() +{ + return FindWindow( ScriptDocument::getApplicationScriptDocument(), u"", u"", TYPE_UNKNOWN ); +} + +VclPtr<BaseWindow> Shell::FindWindow( + ScriptDocument const& rDocument, + std::u16string_view rLibName, std::u16string_view rName, + ItemType eType, bool bFindSuspended +) +{ + for (auto const& window : aWindowTable) + { + BaseWindow* const pWin = window.second; + if (pWin->Is(rDocument, rLibName, rName, eType, bFindSuspended)) + return pWin; + } + return nullptr; +} + +bool Shell::CallBasicErrorHdl( StarBASIC const * pBasic ) +{ + VclPtr<ModulWindow> pModWin = ShowActiveModuleWindow( pBasic ); + if ( pModWin ) + pModWin->BasicErrorHdl( pBasic ); + return false; +} + +BasicDebugFlags Shell::CallBasicBreakHdl( StarBASIC const * pBasic ) +{ + BasicDebugFlags nRet = BasicDebugFlags::NONE; + VclPtr<ModulWindow> pModWin = ShowActiveModuleWindow( pBasic ); + if ( pModWin ) + { + bool bAppWindowDisabled, bDispatcherLocked; + sal_uInt16 nWaitCount; + SfxUInt16Item *pSWActionCount, *pSWLockViewCount; + BasicStopped( &bAppWindowDisabled, &bDispatcherLocked, + &nWaitCount, &pSWActionCount, &pSWLockViewCount ); + + nRet = pModWin->BasicBreakHdl(); + + if ( StarBASIC::IsRunning() ) // if cancelled... + { + if ( bAppWindowDisabled ) + Application::GetDefDialogParent()->set_sensitive(false); + + if ( nWaitCount ) + { + Shell* pShell = GetShell(); + for ( sal_uInt16 n = 0; n < nWaitCount; n++ ) + pShell->GetViewFrame().GetWindow().EnterWait(); + } + } + } + return nRet; +} + +VclPtr<ModulWindow> Shell::ShowActiveModuleWindow( StarBASIC const * pBasic ) +{ + SetCurLib( ScriptDocument::getApplicationScriptDocument(), OUString(), false ); + + SbModule* pActiveModule = StarBASIC::GetActiveModule(); + if (SbClassModuleObject* pCMO = dynamic_cast<SbClassModuleObject*>(pActiveModule)) + pActiveModule = pCMO->getClassModule(); + + DBG_ASSERT( pActiveModule, "No active module in ErrorHdl!?" ); + if ( pActiveModule ) + { + VclPtr<ModulWindow> pWin; + SbxObject* pParent = pActiveModule->GetParent(); + if (StarBASIC* pLib = dynamic_cast<StarBASIC*>(pParent)) + { + if (BasicManager* pBasMgr = FindBasicManager(pLib)) + { + ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) ); + const OUString& aLibName = pLib->GetName(); + pWin = FindBasWin( aDocument, aLibName, pActiveModule->GetName(), true ); + DBG_ASSERT( pWin, "Error/Step-Hdl: Window was not created/found!" ); + SetCurLib( aDocument, aLibName ); + SetCurWindow( pWin, true ); + } + } + else + SAL_WARN( "basctl.basicide", "No BASIC!"); + if (BasicManager* pBasicMgr = FindBasicManager(pBasic)) + StartListening(*pBasicMgr, DuplicateHandling::Prevent /* log on only once */); + return pWin; + } + return nullptr; +} + +void Shell::AdjustPosSizePixel( const Point &rPos, const Size &rSize ) +{ + // not if iconified because the whole text would be displaced then at restore + if ( GetViewFrame().GetWindow().GetOutputSizePixel().Height() == 0 ) + return; + + Size aTabBarSize; + aTabBarSize.setHeight( GetViewFrame().GetWindow().GetFont().GetFontHeight() + TAB_HEIGHT_MARGIN ); + aTabBarSize.setWidth( rSize.Width() ); + + Size aSz( rSize ); + auto nScrollBarSz(Application::GetSettings().GetStyleSettings().GetScrollBarSize()); + aSz.AdjustHeight(-aTabBarSize.Height()); + + Size aOutSz( aSz ); + aSz.AdjustWidth(-nScrollBarSz); + aSz.AdjustHeight(-nScrollBarSz); + aVScrollBar->SetPosSizePixel( Point( rPos.X()+aSz.Width(), rPos.Y() ), Size( nScrollBarSz, aSz.Height() ) ); + aHScrollBar->SetPosSizePixel( Point( rPos.X(), rPos.Y()+aSz.Height() ), Size( aOutSz.Width(), nScrollBarSz ) ); + pTabBar->SetPosSizePixel( Point( rPos.X(), rPos.Y() + nScrollBarSz + aSz.Height()), aTabBarSize ); + + // The size to be applied depends on whether it is a DialogWindow or a ModulWindow + if (pLayout) + { + if (dynamic_cast<DialogWindow*>(pCurWin.get())) + { + pCurWin->ShowShellScrollBars(); + pLayout->SetPosSizePixel(rPos, aSz); + } + else + { + pCurWin->ShowShellScrollBars(false); + pLayout->SetPosSizePixel(rPos, aOutSz); + } + } +} + +Reference< XModel > Shell::GetCurrentDocument() const +{ + Reference< XModel > xDocument; + if ( pCurWin && pCurWin->GetDocument().isDocument() ) + xDocument = pCurWin->GetDocument().getDocument(); + return xDocument; +} + +void Shell::Activate( bool bMDI ) +{ + SfxViewShell::Activate( bMDI ); + + if ( bMDI ) + { + if (DialogWindow* pDCurWin = dynamic_cast<DialogWindow*>(pCurWin.get())) + pDCurWin->UpdateBrowser(); + } +} + +void Shell::Deactivate( bool bMDI ) +{ + // bMDI == true means that another MDI has been activated; in case of a + // deactivate due to a MessageBox bMDI is false + if ( bMDI ) + { + if (DialogWindow* pXDlgWin = dynamic_cast<DialogWindow*>(pCurWin.get())) + { + pXDlgWin->DisableBrowser(); + if( pXDlgWin->IsModified() ) + MarkDocumentModified( pXDlgWin->GetDocument() ); + } + } +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basides2.cxx b/basctl/source/basicide/basides2.cxx new file mode 100644 index 0000000000..5bd69b76f3 --- /dev/null +++ b/basctl/source/basicide/basides2.cxx @@ -0,0 +1,239 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <docsignature.hxx> + +#include "basicrenderable.hxx" + +#include <com/sun/star/frame/XTitle.hpp> + +#include <iderid.hxx> +#include <strings.hrc> +#include "baside2.hxx" +#include "basdoc.hxx" +#include <basidesh.hxx> +#include <tools/debug.hxx> +#include <vcl/texteng.hxx> +#include <vcl/textview.hxx> +#include <sfx2/signaturestate.hxx> +#include <sfx2/viewfrm.hxx> + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +Reference< view::XRenderable > Shell::GetRenderable() +{ + return Reference<view::XRenderable>( new Renderable(pCurWin) ); +} + +bool Shell::HasSelection( bool /* bText */ ) const +{ + if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get())) + { + TextView* pEditView = pMCurWin->GetEditView(); + if ( pEditView && pEditView->HasSelection() ) + return true; + } + return false; +} + +OUString Shell::GetSelectionText( bool bWholeWord, bool /*bOnlyASample*/ ) +{ + OUString aText; + if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get())) + { + if (TextView* pEditView = pMCurWin->GetEditView()) + { + if ( bWholeWord && !pEditView->HasSelection() ) + { + aText = pEditView->GetTextEngine()->GetWord( pEditView->GetSelection().GetEnd() ); + } + else + { + TextSelection aSel = pEditView->GetSelection(); + if ( !bWholeWord || ( aSel.GetStart().GetPara() == aSel.GetEnd().GetPara() ) ) + aText = pEditView->GetSelected(); + } + } + } + return aText; +} + +SfxPrinter* Shell::GetPrinter( bool bCreate ) +{ + if ( pCurWin ) + { + DocShell* pDocShell = static_cast<DocShell*>(GetViewFrame().GetObjectShell()); + assert(pDocShell && "DocShell ?!"); + return pDocShell->GetPrinter( bCreate ); + } + return nullptr; +} + +sal_uInt16 Shell::SetPrinter( SfxPrinter *pNewPrinter, SfxPrinterChangeFlags ) +{ + DocShell* pDocShell = static_cast<DocShell*>(GetViewFrame().GetObjectShell()); + assert(pDocShell && "DocShell ?!"); + pDocShell->SetPrinter( pNewPrinter ); + return 0; +} + +void Shell::SetMDITitle() +{ + OUString aTitle; + if ( !m_aCurLibName.isEmpty() ) + { + LibraryLocation eLocation = m_aCurDocument.getLibraryLocation( m_aCurLibName ); + aTitle = m_aCurDocument.getTitle(eLocation) + "." + m_aCurLibName ; + } + else + aTitle = IDEResId(RID_STR_ALL) ; + + DocumentSignature aCurSignature( m_aCurDocument ); + if ( aCurSignature.getScriptingSignatureState() == SignatureState::OK ) + { + aTitle += " " + IDEResId(RID_STR_SIGNED) + " "; + } + + SfxViewFrame& rViewFrame = GetViewFrame(); + SfxObjectShell* pShell = rViewFrame.GetObjectShell(); + if ( pShell && pShell->GetTitle( SFX_TITLE_CAPTION ) != aTitle ) + { + pShell->SetTitle( aTitle ); + pShell->SetModified(false); + } + + css::uno::Reference< css::frame::XController > xController = GetController (); + css::uno::Reference< css::frame::XTitle > xTitle (xController, css::uno::UNO_QUERY); + if (xTitle.is ()) + xTitle->setTitle (aTitle); +} + +VclPtr<ModulWindow> Shell::CreateBasWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName ) +{ + bCreatingWindow = true; + + sal_uInt16 nKey = 0; + VclPtr<ModulWindow> pWin; + + OUString aLibName( rLibName ); + OUString aModName( rModName ); + + if ( aLibName.isEmpty() ) + aLibName = "Standard" ; + + uno::Reference< container::XNameContainer > xLib = rDocument.getOrCreateLibrary( E_SCRIPTS, aLibName ); + + if ( aModName.isEmpty() ) + aModName = rDocument.createObjectName( E_SCRIPTS, aLibName ); + + // maybe there's an suspended one? + pWin = FindBasWin( rDocument, aLibName, aModName, false, true ); + + if ( !pWin ) + { + OUString aModule; + bool bSuccess = false; + if ( rDocument.hasModule( aLibName, aModName ) ) + bSuccess = rDocument.getModule( aLibName, aModName, aModule ); + else + bSuccess = rDocument.createModule( aLibName, aModName, true, aModule ); + + if ( bSuccess ) + { + pWin = FindBasWin( rDocument, aLibName, aModName, false, true ); + if( !pWin ) + { + // new module window + if (!pModulLayout) + pModulLayout.reset(VclPtr<ModulWindowLayout>::Create(&GetViewFrame().GetWindow(), *aObjectCatalog)); + pWin = VclPtr<ModulWindow>::Create(pModulLayout.get(), rDocument, aLibName, aModName, aModule); + nKey = InsertWindowInTable( pWin ); + } + else // we've gotten called recursively ( via listener from createModule above ), get outta here + return pWin; + } + } + else + { + pWin->SetStatus( pWin->GetStatus() & ~BASWIN_SUSPENDED ); + nKey = GetWindowId( pWin ); + DBG_ASSERT( nKey, "CreateBasWin: No Key - Window not found!" ); + } + if( nKey && xLib.is() && rDocument.isInVBAMode() ) + { + // display a nice friendly name in the ObjectModule tab, + // combining the objectname and module name, e.g. Sheet1 ( Financials ) + OUString sObjName; + ModuleInfoHelper::getObjectName( xLib, rModName, sObjName ); + if( !sObjName.isEmpty() ) + { + aModName += " (" + sObjName + ")"; + } + } + pTabBar->InsertPage( nKey, aModName ); + pTabBar->Sort(); + if(pWin) + { + pWin->GrabScrollBars( aHScrollBar.get(), aVScrollBar.get() ); + if ( !pCurWin ) + SetCurWindow( pWin, false, false ); + } + bCreatingWindow = false; + return pWin; +} + +VclPtr<ModulWindow> Shell::FindBasWin ( + ScriptDocument const& rDocument, + OUString const& rLibName, OUString const& rName, + bool bCreateIfNotExist, bool bFindSuspended +) +{ + if (VclPtr<BaseWindow> pWin = FindWindow(rDocument, rLibName, rName, TYPE_MODULE, bFindSuspended)) + return VclPtr<ModulWindow>(static_cast<ModulWindow*>(pWin.get())); + return bCreateIfNotExist ? CreateBasWin(rDocument, rLibName, rName) : nullptr; +} + +void Shell::Move() +{ +} + +void Shell::ShowCursor( bool bOn ) +{ + if (ModulWindow* pMCurWin = dynamic_cast<ModulWindow*>(pCurWin.get())) + pMCurWin->ShowCursor(bOn); +} + +// only if basic window above: +void Shell::ExecuteBasic( SfxRequest& rReq ) +{ + if (dynamic_cast<ModulWindow*>(pCurWin.get())) + { + pCurWin->ExecuteCommand( rReq ); + if (nShellCount) + CheckWindows(); + } +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basides3.cxx b/basctl/source/basicide/basides3.cxx new file mode 100644 index 0000000000..44bc54ba62 --- /dev/null +++ b/basctl/source/basicide/basides3.cxx @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <baside3.hxx> +#include <basidesh.hxx> +#include <localizationmgr.hxx> +#include <dlgedview.hxx> +#include <xmlscript/xmldlg_imexp.hxx> +#include <sfx2/request.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/viewfrm.hxx> +#include <tools/debug.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> + +namespace basctl +{ + +using namespace comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::io; + +VclPtr<DialogWindow> Shell::CreateDlgWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rDlgName ) +{ + bCreatingWindow = true; + + sal_uInt16 nKey = 0; + VclPtr<DialogWindow> pWin; + OUString aLibName( rLibName ); + OUString aDlgName( rDlgName ); + + if ( aLibName.isEmpty() ) + aLibName = "Standard" ; + + rDocument.getOrCreateLibrary( E_DIALOGS, aLibName ); + + if ( aDlgName.isEmpty() ) + aDlgName = rDocument.createObjectName( E_DIALOGS, aLibName ); + + // maybe there's a suspended one? + pWin = FindDlgWin( rDocument, aLibName, aDlgName, false, true ); + + if ( !pWin ) + { + try + { + Reference< io::XInputStreamProvider > xISP; + if ( rDocument.hasDialog( aLibName, aDlgName ) ) + rDocument.getDialog( aLibName, aDlgName, xISP ); + else + rDocument.createDialog( aLibName, aDlgName, xISP ); + + if ( xISP.is() ) + { + // create dialog model + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + Reference< container::XNameContainer > xDialogModel( xContext->getServiceManager()->createInstanceWithContext + ( "com.sun.star.awt.UnoControlDialogModel", xContext ), UNO_QUERY ); + Reference< XInputStream > xInput( xISP->createInputStream() ); + ::xmlscript::importDialogModel( xInput, xDialogModel, xContext, rDocument.isDocument() ? rDocument.getDocument() : Reference< frame::XModel >() ); + LocalizationMgr::setStringResourceAtDialog( rDocument, rLibName, aDlgName, xDialogModel ); + + // new dialog window + if (!pDialogLayout) + pDialogLayout.reset(VclPtr<DialogWindowLayout>::Create(&GetViewFrame().GetWindow(), *aObjectCatalog)); + pWin = VclPtr<DialogWindow>::Create(pDialogLayout.get(), rDocument, aLibName, aDlgName, xDialogModel); + nKey = InsertWindowInTable( pWin ); + } + } + catch (const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + else + { + pWin->SetStatus( pWin->GetStatus() & ~BASWIN_SUSPENDED ); + nKey = GetWindowId( pWin ); + DBG_ASSERT( nKey, "CreateDlgWin: No Key - Window not found!" ); + } + + if( pWin ) + { + pWin->GrabScrollBars( aHScrollBar.get(), aVScrollBar.get() ); + pTabBar->InsertPage( nKey, aDlgName ); + pTabBar->Sort(); + if ( !pCurWin ) + SetCurWindow( pWin, false, false ); + } + + bCreatingWindow = false; + return pWin; +} + +VclPtr<DialogWindow> Shell::FindDlgWin ( + ScriptDocument const& rDocument, + OUString const& rLibName, OUString const& rName, + bool bCreateIfNotExist, bool bFindSuspended +) +{ + if (VclPtr<BaseWindow> pWin = FindWindow(rDocument, rLibName, rName, TYPE_DIALOG, bFindSuspended)) + return static_cast<DialogWindow*>(pWin.get()); + return bCreateIfNotExist ? CreateDlgWin(rDocument, rLibName, rName) : nullptr; +} + +sal_uInt16 Shell::GetWindowId(const BaseWindow* pWin) const +{ + for (auto const& window : aWindowTable) + if ( window.second == pWin ) + return window.first; + return 0; +} + +SdrView* Shell::GetCurDlgView() const +{ + if (DialogWindow* pDCurWin = dynamic_cast<DialogWindow*>(pCurWin.get())) + return &pDCurWin->GetView(); + else + return nullptr; +} + +// only if dialogue window above: +void Shell::ExecuteDialog( SfxRequest& rReq ) +{ + if (pCurWin && (dynamic_cast<DialogWindow*>(pCurWin.get()) || rReq.GetSlot() == SID_IMPORT_DIALOG)) + pCurWin->ExecuteCommand(rReq); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basidesh.cxx b/basctl/source/basicide/basidesh.cxx new file mode 100644 index 0000000000..d23da94d26 --- /dev/null +++ b/basctl/source/basicide/basidesh.cxx @@ -0,0 +1,994 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_options.h> + +#include <comphelper/diagnose_ex.hxx> +#include <basic/basmgr.hxx> +#include <svx/zoomsliderctrl.hxx> +#include <svx/zoomslideritem.hxx> +#include <svx/svxids.hrc> +#include <iderid.hxx> +#include <strings.hrc> +#include "baside2.hxx" +#include <baside3.hxx> +#include "basdoc.hxx" +#include <IDEComboBox.hxx> +#include <editeng/sizeitem.hxx> +#include "iderdll2.hxx" +#include <basidectrlr.hxx> +#include <basidesh.hxx> +#include <basobj.hxx> +#include <localizationmgr.hxx> +#include <sfx2/app.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/dinfdlg.hxx> +#include <sfx2/infobar.hxx> +#include <sfx2/minfitem.hxx> +#include <sfx2/objface.hxx> +#include <sfx2/viewfrm.hxx> +#include <svl/srchitem.hxx> +#include <tools/debug.hxx> +#include <unotools/viewoptions.hxx> + +#if defined(DISABLE_DYNLOADING) || ENABLE_MERGELIBS +/* Avoid clash with the ones from svx/source/form/typemap.cxx */ +#define aSfxDocumentInfoItem_Impl basctl_source_basicide_basidesh_aSfxDocumentInfoItem_Impl +#define aSfxUnoAnyItem_Impl basctl_source_basicide_basidesh_aSfxUnoAnyItem_Impl +#endif + +#define ShellClass_basctl_Shell +#define SFX_TYPEMAP +#include <basslots.hxx> + +#if defined(DISABLE_DYNLOADING) || ENABLE_MERGELIBS +#undef aSfxDocumentInfoItem_Impl +#undef aSfxUnoAnyItem_Impl +#endif + +#include <iderdll.hxx> +#include <svx/pszctrl.hxx> +#include <svx/insctrl.hxx> +#include <svx/srchdlg.hxx> +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <svx/xmlsecctrl.hxx> +#include <sfx2/viewfac.hxx> +#include <vcl/weld.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <cppuhelper/implbase.hxx> + +namespace basctl +{ +constexpr OUString BASIC_IDE_EDITOR_WINDOW = u"BasicIDEEditorWindow"_ustr; +constexpr OUString BASIC_IDE_CURRENT_ZOOM = u"CurrentZoom"_ustr; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +class ContainerListenerImpl : public ::cppu::WeakImplHelper< container::XContainerListener > +{ + Shell* mpShell; +public: + explicit ContainerListenerImpl(Shell* pShell) + : mpShell(pShell) + { + } + + void addContainerListener( const ScriptDocument& rScriptDocument, const OUString& aLibName ) + { + try + { + uno::Reference< container::XContainer > xContainer( rScriptDocument.getLibrary( E_SCRIPTS, aLibName, false ), uno::UNO_QUERY ); + if ( xContainer.is() ) + { + uno::Reference< container::XContainerListener > xContainerListener( this ); + xContainer->addContainerListener( xContainerListener ); + } + } + catch(const uno::Exception& ) {} + } + void removeContainerListener( const ScriptDocument& rScriptDocument, const OUString& aLibName ) + { + try + { + uno::Reference< container::XContainer > xContainer( rScriptDocument.getLibrary( E_SCRIPTS, aLibName, false ), uno::UNO_QUERY ); + if ( xContainer.is() ) + { + uno::Reference< container::XContainerListener > xContainerListener( this ); + xContainer->removeContainerListener( xContainerListener ); + } + } + catch(const uno::Exception& ) {} + } + + // XEventListener + virtual void SAL_CALL disposing( const lang::EventObject& ) override {} + + // XContainerListener + virtual void SAL_CALL elementInserted( const container::ContainerEvent& Event ) override + { + OUString sModuleName; + if( mpShell && ( Event.Accessor >>= sModuleName ) ) + mpShell->FindBasWin( mpShell->m_aCurDocument, mpShell->m_aCurLibName, sModuleName, true ); + } + virtual void SAL_CALL elementReplaced( const container::ContainerEvent& ) override { } + virtual void SAL_CALL elementRemoved( const container::ContainerEvent& Event ) override + { + OUString sModuleName; + if( mpShell && ( Event.Accessor >>= sModuleName ) ) + { + VclPtr<ModulWindow> pWin = mpShell->FindBasWin(mpShell->m_aCurDocument, mpShell->m_aCurLibName, sModuleName, false, true); + if( pWin ) + mpShell->RemoveWindow( pWin, true ); + } + } + +}; + +SFX_IMPL_NAMED_VIEWFACTORY( Shell, "Default" ) +{ + SFX_VIEW_REGISTRATION( DocShell ); +} + +SFX_IMPL_INTERFACE(basctl_Shell, SfxViewShell) + +void basctl_Shell::InitInterface_Impl() +{ + GetStaticInterface()->RegisterChildWindow(SID_SEARCH_DLG); + GetStaticInterface()->RegisterChildWindow(SID_SHOW_PROPERTYBROWSER, false, SfxShellFeature::BasicShowBrowser); + GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId()); + + GetStaticInterface()->RegisterPopupMenu("dialog"); +} + +unsigned Shell::nShellCount = 0; + +Shell::Shell( SfxViewFrame& rFrame_, SfxViewShell* /* pOldShell */ ) : + SfxViewShell( rFrame_, SfxViewShellFlags::NO_NEWWINDOW ), + m_aCurDocument( ScriptDocument::getApplicationScriptDocument() ), + aHScrollBar( VclPtr<ScrollAdaptor>::Create(&GetViewFrame().GetWindow(), true) ), + aVScrollBar( VclPtr<ScrollAdaptor>::Create(&GetViewFrame().GetWindow(), false) ), + pLayout(nullptr), + aObjectCatalog(VclPtr<ObjectCatalog>::Create(&GetViewFrame().GetWindow())), + m_bAppBasicModified( false ), + m_aNotifier( *this ) +{ + m_xLibListener = new ContainerListenerImpl( this ); + Init(); + nShellCount++; +} + +void Shell::Init() +{ + SvxPosSizeStatusBarControl::RegisterControl(); + SvxInsertStatusBarControl::RegisterControl(); + XmlSecStatusBarControl::RegisterControl( SID_SIGNATURE ); + + SvxSearchDialogWrapper::RegisterChildWindow(); + + GetExtraData()->ShellInCriticalSection() = true; + + SetName( "BasicIDE" ); + + LibBoxControl::RegisterControl( SID_BASICIDE_LIBSELECTOR ); + LanguageBoxControl::RegisterControl( SID_BASICIDE_CURRENT_LANG ); + SvxZoomSliderControl::RegisterControl( SID_ATTR_ZOOMSLIDER ); + + GetViewFrame().GetWindow().SetBackground( + GetViewFrame().GetWindow().GetSettings().GetStyleSettings().GetWindowColor() + ); + + pCurWin = nullptr; + m_aCurDocument = ScriptDocument::getApplicationScriptDocument(); + bCreatingWindow = false; + + pTabBar.reset(VclPtr<TabBar>::Create(&GetViewFrame().GetWindow())); + + nCurKey = 100; + InitScrollBars(); + InitTabBar(); + InitZoomLevel(); + + SetCurLib( ScriptDocument::getApplicationScriptDocument(), "Standard", false, false ); + + ShellCreated(this); + + GetExtraData()->ShellInCriticalSection() = false; + + // It's enough to create the controller ... + // It will be public by using magic :-) + new Controller(this); + + // Force updating the title ! Because it must be set to the controller + // it has to be called directly after creating those controller. + SetMDITitle (); + + UpdateWindows(); +} + +Shell::~Shell() +{ + m_aNotifier.dispose(); + + ShellDestroyed(this); + + // so that on a basic saving error, the shell doesn't pop right up again + GetExtraData()->ShellInCriticalSection() = true; + + SetWindow( nullptr ); + SetCurWindow( nullptr ); + + aObjectCatalog.disposeAndClear(); + aVScrollBar.disposeAndClear(); + aHScrollBar.disposeAndClear(); + + for (auto & window : aWindowTable) + { + // no store; does already happen when the BasicManagers are destroyed + window.second.disposeAndClear(); + } + + // no store; does already happen when the BasicManagers are destroyed + aWindowTable.clear(); + + // Destroy all ContainerListeners for Basic Container. + if (ContainerListenerImpl* pListener = static_cast<ContainerListenerImpl*>(m_xLibListener.get())) + pListener->removeContainerListener(m_aCurDocument, m_aCurLibName); + + GetExtraData()->ShellInCriticalSection() = false; + + nShellCount--; + + pDialogLayout.disposeAndClear(); + pModulLayout.disposeAndClear(); + pTabBar.disposeAndClear(); + + // Remember current zoom level + SvtViewOptions(EViewType::Window, BASIC_IDE_EDITOR_WINDOW).SetUserItem( + BASIC_IDE_CURRENT_ZOOM, Any(m_nCurrentZoomSliderValue)); +} + +void Shell::onDocumentCreated( const ScriptDocument& /*_rDocument*/ ) +{ + if (pCurWin) + pCurWin->OnNewDocument(); + + UpdateWindows(); +} + +void Shell::onDocumentOpened( const ScriptDocument& /*_rDocument*/ ) +{ + if (pCurWin) + pCurWin->OnNewDocument(); + UpdateWindows(); +} + +void Shell::onDocumentSave( const ScriptDocument& /*_rDocument*/ ) +{ + StoreAllWindowData(); +} + +void Shell::onDocumentSaveDone( const ScriptDocument& /*_rDocument*/ ) +{ + // #i115671: Update SID_SAVEDOC after saving is completed + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_SAVEDOC ); +} + +void Shell::onDocumentSaveAs( const ScriptDocument& /*_rDocument*/ ) +{ + StoreAllWindowData(); +} + +void Shell::onDocumentSaveAsDone( const ScriptDocument& /*_rDocument*/ ) +{ + // not interested in +} + +void Shell::onDocumentClosed( const ScriptDocument& _rDocument ) +{ + if ( !_rDocument.isValid() ) + return; + + bool bSetCurWindow = false; + bool bSetCurLib = ( _rDocument == m_aCurDocument ); + std::vector<VclPtr<BaseWindow> > aDeleteVec; + + // remove all windows which belong to this document + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + if ( pWin->IsDocument( _rDocument ) ) + { + if ( pWin->GetStatus() & (BASWIN_RUNNINGBASIC|BASWIN_INRESCHEDULE) ) + { + pWin->AddStatus( BASWIN_TOBEKILLED ); + pWin->Hide(); + StarBASIC::Stop(); + // there's no notify + pWin->BasicStopped(); + } + else + aDeleteVec.emplace_back(pWin ); + } + } + // delete windows outside main loop so we don't invalidate the original iterator + for (VclPtr<BaseWindow> const & pWin : aDeleteVec) + { + pWin->StoreData(); + if ( pWin == pCurWin ) + bSetCurWindow = true; + RemoveWindow( pWin, true, false ); + } + + // remove lib info + if (ExtraData* pData = GetExtraData()) + pData->GetLibInfo().RemoveInfoFor( _rDocument ); + + if ( bSetCurLib ) + SetCurLib( ScriptDocument::getApplicationScriptDocument(), "Standard", true, false ); + else if ( bSetCurWindow ) + SetCurWindow( FindApplicationWindow(), true ); +} + +void Shell::onDocumentTitleChanged( const ScriptDocument& /*_rDocument*/ ) +{ + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_BASICIDE_LIBSELECTOR, true ); + SetMDITitle(); +} + +void Shell::onDocumentModeChanged( const ScriptDocument& _rDocument ) +{ + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + if ( pWin->IsDocument( _rDocument ) && _rDocument.isDocument() ) + pWin->SetReadOnly( _rDocument.isReadOnly() ); + } +} + +void Shell::InitZoomLevel() +{ + m_nCurrentZoomSliderValue = DEFAULT_ZOOM_LEVEL; + SvtViewOptions aWinOpt(EViewType::Window, BASIC_IDE_EDITOR_WINDOW); + if (aWinOpt.Exists()) + { + try + { + aWinOpt.GetUserItem(BASIC_IDE_CURRENT_ZOOM) >>= m_nCurrentZoomSliderValue; + } + catch(const css::container::NoSuchElementException&) + { TOOLS_WARN_EXCEPTION("basctl.basicide", "Zoom level not defined"); } + } +} + +// Applies the new zoom level to all open editor windows +void Shell::SetGlobalEditorZoomLevel(sal_uInt16 nNewZoomLevel) +{ + for (auto const& window : aWindowTable) + { + ModulWindow* pModuleWindow = dynamic_cast<ModulWindow*>(window.second.get()); + if (pModuleWindow) + { + EditorWindow& pEditorWindow = pModuleWindow->GetEditorWindow(); + pEditorWindow.SetEditorZoomLevel(nNewZoomLevel); + } + } + + // Update the zoom slider value based on the new global zoom level + m_nCurrentZoomSliderValue = nNewZoomLevel; + + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_BASICIDE_CURRENT_ZOOM ); + pBindings->Invalidate( SID_ATTR_ZOOMSLIDER ); + } +} + +void Shell::StoreAllWindowData( bool bPersistent ) +{ + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + DBG_ASSERT( pWin, "PrepareClose: NULL-Pointer in Table?" ); + if ( !pWin->IsSuspended() ) + pWin->StoreData(); + } + + if ( bPersistent ) + { + SfxGetpApp()->SaveBasicAndDialogContainer(); + SetAppBasicModified(false); + + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_SAVEDOC ); + pBindings->Update( SID_SAVEDOC ); + } + } +} + +bool Shell::PrepareClose( bool bUI ) +{ + // reset here because it's modified after printing etc. (DocInfo) + GetViewFrame().GetObjectShell()->SetModified(false); + + if ( StarBASIC::IsRunning() ) + { + if( bUI ) + { + std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetViewFrame().GetFrameWeld(), + VclMessageType::Info, VclButtonsType::Ok, + IDEResId(RID_STR_CANNOTCLOSE))); + xInfoBox->run(); + } + return false; + } + else + { + StoreAllWindowData( false ); // don't write on the disk, that will be done later automatically + return true; + } +} + +void Shell::InitScrollBars() +{ + aVScrollBar->SetLineSize( 300 ); + aVScrollBar->SetPageSize( 2000 ); + aHScrollBar->SetLineSize( 300 ); + aHScrollBar->SetPageSize( 2000 ); +} + +void Shell::InitTabBar() +{ + pTabBar->Enable(); + pTabBar->Show(); + pTabBar->SetSelectHdl( LINK( this, Shell, TabBarHdl ) ); +} + +void Shell::OuterResizePixel( const Point &rPos, const Size &rSize ) +{ + AdjustPosSizePixel( rPos, rSize ); +} + +IMPL_LINK( Shell, TabBarHdl, ::TabBar *, pCurTabBar, void ) +{ + sal_uInt16 nCurId = pCurTabBar->GetCurPageId(); + BaseWindow* pWin = aWindowTable[ nCurId ].get(); + DBG_ASSERT( pWin, "Entry in TabBar is not matching a window!" ); + SetCurWindow( pWin ); +} + + +bool Shell::NextPage( bool bPrev ) +{ + bool bRet = false; + sal_uInt16 nPos = pTabBar->GetPagePos( pTabBar->GetCurPageId() ); + + if ( bPrev ) + --nPos; + else + ++nPos; + + if ( nPos < pTabBar->GetPageCount() ) + { + VclPtr<BaseWindow> pWin = aWindowTable[ pTabBar->GetPageId( nPos ) ]; + SetCurWindow( pWin, true ); + bRet = true; + } + + return bRet; +} + +SfxUndoManager* Shell::GetUndoManager() +{ + SfxUndoManager* pMgr = nullptr; + if( pCurWin ) + pMgr = pCurWin->GetUndoManager(); + + return pMgr; +} + + +void Shell::Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) +{ + if (!GetShell()) + return; + + if (rHint.GetId() == SfxHintId::Dying) + { + EndListening( rBC, true /* log off all */ ); + aObjectCatalog->UpdateEntries(); + } + + SbxHint const* pSbxHint = dynamic_cast<SbxHint const*>(&rHint); + if (!pSbxHint) + return; + + const SfxHintId nHintId = pSbxHint->GetId(); + if ( ( nHintId != SfxHintId::BasicStart ) && + ( nHintId != SfxHintId::BasicStop ) ) + return; + + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_BASICRUN ); + pBindings->Update( SID_BASICRUN ); + pBindings->Invalidate( SID_BASICCOMPILE ); + pBindings->Update( SID_BASICCOMPILE ); + pBindings->Invalidate( SID_BASICSTEPOVER ); + pBindings->Update( SID_BASICSTEPOVER ); + pBindings->Invalidate( SID_BASICSTEPINTO ); + pBindings->Update( SID_BASICSTEPINTO ); + pBindings->Invalidate( SID_BASICSTEPOUT ); + pBindings->Update( SID_BASICSTEPOUT ); + pBindings->Invalidate( SID_BASICSTOP ); + pBindings->Update( SID_BASICSTOP ); + pBindings->Invalidate( SID_BASICIDE_TOGGLEBRKPNT ); + pBindings->Update( SID_BASICIDE_TOGGLEBRKPNT ); + pBindings->Invalidate( SID_BASICIDE_MANAGEBRKPNTS ); + pBindings->Update( SID_BASICIDE_MANAGEBRKPNTS ); + pBindings->Invalidate( SID_BASICIDE_MODULEDLG ); + pBindings->Update( SID_BASICIDE_MODULEDLG ); + pBindings->Invalidate( SID_BASICLOAD ); + pBindings->Update( SID_BASICLOAD ); + } + + if ( nHintId == SfxHintId::BasicStop ) + { + // not only at error/break or explicit stoppage, + // if the update is turned off due to a programming bug + BasicStopped(); + if (pLayout) + pLayout->UpdateDebug(true); // clear... + if( m_pCurLocalizationMgr ) + m_pCurLocalizationMgr->handleBasicStopped(); + } + else if( m_pCurLocalizationMgr ) + { + m_pCurLocalizationMgr->handleBasicStarted(); + } + + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + if ( nHintId == SfxHintId::BasicStart ) + pWin->BasicStarted(); + else + pWin->BasicStopped(); + } +} + + +void Shell::CheckWindows() +{ + bool bSetCurWindow = false; + std::vector<VclPtr<BaseWindow> > aDeleteVec; + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + if ( pWin->GetStatus() & BASWIN_TOBEKILLED ) + aDeleteVec.emplace_back(pWin ); + } + for ( VclPtr<BaseWindow> const & pWin : aDeleteVec ) + { + pWin->StoreData(); + if ( pWin == pCurWin ) + bSetCurWindow = true; + RemoveWindow( pWin, true, false ); + } + if ( bSetCurWindow ) + SetCurWindow( FindApplicationWindow(), true ); +} + + +void Shell::RemoveWindows( const ScriptDocument& rDocument, std::u16string_view rLibName ) +{ + bool bChangeCurWindow = pCurWin; + std::vector<VclPtr<BaseWindow> > aDeleteVec; + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + if ( pWin->IsDocument( rDocument ) && pWin->GetLibName() == rLibName ) + aDeleteVec.emplace_back(pWin ); + } + for ( VclPtr<BaseWindow> const & pWin : aDeleteVec ) + { + if ( pWin == pCurWin ) + bChangeCurWindow = true; + pWin->StoreData(); + RemoveWindow( pWin, true/*bDestroy*/, false ); + } + if ( bChangeCurWindow ) + SetCurWindow( FindApplicationWindow(), true ); +} + + +void Shell::UpdateWindows() +{ + // remove all windows that may not be displayed + bool bChangeCurWindow = pCurWin == nullptr; + // stores the total number of modules and dialogs visible + sal_uInt16 nTotalTabs = 0; + + if ( !m_aCurLibName.isEmpty() ) + { + std::vector<VclPtr<BaseWindow> > aDeleteVec; + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + if ( !pWin->IsDocument( m_aCurDocument ) || pWin->GetLibName() != m_aCurLibName ) + { + if ( pWin == pCurWin ) + bChangeCurWindow = true; + pWin->StoreData(); + // The request of RUNNING prevents the crash when in reschedule. + // Window is frozen at first, later the windows should be changed + // anyway to be marked as hidden instead of being deleted. + if ( !(pWin->GetStatus() & ( BASWIN_TOBEKILLED | BASWIN_RUNNINGBASIC | BASWIN_SUSPENDED ) ) ) + aDeleteVec.emplace_back(pWin ); + } + } + for (auto const& elem : aDeleteVec) + { + RemoveWindow( elem, false, false ); + } + } + + if ( bCreatingWindow ) + return; + + BaseWindow* pNextActiveWindow = nullptr; + + // show all windows that are to be shown + ScriptDocuments aDocuments( ScriptDocument::getAllScriptDocuments( ScriptDocument::AllWithApplication ) ); + for (auto const& doc : aDocuments) + { + StartListening(*doc.getBasicManager(), DuplicateHandling::Prevent /* log on only once */); + + // libraries + Sequence< OUString > aLibNames( doc.getLibraryNames() ); + sal_Int32 nLibCount = aLibNames.getLength(); + const OUString* pLibNames = aLibNames.getConstArray(); + + for ( sal_Int32 i = 0 ; i < nLibCount ; i++ ) + { + OUString aLibName = pLibNames[ i ]; + + if ( m_aCurLibName.isEmpty() || ( doc == m_aCurDocument && aLibName == m_aCurLibName ) ) + { + // check, if library is password protected and not verified + bool bProtected = false; + Reference< script::XLibraryContainer > xModLibContainer( doc.getLibraryContainer( E_SCRIPTS ) ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) ) + { + bProtected = true; + } + } + + if ( !bProtected ) + { + LibInfo::Item const* pLibInfoItem = nullptr; + if (ExtraData* pData = GetExtraData()) + pLibInfoItem = pData->GetLibInfo().GetInfo(doc, aLibName); + + // modules + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) ) + { + StarBASIC* pLib = doc.getBasicManager()->GetLib( aLibName ); + if ( pLib ) + StartListening(pLib->GetBroadcaster(), DuplicateHandling::Prevent /* log on only once */); + + try + { + Sequence< OUString > aModNames( doc.getObjectNames( E_SCRIPTS, aLibName ) ); + sal_Int32 nModCount = aModNames.getLength(); + const OUString* pModNames = aModNames.getConstArray(); + nTotalTabs += nModCount; + + for ( sal_Int32 j = 0 ; j < nModCount ; j++ ) + { + OUString aModName = pModNames[ j ]; + VclPtr<ModulWindow> pWin = FindBasWin( doc, aLibName, aModName ); + if ( !pWin ) + pWin = CreateBasWin( doc, aLibName, aModName ); + if ( !pNextActiveWindow && pLibInfoItem && pLibInfoItem->GetCurrentName() == aModName && + pLibInfoItem->GetCurrentType() == TYPE_MODULE ) + { + pNextActiveWindow = pWin; + } + } + } + catch (const container::NoSuchElementException& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + + // dialogs + Reference< script::XLibraryContainer > xDlgLibContainer( doc.getLibraryContainer( E_DIALOGS ) ); + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) ) + { + try + { + Sequence< OUString > aDlgNames = doc.getObjectNames( E_DIALOGS, aLibName ); + sal_Int32 nDlgCount = aDlgNames.getLength(); + const OUString* pDlgNames = aDlgNames.getConstArray(); + nTotalTabs += nDlgCount; + + for ( sal_Int32 j = 0 ; j < nDlgCount ; j++ ) + { + OUString aDlgName = pDlgNames[ j ]; + // this find only looks for non-suspended windows; + // suspended windows are handled in CreateDlgWin + VclPtr<DialogWindow> pWin = FindDlgWin( doc, aLibName, aDlgName ); + if ( !pWin ) + pWin = CreateDlgWin( doc, aLibName, aDlgName ); + if ( !pNextActiveWindow && pLibInfoItem && pLibInfoItem->GetCurrentName() == aDlgName && + pLibInfoItem->GetCurrentType() == TYPE_DIALOG ) + { + pNextActiveWindow = pWin; + } + } + } + catch (const container::NoSuchElementException& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + } + } + } + } + + if ( bChangeCurWindow ) + { + if ( nTotalTabs == 0 ) + { + // If no tabs are opened, create a generic module and make it visible + pNextActiveWindow = CreateBasWin( m_aCurDocument, m_aCurLibName, OUString() ); + } + else if ( !pNextActiveWindow ) + { + pNextActiveWindow = FindApplicationWindow().get(); + } + SetCurWindow( pNextActiveWindow, true ); + } +} + +void Shell::RemoveWindow( BaseWindow* pWindow_, bool bDestroy, bool bAllowChangeCurWindow ) +{ + VclPtr<BaseWindow> pWindowTmp( pWindow_ ); + + DBG_ASSERT( pWindow_, "Cannot delete NULL-Pointer!" ); + sal_uInt16 nKey = GetWindowId( pWindow_ ); + pTabBar->RemovePage( nKey ); + aWindowTable.erase( nKey ); + if ( pWindow_ == pCurWin ) + { + if ( bAllowChangeCurWindow ) + { + SetCurWindow( FindApplicationWindow(), true ); + } + else + { + SetCurWindow( nullptr ); + } + } + if ( bDestroy ) + { + if ( !( pWindow_->GetStatus() & BASWIN_INRESCHEDULE ) ) + { + pWindowTmp.disposeAndClear(); + } + else + { + pWindow_->AddStatus( BASWIN_TOBEKILLED ); + pWindow_->Hide(); + // In normal mode stop basic in windows to be deleted + // In VBA stop basic only if the running script is trying to delete + // its parent module + bool bStop = true; + if ( pWindow_->GetDocument().isInVBAMode() ) + { + SbModule* pMod = StarBASIC::GetActiveModule(); + if ( !pMod || pMod->GetName() != pWindow_->GetName() ) + { + bStop = false; + } + } + if ( bStop ) + { + StarBASIC::Stop(); + // there will be no notify... + pWindow_->BasicStopped(); + } + aWindowTable[ nKey ] = pWindow_; // jump in again + } + } + else + { + pWindow_->AddStatus( BASWIN_SUSPENDED ); + pWindow_->Deactivating(); + aWindowTable[ nKey ] = pWindow_; // jump in again + } + +} + + +sal_uInt16 Shell::InsertWindowInTable( BaseWindow* pNewWin ) +{ + nCurKey++; + aWindowTable[ nCurKey ] = pNewWin; + return nCurKey; +} + + +void Shell::InvalidateBasicIDESlots() +{ + // only those that have an optic effect... + + if (!GetShell()) + return; + + SfxBindings* pBindings = GetBindingsPtr(); + if (!pBindings) + return; + + pBindings->Invalidate( SID_COPY ); + pBindings->Invalidate( SID_CUT ); + pBindings->Invalidate( SID_PASTE ); + pBindings->Invalidate( SID_UNDO ); + pBindings->Invalidate( SID_REDO ); + pBindings->Invalidate( SID_SAVEDOC ); + pBindings->Invalidate( SID_SIGNATURE ); + pBindings->Invalidate( SID_BASICIDE_CHOOSEMACRO ); + pBindings->Invalidate( SID_BASICIDE_MODULEDLG ); + pBindings->Invalidate( SID_BASICIDE_OBJCAT ); + pBindings->Invalidate( SID_BASICSTOP ); + pBindings->Invalidate( SID_BASICRUN ); + pBindings->Invalidate( SID_BASICCOMPILE ); + pBindings->Invalidate( SID_BASICLOAD ); + pBindings->Invalidate( SID_BASICSAVEAS ); + pBindings->Invalidate( SID_BASICIDE_MATCHGROUP ); + pBindings->Invalidate( SID_BASICSTEPINTO ); + pBindings->Invalidate( SID_BASICSTEPOVER ); + pBindings->Invalidate( SID_BASICSTEPOUT ); + pBindings->Invalidate( SID_BASICIDE_TOGGLEBRKPNT ); + pBindings->Invalidate( SID_BASICIDE_MANAGEBRKPNTS ); + pBindings->Invalidate( SID_BASICIDE_ADDWATCH ); + pBindings->Invalidate( SID_BASICIDE_REMOVEWATCH ); + + pBindings->Invalidate( SID_PRINTDOC ); + pBindings->Invalidate( SID_PRINTDOCDIRECT ); + pBindings->Invalidate( SID_SETUPPRINTER ); + pBindings->Invalidate( SID_DIALOG_TESTMODE ); + + pBindings->Invalidate( SID_DOC_MODIFIED ); + pBindings->Invalidate( SID_BASICIDE_STAT_TITLE ); + pBindings->Invalidate( SID_BASICIDE_STAT_POS ); + pBindings->Invalidate( SID_ATTR_INSERT ); + pBindings->Invalidate( SID_ATTR_SIZE ); +} + +void Shell::InvalidateControlSlots() +{ + if (!GetShell()) + return; + + SfxBindings* pBindings = GetBindingsPtr(); + if (!pBindings) + return; + + pBindings->Invalidate( SID_INSERT_FORM_RADIO ); + pBindings->Invalidate( SID_INSERT_FORM_CHECK ); + pBindings->Invalidate( SID_INSERT_FORM_LIST ); + pBindings->Invalidate( SID_INSERT_FORM_COMBO ); + pBindings->Invalidate( SID_INSERT_FORM_VSCROLL ); + pBindings->Invalidate( SID_INSERT_FORM_HSCROLL ); + pBindings->Invalidate( SID_INSERT_FORM_SPIN ); + + pBindings->Invalidate( SID_INSERT_SELECT ); + pBindings->Invalidate( SID_INSERT_PUSHBUTTON ); + pBindings->Invalidate( SID_INSERT_RADIOBUTTON ); + pBindings->Invalidate( SID_INSERT_CHECKBOX ); + pBindings->Invalidate( SID_INSERT_LISTBOX ); + pBindings->Invalidate( SID_INSERT_COMBOBOX ); + pBindings->Invalidate( SID_INSERT_GROUPBOX ); + pBindings->Invalidate( SID_INSERT_EDIT ); + pBindings->Invalidate( SID_INSERT_FIXEDTEXT ); + pBindings->Invalidate( SID_INSERT_IMAGECONTROL ); + pBindings->Invalidate( SID_INSERT_PROGRESSBAR ); + pBindings->Invalidate( SID_INSERT_HSCROLLBAR ); + pBindings->Invalidate( SID_INSERT_VSCROLLBAR ); + pBindings->Invalidate( SID_INSERT_HFIXEDLINE ); + pBindings->Invalidate( SID_INSERT_VFIXEDLINE ); + pBindings->Invalidate( SID_INSERT_DATEFIELD ); + pBindings->Invalidate( SID_INSERT_TIMEFIELD ); + pBindings->Invalidate( SID_INSERT_NUMERICFIELD ); + pBindings->Invalidate( SID_INSERT_CURRENCYFIELD ); + pBindings->Invalidate( SID_INSERT_FORMATTEDFIELD ); + pBindings->Invalidate( SID_INSERT_PATTERNFIELD ); + pBindings->Invalidate( SID_INSERT_FILECONTROL ); + pBindings->Invalidate( SID_INSERT_SPINBUTTON ); + pBindings->Invalidate( SID_INSERT_GRIDCONTROL ); + pBindings->Invalidate( SID_INSERT_HYPERLINKCONTROL ); + pBindings->Invalidate( SID_INSERT_TREECONTROL ); + pBindings->Invalidate( SID_CHOOSE_CONTROLS ); +} + +void Shell::SetCurLib( const ScriptDocument& rDocument, const OUString& aLibName, bool bUpdateWindows, bool bCheck ) +{ + if ( bCheck && rDocument == m_aCurDocument && aLibName == m_aCurLibName ) + return; + + ContainerListenerImpl* pListener = static_cast< ContainerListenerImpl* >( m_xLibListener.get() ); + + if (pListener) + pListener->removeContainerListener(m_aCurDocument, m_aCurLibName); + + m_aCurDocument = rDocument; + m_aCurLibName = aLibName; + + if ( pListener ) + pListener->addContainerListener( m_aCurDocument, aLibName ); + + if ( bUpdateWindows ) + UpdateWindows(); + + SetMDITitle(); + + SetCurLibForLocalization( rDocument, aLibName ); + + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_BASICIDE_LIBSELECTOR ); + pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG ); + pBindings->Invalidate( SID_BASICIDE_MANAGE_LANG ); + } +} + +void Shell::SetCurLibForLocalization( const ScriptDocument& rDocument, const OUString& aLibName ) +{ + // Create LocalizationMgr + Reference< resource::XStringResourceManager > xStringResourceManager; + try + { + if( !aLibName.isEmpty() ) + { + Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) ); + xStringResourceManager = LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + } + } + catch (const container::NoSuchElementException& ) + {} + + m_pCurLocalizationMgr = std::make_shared<LocalizationMgr>(this, rDocument, aLibName, xStringResourceManager); + m_pCurLocalizationMgr->handleTranslationbar(); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basobj2.cxx b/basctl/source/basicide/basobj2.cxx new file mode 100644 index 0000000000..708b1ce035 --- /dev/null +++ b/basctl/source/basicide/basobj2.cxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <basidesh.hxx> +#include <iderdll.hxx> +#include "iderdll2.hxx" +#include "macrodlg.hxx" +#include "moduldlg.hxx" +#include <iderid.hxx> +#include <strings.hrc> +#include "baside2.hxx" + +#include <com/sun/star/document/XScriptInvocationContext.hpp> + +#include <basic/sbmeth.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> +#include <comphelper/sequence.hxx> +#include <framework/documentundoguard.hxx> +#include <sal/log.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <unotools/moduleoptions.hxx> +#include <vcl/settings.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +#include <memory> +#include <vector> +#include <algorithm> +#include <basic/basmgr.hxx> +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; + +extern "C" { + SAL_DLLPUBLIC_EXPORT rtl_uString* basicide_choose_macro(void* pParent, void* pOnlyInDocument_AsXModel, void* pDocFrame_AsXFrame, sal_Bool bChooseOnly ) + { + Reference< frame::XModel > aDocument( static_cast< frame::XModel* >( pOnlyInDocument_AsXModel ) ); + Reference< frame::XFrame > aDocFrame( static_cast< frame::XFrame* >( pDocFrame_AsXFrame ) ); + OUString aScriptURL = basctl::ChooseMacro(static_cast<weld::Window*>(pParent), aDocument, aDocFrame, bChooseOnly); + rtl_uString* pScriptURL = aScriptURL.pData; + rtl_uString_acquire( pScriptURL ); + + return pScriptURL; + } + SAL_DLLPUBLIC_EXPORT void basicide_macro_organizer(void *pParent, void* pDocFrame_AsXFrame, sal_Int16 nTabId) + { + SAL_INFO("basctl.basicide","in basicide_macro_organizer"); + Reference< frame::XFrame > aDocFrame( static_cast< frame::XFrame* >( pDocFrame_AsXFrame ) ); + basctl::Organize(static_cast<weld::Window*>(pParent), aDocFrame, nTabId); + } +} + +void Organize(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, sal_Int16 tabId) +{ + EnsureIde(); + + auto xDlg(std::make_shared<OrganizeDialog>(pParent, xDocFrame, tabId)); + weld::DialogController::runAsync(xDlg, [](int) {}); +} + +bool IsValidSbxName( std::u16string_view rName ) +{ + for ( size_t nChar = 0; nChar < rName.size(); nChar++ ) + { + sal_Unicode c = rName[nChar]; + bool bValid = ( + ( c >= 'A' && c <= 'Z' ) || + ( c >= 'a' && c <= 'z' ) || + ( c >= '0' && c <= '9' && nChar ) || + ( c == '_' ) + ); + if ( !bValid ) + return false; + } + return true; +} + +Sequence< OUString > GetMergedLibraryNames( const Reference< script::XLibraryContainer >& xModLibContainer, const Reference< script::XLibraryContainer >& xDlgLibContainer ) +{ + // create a list of module library names + std::vector<OUString> aLibList; + if ( xModLibContainer.is() ) + { + const Sequence< OUString > aModLibNames = xModLibContainer->getElementNames(); + aLibList.insert( aLibList.end(), aModLibNames.begin(), aModLibNames.end() ); + } + + // create a list of dialog library names + if ( xDlgLibContainer.is() ) + { + const Sequence< OUString > aDlgLibNames = xDlgLibContainer->getElementNames(); + aLibList.insert( aLibList.end(), aDlgLibNames.begin(), aDlgLibNames.end() ); + } + + // sort list + auto const sort = comphelper::string::NaturalStringSorter( + comphelper::getProcessComponentContext(), + Application::GetSettings().GetUILanguageTag().getLocale()); + std::sort(aLibList.begin(), aLibList.end(), + [&sort](const OUString& rLHS, const OUString& rRHS) { + return sort.compare(rLHS, rRHS) < 0; + }); + // remove duplicates + std::vector<OUString>::iterator aIterEnd = std::unique( aLibList.begin(), aLibList.end() ); + aLibList.erase( aIterEnd, aLibList.end() ); + + return comphelper::containerToSequence(aLibList); +} + +bool RenameModule ( + weld::Widget* pErrorParent, + const ScriptDocument& rDocument, + const OUString& rLibName, + const OUString& rOldName, + const OUString& rNewName +) +{ + if ( !rDocument.hasModule( rLibName, rOldName ) ) + { + SAL_WARN( "basctl.basicide","basctl::RenameModule: old module name is invalid!" ); + return false; + } + + if ( rDocument.hasModule( rLibName, rNewName ) ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2))); + xError->run(); + return false; + } + + // #i74440 + if ( rNewName.isEmpty() ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME))); + xError->run(); + return false; + } + + if ( !rDocument.renameModule( rLibName, rOldName, rNewName ) ) + return false; + + Shell* pShell = GetShell(); + if (!pShell) + return true; + VclPtr<ModulWindow> pWin = pShell->FindBasWin(rDocument, rLibName, rNewName, false, true); + if (!pWin) + return true; + + // set new name in window + pWin->SetName( rNewName ); + + // set new module in module window + pWin->SetSbModule( pWin->GetBasic()->FindModule( rNewName ) ); + + // update tabwriter + sal_uInt16 nId = pShell->GetWindowId( pWin ); + SAL_WARN_IF( nId == 0 , "basctl.basicide", "No entry in Tabbar!"); + if ( nId ) + { + TabBar& rTabBar = pShell->GetTabBar(); + rTabBar.SetPageText(nId, rNewName); + rTabBar.Sort(); + rTabBar.MakeVisible(rTabBar.GetCurPageId()); + } + return true; +} + +namespace +{ + struct MacroExecutionData + { + ScriptDocument aDocument; + SbMethodRef xMethod; + + MacroExecutionData() + :aDocument( ScriptDocument::NoDocument ) + { + } + }; + + class MacroExecution + { + public: + DECL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, void*, void ); + }; + + IMPL_STATIC_LINK( MacroExecution, ExecuteMacroEvent, void*, p, void ) + { + MacroExecutionData* i_pData = static_cast<MacroExecutionData*>(p); + ENSURE_OR_RETURN_VOID( i_pData, "wrong MacroExecutionData" ); + // take ownership of the data + std::unique_ptr< MacroExecutionData > pData( i_pData ); + + SAL_WARN_IF( (pData->xMethod->GetParent()->GetFlags() & SbxFlagBits::ExtSearch) == SbxFlagBits::NONE, "basctl.basicide","No EXTSEARCH!" ); + + // in case this is a document-local macro, try to protect the document's Undo Manager from + // flawed scripts + std::optional< ::framework::DocumentUndoGuard > pUndoGuard; + if ( pData->aDocument.isDocument() ) + pUndoGuard.emplace( pData->aDocument.getDocument() ); + + RunMethod( pData->xMethod.get() ); + } +} + +OUString ChooseMacro(weld::Window* pParent, + const uno::Reference< frame::XModel >& rxLimitToDocument, + const uno::Reference< frame::XFrame >& xDocFrame, + bool bChooseOnly) +{ + EnsureIde(); + + GetExtraData()->ChoosingMacro() = true; + + OUString aScriptURL; + SbMethod* pMethod = nullptr; + + MacroChooser aChooser(pParent, xDocFrame); + if ( bChooseOnly || !SvtModuleOptions::IsBasicIDE() ) + aChooser.SetMode(MacroChooser::ChooseOnly); + + if ( !bChooseOnly && rxLimitToDocument.is() ) + { + // Hack! + aChooser.SetMode(MacroChooser::Recording); + } + + short nRetValue = aChooser.run(); + + GetExtraData()->ChoosingMacro() = false; + + switch ( nRetValue ) + { + case Macro_OkRun: + { + bool bError = false; + + pMethod = aChooser.GetMacro(); + if ( !pMethod && aChooser.GetMode() == MacroChooser::Recording ) + pMethod = aChooser.CreateMacro(); + + if ( !pMethod ) + break; + + SbModule* pModule = pMethod->GetModule(); + if ( !pModule ) + { + SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Module found!" ); + break; + } + + StarBASIC* pBasic = dynamic_cast<StarBASIC*>(pModule->GetParent()); + if ( !pBasic ) + { + SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No Basic found!" ); + break; + } + + BasicManager* pBasMgr = FindBasicManager( pBasic ); + if ( !pBasMgr ) + { + SAL_WARN( "basctl.basicide", "basctl::ChooseMacro: No BasicManager found!" ); + break; + } + + // name + OUString aName = pBasic->GetName() + "." + pModule->GetName() + "." + pMethod->GetName(); + + // location + OUString aLocation; + ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) ); + if ( aDocument.isDocument() ) + { + // document basic + aLocation = "document" ; + + if ( rxLimitToDocument.is() ) + { + uno::Reference< frame::XModel > xLimitToDocument( rxLimitToDocument ); + + uno::Reference< document::XEmbeddedScripts > xScripts( rxLimitToDocument, UNO_QUERY ); + if ( !xScripts.is() ) + { // the document itself does not support embedding scripts + uno::Reference< document::XScriptInvocationContext > xContext( rxLimitToDocument, UNO_QUERY ); + if ( xContext.is() ) + xScripts = xContext->getScriptContainer(); + if ( xScripts.is() ) + { // but it is able to refer to a document which actually does support this + xLimitToDocument.set( xScripts, UNO_QUERY ); + if ( !xLimitToDocument.is() ) + { + SAL_WARN_IF(!xLimitToDocument.is(), "basctl.basicide", "basctl::ChooseMacro: a script container which is no document!?" ); + xLimitToDocument = rxLimitToDocument; + } + } + } + + if ( xLimitToDocument != aDocument.getDocument() ) + { + // error + bError = true; + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(nullptr, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_ERRORCHOOSEMACRO))); + xError->run(); + } + } + } + else + { + // application basic + aLocation = "application" ; + } + + // script URL + if ( !bError ) + { + aScriptURL = "vnd.sun.star.script:" + aName + "?language=Basic&location=" + aLocation; + } + + if ( !rxLimitToDocument.is() ) + { + MacroExecutionData* pExecData = new MacroExecutionData; + pExecData->aDocument = aDocument; + pExecData->xMethod = pMethod; // keep alive until the event has been processed + Application::PostUserEvent( LINK( nullptr, MacroExecution, ExecuteMacroEvent ), pExecData ); + } + } + break; + } + + return aScriptURL; +} + +Sequence< OUString > GetMethodNames( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName ) +{ + Sequence< OUString > aSeqMethods; + + // get module + OUString aOUSource; + if ( rDocument.getModule( rLibName, rModName, aOUSource ) ) + { + BasicManager* pBasMgr = rDocument.getBasicManager(); + StarBASIC* pSb = pBasMgr ? pBasMgr->GetLib( rLibName ) : nullptr; + SbModule* pMod = pSb ? pSb->FindModule( rModName ) : nullptr; + + SbModuleRef xModule; + // Only reparse modules if ScriptDocument source is out of sync + // with basic's Module + if ( !pMod || pMod->GetSource32() != aOUSource ) + { + xModule = new SbModule( rModName ); + xModule->SetSource32( aOUSource ); + pMod = xModule.get(); + } + + sal_uInt32 nCount = pMod->GetMethods()->Count(); + sal_uInt32 nRealCount = nCount; + for ( sal_uInt32 i = 0; i < nCount; i++ ) + { + SbMethod* pMethod = static_cast<SbMethod*>(pMod->GetMethods()->Get(i)); + if( pMethod->IsHidden() ) + --nRealCount; + } + aSeqMethods.realloc( nRealCount ); + + sal_uInt32 iTarget = 0; + for ( sal_uInt32 i = 0 ; i < nCount; ++i ) + { + SbMethod* pMethod = static_cast<SbMethod*>(pMod->GetMethods()->Get(i)); + if( pMethod->IsHidden() ) + continue; + SAL_WARN_IF( !pMethod, "basctl.basicide","Method not found! (NULL)" ); + aSeqMethods.getArray()[ iTarget++ ] = pMethod->GetName(); + } + } + + return aSeqMethods; +} + +bool HasMethod ( + ScriptDocument const& rDocument, + OUString const& rLibName, + OUString const& rModName, + OUString const& rMethName +) +{ + bool bHasMethod = false; + + OUString aOUSource; + if ( rDocument.hasModule( rLibName, rModName ) && rDocument.getModule( rLibName, rModName, aOUSource ) ) + { + // Check if we really need to scan the source ( again ) + BasicManager* pBasMgr = rDocument.getBasicManager(); + StarBASIC* pSb = pBasMgr ? pBasMgr->GetLib( rLibName ) : nullptr; + SbModule* pMod = pSb ? pSb->FindModule( rModName ) : nullptr; + SbModuleRef xModule; + // Only reparse modules if ScriptDocument source is out of sync + // with basic's Module + if ( !pMod || pMod->GetSource32() != aOUSource ) + { + xModule = new SbModule( rModName ); + xModule->SetSource32( aOUSource ); + pMod = xModule.get(); + } + SbxArray* pMethods = pMod->GetMethods().get(); + if ( pMethods ) + { + SbMethod* pMethod = static_cast<SbMethod*>(pMethods->Find( rMethName, SbxClassType::Method )); + if ( pMethod && !pMethod->IsHidden() ) + bHasMethod = true; + } + } + + return bHasMethod; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/basobj3.cxx b/basctl/source/basicide/basobj3.cxx new file mode 100644 index 0000000000..4672cdd52c --- /dev/null +++ b/basctl/source/basicide/basobj3.cxx @@ -0,0 +1,466 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <vcl/errinf.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <basic/basmgr.hxx> +#include <basic/sbmeth.hxx> +#include <unotools/moduleoptions.hxx> + +#include <iderdll.hxx> +#include "iderdll2.hxx" +#include "basdoc.hxx" +#include <iderid.hxx> +#include <strings.hrc> + +#include <baside3.hxx> +#include <basidesh.hxx> +#include <basobj.hxx> +#include <localizationmgr.hxx> +#include <dlged.hxx> +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <sfx2/app.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/request.hxx> +#include <sfx2/viewfrm.hxx> +#include <sal/log.hxx> +#include <osl/diagnose.h> +#include <tools/debug.hxx> + +namespace basctl +{ + +using namespace comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::container; + +extern "C" { + SAL_DLLPUBLIC_EXPORT tools::Long basicide_handle_basic_error( void const * pPtr ) + { + return HandleBasicError( static_cast<StarBASIC const *>(pPtr) ); + } +} + +SbMethod* CreateMacro( SbModule* pModule, const OUString& rMacroName ) +{ + SfxDispatcher* pDispatcher = GetDispatcher(); + if( pDispatcher ) + { + pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES ); + } + + if ( pModule->FindMethod( rMacroName, SbxClassType::Method ) ) + return nullptr; + + OUString aMacroName( rMacroName ); + if ( aMacroName.isEmpty() ) + { + if (!pModule->GetMethods()->Count()) + aMacroName = "Main" ; + else + { + bool bValid = false; + sal_Int32 nMacro = 1; + while ( !bValid ) + { + aMacroName = "Macro" + OUString::number( nMacro ); + // test whether existing... + bValid = pModule->FindMethod( aMacroName, SbxClassType::Method ) == nullptr; + nMacro++; + } + } + } + + OUString aOUSource( pModule->GetSource32() ); + + // don't produce too many empty lines... + sal_Int32 nSourceLen = aOUSource.getLength(); + if ( nSourceLen > 2 ) + { + const sal_Unicode* pStr = aOUSource.getStr(); + if ( pStr[ nSourceLen - 1 ] != LINE_SEP ) + aOUSource += "\n\n" ; + else if ( pStr[ nSourceLen - 2 ] != LINE_SEP ) + aOUSource += "\n" ; + else if ( pStr[ nSourceLen - 3 ] == LINE_SEP ) + aOUSource = aOUSource.copy( 0, nSourceLen-1 ); + } + + aOUSource += "Sub " + aMacroName + "\n\nEnd Sub"; + + // update module in library + StarBASIC* pBasic = dynamic_cast<StarBASIC*>(pModule->GetParent()); + BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr; + SAL_WARN_IF(!pBasMgr, "basctl.basicide", "No BasicManager found!"); + ScriptDocument aDocument = pBasMgr + ? ScriptDocument::getDocumentForBasicManager(pBasMgr) + : ScriptDocument(ScriptDocument::NoDocument); + + if (aDocument.isValid()) + { + const OUString& aLibName = pBasic->GetName(); + const OUString& aModName = pModule->GetName(); + OSL_VERIFY( aDocument.updateModule( aLibName, aModName, aOUSource ) ); + } + + SbMethod* pMethod = pModule->FindMethod( aMacroName, SbxClassType::Method ); + + if( pDispatcher ) + { + pDispatcher->Execute( SID_BASICIDE_UPDATEALLMODULESOURCES ); + } + + if (aDocument.isAlive()) + MarkDocumentModified(aDocument); + + return pMethod; +} + +bool RenameDialog ( + weld::Widget* pErrorParent, + ScriptDocument const& rDocument, + OUString const& rLibName, + OUString const& rOldName, + OUString const& rNewName +) +{ + if ( !rDocument.hasDialog( rLibName, rOldName ) ) + { + OSL_FAIL( "basctl::RenameDialog: old module name is invalid!" ); + return false; + } + + if ( rDocument.hasDialog( rLibName, rNewName ) ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2))); + xError->run(); + return false; + } + + // #i74440 + if ( rNewName.isEmpty() ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pErrorParent, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME))); + xError->run(); + return false; + } + + Shell* pShell = GetShell(); + VclPtr<DialogWindow> pWin = pShell ? pShell->FindDlgWin(rDocument, rLibName, rOldName) : nullptr; + Reference< XNameContainer > xExistingDialog; + if ( pWin ) + xExistingDialog = pWin->GetEditor().GetDialog(); + + if ( xExistingDialog.is() ) + LocalizationMgr::renameStringResourceIDs( rDocument, rLibName, rNewName, xExistingDialog ); + + if ( !rDocument.renameDialog( rLibName, rOldName, rNewName, xExistingDialog ) ) + return false; + + if (!pWin || !pShell) + return true; + + // set new name in window + pWin->SetName( rNewName ); + + // update property browser + pWin->UpdateBrowser(); + + // update tabwriter + sal_uInt16 nId = pShell->GetWindowId( pWin ); + DBG_ASSERT( nId, "No entry in Tabbar!" ); + if ( nId ) + { + TabBar& rTabBar = pShell->GetTabBar(); + rTabBar.SetPageText( nId, rNewName ); + rTabBar.Sort(); + rTabBar.MakeVisible( rTabBar.GetCurPageId() ); + } + return true; +} + +bool RemoveDialog( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rDlgName ) +{ + if (Shell* pShell = GetShell()) + { + if (VclPtr<DialogWindow> pDlgWin = pShell->FindDlgWin(rDocument, rLibName, rDlgName)) + { + Reference< container::XNameContainer > xDialogModel = pDlgWin->GetDialog(); + LocalizationMgr::removeResourceForDialog( rDocument, rLibName, rDlgName, xDialogModel ); + } + } + + return rDocument.removeDialog( rLibName, rDlgName ); +} + +StarBASIC* FindBasic( const SbxVariable* pVar ) +{ + SbxVariable const* pSbx = pVar; + while (pSbx && !dynamic_cast<StarBASIC const*>(pSbx)) + pSbx = pSbx->GetParent(); + return const_cast<StarBASIC*>(static_cast<const StarBASIC*>(pSbx)); +} + +BasicManager* FindBasicManager( StarBASIC const * pLib ) +{ + ScriptDocuments aDocuments( ScriptDocument::getAllScriptDocuments( ScriptDocument::AllWithApplication ) ); + for (auto const& doc : aDocuments) + { + BasicManager* pBasicMgr = doc.getBasicManager(); + OSL_ENSURE( pBasicMgr, "basctl::FindBasicManager: no basic manager for the document!" ); + if ( !pBasicMgr ) + continue; + + Sequence< OUString > aLibNames( doc.getLibraryNames() ); + sal_Int32 nLibCount = aLibNames.getLength(); + const OUString* pLibNames = aLibNames.getConstArray(); + + for ( sal_Int32 i = 0 ; i < nLibCount ; i++ ) + { + StarBASIC* pL = pBasicMgr->GetLib( pLibNames[ i ] ); + if ( pL == pLib ) + return pBasicMgr; + } + } + return nullptr; +} + +void MarkDocumentModified( const ScriptDocument& rDocument ) +{ + Shell* pShell = GetShell(); + + // does not have to come from a document... + if ( rDocument.isApplication() ) + { + if (pShell) + pShell->SetAppBasicModified(true); + } + else + { + rDocument.setDocumentModified(); + } + + // tdf#130161 in all cases call UpdateObjectCatalog + if (pShell) + pShell->UpdateObjectCatalog(); + + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_SIGNATURE ); + pBindings->Invalidate( SID_SAVEDOC ); + pBindings->Update( SID_SAVEDOC ); + } +} + +void RunMethod( SbMethod const * pMethod ) +{ + SbxValues aRes; + aRes.eType = SbxVOID; + pMethod->Get( aRes ); +} + +void StopBasic() +{ + StarBASIC::Stop(); + if (Shell* pShell = GetShell()) + { + Shell::WindowTable& rWindows = pShell->GetWindowTable(); + for (auto const& window : rWindows) + { + BaseWindow* pWin = window.second; + // call BasicStopped manually because the Stop-Notify + // might not get through otherwise + pWin->BasicStopped(); + } + } + BasicStopped(); +} + +void BasicStopped( + bool* pbAppWindowDisabled, + bool* pbDispatcherLocked, + sal_uInt16* pnWaitCount, + SfxUInt16Item** ppSWActionCount, SfxUInt16Item** ppSWLockViewCount +) +{ + // maybe there are some locks to be removed after an error + // or an explicit cancelling of the basic... + if ( pbAppWindowDisabled ) + *pbAppWindowDisabled = false; + if ( pbDispatcherLocked ) + *pbDispatcherLocked = false; + if ( pnWaitCount ) + *pnWaitCount = 0; + if ( ppSWActionCount ) + *ppSWActionCount = nullptr; + if ( ppSWLockViewCount ) + *ppSWLockViewCount = nullptr; + + // AppWait? + if (Shell* pShell = GetShell()) + { + sal_uInt16 nWait = 0; + while ( pShell->GetViewFrame().GetWindow().IsWait() ) + { + pShell->GetViewFrame().GetWindow().LeaveWait(); + nWait++; + } + if ( pnWaitCount ) + *pnWaitCount = nWait; + } + + weld::Window* pDefParent = Application::GetDefDialogParent(); + if (pDefParent && !pDefParent->get_sensitive()) + { + pDefParent->set_sensitive(true); + if ( pbAppWindowDisabled ) + *pbAppWindowDisabled = true; + } + +} + +void InvalidateDebuggerSlots() +{ + SfxBindings* pBindings = GetBindingsPtr(); + if (!pBindings) + return; + + pBindings->Invalidate( SID_BASICSTOP ); + pBindings->Update( SID_BASICSTOP ); + pBindings->Invalidate( SID_BASICRUN ); + pBindings->Update( SID_BASICRUN ); + pBindings->Invalidate( SID_BASICCOMPILE ); + pBindings->Update( SID_BASICCOMPILE ); + pBindings->Invalidate( SID_BASICSTEPOVER ); + pBindings->Update( SID_BASICSTEPOVER ); + pBindings->Invalidate( SID_BASICSTEPINTO ); + pBindings->Update( SID_BASICSTEPINTO ); + pBindings->Invalidate( SID_BASICSTEPOUT ); + pBindings->Update( SID_BASICSTEPOUT ); + pBindings->Invalidate( SID_BASICIDE_TOGGLEBRKPNT ); + pBindings->Update( SID_BASICIDE_TOGGLEBRKPNT ); + pBindings->Invalidate( SID_BASICIDE_STAT_POS ); + pBindings->Update( SID_BASICIDE_STAT_POS ); + pBindings->Invalidate( SID_BASICIDE_STAT_TITLE ); + pBindings->Update( SID_BASICIDE_STAT_TITLE ); +} + +tools::Long HandleBasicError( StarBASIC const * pBasic ) +{ + EnsureIde(); + BasicStopped(); + + // no error output during macro choosing + if (GetExtraData()->ChoosingMacro()) + return 1; + if (GetExtraData()->ShellInCriticalSection()) + return 2; + + tools::Long nRet = 0; + Shell* pShell = nullptr; + if ( SvtModuleOptions::IsBasicIDE() ) + { + BasicManager* pBasMgr = FindBasicManager( pBasic ); + if ( pBasMgr ) + { + bool bProtected = false; + ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) ); + OSL_ENSURE( aDocument.isValid(), "basctl::HandleBasicError: no document for the given BasicManager!" ); + if ( aDocument.isValid() ) + { + const OUString& aOULibName( pBasic->GetName() ); + Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) ) + { + bProtected = true; + } + } + } + + if ( !bProtected ) + { + pShell = GetShell(); + if ( !pShell ) + { + SfxAllItemSet aArgs( SfxGetpApp()->GetPool() ); + SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs ); + SfxGetpApp()->ExecuteSlot( aRequest ); + pShell = GetShell(); + } + } + } + } + + if ( pShell ) + nRet = tools::Long(pShell->CallBasicErrorHdl( pBasic )); + else + ErrorHandler::HandleError( StarBASIC::GetErrorCode() ); + + return nRet; +} + +SfxBindings* GetBindingsPtr() +{ + SfxBindings* pBindings = nullptr; + + SfxViewFrame* pFrame = nullptr; + if (Shell* pShell = GetShell()) + { + pFrame = &pShell->GetViewFrame(); + } + else + { + SfxViewFrame* pView = SfxViewFrame::GetFirst(); + while ( pView ) + { + if (dynamic_cast<DocShell*>(pView->GetObjectShell())) + { + pFrame = pView; + break; + } + pView = SfxViewFrame::GetNext( *pView ); + } + } + if ( pFrame != nullptr ) + pBindings = &pFrame->GetBindings(); + + return pBindings; +} + +SfxDispatcher* GetDispatcher () +{ + if (Shell* pShell = GetShell()) + { + SfxViewFrame& rViewFrame = pShell->GetViewFrame(); + if (SfxDispatcher* pDispatcher = rViewFrame.GetDispatcher()) + return pDispatcher; + } + return nullptr; +} +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/bastype2.cxx b/basctl/source/basicide/bastype2.cxx new file mode 100644 index 0000000000..18ca75e01b --- /dev/null +++ b/basctl/source/basicide/bastype2.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 <basobj.hxx> +#include <bastypes.hxx> +#include <bastype2.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <iderid.hxx> +#include <tools/urlobj.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <svtools/imagemgr.hxx> +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <com/sun/star/frame/ModuleManager.hpp> +#include <comphelper/processfactory.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/sfxsids.hrc> +#include <svl/itemset.hxx> + +#include <initializer_list> +#include <memory> +#include <string_view> + +#include <com/sun/star/script/ModuleType.hpp> +#include <com/sun/star/script/vba/XVBAModuleInfo.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <utility> + +namespace basctl +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +void ModuleInfoHelper::getObjectName( const uno::Reference< container::XNameContainer >& rLib, const OUString& rModName, OUString& rObjName ) +{ + try + { + uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( rLib, uno::UNO_QUERY ); + if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( rModName ) ) + { + script::ModuleInfo aModuleInfo = xVBAModuleInfo->getModuleInfo( rModName ); + uno::Any aObject( aModuleInfo.ModuleObject ); + uno::Reference< lang::XServiceInfo > xServiceInfo( aObject, uno::UNO_QUERY ); + if( xServiceInfo.is() && xServiceInfo->supportsService( "ooo.vba.excel.Worksheet" ) ) + { + uno::Reference< container::XNamed > xNamed( aObject, uno::UNO_QUERY ); + if( xNamed.is() ) + rObjName = xNamed->getName(); + } + } + } + catch(const uno::Exception& ) + { + } +} + +sal_Int32 ModuleInfoHelper::getModuleType( const uno::Reference< container::XNameContainer >& rLib, const OUString& rModName ) +{ + sal_Int32 nType = script::ModuleType::NORMAL; + uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( rLib, uno::UNO_QUERY ); + if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( rModName ) ) + { + script::ModuleInfo aModuleInfo = xVBAModuleInfo->getModuleInfo( rModName ); + nType = aModuleInfo.ModuleType; + } + return nType; +} + +Entry::~Entry() +{ } + +DocumentEntry::DocumentEntry ( + ScriptDocument aDocument, + LibraryLocation eLocation, + EntryType eType +) : + Entry(eType), + m_aDocument(std::move(aDocument)), + m_eLocation(eLocation) +{ + OSL_ENSURE( m_aDocument.isValid(), "DocumentEntry::DocumentEntry: illegal document!" ); +} + +DocumentEntry::~DocumentEntry() +{ } + +LibEntry::LibEntry ( + ScriptDocument const& rDocument, + LibraryLocation eLocation, + OUString aLibName +) : + DocumentEntry(rDocument, eLocation, OBJ_TYPE_LIBRARY), + m_aLibName(std::move(aLibName)) +{ } + +LibEntry::~LibEntry() +{ } + +EntryDescriptor::EntryDescriptor () : + m_aDocument(ScriptDocument::getApplicationScriptDocument()), + m_eLocation(LIBRARY_LOCATION_UNKNOWN), + m_eType(OBJ_TYPE_UNKNOWN) +{ } + +EntryDescriptor::EntryDescriptor ( + ScriptDocument aDocument, + LibraryLocation eLocation, + OUString aLibName, + OUString aLibSubName, + OUString aName, + EntryType eType +) : + m_aDocument(std::move(aDocument)), + m_eLocation(eLocation), + m_aLibName(std::move(aLibName)), + m_aLibSubName(std::move(aLibSubName)), + m_aName(std::move(aName)), + m_eType(eType) +{ + OSL_ENSURE( m_aDocument.isValid(), "EntryDescriptor::EntryDescriptor: invalid document!" ); +} + +EntryDescriptor::EntryDescriptor ( + ScriptDocument aDocument, + LibraryLocation eLocation, + OUString aLibName, + OUString aLibSubName, + OUString aName, + OUString aMethodName, + EntryType eType +) : + m_aDocument(std::move(aDocument)), + m_eLocation(eLocation), + m_aLibName(std::move(aLibName)), + m_aLibSubName(std::move(aLibSubName)), + m_aName(std::move(aName)), + m_aMethodName(std::move(aMethodName)), + m_eType(eType) +{ + OSL_ENSURE( m_aDocument.isValid(), "EntryDescriptor::EntryDescriptor: invalid document!" ); +} + +SbTreeListBox::SbTreeListBox(std::unique_ptr<weld::TreeView> xControl, weld::Window* pTopLevel) + : m_xControl(std::move(xControl)) + , m_xScratchIter(m_xControl->make_iterator()) + , m_pTopLevel(pTopLevel) + , m_bFreezeOnFirstAddRemove(false) + , m_aNotifier(*this) +{ + m_xControl->connect_row_activated(LINK(this, SbTreeListBox, OpenCurrentHdl)); + m_xControl->connect_expanding(LINK(this, SbTreeListBox, RequestingChildrenHdl)); + nMode = BrowseMode::All; // everything +} + +SbTreeListBox::~SbTreeListBox() +{ + m_aNotifier.dispose(); + + bool bValidIter = m_xControl->get_iter_first(*m_xScratchIter); + while (bValidIter) + { + Entry* pBasicEntry = weld::fromId<Entry*>(m_xControl->get_id(*m_xScratchIter)); + delete pBasicEntry; + bValidIter = m_xControl->iter_next(*m_xScratchIter); + } +} + +void SbTreeListBox::ScanEntry( const ScriptDocument& rDocument, LibraryLocation eLocation ) +{ + OSL_ENSURE( rDocument.isAlive(), "TreeListBox::ScanEntry: illegal document!" ); + if ( !rDocument.isAlive() ) + return; + + // can be called multiple times for updating! + + // actually test if basic's in the tree already?! + // level 1: BasicManager (application, document, ...) + bool bDocumentRootEntry = FindRootEntry(rDocument, eLocation, *m_xScratchIter); + if (bDocumentRootEntry && m_xControl->get_row_expanded(*m_xScratchIter)) + ImpCreateLibEntries(*m_xScratchIter, rDocument, eLocation); + if (!bDocumentRootEntry) + { + OUString aRootName(GetRootEntryName(rDocument, eLocation)); + OUString aImage(GetRootEntryBitmaps(rDocument)); + AddEntry(aRootName, aImage, nullptr, true, std::make_unique<DocumentEntry>(rDocument, eLocation)); + } +} + +void SbTreeListBox::ImpCreateLibEntries(const weld::TreeIter& rIter, const ScriptDocument& rDocument, LibraryLocation eLocation) +{ + // get a sorted list of library names + Sequence< OUString > aLibNames( rDocument.getLibraryNames() ); + sal_Int32 nLibCount = aLibNames.getLength(); + const OUString* pLibNames = aLibNames.getConstArray(); + + for ( sal_Int32 i = 0 ; i < nLibCount ; i++ ) + { + OUString aLibName = pLibNames[ i ]; + + if ( eLocation == rDocument.getLibraryLocation( aLibName ) ) + { + // check, if the module library is loaded + bool bModLibLoaded = false; + Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryLoaded( aLibName ) ) + bModLibLoaded = true; + + // check, if the dialog library is loaded + bool bDlgLibLoaded = false; + Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) ); + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryLoaded( aLibName ) ) + bDlgLibLoaded = true; + + bool bLoaded = bModLibLoaded || bDlgLibLoaded; + + // if only one of the libraries is loaded, load also the other + if ( bLoaded ) + { + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) ) + xModLibContainer->loadLibrary( aLibName ); + + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && !xDlgLibContainer->isLibraryLoaded( aLibName ) ) + xDlgLibContainer->loadLibrary( aLibName ); + } + + // create tree list box entry + OUString sId; + if ( ( nMode & BrowseMode::Dialogs ) && !( nMode & BrowseMode::Modules ) ) + sId = bLoaded ? RID_BMP_DLGLIB : RID_BMP_DLGLIBNOTLOADED; + else + sId = bLoaded ? RID_BMP_MODLIB : RID_BMP_MODLIBNOTLOADED; + std::unique_ptr<weld::TreeIter> xLibRootEntry(m_xControl->make_iterator(&rIter)); + bool bLibRootEntry = FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xLibRootEntry); + if (bLibRootEntry) + { + SetEntryBitmaps(*xLibRootEntry, sId); + bool bRowExpanded = m_xControl->get_row_expanded(*xLibRootEntry); + bool bRowExpandAttempted = !m_xControl->get_children_on_demand(*xLibRootEntry); + if (bRowExpanded || bRowExpandAttempted) + ImpCreateLibSubEntries(*xLibRootEntry, rDocument, aLibName); + } + else + { + AddEntry(aLibName, sId, &rIter, true, std::make_unique<Entry>(OBJ_TYPE_LIBRARY)); + } + } + } +} + +void SbTreeListBox::ImpCreateLibSubEntries(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName) +{ + // modules + if ( nMode & BrowseMode::Modules ) + { + Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) ); + + if ( xModLibContainer.is() && xModLibContainer->hasByName( rLibName ) && xModLibContainer->isLibraryLoaded( rLibName ) ) + { + try + { + if( rDocument.isInVBAMode() ) + { + ImpCreateLibSubEntriesInVBAMode(rLibRootEntry, rDocument, rLibName); + } + else + { + // get a sorted list of module names + Sequence< OUString > aModNames = rDocument.getObjectNames( E_SCRIPTS, rLibName ); + sal_Int32 nModCount = aModNames.getLength(); + const OUString* pModNames = aModNames.getConstArray(); + + auto xTreeIter = m_xControl->make_iterator(); + + for ( sal_Int32 i = 0 ; i < nModCount ; i++ ) + { + OUString aModName = pModNames[ i ]; + m_xControl->copy_iterator(rLibRootEntry, *xTreeIter); + bool bModuleEntry = FindEntry(aModName, OBJ_TYPE_MODULE, *xTreeIter); + if (!bModuleEntry) + { + AddEntry(aModName, RID_BMP_MODULE, &rLibRootEntry, false, std::make_unique<Entry>(OBJ_TYPE_MODULE), xTreeIter.get()); + } + + // methods + if ( nMode & BrowseMode::Subs ) + { + Sequence< OUString > aNames = GetMethodNames( rDocument, rLibName, aModName ); + sal_Int32 nCount = aNames.getLength(); + const OUString* pNames = aNames.getConstArray(); + + auto xSubTreeIter = m_xControl->make_iterator(); + + for ( sal_Int32 j = 0 ; j < nCount ; j++ ) + { + OUString aName = pNames[ j ]; + m_xControl->copy_iterator(*xTreeIter, *xSubTreeIter); + bool bEntry = FindEntry(aName, OBJ_TYPE_METHOD, *xSubTreeIter); + if (!bEntry) + { + AddEntry(aName, RID_BMP_MACRO, xTreeIter.get(), false, std::make_unique<Entry>(OBJ_TYPE_METHOD)); + } + } + } + } + } + } + catch ( const container::NoSuchElementException& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + } + + // dialogs + if ( !(nMode & BrowseMode::Dialogs) ) + return; + + Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) ); + + if ( !(xDlgLibContainer.is() && xDlgLibContainer->hasByName( rLibName ) && xDlgLibContainer->isLibraryLoaded( rLibName )) ) + return; + + try + { + // get a sorted list of dialog names + Sequence< OUString > aDlgNames( rDocument.getObjectNames( E_DIALOGS, rLibName ) ); + sal_Int32 nDlgCount = aDlgNames.getLength(); + const OUString* pDlgNames = aDlgNames.getConstArray(); + + auto xTreeIter = m_xControl->make_iterator(); + + for ( sal_Int32 i = 0 ; i < nDlgCount ; i++ ) + { + OUString aDlgName = pDlgNames[ i ]; + m_xControl->copy_iterator(rLibRootEntry, *xTreeIter); + bool bDialogEntry = FindEntry(aDlgName, OBJ_TYPE_DIALOG, *xTreeIter); + if (!bDialogEntry) + { + AddEntry(aDlgName, RID_BMP_DIALOG, &rLibRootEntry, false, std::make_unique<Entry>(OBJ_TYPE_DIALOG)); + } + } + } + catch (const container::NoSuchElementException& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } +} + +void SbTreeListBox::ImpCreateLibSubEntriesInVBAMode(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName ) +{ + auto const aEntries = { + std::make_pair( OBJ_TYPE_DOCUMENT_OBJECTS, IDEResId(RID_STR_DOCUMENT_OBJECTS) ), + std::make_pair( OBJ_TYPE_USERFORMS, IDEResId(RID_STR_USERFORMS) ), + std::make_pair( OBJ_TYPE_NORMAL_MODULES, IDEResId(RID_STR_NORMAL_MODULES) ), + std::make_pair( OBJ_TYPE_CLASS_MODULES, IDEResId(RID_STR_CLASS_MODULES) ) }; + for( auto const & iter: aEntries ) + { + EntryType eType = iter.first; + OUString const & aEntryName = iter.second; + std::unique_ptr<weld::TreeIter> xLibSubRootEntry(m_xControl->make_iterator(&rLibRootEntry)); + bool bLibSubRootEntry = FindEntry(aEntryName, eType, *xLibSubRootEntry); + if (bLibSubRootEntry) + { + SetEntryBitmaps(*xLibSubRootEntry, RID_BMP_MODLIB); + if (m_xControl->get_row_expanded(*xLibSubRootEntry)) + ImpCreateLibSubSubEntriesInVBAMode(*xLibSubRootEntry, rDocument, rLibName); + } + else + { + m_xControl->copy_iterator(rLibRootEntry, *xLibSubRootEntry); + AddEntry(aEntryName, RID_BMP_MODLIB, xLibSubRootEntry.get(), true, std::make_unique<Entry>(eType)); + } + } +} + +void SbTreeListBox::ImpCreateLibSubSubEntriesInVBAMode(const weld::TreeIter& rLibSubRootEntry, const ScriptDocument& rDocument, const OUString& rLibName) +{ + uno::Reference< container::XNameContainer > xLib = rDocument.getOrCreateLibrary( E_SCRIPTS, rLibName ); + if( !xLib.is() ) + return; + + try + { + // get a sorted list of module names + Sequence< OUString > aModNames = rDocument.getObjectNames( E_SCRIPTS, rLibName ); + sal_Int32 nModCount = aModNames.getLength(); + const OUString* pModNames = aModNames.getConstArray(); + + EntryDescriptor aDesc(GetEntryDescriptor(&rLibSubRootEntry)); + EntryType eCurrentType(aDesc.GetType()); + + for ( sal_Int32 i = 0 ; i < nModCount ; i++ ) + { + OUString aModName = pModNames[ i ]; + EntryType eType = OBJ_TYPE_UNKNOWN; + switch( ModuleInfoHelper::getModuleType( xLib, aModName ) ) + { + case script::ModuleType::DOCUMENT: + eType = OBJ_TYPE_DOCUMENT_OBJECTS; + break; + case script::ModuleType::FORM: + eType = OBJ_TYPE_USERFORMS; + break; + case script::ModuleType::NORMAL: + eType = OBJ_TYPE_NORMAL_MODULES; + break; + case script::ModuleType::CLASS: + eType = OBJ_TYPE_CLASS_MODULES; + break; + } + if( eType != eCurrentType ) + continue; + + // display a nice friendly name in the ObjectModule tab, + // combining the objectname and module name, e.g. Sheet1 ( Financials ) + OUString aEntryName = aModName; + if( eType == OBJ_TYPE_DOCUMENT_OBJECTS ) + { + OUString sObjName; + ModuleInfoHelper::getObjectName( xLib, aModName, sObjName ); + if( !sObjName.isEmpty() ) + { + aEntryName += " (" + sObjName + ")"; + } + } + std::unique_ptr<weld::TreeIter> xModuleEntry(m_xControl->make_iterator(&rLibSubRootEntry)); + bool bModuleEntry = FindEntry(aEntryName, OBJ_TYPE_MODULE, *xModuleEntry); + if (!bModuleEntry) + { + m_xControl->copy_iterator(rLibSubRootEntry, *xModuleEntry); + AddEntry(aEntryName, RID_BMP_MODULE, xModuleEntry.get(), false, + std::make_unique<Entry>(OBJ_TYPE_MODULE)); + } + + // methods + if ( nMode & BrowseMode::Subs ) + { + Sequence< OUString > aNames = GetMethodNames( rDocument, rLibName, aModName ); + sal_Int32 nCount = aNames.getLength(); + const OUString* pNames = aNames.getConstArray(); + + for ( sal_Int32 j = 0 ; j < nCount ; j++ ) + { + OUString aName = pNames[ j ]; + std::unique_ptr<weld::TreeIter> xEntry(m_xControl->make_iterator(xModuleEntry.get())); + bool bEntry = FindEntry(aName, OBJ_TYPE_METHOD, *xEntry); + if (!bEntry) + { + AddEntry(aName, RID_BMP_MACRO, xModuleEntry.get(), false, std::make_unique<Entry>(OBJ_TYPE_METHOD)); + } + } + } + } + } + catch ( const container::NoSuchElementException& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } +} + +bool SbTreeListBox::ImpFindEntry(weld::TreeIter& rIter, std::u16string_view rText) +{ + bool bValidIter = m_xControl->iter_children(rIter); + while (bValidIter) + { + if (rText == m_xControl->get_text(rIter)) + return true; + bValidIter = m_xControl->iter_next_sibling(rIter); + } + return false; +} + +void SbTreeListBox::onDocumentCreated( const ScriptDocument& /*_rDocument*/ ) +{ + UpdateEntries(); +} + +void SbTreeListBox::onDocumentOpened( const ScriptDocument& /*_rDocument*/ ) +{ + UpdateEntries(); +} + +void SbTreeListBox::onDocumentSave( const ScriptDocument& /*_rDocument*/ ) +{ + // not interested in +} + +void SbTreeListBox::onDocumentSaveDone( const ScriptDocument& /*_rDocument*/ ) +{ + // not interested in +} + +void SbTreeListBox::onDocumentSaveAs( const ScriptDocument& /*_rDocument*/ ) +{ + // not interested in +} + +void SbTreeListBox::onDocumentSaveAsDone( const ScriptDocument& /*_rDocument*/ ) +{ + UpdateEntries(); +} + +void SbTreeListBox::onDocumentClosed( const ScriptDocument& rDocument ) +{ + UpdateEntries(); + // The document is not yet actually deleted, so we need to remove its entry + // manually. + RemoveEntry(rDocument); +} + +void SbTreeListBox::onDocumentTitleChanged( const ScriptDocument& /*_rDocument*/ ) +{ + // not interested in +} + +void SbTreeListBox::onDocumentModeChanged( const ScriptDocument& /*_rDocument*/ ) +{ + // not interested in +} + +void SbTreeListBox::UpdateEntries() +{ + bool bValidIter = m_xControl->get_selected(m_xScratchIter.get()); + EntryDescriptor aCurDesc(GetEntryDescriptor(bValidIter ? m_xScratchIter.get() : nullptr)); + + // removing the invalid entries + std::unique_ptr<weld::TreeIter> xLastValid(m_xControl->make_iterator(nullptr)); + bool bLastValid = false; + bValidIter = m_xControl->get_iter_first(*m_xScratchIter); + while (bValidIter) + { + if (IsValidEntry(*m_xScratchIter)) + { + m_xControl->copy_iterator(*m_xScratchIter, *xLastValid); + bLastValid = true; + } + else + RemoveEntry(*m_xScratchIter); + if (bLastValid) + { + m_xControl->copy_iterator(*xLastValid, *m_xScratchIter); + bValidIter = m_xControl->iter_next(*m_xScratchIter); + } + else + bValidIter = m_xControl->get_iter_first(*m_xScratchIter); + } + + ScanAllEntries(); + + SetCurrentEntry( aCurDesc ); +} + +// Removes the entry from the tree. +void SbTreeListBox::RemoveEntry(const weld::TreeIter& rIter) +{ + if (m_bFreezeOnFirstAddRemove) + { + m_xControl->freeze(); + m_bFreezeOnFirstAddRemove = false; + } + + // removing the associated user data + Entry* pBasicEntry = weld::fromId<Entry*>(m_xControl->get_id(rIter)); + delete pBasicEntry; + // removing the entry + m_xControl->remove(rIter); +} + +// Removes the entry of rDocument. +void SbTreeListBox::RemoveEntry (ScriptDocument const& rDocument) +{ + // finding the entry of rDocument + bool bValidIter = m_xControl->get_iter_first(*m_xScratchIter); + while (bValidIter) + { + if (rDocument == GetEntryDescriptor(m_xScratchIter.get()).GetDocument()) + { + RemoveEntry(*m_xScratchIter); + break; + } + bValidIter = m_xControl->iter_next(*m_xScratchIter); + } +} + +bool SbTreeListBox::FindEntry(std::u16string_view rText, EntryType eType, weld::TreeIter& rIter) +{ + bool bValidIter = m_xControl->iter_children(rIter); + while (bValidIter) + { + Entry* pBasicEntry = weld::fromId<Entry*>(m_xControl->get_id(rIter)); + assert(pBasicEntry && "FindEntry: no Entry ?!"); + if (pBasicEntry->GetType() == eType && rText == m_xControl->get_text(rIter)) + return true; + bValidIter = m_xControl->iter_next_sibling(rIter); + } + return false; +} + +bool SbTreeListBox::IsEntryProtected(const weld::TreeIter* pEntry) +{ + bool bProtected = false; + if (pEntry && m_xControl->get_iter_depth(*pEntry) == 1) + { + EntryDescriptor aDesc(GetEntryDescriptor(pEntry)); + const ScriptDocument& rDocument( aDesc.GetDocument() ); + OSL_ENSURE( rDocument.isAlive(), "TreeListBox::IsEntryProtected: no document, or document is dead!" ); + if ( rDocument.isAlive() ) + { + const OUString& aOULibName( aDesc.GetLibName() ); + Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) ) + { + bProtected = true; + } + } + } + } + return bProtected; +} + +void SbTreeListBox::AddEntry( + const OUString& rText, + const OUString& rImage, + const weld::TreeIter* pParent, + bool bChildrenOnDemand, + std::unique_ptr<Entry>&& rUserData, + weld::TreeIter* pRet) +{ + if (m_bFreezeOnFirstAddRemove) + { + m_xControl->freeze(); + m_bFreezeOnFirstAddRemove= false; + } + std::unique_ptr<weld::TreeIter> xScratch = pRet ? nullptr : m_xControl->make_iterator(); + if (!pRet) + pRet = xScratch.get(); + OUString sId(weld::toId(rUserData.release())); + m_xControl->insert(pParent, -1, &rText, &sId, nullptr, nullptr, bChildrenOnDemand, pRet); + m_xControl->set_image(*pRet, rImage); +} + +void SbTreeListBox::SetEntryBitmaps(const weld::TreeIter& rIter, const OUString& rImage) +{ + m_xControl->set_image(rIter, rImage, -1); +} + +LibraryType SbTreeListBox::GetLibraryType() const +{ + LibraryType eType = LibraryType::All; + if ( ( nMode & BrowseMode::Modules ) && !( nMode & BrowseMode::Dialogs ) ) + eType = LibraryType::Module; + else if ( !( nMode & BrowseMode::Modules ) && ( nMode & BrowseMode::Dialogs ) ) + eType = LibraryType::Dialog; + return eType; +} + +OUString SbTreeListBox::GetRootEntryName( const ScriptDocument& rDocument, LibraryLocation eLocation ) const +{ + return rDocument.getTitle( eLocation, GetLibraryType() ); +} + +OUString SbTreeListBox::GetRootEntryBitmaps(const ScriptDocument& rDocument) +{ + OSL_ENSURE( rDocument.isValid(), "TreeListBox::GetRootEntryBitmaps: illegal document!" ); + if (!rDocument.isValid()) + return OUString(); + + if ( rDocument.isDocument() ) + { + OUString sFactoryURL; + Reference<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext() ); + Reference< frame::XModuleManager2 > xModuleManager( frame::ModuleManager::create(xContext) ); + try + { + OUString sModule( xModuleManager->identify( rDocument.getDocument() ) ); + Sequence< beans::PropertyValue > aModuleDescr; + xModuleManager->getByName( sModule ) >>= aModuleDescr; + sal_Int32 nCount = aModuleDescr.getLength(); + const beans::PropertyValue* pModuleDescr = aModuleDescr.getConstArray(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + { + if ( pModuleDescr[ i ].Name == "ooSetupFactoryEmptyDocumentURL" ) + { + pModuleDescr[ i ].Value >>= sFactoryURL; + break; + } + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + if ( !sFactoryURL.isEmpty() ) + { + return SvFileInformationManager::GetFileImageId(INetURLObject(sFactoryURL)); + } + else + { + // default icon + return RID_BMP_DOCUMENT; + } + } + return RID_BMP_INSTALLATION; +} + +void SbTreeListBox::SetCurrentEntry (EntryDescriptor const & rDesc) +{ + bool bCurEntry = false; + auto xCurIter = m_xControl->make_iterator(); + EntryDescriptor aDesc = rDesc; + if ( aDesc.GetType() == OBJ_TYPE_UNKNOWN ) + { + aDesc = EntryDescriptor( + ScriptDocument::getApplicationScriptDocument(), + LIBRARY_LOCATION_USER, "Standard", + OUString(), ".", OBJ_TYPE_UNKNOWN + ); + } + ScriptDocument aDocument = aDesc.GetDocument(); + OSL_ENSURE( aDocument.isValid(), "TreeListBox::SetCurrentEntry: invalid document!" ); + LibraryLocation eLocation = aDesc.GetLocation(); + bool bRootEntry = FindRootEntry(aDocument, eLocation, *m_xScratchIter); + if (bRootEntry) + { + m_xControl->copy_iterator(*m_xScratchIter, *xCurIter); + bCurEntry = true; + const OUString& aLibName( aDesc.GetLibName() ); + if ( !aLibName.isEmpty() ) + { + m_xControl->expand_row(*m_xScratchIter); + auto xLibIter = m_xControl->make_iterator(m_xScratchIter.get()); + bool bLibEntry = FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xLibIter); + if (bLibEntry) + { + m_xControl->copy_iterator(*xLibIter, *xCurIter); + const OUString& aLibSubName( aDesc.GetLibSubName() ); + if( !aLibSubName.isEmpty() ) + { + m_xControl->expand_row(*xLibIter); + auto xSubLibIter = m_xControl->make_iterator(xLibIter.get()); + bool bSubLibEntry = ImpFindEntry(*xSubLibIter, aLibSubName); + if (bSubLibEntry) + { + m_xControl->copy_iterator(*xSubLibIter, *xCurIter); + } + } + const OUString& aName( aDesc.GetName() ); + if ( !aName.isEmpty() ) + { + m_xControl->expand_row(*xCurIter); + EntryType eType = OBJ_TYPE_MODULE; + if ( aDesc.GetType() == OBJ_TYPE_DIALOG ) + eType = OBJ_TYPE_DIALOG; + auto xEntryIter = m_xControl->make_iterator(xCurIter.get()); + bool bEntry = FindEntry(aName, eType, *xEntryIter); + if (bEntry) + { + m_xControl->copy_iterator(*xEntryIter, *xCurIter); + const OUString& aMethodName( aDesc.GetMethodName() ); + if (!aMethodName.isEmpty()) + { + m_xControl->expand_row(*xCurIter); + auto xSubEntryIter = m_xControl->make_iterator(xCurIter.get()); + bool bSubEntry = FindEntry(aMethodName, OBJ_TYPE_METHOD, *xSubEntryIter); + if (bSubEntry) + { + m_xControl->copy_iterator(*xSubEntryIter, *xCurIter); + } + else + { + m_xControl->copy_iterator(*xCurIter, *xSubEntryIter); + if (m_xControl->iter_children(*xSubEntryIter)) + m_xControl->copy_iterator(*xSubEntryIter, *xCurIter); + } + } + } + else + { + auto xSubEntryIter = m_xControl->make_iterator(xCurIter.get()); + if (m_xControl->iter_children(*xSubEntryIter)) + m_xControl->copy_iterator(*xSubEntryIter, *xCurIter); + } + } + } + else + { + auto xSubLibIter = m_xControl->make_iterator(m_xScratchIter.get()); + if (m_xControl->iter_children(*xSubLibIter)) + m_xControl->copy_iterator(*xLibIter, *xCurIter); + } + } + } + else + { + bCurEntry = m_xControl->get_iter_first(*xCurIter); + } + + if (!bCurEntry) + return; + + m_xControl->set_cursor(*xCurIter); +} + +IMPL_LINK_NOARG(SbTreeListBox, OpenCurrentHdl, weld::TreeView&, bool) +{ + bool bValidIter = m_xControl->get_cursor(m_xScratchIter.get()); + if (!bValidIter) + return true; + if (!m_xControl->get_row_expanded(*m_xScratchIter)) + m_xControl->expand_row(*m_xScratchIter); + else + m_xControl->collapse_row(*m_xScratchIter); + + EntryDescriptor aDesc = GetEntryDescriptor(m_xScratchIter.get()); + switch (aDesc.GetType()) + { + case OBJ_TYPE_METHOD: + case OBJ_TYPE_MODULE: + case OBJ_TYPE_DIALOG: + if (SfxDispatcher* pDispatcher = GetDispatcher()) + { + SbxItem aSbxItem( + SID_BASICIDE_ARG_SBX, aDesc.GetDocument(), + aDesc.GetLibName(), aDesc.GetName(), aDesc.GetMethodName(), + ConvertType(aDesc.GetType()) + ); + pDispatcher->ExecuteList( + SID_BASICIDE_SHOWSBX, SfxCallMode::SYNCHRON, + { &aSbxItem } + ); + } + break; + + default: + break; + } + return true; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/bastype3.cxx b/basctl/source/basicide/bastype3.cxx new file mode 100644 index 0000000000..d26ae83252 --- /dev/null +++ b/basctl/source/basicide/bastype3.cxx @@ -0,0 +1,440 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <basic/basmgr.hxx> +#include <basic/sbmod.hxx> +#include <basobj.hxx> +#include <bastype2.hxx> +#include <bitmaps.hlst> +#include <bastypes.hxx> +#include <com/sun/star/script/XLibraryContainer.hpp> +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <string_view> +#include <osl/diagnose.h> +#include <tools/debug.hxx> + +namespace basctl +{ + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +IMPL_LINK(SbTreeListBox, RequestingChildrenHdl, const weld::TreeIter&, rEntry, bool) +{ + EntryDescriptor aDesc = GetEntryDescriptor(&rEntry); + const ScriptDocument& aDocument = aDesc.GetDocument(); + OSL_ENSURE( aDocument.isAlive(), "basctl::TreeListBox::RequestingChildren: invalid document!" ); + if (!aDocument.isAlive()) + return false; + + LibraryLocation eLocation = aDesc.GetLocation(); + EntryType eType = aDesc.GetType(); + + if ( eType == OBJ_TYPE_DOCUMENT ) + { + ImpCreateLibEntries( rEntry, aDocument, eLocation ); + } + else if ( eType == OBJ_TYPE_LIBRARY ) + { + const OUString& aOULibName( aDesc.GetLibName() ); + + // check password + bool bOK = true; + Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) ) + { + OUString aPassword; + bOK = QueryPassword(m_pTopLevel, xModLibContainer, aOULibName, aPassword); + } + } + + if ( bOK ) + { + // load module library + bool bModLibLoaded = false; + if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) ) + { + if ( !xModLibContainer->isLibraryLoaded( aOULibName ) ) + { + weld::WaitObject aWait(m_pTopLevel); + xModLibContainer->loadLibrary( aOULibName ); + } + bModLibLoaded = xModLibContainer->isLibraryLoaded( aOULibName ); + } + + // load dialog library + bool bDlgLibLoaded = false; + Reference< script::XLibraryContainer > xDlgLibContainer = aDocument.getLibraryContainer( E_DIALOGS ); + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) ) + { + if ( !xDlgLibContainer->isLibraryLoaded( aOULibName ) ) + { + weld::WaitObject aWait(m_pTopLevel); + xDlgLibContainer->loadLibrary( aOULibName ); + } + bDlgLibLoaded = xDlgLibContainer->isLibraryLoaded( aOULibName ); + } + + if ( bModLibLoaded || bDlgLibLoaded ) + { + // create the sub entries + ImpCreateLibSubEntries( rEntry, aDocument, aOULibName ); + + // exchange image + const bool bDlgMode = (nMode & BrowseMode::Dialogs) && !(nMode & BrowseMode::Modules); + auto const aImage(bDlgMode ? RID_BMP_DLGLIB : RID_BMP_MODLIB); + SetEntryBitmaps(rEntry, aImage); + } + else + { + OSL_FAIL( "basctl::TreeListBox::RequestingChildren: Error loading library!" ); + } + } + } + else if ( eType == OBJ_TYPE_DOCUMENT_OBJECTS + || eType == OBJ_TYPE_USERFORMS + || eType == OBJ_TYPE_NORMAL_MODULES + || eType == OBJ_TYPE_CLASS_MODULES ) + { + const OUString& aLibName( aDesc.GetLibName() ); + ImpCreateLibSubSubEntriesInVBAMode( rEntry, aDocument, aLibName ); + } + + return true; +} + +void SbTreeListBox::ScanAllEntries() +{ + // instead of always freezing, freeze on the first add/remove, which keeps gtk + // from relayouting the tree if it's not necessary + m_bFreezeOnFirstAddRemove = true; + + ScanEntry( ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_USER ); + ScanEntry( ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_SHARE ); + + ScriptDocuments aDocuments( ScriptDocument::getAllScriptDocuments( ScriptDocument::DocumentsSorted ) ); + for (auto const& doc : aDocuments) + { + if ( doc.isAlive() ) + ScanEntry(doc, LIBRARY_LOCATION_DOCUMENT); + } + + if (!m_bFreezeOnFirstAddRemove) + m_xControl->thaw(); // m_bFreezeOnFirstAddRemove was changed, so control was frozen + else + m_bFreezeOnFirstAddRemove = false; +} + +SbxVariable* SbTreeListBox::FindVariable(const weld::TreeIter* pEntry) +{ + if ( !pEntry ) + return nullptr; + + ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() ); + std::unique_ptr<weld::TreeIter> xIter(m_xControl->make_iterator(pEntry)); + std::vector<std::pair<Entry*, OUString>> aEntries; + bool bValidIter = true; + do + { + sal_uInt16 nDepth = m_xControl->get_iter_depth(*xIter); + Entry* pBE = weld::fromId<Entry*>(m_xControl->get_id(*xIter)); + switch (nDepth) + { + case 4: + case 3: + case 2: + case 1: + { + aEntries.emplace_back(pBE, m_xControl->get_text(*xIter)); + } + break; + case 0: + { + aDocument = static_cast<DocumentEntry*>(pBE)->GetDocument(); + } + break; + } + bValidIter = m_xControl->iter_parent(*xIter); + } while (bValidIter); + + SbxVariable* pVar = nullptr; + if (!aEntries.empty()) + { + std::reverse(aEntries.begin(), aEntries.end()); + bool bDocumentObjects = false; + for (const auto& pair : aEntries) + { + Entry* pBE = pair.first; + assert(pBE && "No data found in entry!"); + OUString aName(pair.second); + + switch ( pBE->GetType() ) + { + case OBJ_TYPE_LIBRARY: + if (BasicManager* pBasMgr = aDocument.getBasicManager()) + pVar = pBasMgr->GetLib( aName ); + break; + case OBJ_TYPE_MODULE: + DBG_ASSERT(dynamic_cast<StarBASIC*>(pVar), "FindVariable: invalid Basic"); + if(!pVar) + { + break; + } + // extract the module name from the string like "Sheet1 (Example1)" + if( bDocumentObjects ) + { + aName = aName.getToken( 0, ' ' ); + } + pVar = static_cast<StarBASIC*>(pVar)->FindModule( aName ); + break; + case OBJ_TYPE_METHOD: + DBG_ASSERT(dynamic_cast<SbxObject*>(pVar), "FindVariable: invalid module/object"); + if(!pVar) + { + break; + } + pVar = static_cast<SbxObject*>(pVar)->GetMethods()->Find(aName, SbxClassType::Method); + break; + case OBJ_TYPE_DIALOG: + // sbx dialogs removed + break; + case OBJ_TYPE_DOCUMENT_OBJECTS: + bDocumentObjects = true; + [[fallthrough]]; + case OBJ_TYPE_USERFORMS: + case OBJ_TYPE_NORMAL_MODULES: + case OBJ_TYPE_CLASS_MODULES: + // skip, to find the child entry. + continue; + default: + OSL_FAIL( "FindVariable: unknown type" ); + pVar = nullptr; + break; + } + if ( !pVar ) + break; + } + } + return pVar; +} + +EntryDescriptor SbTreeListBox::GetEntryDescriptor(const weld::TreeIter* pEntry) +{ + ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() ); + LibraryLocation eLocation = LIBRARY_LOCATION_UNKNOWN; + OUString aLibName; + OUString aLibSubName; + OUString aName; + OUString aMethodName; + EntryType eType = OBJ_TYPE_UNKNOWN; + + if ( !pEntry ) + return EntryDescriptor( aDocument, eLocation, aLibName, aLibSubName, aName, aMethodName, eType ); + + std::vector<std::pair<Entry*, OUString>> aEntries; + + std::unique_ptr<weld::TreeIter> xIter(m_xControl->make_iterator(pEntry)); + bool bValidIter = true; + do + { + sal_uInt16 nDepth = m_xControl->get_iter_depth(*xIter); + Entry* pBE = weld::fromId<Entry*>(m_xControl->get_id(*xIter)); + switch (nDepth) + { + case 4: + case 3: + case 2: + case 1: + { + aEntries.emplace_back(pBE, m_xControl->get_text(*xIter)); + } + break; + case 0: + { + if (DocumentEntry* pDocumentEntry = static_cast<DocumentEntry*>(pBE)) + { + aDocument = pDocumentEntry->GetDocument(); + eLocation = pDocumentEntry->GetLocation(); + eType = OBJ_TYPE_DOCUMENT; + } + } + break; + } + bValidIter = m_xControl->iter_parent(*xIter); + } while (bValidIter); + + if ( !aEntries.empty() ) + { + std::reverse(aEntries.begin(), aEntries.end()); + for (const auto& pair : aEntries) + { + Entry* pBE = pair.first; + assert(pBE && "No data found in entry!"); + + switch ( pBE->GetType() ) + { + case OBJ_TYPE_LIBRARY: + { + aLibName = pair.second; + eType = pBE->GetType(); + } + break; + case OBJ_TYPE_MODULE: + { + aName = pair.second; + eType = pBE->GetType(); + } + break; + case OBJ_TYPE_METHOD: + { + aMethodName = pair.second; + eType = pBE->GetType(); + } + break; + case OBJ_TYPE_DIALOG: + { + aName = pair.second; + eType = pBE->GetType(); + } + break; + case OBJ_TYPE_DOCUMENT_OBJECTS: + case OBJ_TYPE_USERFORMS: + case OBJ_TYPE_NORMAL_MODULES: + case OBJ_TYPE_CLASS_MODULES: + { + aLibSubName = pair.second; + eType = pBE->GetType(); + } + break; + default: + { + OSL_FAIL( "GetEntryDescriptor: unknown type" ); + eType = OBJ_TYPE_UNKNOWN; + } + break; + } + + if ( eType == OBJ_TYPE_UNKNOWN ) + break; + } + } + + return EntryDescriptor( aDocument, eLocation, aLibName, aLibSubName, aName, aMethodName, eType ); +} + +ItemType SbTreeListBox::ConvertType (EntryType eType) +{ + switch (eType) + { + case OBJ_TYPE_DOCUMENT: return TYPE_SHELL; + case OBJ_TYPE_LIBRARY: return TYPE_LIBRARY; + case OBJ_TYPE_MODULE: return TYPE_MODULE; + case OBJ_TYPE_DIALOG: return TYPE_DIALOG; + case OBJ_TYPE_METHOD: return TYPE_METHOD; + default: + return static_cast<ItemType>(OBJ_TYPE_UNKNOWN); + } +} + +bool SbTreeListBox::IsValidEntry(const weld::TreeIter& rEntry) +{ + bool bIsValid = false; + + EntryDescriptor aDesc(GetEntryDescriptor(&rEntry)); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + LibraryLocation eLocation( aDesc.GetLocation() ); + const OUString& aLibName( aDesc.GetLibName() ); + const OUString& aName( aDesc.GetName() ); + const OUString& aMethodName( aDesc.GetMethodName() ); + EntryType eType( aDesc.GetType() ); + + switch ( eType ) + { + case OBJ_TYPE_DOCUMENT: + { + bIsValid = aDocument.isAlive() + && (aDocument.isApplication() + || GetRootEntryName(aDocument, eLocation) == m_xControl->get_text(rEntry)); + } + break; + case OBJ_TYPE_LIBRARY: + { + bIsValid = aDocument.hasLibrary( E_SCRIPTS, aLibName ) || aDocument.hasLibrary( E_DIALOGS, aLibName ); + } + break; + case OBJ_TYPE_MODULE: + { + bIsValid = aDocument.hasModule( aLibName, aName ); + } + break; + case OBJ_TYPE_DIALOG: + { + bIsValid = aDocument.hasDialog( aLibName, aName ); + } + break; + case OBJ_TYPE_METHOD: + { + bIsValid = HasMethod( aDocument, aLibName, aName, aMethodName ); + } + break; + case OBJ_TYPE_DOCUMENT_OBJECTS: + case OBJ_TYPE_USERFORMS: + case OBJ_TYPE_NORMAL_MODULES: + case OBJ_TYPE_CLASS_MODULES: + { + bIsValid = true; + } + break; + default: ; + } + + return bIsValid; +} + +SbModule* SbTreeListBox::FindModule(const weld::TreeIter* pEntry) +{ + return dynamic_cast<SbModule*>(FindVariable(pEntry)); +} + +bool SbTreeListBox::FindRootEntry( const ScriptDocument& rDocument, LibraryLocation eLocation, weld::TreeIter& rIter) +{ + OSL_ENSURE( rDocument.isValid(), "basctl::TreeListBox::FindRootEntry: invalid document!" ); + bool bValidIter = m_xControl->get_iter_first(rIter); + while (bValidIter) + { + DocumentEntry* pBDEntry = weld::fromId<DocumentEntry*>(m_xControl->get_id(rIter)); + if (pBDEntry && pBDEntry->GetDocument() == rDocument && pBDEntry->GetLocation() == eLocation) + return true; + bValidIter = m_xControl->iter_next_sibling(rIter); + } + return false; +} + +OUString CreateMgrAndLibStr( std::u16string_view rMgrName, std::u16string_view rLibName ) +{ + return OUString::Concat("[") + rMgrName + "]." + rLibName; +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/bastypes.cxx b/basctl/source/basicide/bastypes.cxx new file mode 100644 index 0000000000..e436bc9f7e --- /dev/null +++ b/basctl/source/basicide/bastypes.cxx @@ -0,0 +1,831 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <string_view> + +#include <strings.hrc> +#include <helpids.h> +#include <iderid.hxx> + +#include "baside2.hxx" +#include <baside3.hxx> +#include <basidesh.hxx> +#include <basobj.hxx> +#include <iderdll.hxx> +#include "iderdll2.hxx" + +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <sal/log.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/infobar.hxx> +#include <sfx2/passwd.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/viewfrm.hxx> +#include <svl/intitem.hxx> +#include <svl/stritem.hxx> +#include <svl/srchdefs.hxx> +#include <svl/itemset.hxx> +#include <utility> +#include <vcl/commandevent.hxx> +#include <vcl/event.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <tools/stream.hxx> +#include <o3tl/hash_combine.hxx> + +namespace basctl +{ + +// ID used for the read-only infobar +constexpr OUString BASIC_IDE_READONLY_INFOBAR = u"readonly"_ustr; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star; + +BaseWindow::BaseWindow( vcl::Window* pParent, ScriptDocument aDocument, OUString aLibName, OUString aName ) + :Window( pParent, WinBits( WB_3DLOOK ) ) + ,pShellHScrollBar( nullptr) + ,pShellVScrollBar( nullptr) + ,nStatus( 0) + ,m_aDocument(std::move( aDocument )) + ,m_aLibName(std::move( aLibName )) + ,m_aName(std::move( aName )) +{ +} + +BaseWindow::~BaseWindow() +{ + disposeOnce(); +} + +void BaseWindow::dispose() +{ + if (pShellVScrollBar && !pShellVScrollBar->isDisposed()) + pShellVScrollBar->SetScrollHdl( Link<weld::Scrollbar&,void>() ); + if (pShellHScrollBar && !pShellHScrollBar->isDisposed()) + pShellHScrollBar->SetScrollHdl( Link<weld::Scrollbar&,void>() ); + pShellVScrollBar.clear(); + pShellHScrollBar.clear(); + vcl::Window::dispose(); +} + +void BaseWindow::Init() +{ + if ( pShellVScrollBar ) + pShellVScrollBar->SetScrollHdl( LINK( this, BaseWindow, VertScrollHdl ) ); + if ( pShellHScrollBar ) + pShellHScrollBar->SetScrollHdl( LINK( this, BaseWindow, HorzScrollHdl ) ); + + // Show the read-only infobar if the module/dialog is read-only + GetShell()->GetViewFrame().RemoveInfoBar(BASIC_IDE_READONLY_INFOBAR); + if (IsReadOnly()) + ShowReadOnlyInfoBar(); + + DoInit(); // virtual... +} + +void BaseWindow::DoInit() +{ +} + +void BaseWindow::GrabScrollBars(ScrollAdaptor* pHScroll, ScrollAdaptor* pVScroll) +{ + pShellHScrollBar = pHScroll; + pShellVScrollBar = pVScroll; +} + +IMPL_LINK_NOARG(BaseWindow, VertScrollHdl, weld::Scrollbar&, void) +{ + DoScroll(pShellVScrollBar); +} + +IMPL_LINK_NOARG(BaseWindow, HorzScrollHdl, weld::Scrollbar&, void) +{ + DoScroll(pShellHScrollBar); +} + +void BaseWindow::ExecuteCommand (SfxRequest&) +{ +} + +void BaseWindow::ExecuteGlobal (SfxRequest&) +{ +} + +bool BaseWindow::EventNotify( NotifyEvent& rNEvt ) +{ + bool bDone = false; + + if ( rNEvt.GetType() == NotifyEventType::KEYINPUT ) + { + KeyEvent aKEvt = *rNEvt.GetKeyEvent(); + vcl::KeyCode aCode = aKEvt.GetKeyCode(); + sal_uInt16 nCode = aCode.GetCode(); + + switch ( nCode ) + { + case KEY_PAGEUP: + case KEY_PAGEDOWN: + { + if ( aCode.IsMod1() ) + { + if (Shell* pShell = GetShell()) + pShell->NextPage( nCode == KEY_PAGEUP ); + bDone = true; + } + } + break; + } + } + + return bDone || Window::EventNotify( rNEvt ); +} + +void BaseWindow::ShowShellScrollBars(bool bVisible) +{ + if (bVisible) + { + if (pShellHScrollBar) + { + pShellHScrollBar->Enable(); + pShellHScrollBar->Show(); + } + if (pShellVScrollBar) + { + pShellVScrollBar->Enable(); + pShellVScrollBar->Show(); + } + } + else + { + if (pShellHScrollBar) + { + pShellHScrollBar->Disable(); + pShellHScrollBar->Hide(); + } + if (pShellVScrollBar) + { + pShellVScrollBar->Disable(); + pShellVScrollBar->Hide(); + } + } +} + +void BaseWindow::DoScroll( Scrollable* ) +{ +} + +void BaseWindow::StoreData() +{ +} + +bool BaseWindow::AllowUndo() +{ + return true; +} + +void BaseWindow::UpdateData() +{ +} + +OUString BaseWindow::GetTitle() +{ + return OUString(); +} + +OUString BaseWindow::CreateQualifiedName() +{ + OUString aName; + if ( !m_aLibName.isEmpty() ) + { + LibraryLocation eLocation = m_aDocument.getLibraryLocation( m_aLibName ); + aName = m_aDocument.getTitle(eLocation) + "." + m_aLibName + "." + + GetTitle(); + } + return aName; +} + +void BaseWindow::SetReadOnly (bool) +{ +} + +bool BaseWindow::IsReadOnly () +{ + return false; +} + +// Show the read-only warning messages for module and dialog windows +void BaseWindow::ShowReadOnlyInfoBar() +{ + OUString aMsg; + if (dynamic_cast<ModulWindow*>(this)) + aMsg = IDEResId(RID_STR_MODULE_READONLY); + else + aMsg = IDEResId(RID_STR_DIALOG_READONLY); + + GetShell()->GetViewFrame().AppendInfoBar(BASIC_IDE_READONLY_INFOBAR, OUString(), + aMsg, InfobarType::INFO, true); +} + +void BaseWindow::BasicStarted() +{ +} + +void BaseWindow::BasicStopped() +{ +} + +bool BaseWindow::IsModified () +{ + return true; +} + +SfxUndoManager* BaseWindow::GetUndoManager() +{ + return nullptr; +} + +SearchOptionFlags BaseWindow::GetSearchOptions() +{ + return SearchOptionFlags::NONE; +} + +sal_uInt16 BaseWindow::StartSearchAndReplace (SvxSearchItem const&, bool) +{ + return 0; +} + +void BaseWindow::OnNewDocument () +{ } + +void BaseWindow::InsertLibInfo () const +{ + if (ExtraData* pData = GetExtraData()) + pData->GetLibInfo().InsertInfo(m_aDocument, m_aLibName, m_aName, GetType()); +} + +bool BaseWindow::Is ( + ScriptDocument const& rDocument, + std::u16string_view rLibName, std::u16string_view rName, + ItemType eType, bool bFindSuspended +) +{ + if (bFindSuspended || !IsSuspended()) + { + // any non-suspended window is ok + if (rLibName.empty() || rName.empty() || eType == TYPE_UNKNOWN) + return true; + // ok if the parameters match + if (m_aDocument == rDocument && m_aLibName == rLibName && m_aName == rName && GetType() == eType) + return true; + } + return false; +} + +bool BaseWindow::HasActiveEditor () const +{ + return false; +} + + +// DockingWindow + + +// style bits for DockingWindow +WinBits const DockingWindow::StyleBits = + WB_BORDER | WB_3DLOOK | WB_CLIPCHILDREN | + WB_MOVEABLE | WB_SIZEABLE | WB_DOCKABLE; + +DockingWindow::DockingWindow(vcl::Window* pParent, const OUString& rUIXMLDescription, const OUString& rID) + : ResizableDockingWindow(pParent) + , m_xBuilder(Application::CreateInterimBuilder(m_xBox.get(), rUIXMLDescription, true)) + , pLayout(nullptr) + , nShowCount(0) +{ + m_xContainer = m_xBuilder->weld_container(rID); +} + +DockingWindow::DockingWindow (Layout* pParent) + : ResizableDockingWindow(pParent, StyleBits) + , pLayout(pParent) + , nShowCount(0) +{ } + +DockingWindow::~DockingWindow() +{ + disposeOnce(); +} + +void DockingWindow::dispose() +{ + m_xContainer.reset(); + m_xBuilder.reset(); + pLayout.clear(); + ResizableDockingWindow::dispose(); +} + +// Sets the position and the size of the docking window. This property is saved +// when the window is floating. Called by Layout. +void DockingWindow::ResizeIfDocking (Point const& rPos, Size const& rSize) +{ + tools::Rectangle const rRect(rPos, rSize); + if (rRect != aDockingRect) + { + // saving the position and the size + aDockingRect = rRect; + // resizing if actually docking + if (!IsFloatingMode()) + SetPosSizePixel(rPos, rSize); + } +} +void DockingWindow::ResizeIfDocking (Size const& rSize) +{ + ResizeIfDocking(aDockingRect.TopLeft(), rSize); +} + +// Sets the parent Layout window. +// The physical parent is set only when the window is docking. +void DockingWindow::SetLayoutWindow (Layout* pLayout_) +{ + pLayout = pLayout_; + if (!IsFloatingMode()) + SetParent(pLayout); + +} + +// Increases the "show" reference count. +// The window is shown when the reference count is positive. +void DockingWindow::Show (bool bShow) // = true +{ + if (bShow) + { + if (++nShowCount == 1) + ResizableDockingWindow::Show(); + } + else + { + if (--nShowCount == 0) + ResizableDockingWindow::Hide(); + } +} + +// Decreases the "show" reference count. +// The window is hidden when the reference count reaches zero. +void DockingWindow::Hide () +{ + Show(false); +} + +bool DockingWindow::Docking( const Point& rPos, tools::Rectangle& rRect ) +{ + if (aDockingRect.Contains(rPos)) + { + rRect.SetSize(aDockingRect.GetSize()); + return false; // dock + } + else // adjust old size + { + if (!aFloatingRect.IsEmpty()) + rRect.SetSize(aFloatingRect.GetSize()); + return true; // float + } +} + +void DockingWindow::EndDocking( const tools::Rectangle& rRect, bool bFloatMode ) +{ + if ( bFloatMode ) + ResizableDockingWindow::EndDocking( rRect, bFloatMode ); + else + { + SetFloatingMode(false); + DockThis(); + } +} + +void DockingWindow::ToggleFloatingMode() +{ + if (IsFloatingMode()) + { + if (!aFloatingRect.IsEmpty()) + SetPosSizePixel( + GetParent()->ScreenToOutputPixel(aFloatingRect.TopLeft()), + aFloatingRect.GetSize() + ); + } + DockThis(); +} + +bool DockingWindow::PrepareToggleFloatingMode() +{ + if (IsFloatingMode()) + { + // memorize position and size on the desktop... + aFloatingRect = tools::Rectangle( + GetParent()->OutputToScreenPixel(GetPosPixel()), + GetSizePixel() + ); + } + return true; +} + +void DockingWindow::StartDocking() +{ + if (IsFloatingMode()) + { + aFloatingRect = tools::Rectangle( + GetParent()->OutputToScreenPixel(GetPosPixel()), + GetSizePixel() + ); + } +} + +void DockingWindow::DockThis () +{ + // resizing when floating -> docking + if (!IsFloatingMode()) + { + Point const aPos = aDockingRect.TopLeft(); + Size const aSize = aDockingRect.GetSize(); + if (aSize != GetSizePixel() || aPos != GetPosPixel()) + SetPosSizePixel(aPos, aSize); + } + + if (pLayout) + { + if (!IsFloatingMode() && GetParent() != pLayout) + SetParent(pLayout); + pLayout->ArrangeWindows(); + } +} + +TabBar::TabBar( vcl::Window* pParent ) : + ::TabBar( pParent, WinBits( WB_3DLOOK | WB_SCROLL | WB_BORDER | WB_DRAG ) ) +{ + EnableEditMode(); + + SetHelpId( HID_BASICIDE_TABBAR ); +} + +void TabBar::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if ( rMEvt.IsLeft() && ( rMEvt.GetClicks() == 2 ) && !IsInEditMode() ) + { + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->Execute( SID_BASICIDE_MODULEDLG ); + } + else + { + ::TabBar::MouseButtonDown( rMEvt ); // base class version + } +} + +void TabBar::Command( const CommandEvent& rCEvt ) +{ + if ( ( rCEvt.GetCommand() == CommandEventId::ContextMenu ) && !IsInEditMode() ) + { + Point aPos( rCEvt.IsMouseEvent() ? rCEvt.GetMousePosPixel() : Point(1,1) ); + if ( rCEvt.IsMouseEvent() ) // select right tab + { + Point aP = PixelToLogic( aPos ); + MouseEvent aMouseEvent( aP, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT ); + ::TabBar::MouseButtonDown( aMouseEvent ); // base class + } + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->ExecutePopup("tabbar", this, &aPos); + } +} + +TabBarAllowRenamingReturnCode TabBar::AllowRenaming() +{ + bool const bValid = IsValidSbxName(GetEditText()); + + if ( !bValid ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(GetFrameWeld(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME))); + xError->run(); + } + + return bValid ? TABBAR_RENAMING_YES : TABBAR_RENAMING_NO; +} + + +void TabBar::EndRenaming() +{ + if ( !IsEditModeCanceled() ) + { + SfxUInt16Item aID( SID_BASICIDE_ARG_TABID, GetEditPageId() ); + SfxStringItem aNewName( SID_BASICIDE_ARG_MODULENAME, GetEditText() ); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->ExecuteList( SID_BASICIDE_NAMECHANGEDONTAB, + SfxCallMode::SYNCHRON, { &aID, &aNewName }); + } +} + + +namespace +{ + +// helper class for sorting TabBar +struct TabBarSortHelper +{ + sal_uInt16 nPageId; + OUString aPageText; + + bool operator < (TabBarSortHelper const& rComp) const + { + return aPageText.compareToIgnoreAsciiCase(rComp.aPageText) < 0; + } +}; + +} // namespace + +void TabBar::Sort() +{ + Shell* pShell = GetShell(); + if (!pShell) + return; + + Shell::WindowTable& aWindowTable = pShell->GetWindowTable(); + TabBarSortHelper aTabBarSortHelper; + std::vector<TabBarSortHelper> aModuleList; + std::vector<TabBarSortHelper> aDialogList; + sal_uInt16 nPageCount = GetPageCount(); + sal_uInt16 i; + + // create module and dialog lists for sorting + for ( i = 0; i < nPageCount; i++) + { + sal_uInt16 nId = GetPageId( i ); + aTabBarSortHelper.nPageId = nId; + aTabBarSortHelper.aPageText = GetPageText( nId ); + BaseWindow* pWin = aWindowTable[ nId ].get(); + + if (dynamic_cast<ModulWindow*>(pWin)) + { + aModuleList.push_back( aTabBarSortHelper ); + } + else if (dynamic_cast<DialogWindow*>(pWin)) + { + aDialogList.push_back( aTabBarSortHelper ); + } + } + + // sort module and dialog lists by page text + std::sort( aModuleList.begin() , aModuleList.end() ); + std::sort( aDialogList.begin() , aDialogList.end() ); + + + sal_uInt16 nModules = sal::static_int_cast<sal_uInt16>( aModuleList.size() ); + sal_uInt16 nDialogs = sal::static_int_cast<sal_uInt16>( aDialogList.size() ); + + // move module pages to new positions + for (i = 0; i < nModules; i++) + { + MovePage( aModuleList[i].nPageId , i ); + } + + // move dialog pages to new positions + for (i = 0; i < nDialogs; i++) + { + MovePage( aDialogList[i].nPageId , nModules + i ); + } +} + +void CutLines( OUString& rStr, sal_Int32 nStartLine, sal_Int32 nLines ) +{ + sal_Int32 nStartPos = 0; + sal_Int32 nLine = 0; + while ( nLine < nStartLine ) + { + nStartPos = searchEOL( rStr, nStartPos ); + if( nStartPos == -1 ) + break; + nStartPos++; // not the \n. + nLine++; + } + + SAL_WARN_IF( nStartPos == -1, "basctl.basicide", "CutLines: Start line not found!" ); + + if ( nStartPos == -1 ) + return; + + sal_Int32 nEndPos = nStartPos; + + for ( sal_Int32 i = 0; i < nLines; i++ ) + nEndPos = searchEOL( rStr, nEndPos+1 ); + + if ( nEndPos == -1 ) // might happen at the last line + nEndPos = rStr.getLength(); + else + nEndPos++; + + rStr = OUString::Concat(rStr.subView( 0, nStartPos )) + rStr.subView( nEndPos ); + + // erase trailing empty lines + { + sal_Int32 n = nStartPos; + sal_Int32 nLen = rStr.getLength(); + while ( ( n < nLen ) && ( rStr[ n ] == LINE_SEP || + rStr[ n ] == LINE_SEP_CR ) ) + { + n++; + } + + if ( n > nStartPos ) + { + rStr = OUString::Concat(rStr.subView( 0, nStartPos )) + rStr.subView( n ); + } + } +} + +sal_uInt32 CalcLineCount( SvStream& rStream ) +{ + sal_uInt32 nLFs = 0; + sal_uInt32 nCRs = 0; + char c; + + rStream.Seek( 0 ); + rStream.ReadChar( c ); + while ( !rStream.eof() ) + { + if ( c == '\n' ) + nLFs++; + else if ( c == '\r' ) + nCRs++; + rStream.ReadChar( c ); + } + + rStream.Seek( 0 ); + if ( nLFs > nCRs ) + return nLFs; + return nCRs; +} + + +// LibInfo + + +LibInfo::LibInfo () +{ } + +LibInfo::~LibInfo () +{ } + +void LibInfo::InsertInfo ( + ScriptDocument const& rDocument, + OUString const& rLibName, + OUString const& rCurrentName, + ItemType eCurrentType +) +{ + Key aKey(rDocument, rLibName); + m_aMap.erase(aKey); + m_aMap.emplace(aKey, Item(rCurrentName, eCurrentType)); +} + +void LibInfo::RemoveInfoFor (ScriptDocument const& rDocument) +{ + Map::iterator it = std::find_if(m_aMap.begin(), m_aMap.end(), + [&rDocument](Map::reference rEntry) { return rEntry.first.GetDocument() == rDocument; }); + if (it != m_aMap.end()) + m_aMap.erase(it); +} + +LibInfo::Item const* LibInfo::GetInfo ( + ScriptDocument const& rDocument, OUString const& rLibName +) +{ + Map::iterator it = m_aMap.find(Key(rDocument, rLibName)); + return it != m_aMap.end() ? &it->second : nullptr; +} + +LibInfo::Key::Key (ScriptDocument aDocument, OUString aLibName) : + m_aDocument(std::move(aDocument)), m_aLibName(std::move(aLibName)) +{ } + +bool LibInfo::Key::operator == (Key const& rKey) const +{ + return m_aDocument == rKey.m_aDocument && m_aLibName == rKey.m_aLibName; +} + +size_t LibInfo::Key::Hash::operator () (Key const& rKey) const +{ + std::size_t seed = 0; + o3tl::hash_combine(seed, rKey.m_aDocument.hashCode()); + o3tl::hash_combine(seed, rKey.m_aLibName.hashCode()); + return seed; +} + +LibInfo::Item::Item ( + OUString aCurrentName, + ItemType eCurrentType +) : + m_aCurrentName(std::move(aCurrentName)), + m_eCurrentType(eCurrentType) +{ } + +static bool QueryDel(std::u16string_view rName, const OUString &rStr, weld::Widget* pParent) +{ + OUString aName = OUString::Concat("\'") + rName + "\'"; + OUString aQuery = rStr.replaceAll("XX", aName); + std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pParent, + VclMessageType::Question, VclButtonsType::YesNo, aQuery)); + return (xQueryBox->run() == RET_YES); +} + +bool QueryDelMacro( std::u16string_view rName, weld::Widget* pParent ) +{ + return QueryDel( rName, IDEResId( RID_STR_QUERYDELMACRO ), pParent ); +} + +bool QueryReplaceMacro( std::u16string_view rName, weld::Widget* pParent ) +{ + return QueryDel( rName, IDEResId( RID_STR_QUERYREPLACEMACRO ), pParent ); +} + +bool QueryDelDialog( std::u16string_view rName, weld::Widget* pParent ) +{ + return QueryDel( rName, IDEResId( RID_STR_QUERYDELDIALOG ), pParent ); +} + +bool QueryDelLib( std::u16string_view rName, bool bRef, weld::Widget* pParent ) +{ + return QueryDel( rName, IDEResId( bRef ? RID_STR_QUERYDELLIBREF : RID_STR_QUERYDELLIB ), pParent ); +} + +bool QueryDelModule( std::u16string_view rName, weld::Widget* pParent ) +{ + return QueryDel( rName, IDEResId( RID_STR_QUERYDELMODULE ), pParent ); +} + +bool QueryPassword(weld::Widget* pDialogParent, const Reference< script::XLibraryContainer >& xLibContainer, const OUString& rLibName, OUString& rPassword, bool bRepeat, bool bNewTitle) +{ + bool bOK = false; + sal_uInt16 nRet = 0; + + do + { + // password dialog + SfxPasswordDialog aDlg(pDialogParent); + aDlg.SetMinLen(1); + + // set new title + if ( bNewTitle ) + { + OUString aTitle(IDEResId(RID_STR_ENTERPASSWORD)); + aTitle = aTitle.replaceAll("XX", rLibName); + aDlg.set_title(aTitle); + } + + // execute dialog + nRet = aDlg.run(); + + // verify password + if ( nRet == RET_OK ) + { + if ( xLibContainer.is() && xLibContainer->hasByName( rLibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( rLibName ) && !xPasswd->isLibraryPasswordVerified( rLibName ) ) + { + rPassword = aDlg.GetPassword(); + bOK = xPasswd->verifyLibraryPassword( rLibName, rPassword ); + + if ( !bOK ) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pDialogParent, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_WRONGPASSWORD))); + xErrorBox->run(); + } + } + } + } + } + while ( bRepeat && !bOK && nRet == RET_OK ); + + return bOK; +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/breakpoint.cxx b/basctl/source/basicide/breakpoint.cxx new file mode 100644 index 0000000000..0d0347ace2 --- /dev/null +++ b/basctl/source/basicide/breakpoint.cxx @@ -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 . + */ + +#include "breakpoint.hxx" + +#include <basic/sbmod.hxx> +#include <tools/debug.hxx> + + +namespace basctl +{ + +BreakPointList::BreakPointList() +{} + +BreakPointList::BreakPointList(BreakPointList const & rList) +{ + for (size_t i = 0; i < rList.size(); ++i) + maBreakPoints.push_back( rList.at( i ) ); +} + +BreakPointList::~BreakPointList() +{ +} + +void BreakPointList::reset() +{ + maBreakPoints.clear(); +} + +void BreakPointList::transfer(BreakPointList & rList) +{ + maBreakPoints = std::move(rList.maBreakPoints); +} + +void BreakPointList::InsertSorted(BreakPoint aNewBrk) +{ + auto it = std::find_if(maBreakPoints.begin(), maBreakPoints.end(), + [&aNewBrk](const BreakPoint& rBreakPoint) { return aNewBrk.nLine <= rBreakPoint.nLine; }); + if (it != maBreakPoints.end()) + { + DBG_ASSERT( it->nLine != aNewBrk.nLine, "BreakPoint exists already!" ); + maBreakPoints.insert( it, aNewBrk ); + return; + } + // no insert position found => LIST_APPEND + maBreakPoints.push_back( aNewBrk ); +} + +void BreakPointList::SetBreakPointsInBasic(SbModule* pModule) +{ + pModule->ClearAllBP(); + + for (const BreakPoint& rBrk : maBreakPoints) + { + if ( rBrk.bEnabled ) + pModule->SetBP( rBrk.nLine ); + } +} + +BreakPoint* BreakPointList::FindBreakPoint(sal_uInt16 nLine) +{ + for (BreakPoint& rBrk : maBreakPoints) + { + if ( rBrk.nLine == nLine ) + return &rBrk; + } + return nullptr; +} + +void BreakPointList::AdjustBreakPoints(sal_uInt16 nLine, bool bInserted) +{ + for ( size_t i = 0; i < maBreakPoints.size(); ) + { + BreakPoint& rBrk = maBreakPoints[ i ]; + bool bDelBrk = false; + if ( rBrk.nLine == nLine ) + { + if ( bInserted ) + rBrk.nLine++; + else + bDelBrk = true; + } + else if ( rBrk.nLine > nLine ) + { + if ( bInserted ) + rBrk.nLine++; + else + rBrk.nLine--; + } + + if ( bDelBrk ) + { + maBreakPoints.erase(maBreakPoints.begin() + i); + } + else + { + ++i; + } + } +} + +void BreakPointList::ResetHitCount() +{ + for (BreakPoint& rBrk : maBreakPoints) + { + rBrk.nHitCount = 0; + } +} + +void BreakPointList::remove(const BreakPoint* ptr) +{ + auto i = std::find_if(maBreakPoints.begin(), maBreakPoints.end(), + [&ptr](const BreakPoint& rBreakPoint) { return ptr == &rBreakPoint; }); + if (i != maBreakPoints.end()) + maBreakPoints.erase( i ); + return; +} + +void BreakPointList::remove(size_t idx) +{ + maBreakPoints.erase( maBreakPoints.begin() + idx ); +} + +size_t BreakPointList::size() const +{ + return maBreakPoints.size(); +} + +BreakPoint& BreakPointList::at(size_t i) +{ + return maBreakPoints[ i ]; +} + +const BreakPoint& BreakPointList::at(size_t i) const +{ + return maBreakPoints[ i ]; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/breakpoint.hxx b/basctl/source/basicide/breakpoint.hxx new file mode 100644 index 0000000000..324564aaa7 --- /dev/null +++ b/basctl/source/basicide/breakpoint.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 <cstddef> +#include <vector> + +#include <sal/types.h> + +class SbModule; + +namespace basctl +{ +struct BreakPoint +{ + bool bEnabled; + sal_uInt16 nLine; + size_t nStopAfter; + size_t nHitCount; + + explicit BreakPoint(sal_uInt16 nL) + : bEnabled(true) + , nLine(nL) + , nStopAfter(0) + , nHitCount(0) + { + } +}; + +class BreakPointList +{ +private: + BreakPointList& operator=(BreakPointList const&) = delete; + std::vector<BreakPoint> maBreakPoints; + +public: + BreakPointList(); + + BreakPointList(BreakPointList const& rList); + + ~BreakPointList(); + + void reset(); + + void transfer(BreakPointList& rList); + + void InsertSorted(BreakPoint pBrk); + BreakPoint* FindBreakPoint(sal_uInt16 nLine); + void AdjustBreakPoints(sal_uInt16 nLine, bool bInserted); + void SetBreakPointsInBasic(SbModule* pModule); + void ResetHitCount(); + + size_t size() const; + BreakPoint& at(size_t i); + const BreakPoint& at(size_t i) const; + void remove(const BreakPoint* ptr); + void remove(size_t i); +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/brkdlg.cxx b/basctl/source/basicide/brkdlg.cxx new file mode 100644 index 0000000000..f39255371b --- /dev/null +++ b/basctl/source/basicide/brkdlg.cxx @@ -0,0 +1,231 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include "breakpoint.hxx" +#include "brkdlg.hxx" +#include <basobj.hxx> + +#include <sfx2/dispatch.hxx> +#include <sfx2/sfxsids.hrc> +#include <svl/itemset.hxx> + +namespace basctl +{ +namespace +{ +bool lcl_ParseText(OUString const& rText, size_t& rLineNr) +{ + // aText should look like "# n" where n > 0 + // All spaces are ignored, so there can even be spaces within the + // number n. (Maybe it would be better to ignore all whitespace instead + // of just spaces.) + OUString aText(rText.replaceAll(" ", "")); + if (aText.isEmpty()) + return false; + sal_Unicode cFirst = aText[0]; + if (cFirst != '#' && (cFirst < '0' || cFirst > '9')) + return false; + if (cFirst == '#') + aText = aText.copy(1); + sal_Int32 n = aText.toInt32(); + if (n <= 0) + return false; + rLineNr = static_cast<size_t>(n); + return true; +} + +} // namespace + +BreakPointDialog::BreakPointDialog(weld::Window* pParent, BreakPointList& rBrkPntList) + : GenericDialogController(pParent, "modules/BasicIDE/ui/managebreakpoints.ui", + "ManageBreakpointsDialog") + , m_rOriginalBreakPointList(rBrkPntList) + , m_aModifiedBreakPointList(rBrkPntList) + , m_xComboBox(m_xBuilder->weld_entry_tree_view("entriesgrid", "entries", "entrieslist")) + , m_xOKButton(m_xBuilder->weld_button("ok")) + , m_xNewButton(m_xBuilder->weld_button("new")) + , m_xDelButton(m_xBuilder->weld_button("delete")) + , m_xCheckBox(m_xBuilder->weld_check_button("active")) + , m_xNumericField(m_xBuilder->weld_spin_button("pass")) +{ + m_xComboBox->set_size_request(m_xComboBox->get_approximate_digit_width() * 20, -1); + m_xComboBox->set_height_request_by_rows(12); + + m_xComboBox->freeze(); + for (size_t i = 0, n = m_aModifiedBreakPointList.size(); i < n; ++i) + { + BreakPoint& rBrk = m_aModifiedBreakPointList.at(i); + OUString aEntryStr("# " + OUString::number(rBrk.nLine)); + m_xComboBox->append_text(aEntryStr); + } + m_xComboBox->thaw(); + + m_xOKButton->connect_clicked(LINK(this, BreakPointDialog, ButtonHdl)); + m_xNewButton->connect_clicked(LINK(this, BreakPointDialog, ButtonHdl)); + m_xDelButton->connect_clicked(LINK(this, BreakPointDialog, ButtonHdl)); + + m_xCheckBox->connect_toggled(LINK(this, BreakPointDialog, CheckBoxHdl)); + m_xComboBox->connect_changed(LINK(this, BreakPointDialog, EditModifyHdl)); + m_xComboBox->connect_row_activated(LINK(this, BreakPointDialog, TreeModifyHdl)); + m_xComboBox->grab_focus(); + + m_xNumericField->set_range(0, 0x7FFFFFFF); + m_xNumericField->set_increments(1, 10); + m_xNumericField->connect_value_changed(LINK(this, BreakPointDialog, FieldModifyHdl)); + + if (m_xComboBox->get_count()) + m_xComboBox->set_active(0); + + if (m_aModifiedBreakPointList.size()) + UpdateFields(m_aModifiedBreakPointList.at(0)); + + CheckButtons(); +} + +BreakPointDialog::~BreakPointDialog() {} + +void BreakPointDialog::SetCurrentBreakPoint(BreakPoint const& rBrk) +{ + OUString aStr("# " + OUString::number(rBrk.nLine)); + m_xComboBox->set_entry_text(aStr); + UpdateFields(rBrk); +} + +void BreakPointDialog::CheckButtons() +{ + // "New" button is enabled if the combo box edit contains a valid line + // number that is not already present in the combo box list; otherwise + // "OK" and "Delete" buttons are enabled: + size_t nLine; + if (lcl_ParseText(m_xComboBox->get_active_text(), nLine) + && m_aModifiedBreakPointList.FindBreakPoint(nLine) == nullptr) + { + m_xNewButton->set_sensitive(true); + m_xOKButton->set_sensitive(false); + m_xDelButton->set_sensitive(false); + m_xDialog->change_default_widget(m_xDelButton.get(), m_xNewButton.get()); + } + else + { + m_xNewButton->set_sensitive(false); + m_xOKButton->set_sensitive(true); + m_xDelButton->set_sensitive(true); + m_xDialog->change_default_widget(m_xNewButton.get(), m_xDelButton.get()); + } +} + +IMPL_LINK(BreakPointDialog, CheckBoxHdl, weld::Toggleable&, rButton, void) +{ + BreakPoint* pBrk = GetSelectedBreakPoint(); + if (pBrk) + pBrk->bEnabled = rButton.get_active(); +} + +IMPL_LINK(BreakPointDialog, EditModifyHdl, weld::ComboBox&, rBox, void) +{ + CheckButtons(); + + int nEntry = rBox.find_text(rBox.get_active_text()); + if (nEntry == -1) + return; + BreakPoint& rBrk = m_aModifiedBreakPointList.at(nEntry); + UpdateFields(rBrk); +} + +IMPL_LINK(BreakPointDialog, FieldModifyHdl, weld::SpinButton&, rEdit, void) +{ + BreakPoint* pBrk = GetSelectedBreakPoint(); + if (pBrk) + pBrk->nStopAfter = rEdit.get_value(); +} + +IMPL_LINK_NOARG(BreakPointDialog, TreeModifyHdl, weld::TreeView&, bool) +{ + if (m_xDelButton->get_sensitive()) + ButtonHdl(*m_xDelButton); + return true; +} + +IMPL_LINK(BreakPointDialog, ButtonHdl, weld::Button&, rButton, void) +{ + if (&rButton == m_xOKButton.get()) + { + m_rOriginalBreakPointList.transfer(m_aModifiedBreakPointList); + m_xDialog->response(RET_OK); + } + else if (&rButton == m_xNewButton.get()) + { + // keep checkbox in mind! + OUString aText(m_xComboBox->get_active_text()); + size_t nLine; + bool bValid = lcl_ParseText(aText, nLine); + if (bValid) + { + BreakPoint aBrk(nLine); + aBrk.bEnabled = m_xCheckBox->get_active(); + aBrk.nStopAfter = static_cast<size_t>(m_xNumericField->get_value()); + m_aModifiedBreakPointList.InsertSorted(aBrk); + OUString aEntryStr("# " + OUString::number(aBrk.nLine)); + m_xComboBox->append_text(aEntryStr); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->Execute(SID_BASICIDE_BRKPNTSCHANGED); + } + else + { + m_xComboBox->set_active_text(aText); + m_xComboBox->grab_focus(); + } + CheckButtons(); + } + else if (&rButton == m_xDelButton.get()) + { + int nEntry = m_xComboBox->find_text(m_xComboBox->get_active_text()); + if (nEntry != -1) + { + m_aModifiedBreakPointList.remove(nEntry); + m_xComboBox->remove(nEntry); + if (nEntry && nEntry >= m_xComboBox->get_count()) + nEntry--; + m_xComboBox->set_active_text(m_xComboBox->get_text(nEntry)); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->Execute(SID_BASICIDE_BRKPNTSCHANGED); + CheckButtons(); + } + } +} + +void BreakPointDialog::UpdateFields(BreakPoint const& rBrk) +{ + m_xCheckBox->set_active(rBrk.bEnabled); + m_xNumericField->set_value(rBrk.nStopAfter); +} + +BreakPoint* BreakPointDialog::GetSelectedBreakPoint() +{ + int nEntry = m_xComboBox->find_text(m_xComboBox->get_active_text()); + if (nEntry == -1) + return nullptr; + return &m_aModifiedBreakPointList.at(nEntry); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/brkdlg.hxx b/basctl/source/basicide/brkdlg.hxx new file mode 100644 index 0000000000..89406d2c0c --- /dev/null +++ b/basctl/source/basicide/brkdlg.hxx @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <vcl/weld.hxx> +#include "breakpoint.hxx" + +namespace basctl +{ +class BreakPointDialog final : public weld::GenericDialogController +{ + BreakPointList& m_rOriginalBreakPointList; + BreakPointList m_aModifiedBreakPointList; + + std::unique_ptr<weld::EntryTreeView> m_xComboBox; + std::unique_ptr<weld::Button> m_xOKButton; + std::unique_ptr<weld::Button> m_xNewButton; + std::unique_ptr<weld::Button> m_xDelButton; + std::unique_ptr<weld::CheckButton> m_xCheckBox; + std::unique_ptr<weld::SpinButton> m_xNumericField; + + void CheckButtons(); + DECL_LINK(CheckBoxHdl, weld::Toggleable&, void); + DECL_LINK(EditModifyHdl, weld::ComboBox&, void); + DECL_LINK(FieldModifyHdl, weld::SpinButton&, void); + DECL_LINK(ButtonHdl, weld::Button&, void); + DECL_LINK(TreeModifyHdl, weld::TreeView&, bool); + void UpdateFields(BreakPoint const& rBrk); + BreakPoint* GetSelectedBreakPoint(); + +public: + BreakPointDialog(weld::Window* pParent, BreakPointList& rBrkList); + virtual ~BreakPointDialog() override; + + void SetCurrentBreakPoint(BreakPoint const& rBrk); +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/doceventnotifier.cxx b/basctl/source/basicide/doceventnotifier.cxx new file mode 100644 index 0000000000..254c719bb5 --- /dev/null +++ b/basctl/source/basicide/doceventnotifier.cxx @@ -0,0 +1,250 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <doceventnotifier.hxx> +#include <scriptdocument.hxx> + +#include <com/sun/star/frame/theGlobalEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <comphelper/compbase.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/processfactory.hxx> + +namespace basctl +{ + + using ::com::sun::star::document::XDocumentEventBroadcaster; + using ::com::sun::star::document::XDocumentEventListener; + using ::com::sun::star::document::DocumentEvent; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::Exception; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::frame::theGlobalEventBroadcaster; + using ::com::sun::star::uno::UNO_QUERY; + + // DocumentEventNotifier::Impl + + typedef ::comphelper::WeakComponentImplHelper< XDocumentEventListener + > DocumentEventNotifier_Impl_Base; + + namespace { + + enum ListenerAction + { + RegisterListener, + RemoveListener + }; + + } + + /** impl class for DocumentEventNotifier + */ + class DocumentEventNotifier::Impl : public DocumentEventNotifier_Impl_Base + { + public: + // noncopyable + Impl(const Impl&) = delete; + Impl& operator=(const Impl&) = delete; + + Impl (DocumentEventListener&, Reference<XModel> const& rxDocument); + virtual ~Impl () override; + + // XDocumentEventListener + virtual void SAL_CALL documentEventOccured( const DocumentEvent& Event ) override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& Event ) override; + + // WeakComponentImplHelper + virtual void disposing(std::unique_lock<std::mutex>&) override; + + private: + /// determines whether the instance is already disposed + bool impl_isDisposed_nothrow(std::unique_lock<std::mutex>& /*rGuard*/) const { return m_pListener == nullptr; } + + /// disposes the instance + void impl_dispose_nothrow(std::unique_lock<std::mutex>& rGuard); + + /// registers or revokes the instance as listener at the global event broadcaster + void impl_listenerAction_nothrow( std::unique_lock<std::mutex>& rGuard, ListenerAction _eAction ); + + private: + DocumentEventListener* m_pListener; + Reference< XModel > m_xModel; + }; + + DocumentEventNotifier::Impl::Impl (DocumentEventListener& rListener, Reference<XModel> const& rxDocument) : + m_pListener(&rListener), + m_xModel(rxDocument) + { + std::unique_lock aGuard(m_aMutex); + osl_atomic_increment( &m_refCount ); + impl_listenerAction_nothrow( aGuard, RegisterListener ); + osl_atomic_decrement( &m_refCount ); + } + + DocumentEventNotifier::Impl::~Impl () + { + std::unique_lock aGuard(m_aMutex); + if ( !impl_isDisposed_nothrow(aGuard) ) + { + acquire(); + dispose(); + } + } + + void SAL_CALL DocumentEventNotifier::Impl::documentEventOccured( const DocumentEvent& _rEvent ) + { + std::unique_lock aGuard( m_aMutex ); + + OSL_PRECOND( !impl_isDisposed_nothrow(aGuard), "DocumentEventNotifier::Impl::notifyEvent: disposed, but still getting events?" ); + if ( impl_isDisposed_nothrow(aGuard) ) + return; + + Reference< XModel > xDocument( _rEvent.Source, UNO_QUERY ); + OSL_ENSURE( xDocument.is(), "DocumentEventNotifier::Impl::notifyEvent: illegal source document!" ); + if ( !xDocument.is() ) + return; + + struct EventEntry + { + const char* pEventName; + void (DocumentEventListener::*listenerMethod)( const ScriptDocument& _rDocument ); + }; + static EventEntry const aEvents[] = { + { "OnNew", &DocumentEventListener::onDocumentCreated }, + { "OnLoad", &DocumentEventListener::onDocumentOpened }, + { "OnSave", &DocumentEventListener::onDocumentSave }, + { "OnSaveDone", &DocumentEventListener::onDocumentSaveDone }, + { "OnSaveAs", &DocumentEventListener::onDocumentSaveAs }, + { "OnSaveAsDone", &DocumentEventListener::onDocumentSaveAsDone }, + { "OnUnload", &DocumentEventListener::onDocumentClosed }, + { "OnTitleChanged", &DocumentEventListener::onDocumentTitleChanged }, + { "OnModeChanged", &DocumentEventListener::onDocumentModeChanged } + }; + + for (EventEntry const & aEvent : aEvents) + { + if ( !_rEvent.EventName.equalsAscii( aEvent.pEventName ) ) + continue; + + // Listener implementations require that we hold the mutex, but to avoid lock ordering issues, + // we need to take the solar mutex before we take our own mutex. + aGuard.unlock(); + + // Listener implements require that we hold the solar mutex. + SolarMutexGuard aSolarGuard; + + // Take the lock again, so we can check our local fields. + aGuard.lock(); + if ( impl_isDisposed_nothrow(aGuard) ) + // somebody took the chance to dispose us -> bail out + return; + DocumentEventListener* pListener = m_pListener; + ScriptDocument aDocument( xDocument ); + // We cannot call the listener while holding our mutex because the listener + // call might trigger an event which call back into us. + aGuard.unlock(); + + (pListener->*aEvent.listenerMethod)( aDocument ); + + break; + } + } + + void SAL_CALL DocumentEventNotifier::Impl::disposing( const css::lang::EventObject& /*Event*/ ) + { + SolarMutexGuard aSolarGuard; + std::unique_lock aGuard( m_aMutex ); + + if ( !impl_isDisposed_nothrow(aGuard) ) + impl_dispose_nothrow(aGuard); + } + + void DocumentEventNotifier::Impl::disposing(std::unique_lock<std::mutex>& rGuard) + { + impl_listenerAction_nothrow( rGuard, RemoveListener ); + impl_dispose_nothrow(rGuard); + } + + void DocumentEventNotifier::Impl::impl_dispose_nothrow(std::unique_lock<std::mutex>& /*rGuard*/) + { + m_pListener = nullptr; + m_xModel.clear(); + } + + void DocumentEventNotifier::Impl::impl_listenerAction_nothrow( std::unique_lock<std::mutex>& rGuard, ListenerAction _eAction ) + { + try + { + Reference< XDocumentEventBroadcaster > xBroadcaster; + if ( m_xModel.is() ) + xBroadcaster.set( m_xModel, UNO_QUERY_THROW ); + else + { + Reference< css::uno::XComponentContext > aContext( + comphelper::getProcessComponentContext() ); + xBroadcaster = theGlobalEventBroadcaster::get(aContext); + } + + void ( SAL_CALL XDocumentEventBroadcaster::*listenerAction )( const Reference< XDocumentEventListener >& ) = + ( _eAction == RegisterListener ) ? &XDocumentEventBroadcaster::addDocumentEventListener : &XDocumentEventBroadcaster::removeDocumentEventListener; + + rGuard.unlock(); + (xBroadcaster.get()->*listenerAction)( this ); + rGuard.lock(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + + // DocumentEventNotifier + + DocumentEventNotifier::DocumentEventNotifier (DocumentEventListener& rListener, Reference<XModel> const& rxDocument) : + m_pImpl(new Impl(rListener, rxDocument)) + { } + + DocumentEventNotifier::DocumentEventNotifier (DocumentEventListener& rListener) : + m_pImpl(new Impl(rListener, Reference<XModel>())) + { } + + DocumentEventNotifier::~DocumentEventNotifier() + { + } + + void DocumentEventNotifier::dispose() + { + m_pImpl->dispose(); + } + + // DocumentEventListener + + DocumentEventListener::~DocumentEventListener() + { + } + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/docsignature.cxx b/basctl/source/basicide/docsignature.cxx new file mode 100644 index 0000000000..08d7a1ab9c --- /dev/null +++ b/basctl/source/basicide/docsignature.cxx @@ -0,0 +1,75 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <docsignature.hxx> +#include <scriptdocument.hxx> + +#include <sfx2/objsh.hxx> +#include <sfx2/signaturestate.hxx> + +#include <osl/diagnose.h> + + +namespace basctl +{ + using ::com::sun::star::uno::Reference; + using ::com::sun::star::frame::XModel; + + // DocumentSignature + + DocumentSignature::DocumentSignature (ScriptDocument const& rDocument) : + m_pShell(nullptr) + { + if (!rDocument.isDocument()) + return; + + Reference<XModel> xDocument(rDocument.getDocument()); + // find object shell for document + SfxObjectShell* pShell = SfxObjectShell::GetFirst(); + while ( pShell ) + { + if ( pShell->GetModel() == xDocument ) + break; + pShell = SfxObjectShell::GetNext( *pShell ); + } + m_pShell = pShell; + } + + bool DocumentSignature::supportsSignatures() const + { + return ( m_pShell != nullptr ); + } + + void DocumentSignature::signScriptingContent(weld::Window* pDialogParent) const + { + OSL_PRECOND( supportsSignatures(), "DocumentSignature::signScriptingContent: signatures not supported by this document!" ); + if ( m_pShell ) + m_pShell->SignScriptingContent(pDialogParent); + } + + SignatureState DocumentSignature::getScriptingSignatureState() const + { + if ( m_pShell ) + return m_pShell->GetScriptingSignatureState(); + return SignatureState::NOSIGNATURES; + } + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/documentenumeration.cxx b/basctl/source/basicide/documentenumeration.cxx new file mode 100644 index 0000000000..d71e02139e --- /dev/null +++ b/basctl/source/basicide/documentenumeration.cxx @@ -0,0 +1,157 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <set> + +#include "documentenumeration.hxx" + +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/frame/XModel2.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> + +#include <comphelper/diagnose_ex.hxx> + +namespace basctl::docs { + + using ::com::sun::star::uno::Exception; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::uno::UNO_QUERY_THROW; + using ::com::sun::star::uno::UNO_SET_THROW; + using ::com::sun::star::frame::Desktop; + using ::com::sun::star::frame::XDesktop2; + using ::com::sun::star::container::XEnumeration; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::frame::XFrames; + using ::com::sun::star::frame::XController; + using ::com::sun::star::frame::XModel2; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::frame::XFrame; + + namespace FrameSearchFlag = ::com::sun::star::frame::FrameSearchFlag; + + // DocumentEnumeration + DocumentEnumeration::DocumentEnumeration( Reference< css::uno::XComponentContext > const & _rContext, const IDocumentDescriptorFilter* _pFilter ) + : m_xContext( _rContext ) + , m_pFilter( _pFilter ) + { + } + + DocumentEnumeration::~DocumentEnumeration() + { + } + + namespace + { + void lcl_getDocumentControllers_nothrow( DocumentDescriptor& _io_rDocDesc ) + { + OSL_PRECOND( _io_rDocDesc.xModel.is(), "lcl_getDocumentControllers_nothrow: illegal model!" ); + + _io_rDocDesc.aControllers.clear(); + try + { + Reference< XModel2 > xModel2( _io_rDocDesc.xModel, UNO_QUERY ); + if ( xModel2.is() ) + { + Reference< XEnumeration > xEnum( xModel2->getControllers(), UNO_SET_THROW ); + while ( xEnum->hasMoreElements() ) + { + Reference< XController > xController( xEnum->nextElement(), UNO_QUERY_THROW ); + _io_rDocDesc.aControllers.push_back( xController ); + } + } + else if ( _io_rDocDesc.xModel.is() ) + _io_rDocDesc.aControllers.push_back( _io_rDocDesc.xModel->getCurrentController() ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + + void lcl_getDocuments_nothrow( const Sequence< Reference< XFrame > >& _rFrames, Documents& _out_rDocuments, + const IDocumentDescriptorFilter* _pFilter ) + { + // ensure we don't encounter some models multiple times + std::set< Reference< XModel > > aEncounteredModels; + + for ( auto const & rFrame : _rFrames ) + { + try + { + OSL_ENSURE( rFrame.is(), "lcl_getDocuments_nothrow: illegal frame!" ); + if ( !rFrame.is() ) + continue; + Reference< XController > xController( rFrame->getController() ); + if ( !xController.is() ) + continue; + + Reference< XModel > xModel( xController->getModel() ); + if ( !xModel.is() ) + // though it's legal for a controller to not have a model, we're not interested in + // those + continue; + + if ( !aEncounteredModels.insert( xModel ).second ) + // there might be multiple frames for the same model + // handle it only once + continue; + + // create a DocumentDescriptor + DocumentDescriptor aDescriptor; + aDescriptor.xModel = xModel; + lcl_getDocumentControllers_nothrow( aDescriptor ); + + // consult filter, if there is one + if ( _pFilter && !_pFilter->includeDocument( aDescriptor ) ) + continue; + + _out_rDocuments.push_back( aDescriptor ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + } + } + + void DocumentEnumeration::getDocuments( Documents& _out_rDocuments ) const + { + _out_rDocuments.clear(); + + try + { + const Reference< XDesktop2 > xDesktop = Desktop::create( m_xContext ); + const Reference< XFrames > xFrames( xDesktop->getFrames(), UNO_SET_THROW ); + const Sequence< Reference< XFrame > > aFrames( xFrames->queryFrames( FrameSearchFlag::ALL ) ); + + lcl_getDocuments_nothrow( aFrames, _out_rDocuments, m_pFilter ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + +} // namespace basctl::docs + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/documentenumeration.hxx b/basctl/source/basicide/documentenumeration.hxx new file mode 100644 index 0000000000..dfd4d2e817 --- /dev/null +++ b/basctl/source/basicide/documentenumeration.hxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/frame/XController.hpp> +#include <memory> +#include <vector> + +namespace com::sun::star::uno { class XComponentContext; } + + +namespace basctl::docs { + + + typedef std::vector< css::uno::Reference< css::frame::XController > > Controllers; + + struct DocumentDescriptor + { + css::uno::Reference< css::frame::XModel > xModel; + Controllers aControllers; + }; + + typedef std::vector< DocumentDescriptor > Documents; + + + /// allows pre-filtering when enumerating document descriptors + class SAL_NO_VTABLE IDocumentDescriptorFilter + { + public: + virtual bool includeDocument( const DocumentDescriptor& _rDocument ) const = 0; + + protected: + ~IDocumentDescriptorFilter() {} + }; + + + /** is a helper class for enumerating documents in OOo + + If you need a list of all open documents in OOo, this is little bit of + a hassle: You need to iterate though all components at the desktop, which + might or might not be documents. + + Additionally, you need to examine the existing documents' frames + for sub frames, which might contain sub documents (e.g. embedded objects + edited out-place). + + DocumentEnumeration relieves you from this hassle. + */ + class DocumentEnumeration + { + public: + DocumentEnumeration( css::uno::Reference< css::uno::XComponentContext > const & _rContext, const IDocumentDescriptorFilter* _pFilter ); + ~DocumentEnumeration(); + + /** retrieves a list of all currently known documents in the application + + @param _out_rDocuments + output parameter taking the collected document information + @ + */ + void getDocuments( + Documents& _out_rDocuments + ) const; + + private: + css::uno::Reference< css::uno::XComponentContext > m_xContext; + const IDocumentDescriptorFilter* m_pFilter; + }; + + +} // namespace basctl::docs + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/iderdll.cxx b/basctl/source/basicide/iderdll.cxx new file mode 100644 index 0000000000..022045050e --- /dev/null +++ b/basctl/source/basicide/iderdll.cxx @@ -0,0 +1,205 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <comphelper/unique_disposing_ptr.hxx> +#include <comphelper/processfactory.hxx> + +#include <iderdll.hxx> +#include "iderdll2.hxx" +#include <iderid.hxx> +#include <basidesh.hxx> +#include <basobj.hxx> +#include "basdoc.hxx" +#include "basicmod.hxx" + +#include <basic/sbstar.hxx> +#include <com/sun/star/frame/Desktop.hpp> +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <unotools/resmgr.hxx> +#include <sfx2/app.hxx> +#include <osl/diagnose.h> + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +namespace +{ + +class Dll +{ + Shell* m_pShell; + std::unique_ptr<ExtraData> m_xExtraData; + +public: + Dll (); + + Shell* GetShell() const { return m_pShell; } + void SetShell (Shell* pShell) { m_pShell = pShell; } + ExtraData* GetExtraData (); +}; + +// Holds a basctl::Dll and release it on exit, or dispose of the +//default XComponent, whichever comes first +class DllInstance : public comphelper::unique_disposing_solar_mutex_reset_ptr<Dll> +{ +public: + DllInstance() : comphelper::unique_disposing_solar_mutex_reset_ptr<Dll>(Reference<lang::XComponent>( frame::Desktop::create(comphelper::getProcessComponentContext()), UNO_QUERY_THROW), new Dll, true) + { } +}; + +struct theDllInstance : public rtl::Static<DllInstance, theDllInstance> { }; + +} // namespace + +void EnsureIde () +{ + // coverity[side_effect_free : FALSE] - not actually side-effect-free + theDllInstance::get(); +} + +Shell* GetShell () +{ + if (Dll* pDll = theDllInstance::get().get()) + return pDll->GetShell(); + return nullptr; +} + +void ShellCreated (Shell* pShell) +{ + Dll* pDll = theDllInstance::get().get(); + if (pDll && !pDll->GetShell()) + pDll->SetShell(pShell); +} + +void ShellDestroyed (Shell const * pShell) +{ + Dll* pDll = theDllInstance::get().get(); + if (pDll && pDll->GetShell() == pShell) + pDll->SetShell(nullptr); +} + +ExtraData* GetExtraData() +{ + if (Dll* pDll = theDllInstance::get().get()) + return pDll->GetExtraData(); + return nullptr; +} + +OUString IDEResId(TranslateId aId) +{ + return Translate::get(aId, SfxApplication::GetModule(SfxToolsModule::Basic)->GetResLocale()); +} + +namespace +{ + +Dll::Dll () : + m_pShell(nullptr) +{ + SfxObjectFactory& rFactory = DocShell::Factory(); + + auto pModule = std::make_unique<Module>("basctl", &rFactory); + SfxModule* pMod = pModule.get(); + SfxApplication::SetModule(SfxToolsModule::Basic, std::move(pModule)); + + GetExtraData(); // to cause GlobalErrorHdl to be set + + rFactory.SetDocumentServiceName( "com.sun.star.script.BasicIDE" ); + + DocShell::RegisterInterface( pMod ); + Shell::RegisterFactory( SVX_INTERFACE_BASIDE_VIEWSH ); + Shell::RegisterInterface( pMod ); +} + +ExtraData* Dll::GetExtraData () +{ + if (!m_xExtraData) + m_xExtraData.reset(new ExtraData); + return m_xExtraData.get(); +} + +} // namespace + + +// basctl::ExtraData + + +ExtraData::ExtraData () : + bChoosingMacro(false), + bShellInCriticalSection(false) +{ + StarBASIC::SetGlobalBreakHdl(LINK(this, ExtraData, GlobalBasicBreakHdl)); +} + +ExtraData::~ExtraData () +{ + // Resetting ErrorHdl is cleaner indeed but this instance is destroyed + // pretty late, after the last Basic, anyway. + // Due to the call there is AppData created then though and not + // destroyed anymore => MLK's at Purify +// StarBASIC::SetGlobalErrorHdl( Link() ); +// StarBASIC::SetGlobalBreakHdl( Link() ); +// StarBASIC::setGlobalStarScriptListener( XEngineListenerRef() ); +} + +IMPL_STATIC_LINK(ExtraData, GlobalBasicBreakHdl, StarBASIC *, pBasic, BasicDebugFlags) +{ + BasicDebugFlags nRet = BasicDebugFlags::NONE; + if (Shell* pShell = GetShell()) + { + if (BasicManager* pBasMgr = FindBasicManager(pBasic)) + { + // I do get here twice if Step into protected Basic + // => bad, if password query twice, also you don't see + // the lib in the PasswordDlg... + // => start no password query at this point + ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) ); + OSL_ENSURE( aDocument.isValid(), "basctl::ExtraData::GlobalBasicBreakHdl: no document for the basic manager!" ); + if ( aDocument.isValid() ) + { + OUString aOULibName( pBasic->GetName() ); + Reference< script::XLibraryContainer > xModLibContainer = aDocument.getLibraryContainer( E_SCRIPTS ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aOULibName ) && !xPasswd->isLibraryPasswordVerified( aOULibName ) ) + { + // a step-out should get me out of the protected area... + nRet = BasicDebugFlags::StepOut; + } + else + { + nRet = pShell->CallBasicBreakHdl( pBasic ); + } + } + } + } + } + + return nRet; +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/iderdll2.hxx b/basctl/source/basicide/iderdll2.hxx new file mode 100644 index 0000000000..99534119f8 --- /dev/null +++ b/basctl/source/basicide/iderdll2.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 + +class StarBASIC; +class SvxSearchItem; + + +#include <bastypes.hxx> +#include <bastype2.hxx> + +namespace basctl +{ + +class ExtraData final +{ + LibInfo aLibInfo; + + EntryDescriptor m_aLastEntryDesc; + + OUString aAddLibPath; + OUString aAddLibFilter; + + bool bChoosingMacro; + bool bShellInCriticalSection; + + DECL_STATIC_LINK( ExtraData, GlobalBasicBreakHdl, StarBASIC *, BasicDebugFlags ); + +public: + ExtraData(); + ~ExtraData(); + + LibInfo& GetLibInfo () { return aLibInfo; } + + EntryDescriptor& GetLastEntryDescriptor () { return m_aLastEntryDesc; } + void SetLastEntryDescriptor (EntryDescriptor const & rDesc) { m_aLastEntryDesc = rDesc; } + + bool& ChoosingMacro() { return bChoosingMacro; } + bool& ShellInCriticalSection() { return bShellInCriticalSection; } + + const OUString& GetAddLibPath() const { return aAddLibPath; } + void SetAddLibPath( const OUString& rPath ) { aAddLibPath = rPath; } + + const OUString& GetAddLibFilter() const { return aAddLibFilter; } + void SetAddLibFilter( const OUString& rFilter ) { aAddLibFilter = rFilter; } +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/layout.cxx b/basctl/source/basicide/layout.cxx new file mode 100644 index 0000000000..e6b6676ed6 --- /dev/null +++ b/basctl/source/basicide/layout.cxx @@ -0,0 +1,430 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <layout.hxx> + +#include <bastypes.hxx> +#include <vcl/settings.hxx> +#include <vcl/event.hxx> + +namespace basctl +{ + +namespace +{ +// the thickness of the splitting lines +tools::Long const nSplitThickness = 3; +} // namespace + +// ctor for derived classes +// pParent: the parent window (Shell) +Layout::Layout (vcl::Window* pParent) : + Window(pParent, WB_CLIPCHILDREN), + pChild(nullptr), + bFirstSize(true), + aLeftSide(this, SplittedSide::Side::Left), + aBottomSide(this, SplittedSide::Side::Bottom) +{ + SetBackground(GetSettings().GetStyleSettings().GetWindowColor()); + + vcl::Font aFont = GetFont(); + Size aSz = aFont.GetFontSize(); + aSz.setHeight( aSz.Height() * 1.5 ); + aFont.SetFontSize(aSz); + aFont.SetWeight(WEIGHT_BOLD); + aFont.SetColor(GetSettings().GetStyleSettings().GetWindowTextColor()); + SetFont(aFont); +} + +Layout::~Layout() +{ + disposeOnce(); +} + +void Layout::dispose() +{ + aLeftSide.dispose(); + aBottomSide.dispose(); + pChild.clear(); + Window::dispose(); +} + +// removes a docking window +void Layout::Remove (DockingWindow* pWin) +{ + aLeftSide.Remove(pWin); + aBottomSide.Remove(pWin); +} + +// called by Window when resized +void Layout::Resize() +{ + if (IsVisible()) + ArrangeWindows(); +} + +// ArrangeWindows() -- arranges the child windows +void Layout::ArrangeWindows () +{ + // prevent recursion via OnFirstSize() -> Add() -> ArrangeWindows() + static bool bInArrangeWindows = false; + if (bInArrangeWindows) + return; + bInArrangeWindows = true; + + Size const aSize = GetOutputSizePixel(); + tools::Long const nWidth = aSize.Width(), nHeight = aSize.Height(); + if (nWidth && nHeight) // non-empty size + { + // On first call the derived classes initializes the sizes of the + // docking windows. This cannot be done at construction because + // the Layout has empty size at that point. + if (bFirstSize) + { + bFirstSize = false; + OnFirstSize(nWidth, nHeight); // virtual + } + + // sides + aBottomSide.ArrangeIn(tools::Rectangle(Point(0, 0), aSize)); + aLeftSide.ArrangeIn(tools::Rectangle(Point(0, 0), Size(nWidth, nHeight - aBottomSide.GetSize()))); + // child in the middle + pChild->SetPosSizePixel( + Point(aLeftSide.GetSize(), 0), + Size(nWidth - aLeftSide.GetSize(), nHeight - aBottomSide.GetSize()) + ); + } + + bInArrangeWindows = false; +} + +void Layout::Activating (BaseWindow& rWindow) +{ + // first activation + pChild = &rWindow; + ArrangeWindows(); + Show(); + pChild->Activating(); +} + +void Layout::Deactivating () +{ + if (pChild) + pChild->Deactivating(); + Hide(); + pChild = nullptr; +} + +// virtual +void Layout::DataChanged (DataChangedEvent const& rDCEvt) +{ + Window::DataChanged(rDCEvt); + if (!(rDCEvt.GetType() == DataChangedEventType::SETTINGS && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE))) + return; + + bool bInvalidate = false; + Color aColor = GetSettings().GetStyleSettings().GetWindowColor(); + const AllSettings* pOldSettings = rDCEvt.GetOldSettings(); + if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetWindowColor()) + { + SetBackground(Wallpaper(aColor)); + bInvalidate = true; + } + aColor = GetSettings().GetStyleSettings().GetWindowTextColor(); + if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetWindowTextColor()) + { + vcl::Font aFont(GetFont()); + aFont.SetColor(aColor); + SetFont(aFont); + bInvalidate = true; + } + if (bInvalidate) + Invalidate(); +} + + +// SplittedSide + + +// ctor +Layout::SplittedSide::SplittedSide (Layout* pParent, Side eSide) : + rLayout(*pParent), + bVertical(eSide == Side::Left), + bLower(eSide == Side::Left), + nSize(0), + aSplitter(VclPtr<Splitter>::Create(pParent, bVertical ? WB_HSCROLL : WB_VSCROLL)) +{ + InitSplitter(*aSplitter); +} + +void Layout::SplittedSide::dispose() +{ + aSplitter.disposeAndClear(); + for (auto & item : vItems) + { + item.pSplit.disposeAndClear(); + item.pWin.clear(); + } +} + +// Add() -- adds a new window to the side (after construction) +void Layout::SplittedSide::Add (DockingWindow* pWin, Size const& rSize) +{ + tools::Long const nSize1 = (bVertical ? rSize.Width() : rSize.Height()) + nSplitThickness; + tools::Long const nSize2 = bVertical ? rSize.Height() : rSize.Width(); + // nSize + if (nSize1 > nSize) + nSize = nSize1; + // window + Item aItem; + aItem.pWin = pWin; + aItem.nStartPos = vItems.empty() ? 0 : vItems.back().nEndPos + nSplitThickness; + aItem.nEndPos = aItem.nStartPos + nSize2; + // splitter + if (!vItems.empty()) + { + aItem.pSplit = VclPtr<Splitter>::Create(&rLayout, bVertical ? WB_VSCROLL : WB_HSCROLL); + aItem.pSplit->SetSplitPosPixel(aItem.nStartPos - nSplitThickness); + InitSplitter(*aItem.pSplit); + } + vItems.push_back(aItem); + // refresh + rLayout.ArrangeWindows(); +} + +// Remove() -- removes a window from the side (if contains) +void Layout::SplittedSide::Remove (DockingWindow* pWin) +{ + // contains? + std::vector<Item>::size_type iWin; + for (iWin = 0; iWin != vItems.size(); ++iWin) + if (vItems[iWin].pWin == pWin) + break; + if (iWin == vItems.size()) + return; + // remove + vItems[iWin].pSplit.disposeAndClear(); + vItems[iWin].pWin.clear(); + vItems.erase(vItems.begin() + iWin); + // if that was the first one, remove the first splitter line + if (iWin == 0 && !vItems.empty()) + vItems.front().pSplit.reset(); +} + +// creating a Point or a Size object +// The coordinate order depends on bVertical (reversed if true). +inline Size Layout::SplittedSide::MakeSize (tools::Long A, tools::Long B) const +{ + return bVertical ? Size(B, A) : Size(A, B); +} +inline Point Layout::SplittedSide::MakePoint (tools::Long A, tools::Long B) const +{ + return bVertical ? Point(B, A) : Point(A, B); +} + +// IsDocking() -- is this window currently docking in the strip? +bool Layout::SplittedSide::IsDocking (DockingWindow const& rWin) +{ + return rWin.IsVisible() && !rWin.IsFloatingMode(); +} + +// IsEmpty() -- are there no windows docked in this strip? +bool Layout::SplittedSide::IsEmpty () const +{ + for (auto const & i: vItems) + if (IsDocking(*i.pWin)) + return false; + return true; +} + +// GetSize() -- returns the width or height of the strip (depending on the direction) +tools::Long Layout::SplittedSide::GetSize () const +{ + return IsEmpty() ? 0 : nSize; +} + +// Arrange() -- arranges the docking windows +// rRect: the available space +void Layout::SplittedSide::ArrangeIn (tools::Rectangle const& rRect) +{ + // saving the rectangle + aRect = rRect; + + // the length of the side + tools::Long const nLength = bVertical ? aRect.GetSize().Height() : aRect.GetSize().Width(); + tools::Long const nOtherSize = bVertical ? aRect.GetSize().Width() : aRect.GetSize().Height(); + // bVertical ? horizontal position : vertical position + tools::Long const nPos1 = (bVertical ? aRect.Left() : aRect.Top()) + + (bLower ? 0 : nOtherSize - (nSize - nSplitThickness)); + // bVertical ? vertical position : horizontal position + tools::Long const nPos2 = bVertical ? aRect.Top() : aRect.Left(); + + // main line + bool const bEmpty = IsEmpty(); + // shown if any of the windows is docked + if (!bEmpty) + { + aSplitter->Show(); + // split position + aSplitter->SetSplitPosPixel((bLower ? nSize : nPos1) - nSplitThickness); + // the actual position and size + aSplitter->SetPosSizePixel( + MakePoint(nPos2, aSplitter->GetSplitPosPixel()), + MakeSize(nLength, nSplitThickness) + ); + // dragging rectangle + aSplitter->SetDragRectPixel(aRect); + } + else + aSplitter->Hide(); + + // positioning separator lines and windows + bool bPrevDocking = false; // is the previous window docked? + tools::Long nStartPos = 0; // window position in the strip + std::vector<Item>::size_type iLastWin = vItems.size(); // index of last docking window in the strip + + for (std::vector<Item>::size_type i = 0; i != vItems.size(); ++i) + { + // window + DockingWindow& rWin = *vItems[i].pWin; + bool const bDocking = IsDocking(rWin); + if (bDocking) + iLastWin = i; + // sizing window + rWin.ResizeIfDocking( + MakePoint(nPos2 + nStartPos, nPos1), + MakeSize(vItems[i].nEndPos - nStartPos, nSize - nSplitThickness) + ); + // splitting line before the window + if (i > 0) + { + Splitter& rSplit = *vItems[i].pSplit; + // If neither of two adjacent windows are docked, + // the splitting line is hidden. + // If this window is docking but the previous isn't, + // then the splitting line is also hidden, because this window + // will occupy the space of the previous. + if (bPrevDocking) + { + rSplit.Show(); + // the actual position and size of the line + rSplit.SetPosSizePixel( + MakePoint(nPos2 + nStartPos - nSplitThickness, nPos1), + MakeSize(nSplitThickness, nSize - nSplitThickness) + ); + // the dragging rectangle + rSplit.SetDragRectPixel(tools::Rectangle( + MakePoint(nPos2, nPos1), + MakeSize(nLength, nSize - nSplitThickness) + )); + } + else + rSplit.Hide(); + } + // next + bPrevDocking = bDocking; + if (bDocking) + nStartPos = vItems[i].nEndPos + nSplitThickness; + // We only set nStartPos if this window is docking, because otherwise + // the next window will occupy also the space of this window. + } + + // filling the remaining space with the last docking window + if (bEmpty || vItems[iLastWin].nEndPos == nLength) + return; + + Item& rItem = vItems[iLastWin]; + Size aSize = rItem.pWin->GetDockingSize(); + if (bVertical) + aSize.AdjustHeight( nLength - rItem.nEndPos ); + else + aSize.AdjustWidth( nLength - rItem.nEndPos ); + rItem.pWin->ResizeIfDocking(aSize); + // and hiding the split line after the window + if (iLastWin < vItems.size() - 1) + vItems[iLastWin + 1].pSplit->Hide(); +} + +IMPL_LINK(Layout::SplittedSide, SplitHdl, Splitter*, pSplitter, void) +{ + // checking margins + CheckMarginsFor(pSplitter); + // changing stored sizes + if (pSplitter == aSplitter.get()) + { + // nSize + if (bLower) + nSize = pSplitter->GetSplitPosPixel(); + else + nSize = (bVertical ? aRect.Right() : aRect.Bottom()) + 1 - pSplitter->GetSplitPosPixel(); + } + else + { + // Item::nStartPos, Item::nLength + for (size_t i = 1; i < vItems.size(); ++i) + { + if (vItems[i].pSplit.get() == pSplitter) + { + // before the line + vItems[i - 1].nEndPos = pSplitter->GetSplitPosPixel(); + // after the line + vItems[i].nStartPos = pSplitter->GetSplitPosPixel() + nSplitThickness; + } + } + } + // arranging windows + rLayout.ArrangeWindows(); +} + +void Layout::SplittedSide::CheckMarginsFor (Splitter* pSplitter) +{ + // The splitter line cannot be closer to the edges than nMargin pixels. + static tools::Long const nMargin = 16; + // Checking margins: + tools::Long const nLength = pSplitter->IsHorizontal() ? + aRect.GetWidth() : aRect.GetHeight(); + if (!nLength) + return; + + // bounds + tools::Long const nLower = (pSplitter->IsHorizontal() ? aRect.Left() : aRect.Top()) + nMargin; + tools::Long const nUpper = nLower + nLength - 2*nMargin; + // split position + tools::Long const nPos = pSplitter->GetSplitPosPixel(); + // checking bounds + if (nPos < nLower) + pSplitter->SetSplitPosPixel(nLower); + if (nPos > nUpper) + pSplitter->SetSplitPosPixel(nUpper); +} + +void Layout::SplittedSide::InitSplitter (Splitter& rSplitter) +{ + // link + rSplitter.SetSplitHdl(LINK(this, SplittedSide, SplitHdl)); + // color + Color aColor = rLayout.GetSettings().GetStyleSettings().GetShadowColor(); + rSplitter.GetOutDev()->SetLineColor(aColor); + rSplitter.GetOutDev()->SetFillColor(aColor); +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/linenumberwindow.cxx b/basctl/source/basicide/linenumberwindow.cxx new file mode 100644 index 0000000000..18420199e2 --- /dev/null +++ b/basctl/source/basicide/linenumberwindow.cxx @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "baside2.hxx" + +#include <vcl/event.hxx> +#include <vcl/textview.hxx> +#include <vcl/xtextedt.hxx> +#include <vcl/settings.hxx> + +namespace basctl +{ +LineNumberWindow::LineNumberWindow(vcl::Window* pParent, ModulWindow* pModulWindow) + : Window(pParent, WB_BORDER) + , m_pModulWindow(pModulWindow) + , m_nCurYOffset(0) +{ + const Wallpaper aBackground(GetSettings().GetStyleSettings().GetWindowColor()); + SetBackground(aBackground); + GetWindow(GetWindowType::Border)->SetBackground(aBackground); + m_FontColor = GetSettings().GetStyleSettings().GetWindowTextColor(); + m_nBaseWidth = GetTextWidth("8"); + m_nWidth = m_nBaseWidth * 3 + m_nBaseWidth / 2; +} + +LineNumberWindow::~LineNumberWindow() { disposeOnce(); } + +void LineNumberWindow::dispose() +{ + m_pModulWindow.clear(); + Window::dispose(); +} + +void LineNumberWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) +{ + if (SyncYOffset()) + return; + + ExtTextEngine* txtEngine = m_pModulWindow->GetEditEngine(); + if (!txtEngine) + return; + + TextView* txtView = m_pModulWindow->GetEditView(); + if (!txtView) + return; + + int windowHeight = rRenderContext.GetOutputSize().Height(); + int nLineHeight = rRenderContext.GetTextHeight(); + if (!nLineHeight) + { + return; + } + + int startY = txtView->GetStartDocPos().Y(); + const sal_uInt32 nStartLine = startY / nLineHeight + 1; + sal_uInt32 nEndLine = (startY + windowHeight) / nLineHeight + 1; + + if (txtEngine->GetParagraphCount() + 1 < nEndLine) + nEndLine = txtEngine->GetParagraphCount() + 1; + + // FIXME: it would be best if we could get notified of a font change + // rather than doing that re-calculation at each Paint event + m_nBaseWidth = GetTextWidth("8"); + + // reserve enough for 3 digit minimum, with a bit to spare for comfort + m_nWidth = m_nBaseWidth * 3 + m_nBaseWidth / 2; + auto nMaxLineNumber = std::max(nEndLine, txtEngine->GetParagraphCount() + 1); + sal_uInt32 i = (nMaxLineNumber + 1) / 1000; + while (i) + { + i /= 10; + m_nWidth += m_nBaseWidth; + } + + sal_Int64 y = (nStartLine - 1) * static_cast<sal_Int64>(nLineHeight); + rRenderContext.SetTextColor(m_FontColor); + for (sal_uInt32 n = nStartLine; n <= nEndLine; ++n, y += nLineHeight) + { + const OUString aLineNumber = OUString::number(n); + // tdf#153798 - align line numbers to the right + rRenderContext.DrawText( + Point(m_nWidth - GetTextWidth(aLineNumber) - m_nBaseWidth / 2, y - m_nCurYOffset), + aLineNumber); + } + + // Resize the parent after calculating the new width and height values + GetParent()->Resize(); +} + +void LineNumberWindow::DataChanged(DataChangedEvent const& rDCEvt) +{ + Window::DataChanged(rDCEvt); + if (rDCEvt.GetType() == DataChangedEventType::SETTINGS + && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) + { + Color aColor(GetSettings().GetStyleSettings().GetFieldColor()); + const AllSettings* pOldSettings = rDCEvt.GetOldSettings(); + if (!pOldSettings || aColor != pOldSettings->GetStyleSettings().GetFieldColor()) + { + SetBackground(Wallpaper(aColor)); + Invalidate(); + } + } +} + +void LineNumberWindow::DoScroll(tools::Long nVertScroll) +{ + m_nCurYOffset -= nVertScroll; + Window::Scroll(0, nVertScroll); +} + +bool LineNumberWindow::SyncYOffset() +{ + TextView* pView = m_pModulWindow->GetEditView(); + if (!pView) + return false; + + tools::Long nViewYOffset = pView->GetStartDocPos().Y(); + if (m_nCurYOffset == nViewYOffset) + return false; + + m_nCurYOffset = nViewYOffset; + Invalidate(); + return true; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/linenumberwindow.hxx b/basctl/source/basicide/linenumberwindow.hxx new file mode 100644 index 0000000000..a2e457f711 --- /dev/null +++ b/basctl/source/basicide/linenumberwindow.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/. + */ + +#pragma once + +#include <vcl/window.hxx> + +namespace basctl +{ +class ModulWindow; + +class LineNumberWindow : public vcl::Window +{ +private: + VclPtr<ModulWindow> m_pModulWindow; + int m_nWidth; + tools::Long m_nCurYOffset; + int m_nBaseWidth; + Color m_FontColor; + virtual void DataChanged(DataChangedEvent const& rDCEvt) override; + +protected: + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + +public: + LineNumberWindow(vcl::Window* pParent, ModulWindow* pModulWin); + virtual ~LineNumberWindow() override; + virtual void dispose() override; + + void DoScroll(tools::Long nVertScroll); + + bool SyncYOffset(); + tools::Long& GetCurYOffset() { return m_nCurYOffset; } + + int GetWidth() const { return m_nWidth; } +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/localizationmgr.cxx b/basctl/source/basicide/localizationmgr.cxx new file mode 100644 index 0000000000..68d2f63622 --- /dev/null +++ b/basctl/source/basicide/localizationmgr.cxx @@ -0,0 +1,1100 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <string_view> + +#include <localizationmgr.hxx> + +#include <basidesh.hxx> +#include <baside3.hxx> +#include <basobj.hxx> +#include <iderdll.hxx> +#include <dlged.hxx> +#include <managelang.hxx> + +#include <com/sun/star/frame/XLayoutManager.hpp> +#include <com/sun/star/resource/MissingResourceException.hpp> +#include <com/sun/star/resource/XStringResourceSupplier.hpp> +#include <sfx2/bindings.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/viewfrm.hxx> +#include <tools/debug.hxx> +#include <utility> +#include <osl/diagnose.h> +#include <o3tl/string_view.hxx> + +namespace basctl +{ + +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::resource; + +namespace +{ + +constexpr OUString aDot(u"."_ustr); +constexpr OUString aEsc(u"&"_ustr); +constexpr OUString aSemi(u";"_ustr); + +} // namespace + +LocalizationMgr::LocalizationMgr( + Shell* pShell, + ScriptDocument aDocument, + OUString aLibName, + Reference<XStringResourceManager> const& xStringResourceManager +) : + m_xStringResourceManager(xStringResourceManager), + m_pShell(pShell), + m_aDocument(std::move(aDocument)), + m_aLibName(std::move(aLibName)) +{ } + +bool LocalizationMgr::isLibraryLocalized () +{ + if (m_xStringResourceManager.is()) + return m_xStringResourceManager->getLocales().hasElements(); + return false; +} + +void LocalizationMgr::handleTranslationbar () +{ + static constexpr OUString aToolBarResName = u"private:resource/toolbar/translationbar"_ustr; + + Reference< beans::XPropertySet > xFrameProps + ( m_pShell->GetViewFrame().GetFrame().GetFrameInterface(), uno::UNO_QUERY ); + if ( !xFrameProps.is() ) + return; + + Reference< css::frame::XLayoutManager > xLayoutManager; + uno::Any a = xFrameProps->getPropertyValue( "LayoutManager" ); + a >>= xLayoutManager; + if ( xLayoutManager.is() ) + { + if ( !isLibraryLocalized() ) + { + xLayoutManager->destroyElement( aToolBarResName ); + } + else + { + xLayoutManager->createElement( aToolBarResName ); + xLayoutManager->requestElement( aToolBarResName ); + } + } +} + + +// TODO: -> export from toolkit + + +static bool isLanguageDependentProperty( std::u16string_view aName ) +{ + static struct Prop + { + const char* sName; + sal_Int32 nNameLength; + } + const vProp[] = + { + { "Text", 4 }, + { "Label", 5 }, + { "Title", 5 }, + { "HelpText", 8 }, + { "CurrencySymbol", 14 }, + { "StringItemList", 14 }, + { nullptr, 0 } + }; + + for (Prop const* pProp = vProp; pProp->sName; ++pProp) + if (o3tl::equalsAscii(aName, std::string_view(pProp->sName, pProp->nNameLength))) + return true; + return false; +} + + +void LocalizationMgr::implEnableDisableResourceForAllLibraryDialogs( HandleResourceMode eMode ) +{ + Sequence< OUString > aDlgNames = m_aDocument.getObjectNames( E_DIALOGS, m_aLibName ); + sal_Int32 nDlgCount = aDlgNames.getLength(); + const OUString* pDlgNames = aDlgNames.getConstArray(); + + Reference< XStringResourceResolver > xDummyStringResolver; + for( sal_Int32 i = 0 ; i < nDlgCount ; i++ ) + { + OUString aDlgName = pDlgNames[ i ]; + if (VclPtr<DialogWindow> pWin = m_pShell->FindDlgWin(m_aDocument, m_aLibName, aDlgName)) + { + Reference< container::XNameContainer > xDialog = pWin->GetDialog(); + if( xDialog.is() ) + { + // Handle dialog itself as control + Any aDialogCtrl; + aDialogCtrl <<= xDialog; + implHandleControlResourceProperties( aDialogCtrl, aDlgName, + std::u16string_view(), m_xStringResourceManager, xDummyStringResolver, eMode ); + + // Handle all controls + Sequence< OUString > aNames = xDialog->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + sal_Int32 nCtrls = aNames.getLength(); + for( sal_Int32 j = 0 ; j < nCtrls ; ++j ) + { + OUString aCtrlName( pNames[j] ); + Any aCtrl = xDialog->getByName( aCtrlName ); + implHandleControlResourceProperties( aCtrl, aDlgName, + aCtrlName, m_xStringResourceManager, xDummyStringResolver, eMode ); + } + } + } + } +} + + +static OUString implCreatePureResourceId + ( std::u16string_view aDialogName, std::u16string_view aCtrlName, + std::u16string_view aPropName, + const Reference< XStringResourceManager >& xStringResourceManager ) +{ + sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId(); + OUString aPureIdStr = OUString::number( nUniqueId ) + + aDot + + aDialogName + + aDot; + if( !aCtrlName.empty() ) + { + aPureIdStr += aCtrlName + aDot; + } + aPureIdStr += aPropName; + return aPureIdStr; +} + +// Works on xStringResourceManager's current language for SET_IDS/RESET_IDS, +// anyway only one language should exist when calling this method then, +// either the first one for mode SET_IDS or the last one for mode RESET_IDS +sal_Int32 LocalizationMgr::implHandleControlResourceProperties + (const Any& rControlAny, std::u16string_view aDialogName, std::u16string_view aCtrlName, + const Reference< XStringResourceManager >& xStringResourceManager, + const Reference< XStringResourceResolver >& xSourceStringResolver, HandleResourceMode eMode ) +{ + sal_Int32 nChangedCount = 0; + + Reference< XPropertySet > xPropertySet; + rControlAny >>= xPropertySet; + if( xPropertySet.is() && xStringResourceManager.is()) + { + Sequence< Locale > aLocaleSeq = xStringResourceManager->getLocales(); + sal_Int32 nLocaleCount = aLocaleSeq.getLength(); + if( nLocaleCount == 0 ) + return 0; + + Reference< XPropertySetInfo > xPropertySetInfo = xPropertySet->getPropertySetInfo(); + if( xPropertySetInfo.is() ) + { + // get sequence of control properties + Sequence< Property > aPropSeq = xPropertySetInfo->getProperties(); + const Property* pProps = aPropSeq.getConstArray(); + sal_Int32 nCtrlProps = aPropSeq.getLength(); + + // create a map of tab indices and control names, sorted by tab index + for( sal_Int32 j = 0 ; j < nCtrlProps ; ++j ) + { + const Property& rProp = pProps[j]; + OUString aPropName = rProp.Name; + TypeClass eType = rProp.Type.getTypeClass(); + bool bLanguageDependentProperty = + (eType == TypeClass_STRING || eType == TypeClass_SEQUENCE) + && isLanguageDependentProperty( aPropName ); + if( !bLanguageDependentProperty ) + continue; + + if( eType == TypeClass_STRING ) + { + Any aPropAny = xPropertySet->getPropertyValue( aPropName ); + OUString aPropStr; + aPropAny >>= aPropStr; + + // Replace string by id, add id+string to StringResource + if( eMode == SET_IDS ) + { + bool bEscAlreadyExisting = aPropStr.startsWith("&"); + if( bEscAlreadyExisting ) + continue; + + OUString aPureIdStr = implCreatePureResourceId + ( aDialogName, aCtrlName, aPropName, xStringResourceManager ); + + // Set Id for all locales + const Locale* pLocales = aLocaleSeq.getConstArray(); + for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ ) + { + const Locale& rLocale = pLocales[ i ]; + xStringResourceManager->setStringForLocale( aPureIdStr, aPropStr, rLocale ); + } + + OUString aPropIdStr = aEsc + aPureIdStr; + // TODO?: Change here and in toolkit + (void)aSemi; + xPropertySet->setPropertyValue( aPropName, Any(aPropIdStr) ); + } + // Replace id by string from StringResource + else if( eMode == RESET_IDS ) + { + if( aPropStr.getLength() > 1 ) + { + OUString aPureIdStr = aPropStr.copy( 1 ); + OUString aNewPropStr = aPropStr; + try + { + aNewPropStr = xStringResourceManager->resolveString( aPureIdStr ); + } + catch(const MissingResourceException&) + { + } + xPropertySet->setPropertyValue( aPropName, Any(aNewPropStr) ); + } + } + // Remove Id for all locales + else if( eMode == REMOVE_IDS_FROM_RESOURCE ) + { + if( aPropStr.getLength() > 1 ) + { + OUString aPureIdStr = aPropStr.copy( 1 ); + + const Locale* pLocales = aLocaleSeq.getConstArray(); + for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ ) + { + const Locale& rLocale = pLocales[ i ]; + try + { + xStringResourceManager->removeIdForLocale( aPureIdStr, rLocale ); + } + catch(const MissingResourceException&) + { + } + } + } + } + // Rename resource id + else if( eMode == RENAME_DIALOG_IDS || eMode == RENAME_CONTROL_IDS ) + { + OUString aPureSourceIdStr = aPropStr.copy( 1 ); + + OUString aPureIdStr = implCreatePureResourceId + ( aDialogName, aCtrlName, aPropName, xStringResourceManager ); + + // Set new Id and remove old one for all locales + const Locale* pLocales = aLocaleSeq.getConstArray(); + for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ ) + { + const Locale& rLocale = pLocales[ i ]; + try + { + OUString aResStr = xStringResourceManager->resolveStringForLocale + ( aPureSourceIdStr, rLocale ); + xStringResourceManager->removeIdForLocale( aPureSourceIdStr, rLocale ); + xStringResourceManager->setStringForLocale( aPureIdStr, aResStr, rLocale ); + } + catch(const MissingResourceException&) + {} + } + + OUString aPropIdStr = aEsc + aPureIdStr; + // TODO?: Change here and in toolkit + (void)aSemi; + xPropertySet->setPropertyValue( aPropName, Any(aPropIdStr) ); + } + // Replace string by string from source StringResourceResolver + else if( eMode == MOVE_RESOURCES && xSourceStringResolver.is() ) + { + OUString aPureSourceIdStr = aPropStr.copy( 1 ); + + OUString aPureIdStr = implCreatePureResourceId + ( aDialogName, aCtrlName, aPropName, xStringResourceManager ); + + const Locale& rDefaultLocale = xSourceStringResolver->getDefaultLocale(); + + // Set Id for all locales + const Locale* pLocales = aLocaleSeq.getConstArray(); + for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ ) + { + const Locale& rLocale = pLocales[ i ]; + OUString aResStr; + try + { + aResStr = xSourceStringResolver->resolveStringForLocale + ( aPureSourceIdStr, rLocale ); + } + catch(const MissingResourceException&) + { + aResStr = xSourceStringResolver->resolveStringForLocale + ( aPureSourceIdStr, rDefaultLocale ); + } + xStringResourceManager->setStringForLocale( aPureIdStr, aResStr, rLocale ); + } + + OUString aPropIdStr = aEsc + aPureIdStr; + // TODO?: Change here and in toolkit + (void)aSemi; + xPropertySet->setPropertyValue( aPropName, Any(aPropIdStr) ); + } + // Copy string from source to target resource + else if( eMode == COPY_RESOURCES && xSourceStringResolver.is() ) + { + OUString aPureSourceIdStr = aPropStr.copy( 1 ); + + const Locale& rDefaultLocale = xSourceStringResolver->getDefaultLocale(); + + // Copy Id for all locales + const Locale* pLocales = aLocaleSeq.getConstArray(); + for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ ) + { + const Locale& rLocale = pLocales[ i ]; + OUString aResStr; + try + { + aResStr = xSourceStringResolver->resolveStringForLocale + ( aPureSourceIdStr, rLocale ); + } + catch(const MissingResourceException&) + { + aResStr = xSourceStringResolver->resolveStringForLocale + ( aPureSourceIdStr, rDefaultLocale ); + } + xStringResourceManager->setStringForLocale( aPureSourceIdStr, aResStr, rLocale ); + } + } + nChangedCount++; + } + + // Listbox / Combobox + else if( eType == TypeClass_SEQUENCE ) + { + Any aPropAny = xPropertySet->getPropertyValue( aPropName ); + Sequence< OUString > aPropStrings; + aPropAny >>= aPropStrings; + + const OUString* pPropStrings = aPropStrings.getConstArray(); + sal_Int32 nPropStringCount = aPropStrings.getLength(); + if( nPropStringCount == 0 ) + continue; + + // Replace string by id, add id+string to StringResource + if( eMode == SET_IDS ) + { + Sequence< OUString > aIdStrings; + aIdStrings.realloc( nPropStringCount ); + OUString* pIdStrings = aIdStrings.getArray(); + + OUString aIdStrBase = aDot + + aCtrlName + + aDot + + aPropName; + + const Locale* pLocales = aLocaleSeq.getConstArray(); + sal_Int32 i; + for ( i = 0; i < nPropStringCount; ++i ) + { + OUString aPropStr = pPropStrings[i]; + bool bEscAlreadyExisting = aPropStr.startsWith("&"); + if( bEscAlreadyExisting ) + { + pIdStrings[i] = aPropStr; + continue; + } + + sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId(); + OUString aPureIdStr = OUString::number( nUniqueId ) + + aIdStrBase; + + // Set Id for all locales + for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ ) + { + const Locale& rLocale = pLocales[ iLocale ]; + xStringResourceManager->setStringForLocale( aPureIdStr, aPropStr, rLocale ); + } + + OUString aPropIdStr = aEsc + aPureIdStr; + pIdStrings[i] = aPropIdStr; + } + xPropertySet->setPropertyValue( aPropName, Any(aIdStrings) ); + } + // Replace id by string from StringResource + else if( eMode == RESET_IDS ) + { + Sequence< OUString > aNewPropStrings; + aNewPropStrings.realloc( nPropStringCount ); + OUString* pNewPropStrings = aNewPropStrings.getArray(); + + sal_Int32 i; + for ( i = 0; i < nPropStringCount; ++i ) + { + OUString aIdStr = pPropStrings[i]; + OUString aNewPropStr = aIdStr; + if( aIdStr.getLength() > 1 ) + { + OUString aPureIdStr = aIdStr.copy( 1 ); + try + { + aNewPropStr = xStringResourceManager->resolveString( aPureIdStr ); + } + catch(const MissingResourceException&) + { + } + } + pNewPropStrings[i] = aNewPropStr; + } + xPropertySet->setPropertyValue( aPropName, Any(aNewPropStrings) ); + } + // Remove Id for all locales + else if( eMode == REMOVE_IDS_FROM_RESOURCE ) + { + const Locale* pLocales = aLocaleSeq.getConstArray(); + sal_Int32 i; + for ( i = 0; i < nPropStringCount; ++i ) + { + OUString aIdStr = pPropStrings[i]; + if( aIdStr.getLength() > 1 ) + { + OUString aPureIdStr = aIdStr.copy( 1 ); + + for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ ) + { + const Locale& rLocale = pLocales[iLocale]; + try + { + xStringResourceManager->removeIdForLocale( aPureIdStr, rLocale ); + } + catch(const MissingResourceException&) + { + } + } + } + } + } + // Rename resource id + else if( eMode == RENAME_CONTROL_IDS ) + { + Sequence< OUString > aIdStrings; + aIdStrings.realloc( nPropStringCount ); + OUString* pIdStrings = aIdStrings.getArray(); + + OUString aIdStrBase = aDot + + aCtrlName + + aDot + + aPropName; + + const Locale* pLocales = aLocaleSeq.getConstArray(); + sal_Int32 i; + for ( i = 0; i < nPropStringCount; ++i ) + { + OUString aSourceIdStr = pPropStrings[i]; + OUString aPureSourceIdStr = aSourceIdStr.copy( 1 ); + + sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId(); + OUString aPureIdStr = OUString::number( nUniqueId ) + + aIdStrBase; + + // Set Id for all locales + for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ ) + { + const Locale& rLocale = pLocales[ iLocale ]; + + try + { + OUString aResStr = xStringResourceManager->resolveStringForLocale + ( aPureSourceIdStr, rLocale ); + xStringResourceManager->removeIdForLocale( aPureSourceIdStr, rLocale ); + xStringResourceManager->setStringForLocale( aPureIdStr, aResStr, rLocale ); + } + catch(const MissingResourceException&) + {} + } + + OUString aPropIdStr = aEsc + aPureIdStr; + pIdStrings[i] = aPropIdStr; + } + xPropertySet->setPropertyValue( aPropName, Any(aIdStrings) ); + } + // Replace string by string from source StringResourceResolver + else if( eMode == MOVE_RESOURCES && xSourceStringResolver.is() ) + { + Sequence< OUString > aIdStrings; + aIdStrings.realloc( nPropStringCount ); + OUString* pIdStrings = aIdStrings.getArray(); + + OUString aIdStrBase = aDot + + aCtrlName + + aDot + + aPropName; + + const Locale& rDefaultLocale = xSourceStringResolver->getDefaultLocale(); + + const Locale* pLocales = aLocaleSeq.getConstArray(); + sal_Int32 i; + for ( i = 0; i < nPropStringCount; ++i ) + { + OUString aSourceIdStr = pPropStrings[i]; + OUString aPureSourceIdStr = aSourceIdStr.copy( 1 ); + + sal_Int32 nUniqueId = xStringResourceManager->getUniqueNumericId(); + OUString aPureIdStr = OUString::number( nUniqueId ) + + aIdStrBase; + + // Set Id for all locales + for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ ) + { + const Locale& rLocale = pLocales[ iLocale ]; + + OUString aResStr; + try + { + aResStr = xSourceStringResolver->resolveStringForLocale + ( aPureSourceIdStr, rLocale ); + } + catch(const MissingResourceException&) + { + aResStr = xSourceStringResolver->resolveStringForLocale + ( aPureSourceIdStr, rDefaultLocale ); + } + xStringResourceManager->setStringForLocale( aPureIdStr, aResStr, rLocale ); + } + + OUString aPropIdStr = aEsc + aPureIdStr; + pIdStrings[i] = aPropIdStr; + } + xPropertySet->setPropertyValue( aPropName, Any(aIdStrings) ); + } + // Copy string from source to target resource + else if( eMode == COPY_RESOURCES && xSourceStringResolver.is() ) + { + const Locale& rDefaultLocale = xSourceStringResolver->getDefaultLocale(); + + const Locale* pLocales = aLocaleSeq.getConstArray(); + sal_Int32 i; + for ( i = 0; i < nPropStringCount; ++i ) + { + OUString aSourceIdStr = pPropStrings[i]; + OUString aPureSourceIdStr = aSourceIdStr.copy( 1 ); + + // Set Id for all locales + for( sal_Int32 iLocale = 0 ; iLocale < nLocaleCount ; iLocale++ ) + { + const Locale& rLocale = pLocales[ iLocale ]; + + OUString aResStr; + try + { + aResStr = xSourceStringResolver->resolveStringForLocale + ( aPureSourceIdStr, rLocale ); + } + catch(const MissingResourceException&) + { + aResStr = xSourceStringResolver->resolveStringForLocale + ( aPureSourceIdStr, rDefaultLocale ); + } + xStringResourceManager->setStringForLocale( aPureSourceIdStr, aResStr, rLocale ); + } + } + } + nChangedCount++; + } + } + } + } + return nChangedCount; +} + + +void LocalizationMgr::handleAddLocales( const Sequence< Locale >& aLocaleSeq ) +{ + const Locale* pLocales = aLocaleSeq.getConstArray(); + sal_Int32 nLocaleCount = aLocaleSeq.getLength(); + + if( isLibraryLocalized() ) + { + for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ ) + { + const Locale& rLocale = pLocales[ i ]; + m_xStringResourceManager->newLocale( rLocale ); + } + } + else + { + DBG_ASSERT( nLocaleCount==1, "LocalizationMgr::handleAddLocales(): Only one first locale allowed" ); + + const Locale& rLocale = pLocales[ 0 ]; + m_xStringResourceManager->newLocale( rLocale ); + enableResourceForAllLibraryDialogs(); + } + + MarkDocumentModified( m_aDocument ); + + // update locale toolbar + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG ); + + handleTranslationbar(); +} + + +void LocalizationMgr::handleRemoveLocales( const Sequence< Locale >& aLocaleSeq ) +{ + const Locale* pLocales = aLocaleSeq.getConstArray(); + sal_Int32 nLocaleCount = aLocaleSeq.getLength(); + bool bConsistent = true; + bool bModified = false; + + for( sal_Int32 i = 0 ; i < nLocaleCount ; i++ ) + { + const Locale& rLocale = pLocales[ i ]; + bool bRemove = true; + + // Check if last locale + Sequence< Locale > aResLocaleSeq = m_xStringResourceManager->getLocales(); + if( aResLocaleSeq.getLength() == 1 ) + { + const Locale& rLastResLocale = aResLocaleSeq.getConstArray()[ 0 ]; + if( localesAreEqual( rLocale, rLastResLocale ) ) + { + disableResourceForAllLibraryDialogs(); + } + else + { + // Inconsistency, keep last locale + bConsistent = false; + bRemove = false; + } + } + + if( bRemove ) + { + try + { + m_xStringResourceManager->removeLocale( rLocale ); + bModified = true; + } + catch(const IllegalArgumentException&) + { + bConsistent = false; + } + } + } + if( bModified ) + { + MarkDocumentModified( m_aDocument ); + + // update slots + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG ); + pBindings->Invalidate( SID_BASICIDE_MANAGE_LANG ); + } + + handleTranslationbar(); + } + + DBG_ASSERT( bConsistent, + "LocalizationMgr::handleRemoveLocales(): sequence contains unsupported locales" ); +} + +void LocalizationMgr::handleSetDefaultLocale(const Locale& rLocale) +{ + if( !m_xStringResourceManager.is() ) + return; + + try + { + m_xStringResourceManager->setDefaultLocale(rLocale); + } + catch(const IllegalArgumentException&) + { + OSL_FAIL( "LocalizationMgr::handleSetDefaultLocale: Invalid locale" ); + } + + // update locale toolbar + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG ); +} + +void LocalizationMgr::handleSetCurrentLocale(const css::lang::Locale& rLocale) +{ + if( !m_xStringResourceManager.is() ) + return; + + try + { + m_xStringResourceManager->setCurrentLocale(rLocale, false); + } + catch(const IllegalArgumentException&) + { + OSL_FAIL( "LocalizationMgr::handleSetCurrentLocale: Invalid locale" ); + } + + // update locale toolbar + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG ); + + if (DialogWindow* pDlgWin = dynamic_cast<DialogWindow*>(m_pShell->GetCurWindow())) + if (!pDlgWin->IsSuspended()) + pDlgWin->GetEditor().UpdatePropertyBrowserDelayed(); +} + +void LocalizationMgr::handleBasicStarted() +{ + if( m_xStringResourceManager.is() ) + m_aLocaleBeforeBasicStart = m_xStringResourceManager->getCurrentLocale(); +} + +void LocalizationMgr::handleBasicStopped() +{ + try + { + if( m_xStringResourceManager.is() ) + m_xStringResourceManager->setCurrentLocale( m_aLocaleBeforeBasicStart, true ); + } + catch(const IllegalArgumentException&) + { + } +} + + +static DialogWindow* FindDialogWindowForEditor( DlgEditor const * pEditor ) +{ + Shell::WindowTable const& aWindowTable = GetShell()->GetWindowTable(); + for (auto const& window : aWindowTable) + { + BaseWindow* pWin = window.second; + if (!pWin->IsSuspended()) + if (DialogWindow* pDlgWin = dynamic_cast<DialogWindow*>(pWin)) + { + if (&pDlgWin->GetEditor() == pEditor) + return pDlgWin; + } + } + return nullptr; +} + + +void LocalizationMgr::setControlResourceIDsForNewEditorObject( DlgEditor const * pEditor, + const Any& rControlAny, std::u16string_view aCtrlName ) +{ + // Get library for DlgEditor + DialogWindow* pDlgWin = FindDialogWindowForEditor( pEditor ); + if( !pDlgWin ) + return; + ScriptDocument aDocument( pDlgWin->GetDocument() ); + DBG_ASSERT( aDocument.isValid(), "LocalizationMgr::setControlResourceIDsForNewEditorObject: invalid document!" ); + if ( !aDocument.isValid() ) + return; + const OUString& rLibName = pDlgWin->GetLibName(); + Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, rLibName, true ) ); + Reference< XStringResourceManager > xStringResourceManager = + LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + + // Set resource property + if( !xStringResourceManager.is() || !xStringResourceManager->getLocales().hasElements() ) + return; + + OUString aDialogName = pDlgWin->GetName(); + Reference< XStringResourceResolver > xDummyStringResolver; + sal_Int32 nChangedCount = implHandleControlResourceProperties + ( rControlAny, aDialogName, aCtrlName, xStringResourceManager, + xDummyStringResolver, SET_IDS ); + + if( nChangedCount ) + MarkDocumentModified( aDocument ); +} + +void LocalizationMgr::renameControlResourceIDsForEditorObject( DlgEditor const * pEditor, + const css::uno::Any& rControlAny, std::u16string_view aNewCtrlName ) +{ + // Get library for DlgEditor + DialogWindow* pDlgWin = FindDialogWindowForEditor( pEditor ); + if( !pDlgWin ) + return; + ScriptDocument aDocument( pDlgWin->GetDocument() ); + DBG_ASSERT( aDocument.isValid(), "LocalizationMgr::renameControlResourceIDsForEditorObject: invalid document!" ); + if ( !aDocument.isValid() ) + return; + const OUString& rLibName = pDlgWin->GetLibName(); + Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, rLibName, true ) ); + Reference< XStringResourceManager > xStringResourceManager = + LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + + // Set resource property + if( !xStringResourceManager.is() || !xStringResourceManager->getLocales().hasElements() ) + return; + + OUString aDialogName = pDlgWin->GetName(); + Reference< XStringResourceResolver > xDummyStringResolver; + implHandleControlResourceProperties + ( rControlAny, aDialogName, aNewCtrlName, xStringResourceManager, + xDummyStringResolver, RENAME_CONTROL_IDS ); +} + + +void LocalizationMgr::deleteControlResourceIDsForDeletedEditorObject( DlgEditor const * pEditor, + const Any& rControlAny, std::u16string_view aCtrlName ) +{ + // Get library for DlgEditor + DialogWindow* pDlgWin = FindDialogWindowForEditor( pEditor ); + if( !pDlgWin ) + return; + ScriptDocument aDocument( pDlgWin->GetDocument() ); + DBG_ASSERT( aDocument.isValid(), "LocalizationMgr::deleteControlResourceIDsForDeletedEditorObject: invalid document!" ); + if ( !aDocument.isValid() ) + return; + const OUString& rLibName = pDlgWin->GetLibName(); + Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, rLibName, true ) ); + Reference< XStringResourceManager > xStringResourceManager = + LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + + OUString aDialogName = pDlgWin->GetName(); + Reference< XStringResourceResolver > xDummyStringResolver; + sal_Int32 nChangedCount = implHandleControlResourceProperties + ( rControlAny, aDialogName, aCtrlName, xStringResourceManager, + xDummyStringResolver, REMOVE_IDS_FROM_RESOURCE ); + + if( nChangedCount ) + MarkDocumentModified( aDocument ); +} + +void LocalizationMgr::setStringResourceAtDialog( const ScriptDocument& rDocument, const OUString& aLibName, + std::u16string_view aDlgName, const Reference< container::XNameContainer >& xDialogModel ) +{ + // Get library + Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) ); + Reference< XStringResourceManager > xStringResourceManager = + LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + + // Set resource property + if( !xStringResourceManager.is() ) + return; + + // Not very elegant as dialog may or may not be localized yet + // TODO: Find better place, where dialog is created + if( xStringResourceManager->getLocales().hasElements() ) + { + Any aDialogCtrl; + aDialogCtrl <<= xDialogModel; + Reference< XStringResourceResolver > xDummyStringResolver; + implHandleControlResourceProperties( aDialogCtrl, aDlgName, + std::u16string_view(), xStringResourceManager, + xDummyStringResolver, SET_IDS ); + } + + Reference< beans::XPropertySet > xDlgPSet( xDialogModel, UNO_QUERY ); + xDlgPSet->setPropertyValue( "ResourceResolver", Any(xStringResourceManager) ); +} + +void LocalizationMgr::renameStringResourceIDs( const ScriptDocument& rDocument, const OUString& aLibName, + std::u16string_view aDlgName, const Reference< container::XNameContainer >& xDialogModel ) +{ + // Get library + Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) ); + Reference< XStringResourceManager > xStringResourceManager = + LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + if( !xStringResourceManager.is() ) + return; + + Any aDialogCtrl; + aDialogCtrl <<= xDialogModel; + Reference< XStringResourceResolver > xDummyStringResolver; + implHandleControlResourceProperties( aDialogCtrl, aDlgName, + std::u16string_view(), xStringResourceManager, + xDummyStringResolver, RENAME_DIALOG_IDS ); + + // Handle all controls + for(const auto& rCtrlName : xDialogModel->getElementNames()) { + Any aCtrl = xDialogModel->getByName( rCtrlName ); + implHandleControlResourceProperties( aCtrl, aDlgName, + rCtrlName, xStringResourceManager, + xDummyStringResolver, RENAME_DIALOG_IDS ); + } +} + +void LocalizationMgr::removeResourceForDialog( const ScriptDocument& rDocument, const OUString& aLibName, + std::u16string_view aDlgName, const Reference< container::XNameContainer >& xDialogModel ) +{ + // Get library + Reference< container::XNameContainer > xDialogLib( rDocument.getLibrary( E_DIALOGS, aLibName, true ) ); + Reference< XStringResourceManager > xStringResourceManager = + LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + if( !xStringResourceManager.is() ) + return; + + Any aDialogCtrl; + aDialogCtrl <<= xDialogModel; + Reference< XStringResourceResolver > xDummyStringResolver; + implHandleControlResourceProperties( aDialogCtrl, aDlgName, + std::u16string_view(), xStringResourceManager, + xDummyStringResolver, REMOVE_IDS_FROM_RESOURCE ); + + // Handle all controls + for(const auto& rCtrlName : xDialogModel->getElementNames()) { + Any aCtrl = xDialogModel->getByName( rCtrlName ); + implHandleControlResourceProperties( aCtrl, aDlgName, + rCtrlName, xStringResourceManager, + xDummyStringResolver, REMOVE_IDS_FROM_RESOURCE ); + } +} + +void LocalizationMgr::resetResourceForDialog( const Reference< container::XNameContainer >& xDialogModel, + const Reference< XStringResourceManager >& xStringResourceManager ) +{ + if( !xStringResourceManager.is() ) + return; + + // Dialog as control + std::u16string_view aDummyName; + Any aDialogCtrl; + aDialogCtrl <<= xDialogModel; + Reference< XStringResourceResolver > xDummyStringResolver; + implHandleControlResourceProperties( aDialogCtrl, aDummyName, + aDummyName, xStringResourceManager, xDummyStringResolver, RESET_IDS ); + + // Handle all controls + for(const auto& rCtrlName : xDialogModel->getElementNames()){ + Any aCtrl = xDialogModel->getByName( rCtrlName ); + implHandleControlResourceProperties( aCtrl, aDummyName, + rCtrlName, xStringResourceManager, xDummyStringResolver, RESET_IDS ); + } +} + +void LocalizationMgr::setResourceIDsForDialog( const Reference< container::XNameContainer >& xDialogModel, + const Reference< XStringResourceManager >& xStringResourceManager ) +{ + if( !xStringResourceManager.is() ) + return; + + // Dialog as control + std::u16string_view aDummyName; + Any aDialogCtrl; + aDialogCtrl <<= xDialogModel; + Reference< XStringResourceResolver > xDummyStringResolver; + implHandleControlResourceProperties( aDialogCtrl, aDummyName, + aDummyName, xStringResourceManager, xDummyStringResolver, SET_IDS ); + + // Handle all controls + for(const auto& rCtrlName : xDialogModel->getElementNames()) { + Any aCtrl = xDialogModel->getByName( rCtrlName ); + implHandleControlResourceProperties( aCtrl, aDummyName, + rCtrlName, xStringResourceManager, xDummyStringResolver, SET_IDS ); + } +} + +void LocalizationMgr::copyResourcesForPastedEditorObject( DlgEditor const * pEditor, + const Any& rControlAny, std::u16string_view aCtrlName, + const Reference< XStringResourceResolver >& xSourceStringResolver ) +{ + // Get library for DlgEditor + DialogWindow* pDlgWin = FindDialogWindowForEditor( pEditor ); + if( !pDlgWin ) + return; + ScriptDocument aDocument( pDlgWin->GetDocument() ); + DBG_ASSERT( aDocument.isValid(), "LocalizationMgr::copyResourcesForPastedEditorObject: invalid document!" ); + if ( !aDocument.isValid() ) + return; + const OUString& rLibName = pDlgWin->GetLibName(); + Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, rLibName, true ) ); + Reference< XStringResourceManager > xStringResourceManager = + LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + + // Set resource property + if( !xStringResourceManager.is() || !xStringResourceManager->getLocales().hasElements() ) + return; + + OUString aDialogName = pDlgWin->GetName(); + implHandleControlResourceProperties + ( rControlAny, aDialogName, aCtrlName, xStringResourceManager, + xSourceStringResolver, MOVE_RESOURCES ); +} + +void LocalizationMgr::copyResourceForDroppedDialog( const Reference< container::XNameContainer >& xDialogModel, + std::u16string_view aDialogName, + const Reference< XStringResourceManager >& xStringResourceManager, + const Reference< XStringResourceResolver >& xSourceStringResolver ) +{ + if( !xStringResourceManager.is() ) + return; + + // Dialog as control + Any aDialogCtrl; + aDialogCtrl <<= xDialogModel; + implHandleControlResourceProperties( aDialogCtrl, aDialogName, + std::u16string_view(), xStringResourceManager, xSourceStringResolver, MOVE_RESOURCES ); + + // Handle all controls + for(const auto& rCtrlName : xDialogModel->getElementNames()) { + Any aCtrl = xDialogModel->getByName( rCtrlName ); + implHandleControlResourceProperties( aCtrl, aDialogName, + rCtrlName, xStringResourceManager, xSourceStringResolver, MOVE_RESOURCES ); + } +} + +void LocalizationMgr::copyResourceForDialog( + const Reference< container::XNameContainer >& xDialogModel, + const Reference< XStringResourceResolver >& xSourceStringResolver, + const Reference< XStringResourceManager >& xTargetStringResourceManager ) +{ + if( !xDialogModel.is() || !xSourceStringResolver.is() || !xTargetStringResourceManager.is() ) + return; + + std::u16string_view aDummyName; + Any aDialogCtrl; + aDialogCtrl <<= xDialogModel; + implHandleControlResourceProperties + ( aDialogCtrl, aDummyName, aDummyName, xTargetStringResourceManager, + xSourceStringResolver, COPY_RESOURCES ); + + // Handle all controls + for(const auto& rCtrlName : xDialogModel->getElementNames()) { + Any aCtrl = xDialogModel->getByName( rCtrlName ); + implHandleControlResourceProperties( aCtrl, aDummyName, aDummyName, + xTargetStringResourceManager, xSourceStringResolver, COPY_RESOURCES ); + } +} + +Reference< XStringResourceManager > LocalizationMgr::getStringResourceFromDialogLibrary + ( const Reference< container::XNameContainer >& xDialogLib ) +{ + Reference< XStringResourceManager > xStringResourceManager; + if( xDialogLib.is() ) + { + Reference< resource::XStringResourceSupplier > xStringResourceSupplier( xDialogLib, UNO_QUERY ); + if( xStringResourceSupplier.is() ) + { + Reference< resource::XStringResourceResolver > + xStringResourceResolver = xStringResourceSupplier->getStringResource(); + + xStringResourceManager = + Reference< resource::XStringResourceManager >( xStringResourceResolver, UNO_QUERY ); + } + } + return xStringResourceManager; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/macrodlg.cxx b/basctl/source/basicide/macrodlg.cxx new file mode 100644 index 0000000000..6b4afb79f7 --- /dev/null +++ b/basctl/source/basicide/macrodlg.cxx @@ -0,0 +1,879 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "macrodlg.hxx" +#include <basidesh.hxx> +#include <strings.hrc> +#include <iderid.hxx> + +#include <iderdll.hxx> +#include "iderdll2.hxx" + +#include "moduldlg.hxx" +#include <basic/basmgr.hxx> +#include <basic/sbmeth.hxx> +#include <basic/sbmod.hxx> +#include <com/sun/star/script/XLibraryContainer2.hpp> +#include <sal/log.hxx> +#include <sfx2/app.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/frame.hxx> +#include <sfx2/minfitem.hxx> +#include <sfx2/request.hxx> +#include <sfx2/sfxsids.hrc> +#include <tools/debug.hxx> +#include <vcl/commandevent.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <osl/diagnose.h> + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +MacroChooser::MacroChooser(weld::Window* pParnt, const Reference< frame::XFrame >& xDocFrame) + : SfxDialogController(pParnt, "modules/BasicIDE/ui/basicmacrodialog.ui", "BasicMacroDialog") + , m_xDocumentFrame(xDocFrame) + // the Sfx doesn't ask the BasicManager whether modified or not + // => start saving in case of a change without a into the BasicIDE. + , bForceStoreBasic(false) + , nMode(All) + , m_xMacroNameEdit(m_xBuilder->weld_entry("macronameedit")) + , m_xMacroFromTxT(m_xBuilder->weld_label("macrofromft")) + , m_xMacrosSaveInTxt(m_xBuilder->weld_label("macrotoft")) + , m_xBasicBox(new SbTreeListBox(m_xBuilder->weld_tree_view("libraries"), m_xDialog.get())) + , m_xBasicBoxIter(m_xBasicBox->make_iterator()) + , m_xMacrosInTxt(m_xBuilder->weld_label("existingmacrosft")) + , m_xMacroBox(m_xBuilder->weld_tree_view("macros")) + , m_xMacroBoxIter(m_xMacroBox->make_iterator()) + , m_xRunButton(m_xBuilder->weld_button("ok")) + , m_xCloseButton(m_xBuilder->weld_button("close")) + , m_xAssignButton(m_xBuilder->weld_button("assign")) + , m_xEditButton(m_xBuilder->weld_button("edit")) + , m_xDelButton(m_xBuilder->weld_button("delete")) + , m_xNewButton(m_xBuilder->weld_button("new")) + , m_xOrganizeButton(m_xBuilder->weld_button("organize")) + , m_xNewLibButton(m_xBuilder->weld_button("newlibrary")) + , m_xNewModButton(m_xBuilder->weld_button("newmodule")) +{ + m_xBasicBox->set_size_request(m_xBasicBox->get_approximate_digit_width() * 30, m_xBasicBox->get_height_rows(18)); + m_xMacroBox->set_size_request(m_xMacroBox->get_approximate_digit_width() * 30, m_xMacroBox->get_height_rows(18)); + + m_aMacrosInTxtBaseStr = m_xMacrosInTxt->get_label(); + + m_xRunButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) ); + m_xCloseButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) ); + m_xAssignButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) ); + m_xEditButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) ); + m_xDelButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) ); + m_xNewButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) ); + m_xOrganizeButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) ); + + // Buttons only for MacroChooser::Recording + m_xNewLibButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) ); + m_xNewModButton->connect_clicked( LINK( this, MacroChooser, ButtonHdl ) ); + m_xNewLibButton->hide(); // default + m_xNewModButton->hide(); // default + m_xMacrosSaveInTxt->hide(); // default + + m_xMacroNameEdit->connect_changed( LINK( this, MacroChooser, EditModifyHdl ) ); + + m_xBasicBox->connect_changed( LINK( this, MacroChooser, BasicSelectHdl ) ); + + m_xMacroBox->connect_row_activated( LINK( this, MacroChooser, MacroDoubleClickHdl ) ); + m_xMacroBox->connect_changed( LINK( this, MacroChooser, MacroSelectHdl ) ); + m_xMacroBox->connect_popup_menu( LINK( this, MacroChooser, ContextMenuHdl ) ); + + m_xBasicBox->SetMode( BrowseMode::Modules ); + + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES ); + + m_xBasicBox->ScanAllEntries(); +} + +MacroChooser::~MacroChooser() +{ + if (bForceStoreBasic) + { + SfxGetpApp()->SaveBasicAndDialogContainer(); + bForceStoreBasic = false; + } +} + +void MacroChooser::StoreMacroDescription() +{ + if (!m_xBasicBox->get_selected(m_xBasicBoxIter.get())) + return; + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get()); + OUString aMethodName; + if (m_xMacroBox->get_selected(m_xMacroBoxIter.get())) + aMethodName = m_xMacroBox->get_text(*m_xMacroBoxIter); + else + aMethodName = m_xMacroNameEdit->get_text(); + if ( !aMethodName.isEmpty() ) + { + aDesc.SetMethodName( aMethodName ); + aDesc.SetType( OBJ_TYPE_METHOD ); + } + + if (ExtraData* pData = basctl::GetExtraData()) + pData->SetLastEntryDescriptor( aDesc ); +} + +void MacroChooser::RestoreMacroDescription() +{ + // The following call is a workaround to ensure the last used macro is scrolled to in kf5 + m_xDialog->resize_to_request(); + + EntryDescriptor aDesc; + if (Shell* pShell = GetShell()) + { + if (BaseWindow* pCurWin = pShell->GetCurWindow()) + aDesc = pCurWin->CreateEntryDescriptor(); + } + else + { + if (ExtraData* pData = basctl::GetExtraData()) + aDesc = pData->GetLastEntryDescriptor(); + } + + m_xBasicBox->SetCurrentEntry(aDesc); + BasicSelectHdl(m_xBasicBox->get_widget()); + + OUString aLastMacro( aDesc.GetMethodName() ); + if (!aLastMacro.isEmpty()) + { + // find entry in macro box + auto nIndex = m_xMacroBox->find_text(aLastMacro); + if (nIndex != -1) + m_xMacroBox->select(nIndex); + else + { + m_xMacroNameEdit->set_text(aLastMacro); + m_xMacroNameEdit->select_region(0, 0); + } + } +} + +short MacroChooser::run() +{ + RestoreMacroDescription(); + + // #104198 Check if "wrong" document is active + bool bSelectedEntry = m_xBasicBox->get_cursor(m_xBasicBoxIter.get()); + EntryDescriptor aDesc(m_xBasicBox->GetEntryDescriptor(bSelectedEntry ? m_xBasicBoxIter.get() : nullptr)); + const ScriptDocument& rSelectedDoc(aDesc.GetDocument()); + + // App Basic is always ok, so only check if shell was found + if( rSelectedDoc.isDocument() && !rSelectedDoc.isActive() ) + { + // Search for the right entry + bool bValidIter = m_xBasicBox->get_iter_first(*m_xBasicBoxIter); + while (bValidIter) + { + EntryDescriptor aCmpDesc(m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get())); + const ScriptDocument& rCmpDoc( aCmpDesc.GetDocument() ); + if (rCmpDoc.isDocument() && rCmpDoc.isActive()) + { + std::unique_ptr<weld::TreeIter> xEntry(m_xBasicBox->make_iterator()); + m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xEntry); + std::unique_ptr<weld::TreeIter> xLastValid(m_xBasicBox->make_iterator()); + bool bValidEntryIter = true; + do + { + m_xBasicBox->copy_iterator(*xEntry, *xLastValid); + bValidEntryIter = m_xBasicBox->iter_children(*xEntry); + } + while (bValidEntryIter); + m_xBasicBox->set_cursor(*xLastValid); + } + bValidIter = m_xBasicBox->iter_next_sibling(*m_xBasicBoxIter); + } + } + + CheckButtons(); + UpdateFields(); + + // tdf#62955 - Allow searching a name with typing the first letter + m_xBasicBox->get_widget().grab_focus(); + + if ( StarBASIC::IsRunning() ) + m_xCloseButton->grab_focus(); + + return SfxDialogController::run(); +} + +void MacroChooser::EnableButton(weld::Button& rButton, bool bEnable) +{ + if ( bEnable ) + { + if (nMode == ChooseOnly || nMode == Recording) + rButton.set_sensitive(&rButton == m_xRunButton.get()); + else + rButton.set_sensitive(true); + } + else + rButton.set_sensitive(false); +} + +SbMethod* MacroChooser::GetMacro() +{ + if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get())) + return nullptr; + SbModule* pModule = m_xBasicBox->FindModule(m_xBasicBoxIter.get()); + if (!pModule) + return nullptr; + if (!m_xMacroBox->get_selected(m_xMacroBoxIter.get())) + return nullptr; + OUString aMacroName(m_xMacroBox->get_text(*m_xMacroBoxIter)); + return pModule->FindMethod(aMacroName, SbxClassType::Method); +} + +void MacroChooser::DeleteMacro() +{ + SbMethod* pMethod = GetMacro(); + DBG_ASSERT( pMethod, "DeleteMacro: No Macro !" ); + if (!(pMethod && QueryDelMacro(pMethod->GetName(), m_xDialog.get()))) + return; + + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES ); + + // mark current doc as modified: + StarBASIC* pBasic = FindBasic(pMethod); + assert(pBasic && "Basic?!"); + BasicManager* pBasMgr = FindBasicManager( pBasic ); + DBG_ASSERT( pBasMgr, "BasMgr?" ); + ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) ); + if ( aDocument.isDocument() ) + { + aDocument.setDocumentModified(); + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_SAVEDOC ); + } + + SbModule* pModule = pMethod->GetModule(); + assert(pModule && "DeleteMacro: No Module?!"); + OUString aSource( pModule->GetSource32() ); + sal_uInt16 nStart, nEnd; + pMethod->GetLineRange( nStart, nEnd ); + pModule->GetMethods()->Remove( pMethod ); + CutLines( aSource, nStart-1, nEnd-nStart+1 ); + pModule->SetSource32( aSource ); + + // update module in library + OUString aLibName = pBasic->GetName(); + OUString aModName = pModule->GetName(); + OSL_VERIFY( aDocument.updateModule( aLibName, aModName, aSource ) ); + + bool bSelected = m_xMacroBox->get_selected(m_xMacroBoxIter.get()); + DBG_ASSERT(bSelected, "DeleteMacro: Entry ?!"); + m_xMacroBox->remove(*m_xMacroBoxIter); + bForceStoreBasic = true; +} + +SbMethod* MacroChooser::CreateMacro() +{ + SbMethod* pMethod = nullptr; + if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter)) + { + SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback"); + return nullptr; + } + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get()); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + OSL_ENSURE( aDocument.isAlive(), "MacroChooser::CreateMacro: no document!" ); + if ( !aDocument.isAlive() ) + return nullptr; + + OUString aLibName( aDesc.GetLibName() ); + + if ( aLibName.isEmpty() ) + aLibName = "Standard" ; + + aDocument.getOrCreateLibrary( E_SCRIPTS, aLibName ); + + OUString aOULibName( aLibName ); + Reference< script::XLibraryContainer > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ) ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) && !xModLibContainer->isLibraryLoaded( aOULibName ) ) + xModLibContainer->loadLibrary( aOULibName ); + Reference< script::XLibraryContainer > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ) ); + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && !xDlgLibContainer->isLibraryLoaded( aOULibName ) ) + xDlgLibContainer->loadLibrary( aOULibName ); + + BasicManager* pBasMgr = aDocument.getBasicManager(); + StarBASIC* pBasic = pBasMgr ? pBasMgr->GetLib( aLibName ) : nullptr; + if ( pBasic ) + { + SbModule* pModule = nullptr; + OUString aModName( aDesc.GetName() ); + if ( !aModName.isEmpty() ) + { + // extract the module name from the string like "Sheet1 (Example1)" + if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) ) + { + aModName = aModName.getToken( 0, ' ' ); + } + pModule = pBasic->FindModule( aModName ); + } + else if ( !pBasic->GetModules().empty() ) + pModule = pBasic->GetModules().front().get(); + + // Retain the desired macro name before the macro dialog box is forced to close + // by opening the module name dialog window when no module exists in the current library. + OUString aSubName = m_xMacroNameEdit->get_text(); + + if ( !pModule ) + { + pModule = createModImpl(m_xDialog.get(), aDocument, *m_xBasicBox, aLibName, aModName, false); + } + + DBG_ASSERT( !pModule || !pModule->FindMethod( aSubName, SbxClassType::Method ), "Macro exists already!" ); + pMethod = pModule ? basctl::CreateMacro( pModule, aSubName ) : nullptr; + } + + return pMethod; +} + +void MacroChooser::SaveSetCurEntry(weld::TreeView& rBox, const weld::TreeIter& rEntry) +{ + // the edit would be killed by the highlight otherwise: + + OUString aSaveText(m_xMacroNameEdit->get_text()); + int nStartPos, nEndPos; + m_xMacroNameEdit->get_selection_bounds(nStartPos, nEndPos); + + rBox.set_cursor(rEntry); + + m_xMacroNameEdit->set_text(aSaveText); + m_xMacroNameEdit->select_region(nStartPos, nEndPos); +} + +void MacroChooser::CheckButtons() +{ + const bool bCurEntry = m_xBasicBox->get_cursor(m_xBasicBoxIter.get()); + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(bCurEntry ? m_xBasicBoxIter.get() : nullptr); + const bool bMacroEntry = m_xMacroBox->get_selected(nullptr); + SbMethod* pMethod = GetMacro(); + + // check, if corresponding libraries are readonly + bool bReadOnly = false; + sal_uInt16 nDepth = bCurEntry ? m_xBasicBox->get_iter_depth(*m_xBasicBoxIter) : 0; + if ( nDepth == 1 || nDepth == 2 ) + { + const ScriptDocument& aDocument( aDesc.GetDocument() ); + const OUString& aOULibName( aDesc.GetLibName() ); + Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aOULibName ) && xModLibContainer->isLibraryReadOnly( aOULibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aOULibName ) && xDlgLibContainer->isLibraryReadOnly( aOULibName ) ) ) + { + bReadOnly = true; + } + } + + if (nMode != Recording) + { + // Run... + bool bEnable = pMethod != nullptr; + if (nMode != ChooseOnly && StarBASIC::IsRunning()) + bEnable = false; + EnableButton(*m_xRunButton, bEnable); + } + + // organising still possible? + + // Assign... + EnableButton(*m_xAssignButton, pMethod != nullptr); + + // Edit... + EnableButton(*m_xEditButton, bMacroEntry); + + // Organizer... + EnableButton(*m_xOrganizeButton, !StarBASIC::IsRunning() && nMode == All); + + // m_xDelButton/m_xNewButton ->... + bool bProtected = bCurEntry && m_xBasicBox->IsEntryProtected(m_xBasicBoxIter.get()); + bool bShare = ( aDesc.GetLocation() == LIBRARY_LOCATION_SHARE ); + bool bEnable = !StarBASIC::IsRunning() && nMode == All && !bProtected && !bReadOnly && !bShare; + EnableButton(*m_xDelButton, bEnable); + EnableButton(*m_xNewButton, bEnable); + if (nMode == All) + { + if (pMethod) + { + m_xDelButton->show(); + m_xNewButton->hide(); + } + else + { + m_xNewButton->show(); + m_xDelButton->hide(); + } + } + + if (nMode == Recording) + { + // save button + m_xRunButton->set_sensitive(!bProtected && !bReadOnly && !bShare); + // new library button + m_xNewLibButton->set_sensitive(!bShare); + // new module button + m_xNewModButton->set_sensitive(!bProtected && !bReadOnly && !bShare); + } +} + +IMPL_LINK_NOARG(MacroChooser, MacroDoubleClickHdl, weld::TreeView&, bool) +{ + SbMethod* pMethod = GetMacro(); + SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr; + StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr; + BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr; + ScriptDocument aDocument(ScriptDocument::getDocumentForBasicManager(pBasMgr)); + if (aDocument.isDocument() && !aDocument.allowMacros()) + { + std::unique_ptr<weld::MessageDialog> xError( + Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning, + VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO))); + xError->run(); + return true; + } + + StoreMacroDescription(); + if (nMode == Recording) + { + if (pMethod && !QueryReplaceMacro(pMethod->GetName(), m_xDialog.get())) + return true; + } + + m_xDialog->response(Macro_OkRun); + return true; +} + +IMPL_LINK_NOARG(MacroChooser, MacroSelectHdl, weld::TreeView&, void) +{ + UpdateFields(); + CheckButtons(); +} + +IMPL_LINK_NOARG(MacroChooser, BasicSelectHdl, weld::TreeView&, void) +{ + SbModule* pModule = nullptr; + if (m_xBasicBox->get_cursor(m_xBasicBoxIter.get())) + pModule = m_xBasicBox->FindModule(m_xBasicBoxIter.get()); + m_xMacroBox->clear(); + if (pModule) + { + m_xMacrosInTxt->set_label(m_aMacrosInTxtBaseStr + " " + pModule->GetName()); + + m_xMacroBox->freeze(); + + sal_uInt32 nMacroCount = pModule->GetMethods()->Count(); + for ( sal_uInt32 iMeth = 0; iMeth < nMacroCount; iMeth++ ) + { + SbMethod* pMethod = static_cast<SbMethod*>(pModule->GetMethods()->Get(iMeth)); + assert(pMethod && "Method not found!"); + if (pMethod->IsHidden()) + continue; + m_xMacroBox->append_text(pMethod->GetName()); + } + + m_xMacroBox->thaw(); + + if (m_xMacroBox->get_iter_first(*m_xMacroBoxIter)) + m_xMacroBox->set_cursor(*m_xMacroBoxIter); + } + + UpdateFields(); + CheckButtons(); +} + +IMPL_LINK_NOARG(MacroChooser, EditModifyHdl, weld::Entry&, void) +{ + // select the module in which the macro is put at "new", + // if BasicManager or Lib is selecting + if (m_xBasicBox->get_cursor(m_xBasicBoxIter.get())) + { + sal_uInt16 nDepth = m_xBasicBox->get_iter_depth(*m_xBasicBoxIter); + if (nDepth == 1 && m_xBasicBox->IsEntryProtected(m_xBasicBoxIter.get())) + { + // then put to the respective Std-Lib... + m_xBasicBox->iter_parent(*m_xBasicBoxIter); + m_xBasicBox->iter_children(*m_xBasicBoxIter); + } + if (nDepth < 2) + { + std::unique_ptr<weld::TreeIter> xNewEntry(m_xBasicBox->make_iterator()); + m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xNewEntry); + bool bCurEntry = true; + do + { + bCurEntry = m_xBasicBox->iter_children(*m_xBasicBoxIter); + if (bCurEntry) + { + m_xBasicBox->copy_iterator(*m_xBasicBoxIter, *xNewEntry); + nDepth = m_xBasicBox->get_iter_depth(*m_xBasicBoxIter); + } + } + while (bCurEntry && (nDepth < 2)); + SaveSetCurEntry(m_xBasicBox->get_widget(), *xNewEntry); + } + auto nCount = m_xMacroBox->n_children(); + if (nCount) + { + OUString aEdtText(m_xMacroNameEdit->get_text()); + bool bFound = false; + bool bValidIter = m_xMacroBox->get_iter_first(*m_xMacroBoxIter); + while (bValidIter) + { + if (m_xMacroBox->get_text(*m_xMacroBoxIter).equalsIgnoreAsciiCase(aEdtText)) + { + SaveSetCurEntry(*m_xMacroBox, *m_xMacroBoxIter); + bFound = true; + break; + } + bValidIter = m_xMacroBox->iter_next_sibling(*m_xMacroBoxIter); + } + if (!bFound) + { + bValidIter = m_xMacroBox->get_selected(m_xMacroBoxIter.get()); + // if the entry exists ->Select ->Description... + if (bValidIter) + m_xMacroBox->unselect(*m_xMacroBoxIter); + } + } + } + + CheckButtons(); +} + +IMPL_LINK(MacroChooser, ButtonHdl, weld::Button&, rButton, void) +{ + // apart from New/Record the Description is done by LoseFocus + if (&rButton == m_xRunButton.get()) + { + StoreMacroDescription(); + + // #116444# check security settings before macro execution + if (nMode == All) + { + SbMethod* pMethod = GetMacro(); + SbModule* pModule = pMethod ? pMethod->GetModule() : nullptr; + StarBASIC* pBasic = pModule ? static_cast<StarBASIC*>(pModule->GetParent()) : nullptr; + BasicManager* pBasMgr = pBasic ? FindBasicManager(pBasic) : nullptr; + if ( pBasMgr ) + { + ScriptDocument aDocument( ScriptDocument::getDocumentForBasicManager( pBasMgr ) ); + if ( aDocument.isDocument() && !aDocument.allowMacros() ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_CANNOTRUNMACRO))); + xError->run(); + return; + } + } + } + else if (nMode == Recording ) + { + if ( !IsValidSbxName(m_xMacroNameEdit->get_text()) ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME))); + xError->run(); + m_xMacroNameEdit->select_region(0, -1); + m_xMacroNameEdit->grab_focus(); + return; + } + + SbMethod* pMethod = GetMacro(); + if (pMethod && !QueryReplaceMacro(pMethod->GetName(), m_xDialog.get())) + return; + } + + m_xDialog->response(Macro_OkRun); + } + else if (&rButton == m_xCloseButton.get()) + { + StoreMacroDescription(); + m_xDialog->response(Macro_Close); + } + else if (&rButton == m_xEditButton.get() || &rButton == m_xDelButton.get() || &rButton == m_xNewButton.get()) + { + if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter)) + { + SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback"); + return; + } + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get()); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" ); + if ( !aDocument.isAlive() ) + return; + BasicManager* pBasMgr = aDocument.getBasicManager(); + const OUString& aLib( aDesc.GetLibName() ); + OUString aMod( aDesc.GetName() ); + // extract the module name from the string like "Sheet1 (Example1)" + if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) ) + { + aMod = aMod.getToken( 0, ' ' ); + } + const OUString& aSub( aDesc.GetMethodName() ); + SfxMacroInfoItem aInfoItem( SID_BASICIDE_ARG_MACROINFO, pBasMgr, aLib, aMod, aSub, OUString() ); + if (&rButton == m_xEditButton.get()) + { + if (m_xMacroBox->get_selected(m_xMacroBoxIter.get())) + aInfoItem.SetMethod(m_xMacroBox->get_text(*m_xMacroBoxIter)); + StoreMacroDescription(); + m_xDialog->hide(); // tdf#126828 dismiss dialog before opening new window + + SfxAllItemSet aArgs( SfxGetpApp()->GetPool() ); + SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs ); + SfxGetpApp()->ExecuteSlot( aRequest ); + + if (SfxDispatcher* pDispatcher = GetDispatcher()) + { + pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO, + SfxCallMode::ASYNCHRON, { &aInfoItem }); + } + m_xDialog->response(Macro_Edit); + } + else + { + if (&rButton == m_xDelButton.get()) + { + DeleteMacro(); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + { + pDispatcher->ExecuteList( SID_BASICIDE_UPDATEMODULESOURCE, + SfxCallMode::SYNCHRON, { &aInfoItem }); + } + CheckButtons(); + UpdateFields(); + //if ( m_xMacroBox->GetCurEntry() ) // OV-Bug ? + // m_xMacroBox->Select( m_xMacroBox->GetCurEntry() ); + } + else + { + if ( !IsValidSbxName(m_xMacroNameEdit->get_text()) ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME))); + xError->run(); + m_xMacroNameEdit->select_region(0, -1); + m_xMacroNameEdit->grab_focus(); + return; + } + SbMethod* pMethod = CreateMacro(); + if ( pMethod ) + { + aInfoItem.SetMethod( pMethod->GetName() ); + aInfoItem.SetModule( pMethod->GetModule()->GetName() ); + aInfoItem.SetLib( pMethod->GetModule()->GetParent()->GetName() ); + SfxAllItemSet aArgs( SfxGetpApp()->GetPool() ); + SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs ); + SfxGetpApp()->ExecuteSlot( aRequest ); + + if (SfxDispatcher* pDispatcher = GetDispatcher()) + { + pDispatcher->ExecuteList(SID_BASICIDE_EDITMACRO, + SfxCallMode::ASYNCHRON, { &aInfoItem }); + } + StoreMacroDescription(); + m_xDialog->response(Macro_New); + } + } + } + } + else if (&rButton == m_xAssignButton.get()) + { + if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter)) + { + SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback"); + return; + } + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get()); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + DBG_ASSERT( aDocument.isAlive(), "MacroChooser::ButtonHdl: no document, or document is dead!" ); + if ( !aDocument.isAlive() ) + return; + BasicManager* pBasMgr = aDocument.getBasicManager(); + const OUString& aLib( aDesc.GetLibName() ); + const OUString& aMod( aDesc.GetName() ); + OUString aSub( m_xMacroNameEdit->get_text() ); + SbMethod* pMethod = GetMacro(); + DBG_ASSERT( pBasMgr, "BasMgr?" ); + DBG_ASSERT( pMethod, "Method?" ); + OUString aComment( GetInfo( pMethod ) ); + SfxMacroInfoItem aItem( SID_MACROINFO, pBasMgr, aLib, aMod, aSub, aComment ); + SfxAllItemSet Args( SfxGetpApp()->GetPool() ); + + SfxAllItemSet aInternalSet(SfxGetpApp()->GetPool()); + if (m_xDocumentFrame.is()) + aInternalSet.Put(SfxUnoFrameItem(SID_FILLFRAME, m_xDocumentFrame)); + + SfxRequest aRequest(SID_CONFIGACCEL, SfxCallMode::SYNCHRON, Args, aInternalSet); + aRequest.AppendItem( aItem ); + SfxGetpApp()->ExecuteSlot( aRequest ); + } + else if (&rButton == m_xNewLibButton.get()) + { + if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter)) + { + SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback"); + return; + } + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get()); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + createLibImpl(m_xDialog.get(), aDocument, nullptr, m_xBasicBox.get()); + } + else if (&rButton == m_xNewModButton.get()) + { + if (!m_xBasicBox->get_cursor(m_xBasicBoxIter.get()) && !m_xBasicBox->get_iter_first(*m_xBasicBoxIter)) + { + SAL_WARN("basctl.basicide", "neither cursor set nor root entry to use as fallback"); + return; + } + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(m_xBasicBoxIter.get()); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + const OUString& aLibName( aDesc.GetLibName() ); + createModImpl(m_xDialog.get(), aDocument, *m_xBasicBox, aLibName, OUString(), true); + } + else if (&rButton == m_xOrganizeButton.get()) + { + StoreMacroDescription(); + + m_xBasicBox->get_selected(m_xBasicBoxIter.get()); + auto xDlg(std::make_shared<OrganizeDialog>(m_xDialog.get(), nullptr, 0)); + weld::DialogController::runAsync(xDlg, [this](sal_Int32 nRet) { + if (nRet == RET_OK) // not only closed + { + m_xDialog->response(Macro_Edit); + return; + } + + Shell* pShell = GetShell(); + if ( pShell && pShell->IsAppBasicModified() ) + bForceStoreBasic = true; + + m_xBasicBox->UpdateEntries(); + }); + } +} + +IMPL_LINK(MacroChooser, ContextMenuHdl, const CommandEvent&, rCEvt, bool) +{ + if (rCEvt.GetCommand() != CommandEventId::ContextMenu || !m_xMacroBox->n_children()) + return false; + + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xMacroBox.get(), "modules/BasicIDE/ui/sortmenu.ui")); + std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("sortmenu")); + std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu("sortsubmenu")); + xDropMenu->set_active("alphabetically", m_xMacroBox->get_sort_order()); + xDropMenu->set_active("properorder", !m_xMacroBox->get_sort_order()); + + OUString sCommand(xPopup->popup_at_rect(m_xMacroBox.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)))); + if (sCommand == "alphabetically") + { + m_xMacroBox->make_sorted(); + } + else if (sCommand == "properorder") + { + m_xMacroBox->make_unsorted(); + BasicSelectHdl(m_xBasicBox->get_widget()); + } + else if (!sCommand.isEmpty()) + { + SAL_WARN("basctl.basicide", "Unknown context menu action: " << sCommand ); + } + + return true; +} + +void MacroChooser::UpdateFields() +{ + auto nMacroEntry = m_xMacroBox->get_selected_index(); + m_xMacroNameEdit->set_text(""); + if (nMacroEntry != -1) + m_xMacroNameEdit->set_text(m_xMacroBox->get_text(nMacroEntry)); +} + +void MacroChooser::SetMode (Mode nM) +{ + nMode = nM; + switch (nMode) + { + case All: + { + m_xRunButton->set_label(IDEResId(RID_STR_RUN)); + EnableButton(*m_xDelButton, true); + EnableButton(*m_xNewButton, true); + EnableButton(*m_xOrganizeButton, true); + break; + } + + case ChooseOnly: + { + m_xRunButton->set_label(IDEResId(RID_STR_CHOOSE)); + EnableButton(*m_xDelButton, false); + EnableButton(*m_xNewButton, false); + EnableButton(*m_xOrganizeButton, false); + break; + } + + case Recording: + { + m_xRunButton->set_label(IDEResId(RID_STR_RECORD)); + EnableButton(*m_xDelButton, false); + EnableButton(*m_xNewButton, false); + EnableButton(*m_xOrganizeButton, false); + + m_xAssignButton->hide(); + m_xEditButton->hide(); + m_xDelButton->hide(); + m_xNewButton->hide(); + m_xOrganizeButton->hide(); + m_xMacroFromTxT->hide(); + + m_xNewLibButton->show(); + m_xNewModButton->show(); + m_xMacrosSaveInTxt->show(); + + break; + } + } + CheckButtons(); +} + +OUString MacroChooser::GetInfo( SbxVariable* pVar ) +{ + OUString aComment; + SbxInfoRef xInfo = pVar->GetInfo(); + if ( xInfo.is() ) + aComment = xInfo->GetComment(); + return aComment; +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/macrodlg.hxx b/basctl/source/basicide/macrodlg.hxx new file mode 100644 index 0000000000..0e50ee5de0 --- /dev/null +++ b/basctl/source/basicide/macrodlg.hxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <basobj.hxx> +#include <bastype2.hxx> +#include <sfx2/basedlgs.hxx> +#include <com/sun/star/frame/XFrame.hpp> +#include <vcl/weld.hxx> + +namespace basctl +{ + +enum MacroExitCode { + Macro_Close = 110, + Macro_OkRun = 111, + Macro_New = 112, + Macro_Edit = 114, +}; + +class MacroChooser : public SfxDialogController +{ +public: + enum Mode { + All = 1, + ChooseOnly = 2, + Recording = 3, + }; + +private: + OUString m_aMacrosInTxtBaseStr; + + // For forwarding to Assign dialog + ::css::uno::Reference< ::css::frame::XFrame > m_xDocumentFrame; + + bool bForceStoreBasic; + + Mode nMode; + + DECL_LINK(MacroSelectHdl, weld::TreeView&, void); + DECL_LINK(MacroDoubleClickHdl, weld::TreeView&, bool); + DECL_LINK(BasicSelectHdl, weld::TreeView&, void); + DECL_LINK(EditModifyHdl, weld::Entry&, void); + DECL_LINK(ContextMenuHdl, const CommandEvent&, bool); + DECL_LINK(ButtonHdl, weld::Button&, void); + + void CheckButtons(); + void SaveSetCurEntry(weld::TreeView& rBox, const weld::TreeIter& rEntry); + void UpdateFields(); + + void EnableButton(weld::Button& rButton, bool bEnable); + + static OUString GetInfo( SbxVariable* pVar ); + + void StoreMacroDescription(); + void RestoreMacroDescription(); + + std::unique_ptr<weld::Entry> m_xMacroNameEdit; + std::unique_ptr<weld::Label> m_xMacroFromTxT; + std::unique_ptr<weld::Label> m_xMacrosSaveInTxt; + std::unique_ptr<SbTreeListBox> m_xBasicBox; + std::unique_ptr<weld::TreeIter> m_xBasicBoxIter; + std::unique_ptr<weld::Label> m_xMacrosInTxt; + std::unique_ptr<weld::TreeView> m_xMacroBox; + std::unique_ptr<weld::TreeIter> m_xMacroBoxIter; + std::unique_ptr<weld::Button> m_xRunButton; + std::unique_ptr<weld::Button> m_xCloseButton; + std::unique_ptr<weld::Button> m_xAssignButton; + std::unique_ptr<weld::Button> m_xEditButton; + std::unique_ptr<weld::Button> m_xDelButton; + std::unique_ptr<weld::Button> m_xNewButton; + std::unique_ptr<weld::Button> m_xOrganizeButton; + std::unique_ptr<weld::Button> m_xNewLibButton; + std::unique_ptr<weld::Button> m_xNewModButton; +public: + MacroChooser(weld::Window *pParent, const ::css::uno::Reference< ::css::frame::XFrame >& xDocFrame); + virtual ~MacroChooser() override; + + SbMethod* GetMacro(); + void DeleteMacro(); + SbMethod* CreateMacro(); + + virtual short run() override; + + void SetMode (Mode); + Mode GetMode () const { return nMode; } +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/moduldl2.cxx b/basctl/source/basicide/moduldl2.cxx new file mode 100644 index 0000000000..1221b00942 --- /dev/null +++ b/basctl/source/basicide/moduldl2.cxx @@ -0,0 +1,1373 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "moduldlg.hxx" +#include <basidesh.hxx> +#include <strings.hrc> +#include <bitmaps.hlst> +#include <iderdll.hxx> +#include "iderdll2.hxx" +#include <iderid.hxx> +#include <basobj.hxx> +#include <svx/passwd.hxx> +#include <ucbhelper/content.hxx> +#include <rtl/uri.hxx> +#include <sfx2/app.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/filedlghelper.hxx> +#include <sfx2/request.hxx> +#include <sfx2/sfxsids.hrc> +#include <sfx2/viewfrm.hxx> +#include <svl/stritem.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> + +#include <com/sun/star/io/Pipe.hpp> +#include <com/sun/star/ui/dialogs/XFilePicker3.hpp> +#include <com/sun/star/ui/dialogs/XFolderPicker2.hpp> +#include <com/sun/star/ui/dialogs/TemplateDescription.hpp> +#include <com/sun/star/script/DocumentScriptLibraryContainer.hpp> +#include <com/sun/star/script/DocumentDialogLibraryContainer.hpp> +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <com/sun/star/script/XLibraryContainerExport.hpp> +#include <com/sun/star/task/InteractionHandler.hpp> +#include <com/sun/star/ucb/SimpleFileAccess.hpp> +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/packages/manifest/ManifestWriter.hpp> +#include <unotools/pathoptions.hxx> + +#include <com/sun/star/util/VetoException.hpp> +#include <com/sun/star/script/ModuleSizeExceededRequest.hpp> + +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <cppuhelper/implbase.hxx> +#include <o3tl/string_view.hxx> + +#include <cassert> + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::ucb; +using namespace ::com::sun::star::ui::dialogs; + +namespace +{ + +class DummyInteractionHandler : public ::cppu::WeakImplHelper< task::XInteractionHandler > +{ + Reference< task::XInteractionHandler2 > m_xHandler; +public: + explicit DummyInteractionHandler(const Reference<task::XInteractionHandler2>& xHandler) + : m_xHandler(xHandler) + { + } + + virtual void SAL_CALL handle( const Reference< task::XInteractionRequest >& rRequest ) override + { + if ( m_xHandler.is() ) + { + script::ModuleSizeExceededRequest aModSizeException; + if ( rRequest->getRequest() >>= aModSizeException ) + m_xHandler->handle( rRequest ); + } + } +}; + +} // namespace + +namespace +{ + int FindEntry(const weld::TreeView& rBox, std::u16string_view rName) + { + int nCount = rBox.n_children(); + for (int i = 0; i < nCount; ++i) + { + if (o3tl::equalsIgnoreAsciiCase(rName, rBox.get_text(i, 0))) + return i; + } + return -1; + } +} + +// NewObjectDialog +IMPL_LINK_NOARG(NewObjectDialog, OkButtonHandler, weld::Button&, void) +{ + if (!m_bCheckName || IsValidSbxName(m_xEdit->get_text())) + m_xDialog->response(RET_OK); + else + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_xDialog.get(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME))); + xErrorBox->run(); + m_xEdit->grab_focus(); + } +} + +NewObjectDialog::NewObjectDialog(weld::Window * pParent, ObjectMode eMode, bool bCheckName) + : GenericDialogController(pParent, "modules/BasicIDE/ui/newlibdialog.ui", "NewLibDialog") + , m_xEdit(m_xBuilder->weld_entry("entry")) + , m_xOKButton(m_xBuilder->weld_button("ok")) + , m_bCheckName(bCheckName) +{ + switch (eMode) + { + case ObjectMode::Library: + m_xDialog->set_title(IDEResId(RID_STR_NEWLIB)); + break; + case ObjectMode::Module: + m_xDialog->set_title(IDEResId(RID_STR_NEWMOD)); + break; + case ObjectMode::Dialog: + m_xDialog->set_title(IDEResId(RID_STR_NEWDLG)); + break; + default: + assert(false); + } + m_xOKButton->connect_clicked(LINK(this, NewObjectDialog, OkButtonHandler)); +} + +// GotoLineDialog +GotoLineDialog::GotoLineDialog(weld::Window* pParent ) + : GenericDialogController(pParent, "modules/BasicIDE/ui/gotolinedialog.ui", "GotoLineDialog") + , m_xEdit(m_xBuilder->weld_entry("entry")) + , m_xOKButton(m_xBuilder->weld_button("ok")) +{ + m_xEdit->grab_focus(); + m_xOKButton->connect_clicked(LINK(this, GotoLineDialog, OkButtonHandler)); +} + +GotoLineDialog::~GotoLineDialog() +{ +} + +sal_Int32 GotoLineDialog::GetLineNumber() const +{ + return m_xEdit->get_text().toInt32(); +} + +IMPL_LINK_NOARG(GotoLineDialog, OkButtonHandler, weld::Button&, void) +{ + if (GetLineNumber()) + m_xDialog->response(RET_OK); + else + m_xEdit->select_region(0, -1); +} + +// ExportDialog +IMPL_LINK_NOARG(ExportDialog, OkButtonHandler, weld::Button&, void) +{ + m_bExportAsPackage = m_xExportAsPackageButton->get_active(); + m_xDialog->response(RET_OK); +} + +ExportDialog::ExportDialog(weld::Window * pParent) + : GenericDialogController(pParent, "modules/BasicIDE/ui/exportdialog.ui", "ExportDialog") + , m_bExportAsPackage(false) + , m_xExportAsPackageButton(m_xBuilder->weld_radio_button("extension")) + , m_xOKButton(m_xBuilder->weld_button("ok")) +{ + m_xExportAsPackageButton->set_active(true); + m_xOKButton->connect_clicked(LINK(this, ExportDialog, OkButtonHandler)); +} + +ExportDialog::~ExportDialog() +{ +} + +// LibPage +LibPage::LibPage(weld::Container* pParent, OrganizeDialog* pDialog) + : OrganizePage(pParent, "modules/BasicIDE/ui/libpage.ui", "LibPage", pDialog) + , m_xBasicsBox(m_xBuilder->weld_combo_box("location")) + , m_xLibBox(m_xBuilder->weld_tree_view("library")) + , m_xEditButton(m_xBuilder->weld_button("edit")) + , m_xPasswordButton(m_xBuilder->weld_button("password")) + , m_xNewLibButton(m_xBuilder->weld_button("new")) + , m_xInsertLibButton(m_xBuilder->weld_button("import")) + , m_xExportButton(m_xBuilder->weld_button("export")) + , m_xDelButton(m_xBuilder->weld_button("delete")) + , m_aCurDocument(ScriptDocument::getApplicationScriptDocument()) + , m_eCurLocation(LIBRARY_LOCATION_UNKNOWN) +{ + Size aSize(m_xLibBox->get_approximate_digit_width() * 40, + m_xLibBox->get_height_rows(10)); + m_xLibBox->set_size_request(aSize.Width(), aSize.Height()); + + // tdf#93476 The libraries should be listed alphabetically + m_xLibBox->make_sorted(); + + m_xEditButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) ); + m_xNewLibButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) ); + m_xPasswordButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) ); + m_xExportButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) ); + m_xInsertLibButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) ); + m_xDelButton->connect_clicked( LINK( this, LibPage, ButtonHdl ) ); + m_xLibBox->connect_changed( LINK( this, LibPage, TreeListHighlightHdl ) ); + + m_xBasicsBox->connect_changed( LINK( this, LibPage, BasicSelectHdl ) ); + + m_xLibBox->connect_editing(LINK(this, LibPage, EditingEntryHdl), + LINK(this, LibPage, EditedEntryHdl)); + + FillListBox(); + m_xBasicsBox->set_active(0); + SetCurLib(); + + CheckButtons(); +} + +IMPL_LINK(LibPage, EditingEntryHdl, const weld::TreeIter&, rIter, bool) +{ + // check, if Standard library + OUString aLibName = m_xLibBox->get_text(rIter, 0); + + if ( aLibName.equalsIgnoreAsciiCase( "Standard" ) ) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_CANNOTCHANGENAMESTDLIB))); + xErrorBox->run(); + return false; + } + + // check, if library is readonly + Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) && !xModLibContainer->isLibraryLink( aLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) && !xDlgLibContainer->isLibraryLink( aLibName ) ) ) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_LIBISREADONLY))); + xErrorBox->run(); + return false; + } + + // i24094: Password verification necessary for renaming + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) ) + { + bool bOK = true; + // check password + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) ) + { + OUString aPassword; + bOK = QueryPassword(m_pDialog->getDialog(), xModLibContainer, aLibName, aPassword); + } + if ( !bOK ) + return false; + } + + // TODO: check if library is reference/link + + return true; +} + +IMPL_LINK(LibPage, EditedEntryHdl, const IterString&, rIterString, bool) +{ + const weld::TreeIter& rIter = rIterString.first; + OUString sNewName = rIterString.second; + + bool bValid = sNewName.getLength() <= 30 && IsValidSbxName(sNewName); + OUString aOldName(m_xLibBox->get_text(rIter, 0)); + + if (bValid && aOldName != sNewName) + { + try + { + Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + if ( xModLibContainer.is() ) + xModLibContainer->renameLibrary( aOldName, sNewName ); + + Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( xDlgLibContainer.is() ) + xDlgLibContainer->renameLibrary( aOldName, sNewName ); + + MarkDocumentModified( m_aCurDocument ); + if (SfxBindings* pBindings = GetBindingsPtr()) + { + pBindings->Invalidate( SID_BASICIDE_LIBSELECTOR ); + pBindings->Update( SID_BASICIDE_LIBSELECTOR ); + } + } + catch (const container::ElementExistException& ) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED))); + xErrorBox->run(); + return false; + } + catch (const container::NoSuchElementException& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + return false; + } + } + + if ( !bValid ) + { + OUString sWarning(sNewName.getLength() > 30 ? IDEResId(RID_STR_LIBNAMETOLONG) : IDEResId(RID_STR_BADSBXNAME)); + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, sWarning)); + xErrorBox->run(); + + } + + return bValid; +} + +LibPage::~LibPage() +{ + if (m_xBasicsBox) + { + const sal_Int32 nCount = m_xBasicsBox->get_count(); + for (sal_Int32 i = 0; i < nCount; ++i) + { + DocumentEntry* pEntry = weld::fromId<DocumentEntry*>(m_xBasicsBox->get_id(i)); + delete pEntry; + } + } +} + +void LibPage::CheckButtons() +{ + std::unique_ptr<weld::TreeIter> xCur(m_xLibBox->make_iterator()); + if (!m_xLibBox->get_cursor(xCur.get())) + return; + + OUString aLibName = m_xLibBox->get_text(*xCur, 0); + Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + + if ( m_eCurLocation == LIBRARY_LOCATION_SHARE ) + { + m_xPasswordButton->set_sensitive(false); + m_xNewLibButton->set_sensitive(false); + m_xInsertLibButton->set_sensitive(false); + m_xDelButton->set_sensitive(false); + } + else if ( aLibName.equalsIgnoreAsciiCase( "Standard" ) ) + { + m_xPasswordButton->set_sensitive(false); + m_xNewLibButton->set_sensitive(true); + m_xInsertLibButton->set_sensitive(true); + m_xExportButton->set_sensitive(false); + m_xDelButton->set_sensitive(false); + } + else if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) ) + { + m_xPasswordButton->set_sensitive(false); + m_xNewLibButton->set_sensitive(true); + m_xInsertLibButton->set_sensitive(true); + if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) && !xModLibContainer->isLibraryLink( aLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) && !xDlgLibContainer->isLibraryLink( aLibName ) ) ) + m_xDelButton->set_sensitive(false); + else + m_xDelButton->set_sensitive(true); + } + else + { + if ( xModLibContainer.is() && !xModLibContainer->hasByName( aLibName ) ) + m_xPasswordButton->set_sensitive(false); + else + m_xPasswordButton->set_sensitive(true); + + m_xNewLibButton->set_sensitive(true); + m_xInsertLibButton->set_sensitive(true); + m_xExportButton->set_sensitive(true); + m_xDelButton->set_sensitive(true); + } +} + +void LibPage::ActivatePage() +{ + SetCurLib(); +} + +IMPL_LINK_NOARG(LibPage, TreeListHighlightHdl, weld::TreeView&, void) +{ + CheckButtons(); +} + +IMPL_LINK_NOARG( LibPage, BasicSelectHdl, weld::ComboBox&, void ) +{ + SetCurLib(); + CheckButtons(); +} + +IMPL_LINK( LibPage, ButtonHdl, weld::Button&, rButton, void ) +{ + if (&rButton == m_xEditButton.get()) + { + SfxAllItemSet aArgs( SfxGetpApp()->GetPool() ); + SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs ); + SfxGetpApp()->ExecuteSlot( aRequest ); + + SfxUnoAnyItem aDocItem( SID_BASICIDE_ARG_DOCUMENT_MODEL, Any( m_aCurDocument.getDocumentOrNull() ) ); + + std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator()); + if (!m_xLibBox->get_cursor(xCurEntry.get())) + return; + OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0)); + SfxStringItem aLibNameItem( SID_BASICIDE_ARG_LIBNAME, aLibName ); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->ExecuteList( SID_BASICIDE_LIBSELECTED, + SfxCallMode::ASYNCHRON, { &aDocItem, &aLibNameItem }); + EndTabDialog(); + return; + } + else if (&rButton == m_xNewLibButton.get()) + NewLib(); + else if (&rButton == m_xInsertLibButton.get()) + InsertLib(); + else if (&rButton == m_xExportButton.get()) + Export(); + else if (&rButton == m_xDelButton.get()) + DeleteCurrent(); + else if (&rButton == m_xPasswordButton.get()) + { + std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator()); + if (!m_xLibBox->get_cursor(xCurEntry.get())) + return; + OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0)); + + // load module library (if not loaded) + Reference< script::XLibraryContainer > xModLibContainer = m_aCurDocument.getLibraryContainer( E_SCRIPTS ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) ) + { + Shell* pShell = GetShell(); + if (pShell) + pShell->GetViewFrame().GetWindow().EnterWait(); + xModLibContainer->loadLibrary( aLibName ); + if (pShell) + pShell->GetViewFrame().GetWindow().LeaveWait(); + } + + // load dialog library (if not loaded) + Reference< script::XLibraryContainer > xDlgLibContainer = m_aCurDocument.getLibraryContainer( E_DIALOGS ); + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && !xDlgLibContainer->isLibraryLoaded( aLibName ) ) + { + Shell* pShell = GetShell(); + if (pShell) + pShell->GetViewFrame().GetWindow().EnterWait(); + xDlgLibContainer->loadLibrary( aLibName ); + if (pShell) + pShell->GetViewFrame().GetWindow().LeaveWait(); + } + + // check, if library is password protected + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() ) + { + bool const bProtected = xPasswd->isLibraryPasswordProtected( aLibName ); + + // change password dialog + SvxPasswordDialog aDlg(m_pDialog->getDialog(), !bProtected); + aDlg.SetCheckPasswordHdl(LINK(this, LibPage, CheckPasswordHdl)); + + if (aDlg.run() == RET_OK) + { + bool const bNewProtected = xPasswd->isLibraryPasswordProtected( aLibName ); + + if ( bNewProtected != bProtected ) + { + int nPos = m_xLibBox->get_iter_index_in_parent(*xCurEntry); + m_xLibBox->remove(*xCurEntry); + ImpInsertLibEntry(aLibName, nPos); + m_xLibBox->set_cursor(nPos); + } + + MarkDocumentModified( m_aCurDocument ); + } + } + } + } + CheckButtons(); +} + +IMPL_LINK( LibPage, CheckPasswordHdl, SvxPasswordDialog *, pDlg, bool ) +{ + bool bRet = false; + + std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator()); + if (!m_xLibBox->get_cursor(xCurEntry.get())) + return bRet; + + OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0)); + Reference< script::XLibraryContainerPassword > xPasswd( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + + if ( xPasswd.is() ) + { + try + { + OUString aOldPassword( pDlg->GetOldPassword() ); + OUString aNewPassword( pDlg->GetNewPassword() ); + xPasswd->changeLibraryPassword( aLibName, aOldPassword, aNewPassword ); + bRet = true; + } + catch (...) + { + } + } + + return bRet; +} + +void LibPage::NewLib() +{ + createLibImpl(m_pDialog->getDialog(), m_aCurDocument, m_xLibBox.get(), nullptr); +} + +void LibPage::InsertLib() +{ + Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + // file open dialog + sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE, FileDialogFlags::NONE, m_pDialog->getDialog()); + aDlg.SetContext(sfx2::FileDialogHelper::BasicInsertLib); + const Reference <XFilePicker3>& xFP = aDlg.GetFilePicker(); + + xFP->setTitle(IDEResId(RID_STR_APPENDLIBS)); + + // filter + OUString aTitle(IDEResId(RID_STR_BASIC)); + xFP->appendFilter( aTitle, "*.sbl;*.xlc;*.xlb" // library files + ";*.sdw;*.sxw;*.odt" // text + ";*.vor;*.stw;*.ott" // text template + ";*.sgl;*.sxg;*.odm" // master document + ";*.oth" // html document template + ";*.sdc;*.sxc;*.ods" // spreadsheet + ";*.stc;*.ots" // spreadsheet template + ";*.sda;*.sxd;*.odg" // drawing + ";*.std;*.otg" // drawing template + ";*.sdd;*.sxi;*.odp" // presentation + ";*.sti;*.otp" // presentation template + ";*.sxm;*.odf" ); // formula + + OUString aLastFilter(GetExtraData()->GetAddLibFilter()); + if ( !aLastFilter.isEmpty() ) + xFP->setCurrentFilter( aLastFilter ); + else + xFP->setCurrentFilter( IDEResId(RID_STR_BASIC) ); + + if ( xFP->execute() != RET_OK ) + return; + + GetExtraData()->SetAddLibPath( xFP->getDisplayDirectory() ); + GetExtraData()->SetAddLibFilter( xFP->getCurrentFilter() ); + + // library containers for import + Reference< script::XLibraryContainer2 > xModLibContImport; + Reference< script::XLibraryContainer2 > xDlgLibContImport; + + // file URLs + Sequence< OUString > aFiles = xFP->getSelectedFiles(); + INetURLObject aURLObj( aFiles[0] ); + auto xModURLObj = std::make_shared<INetURLObject>(aURLObj); + auto xDlgURLObj = std::make_shared<INetURLObject>(aURLObj); + + OUString aBase = aURLObj.getBase(); + OUString aModBase( "script" ); + OUString aDlgBase( "dialog" ); + + if ( aBase == aModBase || aBase == aDlgBase ) + { + xModURLObj->setBase( aModBase ); + xDlgURLObj->setBase( aDlgBase ); + } + + Reference< XSimpleFileAccess3 > xSFA( SimpleFileAccess::create(comphelper::getProcessComponentContext()) ); + + OUString aModURL( xModURLObj->GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + if ( xSFA->exists( aModURL ) ) + { + xModLibContImport = script::DocumentScriptLibraryContainer::createWithURL(xContext, aModURL); + } + + OUString aDlgURL( xDlgURLObj->GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + if ( xSFA->exists( aDlgURL ) ) + { + xDlgLibContImport = script::DocumentDialogLibraryContainer::createWithURL(xContext, aDlgURL); + } + + if ( !xModLibContImport.is() && !xDlgLibContImport.is() ) + return; + + std::shared_ptr<LibDialog> xLibDlg; + + Sequence< OUString > aLibNames = GetMergedLibraryNames( xModLibContImport, xDlgLibContImport ); + sal_Int32 nLibCount = aLibNames.getLength(); + if (nLibCount) + { + // library import dialog + xLibDlg = std::make_shared<LibDialog>(m_pDialog->getDialog()); + xLibDlg->SetStorageName(aURLObj.getName()); + weld::TreeView& rView = xLibDlg->GetLibBox(); + rView.make_unsorted(); + rView.freeze(); + + const OUString* pLibNames = aLibNames.getConstArray(); + for (sal_Int32 i = 0 ; i < nLibCount; ++i) + { + // libbox entries + OUString aLibName( pLibNames[ i ] ); + if ( !( ( xModLibContImport.is() && xModLibContImport->hasByName( aLibName ) && xModLibContImport->isLibraryLink( aLibName ) ) || + ( xDlgLibContImport.is() && xDlgLibContImport->hasByName( aLibName ) && xDlgLibContImport->isLibraryLink( aLibName ) ) ) ) + { + rView.append(); + const int nRow = rView.n_children() - 1; + rView.set_toggle(nRow, TRISTATE_TRUE); + rView.set_text(nRow, aLibName, 0); + } + } + + rView.thaw(); + rView.make_sorted(); + + if (rView.n_children()) + rView.set_cursor(0); + } + + if (!xLibDlg) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_NOLIBINSTORAGE))); + xErrorBox->run(); + return; + } + + OUString aExtension( aURLObj.getExtension() ); + OUString aLibExtension( "xlb" ); + OUString aContExtension( "xlc" ); + + // disable reference checkbox for documents and sbls + if ( aExtension != aLibExtension && aExtension != aContExtension ) + xLibDlg->EnableReference(false); + + weld::DialogController::runAsync(xLibDlg, [aContExtension, xDlgURLObj, aExtension, aLibExtension, xModURLObj, xLibDlg, xDlgLibContImport, xModLibContImport, this](sal_Int32 nResult) + { + if (!nResult ) + return; + + bool bChanges = false; + bool bRemove = false; + bool bReplace = xLibDlg->IsReplace(); + bool bReference = xLibDlg->IsReference(); + weld::TreeView& rView = xLibDlg->GetLibBox(); + for (int nLib = 0, nChildren = rView.n_children(); nLib < nChildren; ++nLib) + { + if (rView.get_toggle(nLib) == TRISTATE_TRUE) + { + OUString aLibName(rView.get_text(nLib)); + Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + + // check, if the library is already existing + if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) ) ) + { + if ( bReplace ) + { + // check, if the library is the Standard library + if ( aLibName == "Standard" ) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_REPLACESTDLIB))); + xErrorBox->run(); + continue; + } + + // check, if the library is readonly and not a link + if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) && !xModLibContainer->isLibraryLink( aLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) && !xDlgLibContainer->isLibraryLink( aLibName ) ) ) + { + OUString aErrStr( IDEResId(RID_STR_REPLACELIB) ); + aErrStr = aErrStr.replaceAll("XX", aLibName) + "\n" + IDEResId(RID_STR_LIBISREADONLY); + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, aErrStr)); + xErrorBox->run(); + continue; + } + + // remove existing libraries + bRemove = true; + } + else + { + OUString aErrStr; + if ( bReference ) + aErrStr = IDEResId(RID_STR_REFNOTPOSSIBLE); + else + aErrStr = IDEResId(RID_STR_IMPORTNOTPOSSIBLE); + aErrStr = aErrStr.replaceAll("XX", aLibName) + "\n" +IDEResId(RID_STR_SBXNAMEALLREADYUSED); + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, aErrStr)); + xErrorBox->run(); + continue; + } + } + + // check, if the library is password protected + bool bOK = false; + OUString aPassword; + if ( xModLibContImport.is() && xModLibContImport->hasByName( aLibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContImport, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) && !bReference ) + { + bOK = QueryPassword(m_pDialog->getDialog(), xModLibContImport, aLibName, aPassword, true, true); + + if ( !bOK ) + { + OUString aErrStr( IDEResId(RID_STR_NOIMPORT) ); + aErrStr = aErrStr.replaceAll("XX", aLibName); + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, aErrStr)); + xErrorBox->run(); + continue; + } + } + } + + // remove existing libraries + if ( bRemove ) + { + // remove listbox entry + int nEntry_ = FindEntry(*m_xLibBox, aLibName); + if (nEntry_ != -1) + m_xLibBox->remove(nEntry_); + + // remove module library + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) ) + xModLibContainer->removeLibrary( aLibName ); + + // remove dialog library + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) ) + xDlgLibContainer->removeLibrary( aLibName ); + } + + // copy module library + if ( xModLibContImport.is() && xModLibContImport->hasByName( aLibName ) && xModLibContainer.is() && !xModLibContainer->hasByName( aLibName ) ) + { + Reference< container::XNameContainer > xModLib; + if ( bReference ) + { + // storage URL + INetURLObject aModStorageURLObj(*xModURLObj); + if ( aExtension == aContExtension ) + { + sal_Int32 nCount = aModStorageURLObj.getSegmentCount(); + aModStorageURLObj.insertName( aLibName, false, nCount-1 ); + aModStorageURLObj.setExtension( aLibExtension ); + aModStorageURLObj.setFinalSlash(); + } + OUString aModStorageURL( aModStorageURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + + // create library link + xModLib.set( xModLibContainer->createLibraryLink( aLibName, aModStorageURL, true ), UNO_QUERY); + } + else + { + // create library + xModLib = xModLibContainer->createLibrary( aLibName ); + if ( xModLib.is() ) + { + // get import library + Reference< container::XNameContainer > xModLibImport; + Any aElement = xModLibContImport->getByName( aLibName ); + aElement >>= xModLibImport; + + if ( xModLibImport.is() ) + { + // load library + if ( !xModLibContImport->isLibraryLoaded( aLibName ) ) + xModLibContImport->loadLibrary( aLibName ); + + // copy all modules + Sequence< OUString > aModNames = xModLibImport->getElementNames(); + sal_Int32 nModCount = aModNames.getLength(); + const OUString* pModNames = aModNames.getConstArray(); + for ( sal_Int32 i = 0 ; i < nModCount ; i++ ) + { + OUString aModName( pModNames[ i ] ); + Any aElement_ = xModLibImport->getByName( aModName ); + xModLib->insertByName( aModName, aElement_ ); + } + + // set password + if ( bOK ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() ) + { + try + { + xPasswd->changeLibraryPassword( aLibName, OUString(), aPassword ); + } + catch (...) + { + } + } + } + } + } + } + } + + // copy dialog library + if ( xDlgLibContImport.is() && xDlgLibContImport->hasByName( aLibName ) && xDlgLibContainer.is() && !xDlgLibContainer->hasByName( aLibName ) ) + { + Reference< container::XNameContainer > xDlgLib; + if ( bReference ) + { + // storage URL + INetURLObject aDlgStorageURLObj( *xDlgURLObj ); + if ( aExtension == aContExtension ) + { + sal_Int32 nCount = aDlgStorageURLObj.getSegmentCount(); + aDlgStorageURLObj.insertName( aLibName, false, nCount - 1 ); + aDlgStorageURLObj.setExtension( aLibExtension ); + aDlgStorageURLObj.setFinalSlash(); + } + OUString aDlgStorageURL( aDlgStorageURLObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + + // create library link + xDlgLib.set( xDlgLibContainer->createLibraryLink( aLibName, aDlgStorageURL, true ), UNO_QUERY); + } + else + { + // create library + xDlgLib = xDlgLibContainer->createLibrary( aLibName ); + if ( xDlgLib.is() ) + { + // get import library + Reference< container::XNameContainer > xDlgLibImport; + Any aElement = xDlgLibContImport->getByName( aLibName ); + aElement >>= xDlgLibImport; + + if ( xDlgLibImport.is() ) + { + // load library + if ( !xDlgLibContImport->isLibraryLoaded( aLibName ) ) + xDlgLibContImport->loadLibrary( aLibName ); + + // copy all dialogs + Sequence< OUString > aDlgNames = xDlgLibImport->getElementNames(); + sal_Int32 nDlgCount = aDlgNames.getLength(); + const OUString* pDlgNames = aDlgNames.getConstArray(); + for ( sal_Int32 i = 0 ; i < nDlgCount ; i++ ) + { + OUString aDlgName( pDlgNames[ i ] ); + Any aElement_ = xDlgLibImport->getByName( aDlgName ); + xDlgLib->insertByName( aDlgName, aElement_ ); + } + } + } + } + } + + // insert listbox entry + ImpInsertLibEntry( aLibName, m_xLibBox->n_children() ); + m_xLibBox->set_cursor( m_xLibBox->find_text(aLibName) ); + bChanges = true; + } + } + + if ( bChanges ) + MarkDocumentModified( m_aCurDocument ); + }); +} + +void LibPage::Export() +{ + std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator()); + if (!m_xLibBox->get_cursor(xCurEntry.get())) + return; + OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0)); + + // Password verification + Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) ) + { + bool bOK = true; + + // check password + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) ) + { + OUString aPassword; + bOK = QueryPassword(m_pDialog->getDialog(), xModLibContainer, aLibName, aPassword); + } + if ( !bOK ) + return; + } + + std::unique_ptr<ExportDialog> xNewDlg(new ExportDialog(m_pDialog->getDialog())); + if (xNewDlg->run() != RET_OK) + return; + + try + { + bool bExportAsPackage = xNewDlg->isExportAsPackage(); + //tdf#112063 ensure closing xNewDlg is not selected as + //parent of file dialog from ExportAs... + xNewDlg.reset(); + if (bExportAsPackage) + ExportAsPackage( aLibName ); + else + ExportAsBasic( aLibName ); + } + catch(const util::VetoException& ) // user canceled operation + { + } +} + +void LibPage::implExportLib( const OUString& aLibName, const OUString& aTargetURL, + const Reference< task::XInteractionHandler >& Handler ) +{ + Reference< script::XLibraryContainerExport > xModLibContainerExport + ( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainerExport > xDlgLibContainerExport + ( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( xModLibContainerExport.is() ) + xModLibContainerExport->exportLibrary( aLibName, aTargetURL, Handler ); + + if (!xDlgLibContainerExport.is()) + return; + Reference<container::XNameAccess> xNameAcc(xDlgLibContainerExport, UNO_QUERY); + if (!xNameAcc.is()) + return; + if (!xNameAcc->hasByName(aLibName)) + return; + xDlgLibContainerExport->exportLibrary(aLibName, aTargetURL, Handler); +} + +// Implementation XCommandEnvironment + +namespace { + +class OLibCommandEnvironment : public cppu::WeakImplHelper< XCommandEnvironment > +{ + Reference< task::XInteractionHandler > mxInteraction; + +public: + explicit OLibCommandEnvironment(const Reference<task::XInteractionHandler>& xInteraction) + : mxInteraction( xInteraction ) + {} + + // Methods + virtual Reference< task::XInteractionHandler > SAL_CALL getInteractionHandler() override; + virtual Reference< XProgressHandler > SAL_CALL getProgressHandler() override; +}; + +} + +Reference< task::XInteractionHandler > OLibCommandEnvironment::getInteractionHandler() +{ + return mxInteraction; +} + +Reference< XProgressHandler > OLibCommandEnvironment::getProgressHandler() +{ + Reference< XProgressHandler > xRet; + return xRet; +} + +void LibPage::ExportAsPackage( const OUString& aLibName ) +{ + // file open dialog + sfx2::FileDialogHelper aDlg(ui::dialogs::TemplateDescription::FILESAVE_SIMPLE, FileDialogFlags::NONE, m_pDialog->getDialog()); + aDlg.SetContext(sfx2::FileDialogHelper::BasicExportPackage); + const Reference <XFilePicker3>& xFP = aDlg.GetFilePicker(); + + Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference< task::XInteractionHandler2 > xHandler( task::InteractionHandler::createWithParent(xContext, nullptr) ); + Reference< XSimpleFileAccess3 > xSFA = SimpleFileAccess::create(xContext); + + xFP->setTitle(IDEResId(RID_STR_EXPORTPACKAGE)); + + // filter + OUString aTitle(IDEResId(RID_STR_PACKAGE_BUNDLE)); + xFP->appendFilter( aTitle, "*.oxt" ); // library files + + xFP->setCurrentFilter( aTitle ); + + if ( xFP->execute() != RET_OK ) + return; + + GetExtraData()->SetAddLibPath(xFP->getDisplayDirectory()); + + Sequence< OUString > aFiles = xFP->getSelectedFiles(); + INetURLObject aURL( aFiles[0] ); + if( aURL.getExtension().isEmpty() ) + aURL.setExtension( u"oxt" ); + + OUString aPackageURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); + + OUString aTmpPath = SvtPathOptions().GetTempPath(); + INetURLObject aInetObj( aTmpPath ); + aInetObj.insertName( aLibName, true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All ); + OUString aSourcePath = aInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + if( xSFA->exists( aSourcePath ) ) + xSFA->kill( aSourcePath ); + Reference< task::XInteractionHandler > xDummyHandler( new DummyInteractionHandler( xHandler ) ); + implExportLib( aLibName, aTmpPath, xDummyHandler ); + + Reference< XCommandEnvironment > xCmdEnv = new OLibCommandEnvironment(xHandler); + + ::ucbhelper::Content sourceContent( aSourcePath, xCmdEnv, comphelper::getProcessComponentContext() ); + + OUString destFolder = "vnd.sun.star.zip://" + + ::rtl::Uri::encode( aPackageURL, + rtl_UriCharClassRegName, + rtl_UriEncodeIgnoreEscapes, + RTL_TEXTENCODING_UTF8 ) + + "/"; + + if( xSFA->exists( aPackageURL ) ) + xSFA->kill( aPackageURL ); + + ::ucbhelper::Content destFolderContent( destFolder, xCmdEnv, comphelper::getProcessComponentContext() ); + destFolderContent.transferContent( + sourceContent, ::ucbhelper::InsertOperation::Copy, + OUString(), NameClash::OVERWRITE ); + + INetURLObject aMetaInfInetObj( aTmpPath ); + aMetaInfInetObj.insertName( u"META-INF", + true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All ); + OUString aMetaInfFolder = aMetaInfInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ); + if( xSFA->exists( aMetaInfFolder ) ) + xSFA->kill( aMetaInfFolder ); + xSFA->createFolder( aMetaInfFolder ); + + std::vector< Sequence<beans::PropertyValue> > manifest; + + OUString fullPath = aLibName + + "/" ; + auto attribs(::comphelper::InitPropertySequence({ + { "FullPath", Any(fullPath) }, + { "MediaType", Any(OUString("application/vnd.sun.star.basic-library")) } + })); + manifest.push_back( attribs ); + + // write into pipe: + Reference<packages::manifest::XManifestWriter> xManifestWriter = packages::manifest::ManifestWriter::create( xContext ); + Reference<io::XOutputStream> xPipe( io::Pipe::create( xContext ), UNO_QUERY_THROW ); + xManifestWriter->writeManifestSequence( + xPipe, Sequence< Sequence<beans::PropertyValue> >( + manifest.data(), manifest.size() ) ); + + aMetaInfInetObj.insertName( u"manifest.xml", + true, INetURLObject::LAST_SEGMENT, INetURLObject::EncodeMechanism::All ); + + // write buffered pipe data to content: + ::ucbhelper::Content manifestContent( aMetaInfInetObj.GetMainURL( INetURLObject::DecodeMechanism::NONE ), xCmdEnv, comphelper::getProcessComponentContext() ); + manifestContent.writeStream( Reference<io::XInputStream>( xPipe, UNO_QUERY_THROW ), true ); + + ::ucbhelper::Content MetaInfContent( aMetaInfFolder, xCmdEnv, comphelper::getProcessComponentContext() ); + destFolderContent.transferContent( + MetaInfContent, ::ucbhelper::InsertOperation::Copy, + OUString(), NameClash::OVERWRITE ); + + if( xSFA->exists( aSourcePath ) ) + xSFA->kill( aSourcePath ); + if( xSFA->exists( aMetaInfFolder ) ) + xSFA->kill( aMetaInfFolder ); +} + +void LibPage::ExportAsBasic( const OUString& aLibName ) +{ + // Folder picker + Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference< XFolderPicker2 > xFolderPicker = sfx2::createFolderPicker(xContext, m_pDialog->getDialog()); + Reference< task::XInteractionHandler2 > xHandler( task::InteractionHandler::createWithParent(xContext, nullptr) ); + + xFolderPicker->setTitle(IDEResId(RID_STR_EXPORTBASIC)); + + // set display directory and filter + OUString aPath =GetExtraData()->GetAddLibPath(); + if( aPath.isEmpty() ) + aPath = SvtPathOptions().GetWorkPath(); + + // INetURLObject aURL(m_sSavePath, INetProtocol::File); + xFolderPicker->setDisplayDirectory( aPath ); + short nRet = xFolderPicker->execute(); + if( nRet == RET_OK ) + { + OUString aTargetURL = xFolderPicker->getDirectory(); + GetExtraData()->SetAddLibPath(aTargetURL); + + Reference< task::XInteractionHandler > xDummyHandler( new DummyInteractionHandler( xHandler ) ); + implExportLib( aLibName, aTargetURL, xDummyHandler ); + } +} + +void LibPage::DeleteCurrent() +{ + std::unique_ptr<weld::TreeIter> xCurEntry(m_xLibBox->make_iterator()); + if (!m_xLibBox->get_cursor(xCurEntry.get())) + return; + OUString aLibName(m_xLibBox->get_text(*xCurEntry, 0)); + + // check, if library is link + bool bIsLibraryLink = false; + Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainer2 > xDlgLibContainer( m_aCurDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryLink( aLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryLink( aLibName ) ) ) + { + bIsLibraryLink = true; + } + + if (!QueryDelLib(aLibName, bIsLibraryLink, m_pDialog->getDialog())) + return; + + // inform BasicIDE + SfxUnoAnyItem aDocItem( SID_BASICIDE_ARG_DOCUMENT_MODEL, Any( m_aCurDocument.getDocumentOrNull() ) ); + SfxStringItem aLibNameItem( SID_BASICIDE_ARG_LIBNAME, aLibName ); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->ExecuteList(SID_BASICIDE_LIBREMOVED, + SfxCallMode::SYNCHRON, { &aDocItem, &aLibNameItem }); + + // remove library from module and dialog library containers + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) ) + xModLibContainer->removeLibrary( aLibName ); + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) ) + xDlgLibContainer->removeLibrary( aLibName ); + + m_xLibBox->remove(*xCurEntry); + MarkDocumentModified( m_aCurDocument ); +} + +void LibPage::EndTabDialog() +{ + m_pDialog->response(RET_OK); +} + +void LibPage::FillListBox() +{ + InsertListBoxEntry( ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_USER ); + InsertListBoxEntry( ScriptDocument::getApplicationScriptDocument(), LIBRARY_LOCATION_SHARE ); + + ScriptDocuments aDocuments( ScriptDocument::getAllScriptDocuments( ScriptDocument::DocumentsSorted ) ); + for (auto const& doc : aDocuments) + { + InsertListBoxEntry( doc, LIBRARY_LOCATION_DOCUMENT ); + } +} + +void LibPage::InsertListBoxEntry( const ScriptDocument& rDocument, LibraryLocation eLocation ) +{ + OUString aEntryText(rDocument.getTitle(eLocation)); + OUString sId(weld::toId(new DocumentEntry(rDocument, eLocation))); + m_xBasicsBox->append(sId, aEntryText); +} + +void LibPage::SetCurLib() +{ + DocumentEntry* pEntry = weld::fromId<DocumentEntry*>(m_xBasicsBox->get_active_id()); + if (!pEntry) + return; + + const ScriptDocument& aDocument( pEntry->GetDocument() ); + DBG_ASSERT( aDocument.isAlive(), "LibPage::SetCurLib: no document, or document is dead!" ); + if ( !aDocument.isAlive() ) + return; + LibraryLocation eLocation = pEntry->GetLocation(); + if ( aDocument == m_aCurDocument && eLocation == m_eCurLocation ) + return; + + m_aCurDocument = aDocument; + m_eCurLocation = eLocation; + m_xLibBox->clear(); + + // get a sorted list of library names + Sequence< OUString > aLibNames = aDocument.getLibraryNames(); + sal_Int32 nLibCount = aLibNames.getLength(); + const OUString* pLibNames = aLibNames.getConstArray(); + + int nEntry = 0; + for (int i = 0 ; i < nLibCount; ++i) + { + OUString aLibName(pLibNames[i]); + if (eLocation == aDocument.getLibraryLocation(aLibName)) + ImpInsertLibEntry(aLibName, nEntry++); + } + + int nEntry_ = FindEntry(*m_xLibBox, u"Standard"); + if (nEntry_ == -1 && m_xLibBox->n_children()) + nEntry_ = 0; + m_xLibBox->set_cursor(nEntry_); +} + +void LibPage::ImpInsertLibEntry( const OUString& rLibName, int nPos ) +{ + // check, if library is password protected + bool bProtected = false; + Reference< script::XLibraryContainer2 > xModLibContainer( m_aCurDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( rLibName ) ) + { + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() ) + { + bProtected = xPasswd->isLibraryPasswordProtected( rLibName ); + } + } + + m_xLibBox->insert_text(nPos, rLibName); + + if (bProtected) + m_xLibBox->set_image(nPos, RID_BMP_LOCKED); + + // check, if library is link + if ( xModLibContainer.is() && xModLibContainer->hasByName( rLibName ) && xModLibContainer->isLibraryLink( rLibName ) ) + { + OUString aLinkURL = xModLibContainer->getLibraryLinkURL( rLibName ); + m_xLibBox->set_text(nPos, aLinkURL, 1); + } +} + +// Helper function +void createLibImpl(weld::Window* pWin, const ScriptDocument& rDocument, + weld::TreeView* pLibBox, SbTreeListBox* pBasicBox) +{ + OSL_ENSURE( rDocument.isAlive(), "createLibImpl: invalid document!" ); + if ( !rDocument.isAlive() ) + return; + + // create library name + OUString aLibName; + bool bValid = false; + sal_Int32 i = 1; + while ( !bValid ) + { + aLibName = "Library" + OUString::number( i ); + if ( !rDocument.hasLibrary( E_SCRIPTS, aLibName ) && !rDocument.hasLibrary( E_DIALOGS, aLibName ) ) + bValid = true; + i++; + } + + NewObjectDialog aNewDlg(pWin, ObjectMode::Library); + aNewDlg.SetObjectName(aLibName); + + if (!aNewDlg.run()) + return; + + if (!aNewDlg.GetObjectName().isEmpty()) + aLibName = aNewDlg.GetObjectName(); + + if ( aLibName.getLength() > 30 ) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pWin, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_LIBNAMETOLONG))); + xErrorBox->run(); + } + else if ( !IsValidSbxName( aLibName ) ) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pWin, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME))); + xErrorBox->run(); + } + else if ( rDocument.hasLibrary( E_SCRIPTS, aLibName ) || rDocument.hasLibrary( E_DIALOGS, aLibName ) ) + { + std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pWin, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2))); + xErrorBox->run(); + } + else + { + try + { + // create module and dialog library + rDocument.getOrCreateLibrary( E_SCRIPTS, aLibName ); + rDocument.getOrCreateLibrary( E_DIALOGS, aLibName ); + + if( pLibBox ) + { + pLibBox->append_text(aLibName); + pLibBox->set_cursor(pLibBox->find_text(aLibName)); + } + + // create a module + OUString aModName = rDocument.createObjectName( E_SCRIPTS, aLibName ); + OUString sModuleCode; + if ( !rDocument.createModule( aLibName, aModName, true, sModuleCode ) ) + throw Exception("could not create module " + aModName, nullptr); + + // tdf#151741 - store all libraries to the file system, otherwise they + // cannot be renamed/moved since the SfxLibraryContainer::renameLibrary + // moves the folders/files on the file system + Reference<script::XLibraryContainer2> xModLibContainer( + rDocument.getLibraryContainer(E_SCRIPTS), UNO_QUERY); + Reference<script::XLibraryContainer2> xDlgLibContainer( + rDocument.getLibraryContainer(E_DIALOGS), UNO_QUERY); + Reference<script::XPersistentLibraryContainer> xModPersLibContainer(xModLibContainer, + UNO_QUERY); + if (xModPersLibContainer.is()) + xModPersLibContainer->storeLibraries(); + Reference<script::XPersistentLibraryContainer> xDlgPersLibContainer(xDlgLibContainer, + UNO_QUERY); + if (xDlgPersLibContainer.is()) + xDlgPersLibContainer->storeLibraries(); + + SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rDocument, aLibName, aModName, TYPE_MODULE ); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->ExecuteList(SID_BASICIDE_SBXINSERTED, + SfxCallMode::SYNCHRON, { &aSbxItem }); + + if( pBasicBox ) + { + std::unique_ptr<weld::TreeIter> xIter(pBasicBox->make_iterator(nullptr)); + bool bValidIter = pBasicBox->get_cursor(xIter.get()); + std::unique_ptr<weld::TreeIter> xRootEntry(pBasicBox->make_iterator(xIter.get())); + while (bValidIter) + { + pBasicBox->copy_iterator(*xIter, *xRootEntry); + bValidIter = pBasicBox->iter_parent(*xIter); + } + + BrowseMode nMode = pBasicBox->GetMode(); + bool bDlgMode = ( nMode & BrowseMode::Dialogs ) && !( nMode & BrowseMode::Modules ); + const auto sId = bDlgMode ? RID_BMP_DLGLIB : RID_BMP_MODLIB; + pBasicBox->AddEntry(aLibName, sId, xRootEntry.get(), false, std::make_unique<Entry>(OBJ_TYPE_LIBRARY)); + pBasicBox->AddEntry(aModName, RID_BMP_MODULE, xRootEntry.get(), false, std::make_unique<Entry>(OBJ_TYPE_MODULE)); + pBasicBox->set_cursor(*xRootEntry); + pBasicBox->select(*xRootEntry); + } + } + catch (const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/moduldlg.cxx b/basctl/source/basicide/moduldlg.cxx new file mode 100644 index 0000000000..4b67e320b5 --- /dev/null +++ b/basctl/source/basicide/moduldlg.cxx @@ -0,0 +1,1052 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <strings.hrc> +#include <iderid.hxx> +#include <bitmaps.hlst> + +#include "moduldlg.hxx" +#include <localizationmgr.hxx> +#include <basidesh.hxx> +#include <basobj.hxx> + +#include <basic/basmgr.hxx> +#include <com/sun/star/script/XLibraryContainerPassword.hpp> +#include <com/sun/star/script/XLibraryContainer2.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <comphelper/processfactory.hxx> +#include <sfx2/app.hxx> +#include <sfx2/dispatch.hxx> +#include <sfx2/frame.hxx> +#include <sfx2/request.hxx> +#include <sfx2/sfxsids.hrc> +#include <svl/stritem.hxx> +#include <vcl/transfer.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <tools/debug.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <xmlscript/xmldlg_imexp.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::resource; + +IMPL_LINK(ObjectPage, EditingEntryHdl, const weld::TreeIter&, rEntry, bool) +{ + bool bRet = false; + + sal_uInt16 nDepth = m_xBasicBox->get_iter_depth(rEntry); + if (nDepth >= 2) + { + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(&rEntry); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + const OUString& aLibName( aDesc.GetLibName() ); + Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( !( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) ) ) + { + // allow editing only for libraries, which are not readonly + bRet = true; + } + } + + return bRet; +} + +IMPL_LINK(ObjectPage, EditedEntryHdl, const IterString&, rIterString, bool) +{ + const weld::TreeIter& rEntry = rIterString.first; + OUString sNewText = rIterString.second; + + if ( !IsValidSbxName(sNewText) ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_BADSBXNAME))); + xError->run(); + return false; + } + + OUString aCurText(m_xBasicBox->get_text(rEntry)); + if ( aCurText == sNewText ) + // nothing to do + return true; + + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(&rEntry); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + DBG_ASSERT( aDocument.isValid(), "ExtTreeListBox::EditedEntry: no document!" ); + if ( !aDocument.isValid() ) + return false; + const OUString& aLibName( aDesc.GetLibName() ); + EntryType eType = aDesc.GetType(); + + bool bSuccess = eType == OBJ_TYPE_MODULE ? + RenameModule(m_pDialog->getDialog(), aDocument, aLibName, aCurText, sNewText) : + RenameDialog(m_pDialog->getDialog(), aDocument, aLibName, aCurText, sNewText); + + if ( !bSuccess ) + return false; + + MarkDocumentModified( aDocument ); + + if (SfxDispatcher* pDispatcher = GetDispatcher()) + { + SbxItem aSbxItem(SID_BASICIDE_ARG_SBX, aDocument, aLibName, sNewText, SbTreeListBox::ConvertType(eType)); + pDispatcher->ExecuteList( SID_BASICIDE_SBXRENAMED, + SfxCallMode::SYNCHRON, { &aSbxItem }); + } + + // OV-Bug?! + m_xBasicBox->set_text(rEntry, sNewText); + m_xBasicBox->set_cursor(rEntry); + m_xBasicBox->unselect(rEntry); + m_xBasicBox->select(rEntry); // so that handler is called => update edit + + return true; +} + +void Shell::CopyDialogResources( + Reference< io::XInputStreamProvider >& io_xISP, + ScriptDocument const& rSourceDoc, + OUString const& rSourceLibName, + ScriptDocument const& rDestDoc, + OUString const& rDestLibName, + std::u16string_view rDlgName +) +{ + if ( !io_xISP.is() ) + return; + + // Get StringResourceManager + Reference< container::XNameContainer > xSourceDialogLib( rSourceDoc.getLibrary( E_DIALOGS, rSourceLibName, true ) ); + Reference< XStringResourceManager > xSourceMgr = + LocalizationMgr::getStringResourceFromDialogLibrary( xSourceDialogLib ); + if( !xSourceMgr.is() ) + return; + bool bSourceLocalized = xSourceMgr->getLocales().hasElements(); + + Reference< container::XNameContainer > xDestDialogLib( rDestDoc.getLibrary( E_DIALOGS, rDestLibName, true ) ); + Reference< XStringResourceManager > xDestMgr = + LocalizationMgr::getStringResourceFromDialogLibrary( xDestDialogLib ); + if( !xDestMgr.is() ) + return; + bool bDestLocalized = xDestMgr->getLocales().hasElements(); + + if( !bSourceLocalized && !bDestLocalized ) + return; + + // create dialog model + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + Reference< container::XNameContainer > xDialogModel( xContext->getServiceManager()->createInstanceWithContext + ( "com.sun.star.awt.UnoControlDialogModel", xContext ), UNO_QUERY ); + Reference< io::XInputStream > xInput( io_xISP->createInputStream() ); + ::xmlscript::importDialogModel( xInput, xDialogModel, xContext, rSourceDoc.isDocument() ? rSourceDoc.getDocument() : Reference< frame::XModel >() ); + + if( !xDialogModel.is() ) + return; + + if( bSourceLocalized && bDestLocalized ) + { + LocalizationMgr::copyResourceForDroppedDialog( xDialogModel, rDlgName, xDestMgr, xSourceMgr ); + } + else if( bSourceLocalized ) + { + LocalizationMgr::resetResourceForDialog( xDialogModel, xSourceMgr ); + } + else if( bDestLocalized ) + { + LocalizationMgr::setResourceIDsForDialog( xDialogModel, xDestMgr ); + } + io_xISP = ::xmlscript::exportDialogModel( xDialogModel, xContext, rDestDoc.isDocument() ? rDestDoc.getDocument() : Reference< frame::XModel >() ); +} + +void OrganizeDialog::SetCurrentEntry(const css::uno::Reference<css::frame::XFrame>& xDocFrame) +{ + if (!xDocFrame) + return; + Reference<css::frame::XController> xController(xDocFrame->getController()); + if (!xController) + return; + Reference<css::frame::XModel> xModel(xController->getModel()); + if (!xModel) + return; + ScriptDocument aScriptDocument(xModel); + EntryDescriptor aDesc(aScriptDocument, LIBRARY_LOCATION_DOCUMENT, OUString(), OUString(), OUString(), OBJ_TYPE_DOCUMENT); + m_xModulePage->SetCurrentEntry(aDesc); + m_xDialogPage->SetCurrentEntry(aDesc); +} + +// OrganizeDialog +OrganizeDialog::OrganizeDialog(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, sal_Int16 tabId) + : GenericDialogController(pParent, "modules/BasicIDE/ui/organizedialog.ui", "OrganizeDialog") + , m_xTabCtrl(m_xBuilder->weld_notebook("tabcontrol")) + , m_xModulePage(new ObjectPage(m_xTabCtrl->get_page("modules"), "ModulePage", BrowseMode::Modules, this)) + , m_xDialogPage(new ObjectPage(m_xTabCtrl->get_page("dialogs"), "DialogPage", BrowseMode::Dialogs, this)) + , m_xLibPage(new LibPage(m_xTabCtrl->get_page("libraries"), this)) +{ + m_xTabCtrl->connect_enter_page(LINK(this, OrganizeDialog, ActivatePageHdl)); + + SetCurrentEntry(xDocFrame); + + OUString sPage; + if (tabId == 0) + sPage = "modules"; + else if (tabId == 1) + sPage = "dialogs"; + else + sPage = "libraries"; + m_xTabCtrl->set_current_page(sPage); + ActivatePageHdl(sPage); + + if (SfxDispatcher* pDispatcher = GetDispatcher()) + pDispatcher->Execute( SID_BASICIDE_STOREALLMODULESOURCES ); +} + +IMPL_LINK(OrganizeDialog, ActivatePageHdl, const OUString&, rPage, void) +{ + if (rPage == "modules") + m_xModulePage->ActivatePage(); + else if (rPage == "dialogs") + m_xDialogPage->ActivatePage(); + else if (rPage == "libraries") + m_xLibPage->ActivatePage(); +} + +OrganizeDialog::~OrganizeDialog() +{ +} + +OrganizePage::OrganizePage(weld::Container* pParent, const OUString& rUIFile, const OUString &rName, OrganizeDialog* pDialog) + : m_pDialog(pDialog) + , m_xBuilder(Application::CreateBuilder(pParent, rUIFile)) + , m_xContainer(m_xBuilder->weld_container(rName)) +{ +} + +OrganizePage::~OrganizePage() +{ +} + +class SbTreeListBoxDropTarget : public DropTargetHelper +{ +private: + SbTreeListBox& m_rTreeView; + + virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override + { + // to enable the autoscroll when we're close to the edges + weld::TreeView& rWidget = m_rTreeView.get_widget(); + rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true); + + weld::TreeView* pSource = rWidget.get_drag_source(); + if (!pSource) + return DND_ACTION_NONE; + + // tdf#145722 only return a DND_ACTION_MOVE possibility if that + // is requested as an option + const bool bCheckForMove = rEvt.mnAction & DND_ACTION_MOVE; + + sal_Int8 nMode = DND_ACTION_NONE; + + std::unique_ptr<weld::TreeIter> xEntry(pSource->make_iterator()); + if (pSource->get_selected(xEntry.get())) + { + sal_uInt16 nDepth = pSource->get_iter_depth(*xEntry); + if (nDepth >= 2) + { + nMode = DND_ACTION_COPY; + if (bCheckForMove) + { + EntryDescriptor aDesc = m_rTreeView.GetEntryDescriptor(xEntry.get()); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + const OUString& aLibName( aDesc.GetLibName() ); + // allow MOVE mode only for libraries, which are not readonly + Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( !( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) ) ) + { + // Only allow copy for localized libraries + bool bAllowMove = true; + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) ) + { + // Get StringResourceManager + Reference< container::XNameContainer > xDialogLib( aDocument.getLibrary( E_DIALOGS, aLibName, true ) ); + Reference< XStringResourceManager > xSourceMgr = + LocalizationMgr::getStringResourceFromDialogLibrary( xDialogLib ); + if( xSourceMgr.is() ) + bAllowMove = ( xSourceMgr->getLocales().getLength() == 0 ); + } + if( bAllowMove ) + nMode |= DND_ACTION_MOVE; + } + } + } + } + return nMode; + } + + virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override + { + weld::TreeView& rWidget = m_rTreeView.get_widget(); + weld::TreeView* pSource = rWidget.get_drag_source(); + if (!pSource) + return DND_ACTION_NONE; + + std::unique_ptr<weld::TreeIter> xEntry(rWidget.make_iterator()); + bool bEntry = rWidget.get_dest_row_at_pos(rEvt.maPosPixel, xEntry.get(), true); + + // don't drop on a BasicManager (nDepth == 0) + sal_uInt16 nDepth = bEntry ? m_rTreeView.get_iter_depth(*xEntry) : 0; + bool bValid = nDepth != 0; + // don't drop in the same library + std::unique_ptr<weld::TreeIter> xSelected(pSource->make_iterator()); + bool bSelected = pSource->get_selected(xSelected.get()); + if (!bSelected) + bValid = false; + else if (nDepth == 1) + { + std::unique_ptr<weld::TreeIter> xSelParent(pSource->make_iterator(xSelected.get())); + if (pSource->iter_parent(*xSelParent) && pSource->iter_compare(*xEntry, *xSelParent) == 0) + bValid = false; + } + else if (nDepth == 2) + { + std::unique_ptr<weld::TreeIter> xParent(pSource->make_iterator(xEntry.get())); + std::unique_ptr<weld::TreeIter> xSelParent(pSource->make_iterator(xSelected.get())); + if (pSource->iter_parent(*xParent) && pSource->iter_parent(*xSelParent) && pSource->iter_compare(*xParent, *xSelParent) == 0) + bValid = false; + } + + // don't drop on a library, which is not loaded, readonly or password protected + // or which already has a module/dialog with this name + if ( bValid && ( nDepth > 0 ) ) + { + // get source module/dialog name + EntryDescriptor aSourceDesc = m_rTreeView.GetEntryDescriptor(xSelected.get()); + const OUString& aSourceName = aSourceDesc.GetName(); + EntryType eSourceType = aSourceDesc.GetType(); + + // get target shell and target library name + EntryDescriptor aDestDesc = m_rTreeView.GetEntryDescriptor(xEntry.get()); + ScriptDocument const& rDestDoc = aDestDesc.GetDocument(); + const OUString& aDestLibName = aDestDesc.GetLibName(); + + // check if module library is not loaded, readonly or password protected + Reference< script::XLibraryContainer2 > xModLibContainer( rDestDoc.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aDestLibName ) ) + { + if ( !xModLibContainer->isLibraryLoaded( aDestLibName ) ) + bValid = false; + + if ( xModLibContainer->isLibraryReadOnly( aDestLibName ) ) + bValid = false; + + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aDestLibName ) && !xPasswd->isLibraryPasswordVerified( aDestLibName ) ) + bValid = false; + } + + // check if dialog library is not loaded or readonly + Reference< script::XLibraryContainer2 > xDlgLibContainer( rDestDoc.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aDestLibName ) ) + { + if ( !xDlgLibContainer->isLibraryLoaded( aDestLibName ) ) + bValid = false; + + if ( xDlgLibContainer->isLibraryReadOnly( aDestLibName ) ) + bValid = false; + } + + // check, if module/dialog with this name is already existing in target library + if ( ( eSourceType == OBJ_TYPE_MODULE && rDestDoc.hasModule( aDestLibName, aSourceName ) ) || + ( eSourceType == OBJ_TYPE_DIALOG && rDestDoc.hasDialog( aDestLibName, aSourceName ) ) ) + { + bValid = false; + } + } + + if (bValid) + NotifyCopyingMoving(*xEntry, rEvt.mnAction & DND_ACTION_MOVE); + + return DND_ACTION_NONE; + } + + void NotifyCopyingMoving(const weld::TreeIter& rTarget, bool bMove) + { + sal_uInt16 nDepth = m_rTreeView.get_iter_depth(rTarget); + std::unique_ptr<weld::TreeIter> xNewParent(m_rTreeView.make_iterator(&rTarget)); + int nNewChildPos = 0; + DBG_ASSERT( nDepth, "Depth?" ); + if ( nDepth >= 2 ) + { + // Target = module/dialog => put module/dialog under the superordinate Basic + m_rTreeView.iter_parent(*xNewParent); + nNewChildPos = m_rTreeView.get_iter_index_in_parent(rTarget) + 1; + } + + // get target shell and target library name + EntryDescriptor aDestDesc = m_rTreeView.GetEntryDescriptor(xNewParent.get()); + const ScriptDocument& rDestDoc( aDestDesc.GetDocument() ); + const OUString& aDestLibName( aDestDesc.GetLibName() ); + + // get source shell, library name and module/dialog name + std::unique_ptr<weld::TreeIter> xSelected(m_rTreeView.make_iterator()); + if (!m_rTreeView.get_selected(xSelected.get())) + return; + EntryDescriptor aSourceDesc = m_rTreeView.GetEntryDescriptor(xSelected.get()); + const ScriptDocument& rSourceDoc( aSourceDesc.GetDocument() ); + const OUString& aSourceLibName( aSourceDesc.GetLibName() ); + const OUString& aSourceName( aSourceDesc.GetName() ); + EntryType eType = aSourceDesc.GetType(); + + // get dispatcher + SfxDispatcher* pDispatcher = GetDispatcher(); + + if ( bMove ) // move + { + // remove source module/dialog window + if ( rSourceDoc != rDestDoc || aSourceLibName != aDestLibName ) + { + if( pDispatcher ) + { + SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rSourceDoc, aSourceLibName, aSourceName, SbTreeListBox::ConvertType(eType) ); + pDispatcher->ExecuteList( SID_BASICIDE_SBXDELETED, + SfxCallMode::SYNCHRON, { &aSbxItem }); + } + } + + try + { + if ( eType == OBJ_TYPE_MODULE ) // module + { + // get module + OUString aModule; + if ( rSourceDoc.getModule( aSourceLibName, aSourceName, aModule ) ) + { + // remove module from source library + if ( rSourceDoc.removeModule( aSourceLibName, aSourceName ) ) + { + MarkDocumentModified( rSourceDoc ); + + // insert module into target library + if ( rDestDoc.insertModule( aDestLibName, aSourceName, aModule ) ) + MarkDocumentModified( rDestDoc ); + } + } + } + else if ( eType == OBJ_TYPE_DIALOG ) // dialog + { + // get dialog + Reference< io::XInputStreamProvider > xISP; + if ( rSourceDoc.getDialog( aSourceLibName, aSourceName, xISP ) ) + { + Shell::CopyDialogResources( xISP, rSourceDoc, + aSourceLibName, rDestDoc, aDestLibName, aSourceName ); + + // remove dialog from source library + if (RemoveDialog(rSourceDoc, aSourceLibName, aSourceName)) + { + MarkDocumentModified(rSourceDoc); + + // insert dialog into target library + if ( rDestDoc.insertDialog( aDestLibName, aSourceName, xISP ) ) + MarkDocumentModified(rDestDoc); + } + } + } + } + catch (const uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + else // copy + { + try + { + if ( eType == OBJ_TYPE_MODULE ) // module + { + // get module + OUString aModule; + if ( rSourceDoc.getModule( aSourceLibName, aSourceName, aModule ) ) + { + // insert module into target library + if ( rDestDoc.insertModule( aDestLibName, aSourceName, aModule ) ) + MarkDocumentModified( rDestDoc ); + } + } + else if ( eType == OBJ_TYPE_DIALOG ) // dialog + { + // get dialog + Reference< io::XInputStreamProvider > xISP; + if ( rSourceDoc.getDialog( aSourceLibName, aSourceName, xISP ) ) + { + Shell::CopyDialogResources( xISP, rSourceDoc, + aSourceLibName, rDestDoc, aDestLibName, aSourceName ); + + // insert dialog into target library + if ( rDestDoc.insertDialog( aDestLibName, aSourceName, xISP ) ) + MarkDocumentModified( rDestDoc ); + } + } + } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + + OUString sText(m_rTreeView.get_text(*xSelected)); + OUString sId(m_rTreeView.get_id(*xSelected)); + /// if copying then clone the userdata + if (Entry* pEntry = bMove ? nullptr : weld::fromId<Entry*>(sId)) + { + assert(pEntry->GetType() != OBJ_TYPE_DOCUMENT); + std::unique_ptr<Entry> xNewUserData(std::make_unique<Entry>(*pEntry)); + sId = weld::toId(xNewUserData.release()); + } + std::unique_ptr<weld::TreeIter> xRet(m_rTreeView.make_iterator()); + m_rTreeView.get_widget().insert(xNewParent.get(), nNewChildPos, &sText, &sId, nullptr, nullptr, false, xRet.get()); + if (eType == OBJ_TYPE_MODULE) + m_rTreeView.get_widget().set_image(*xRet, RID_BMP_MODULE); + else if (eType == OBJ_TYPE_DIALOG) + m_rTreeView.get_widget().set_image(*xRet, RID_BMP_DIALOG); + if (!m_rTreeView.get_row_expanded(*xNewParent)) + m_rTreeView.expand_row(*xNewParent); + m_rTreeView.select(*xRet); + + if (bMove) + m_rTreeView.remove(*xSelected); + + // create target module/dialog window + if ( rSourceDoc != rDestDoc || aSourceLibName != aDestLibName ) + { + if( pDispatcher ) + { + SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rDestDoc, aDestLibName, aSourceName, SbTreeListBox::ConvertType(eType) ); + pDispatcher->ExecuteList( SID_BASICIDE_SBXINSERTED, + SfxCallMode::SYNCHRON, { &aSbxItem }); + } + } + } + +public: + SbTreeListBoxDropTarget(SbTreeListBox& rTreeView) + : DropTargetHelper(rTreeView.get_widget().get_drop_target()) + , m_rTreeView(rTreeView) + { + } +}; + +// ObjectPage +ObjectPage::ObjectPage(weld::Container* pParent, const OUString &rName, BrowseMode nMode, OrganizeDialog* pDialog) + : OrganizePage(pParent, "modules/BasicIDE/ui/" + rName.toAsciiLowerCase() + ".ui", + rName, pDialog) + , m_xBasicBox(new SbTreeListBox(m_xBuilder->weld_tree_view("library"), pDialog->getDialog())) + , m_xEditButton(m_xBuilder->weld_button("edit")) + , m_xNewModButton(m_xBuilder->weld_button("newmodule")) + , m_xNewDlgButton(m_xBuilder->weld_button("newdialog")) + , m_xDelButton(m_xBuilder->weld_button("delete")) +{ + Size aSize(m_xBasicBox->get_approximate_digit_width() * 40, + m_xBasicBox->get_height_rows(14)); + m_xBasicBox->set_size_request(aSize.Width(), aSize.Height()); + + // tdf#93476 The dialogs should be listed alphabetically + m_xBasicBox->make_sorted(); + + m_xEditButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) ); + m_xDelButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) ); + m_xBasicBox->connect_changed( LINK( this, ObjectPage, BasicBoxHighlightHdl ) ); + + if( nMode & BrowseMode::Modules ) + { + m_xNewModButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) ); + m_xNewDlgButton->hide(); + } + else if ( nMode & BrowseMode::Dialogs ) + { + m_xNewDlgButton->connect_clicked( LINK( this, ObjectPage, ButtonHdl ) ); + m_xNewModButton->hide(); + } + + m_xDropTarget.reset(new SbTreeListBoxDropTarget(*m_xBasicBox)); + // tdf#145722 explicitly claim COPY and MOVE are options + rtl::Reference<TransferDataContainer> xHelper(new TransferDataContainer); + m_xBasicBox->get_widget().enable_drag_source(xHelper, DND_ACTION_COPYMOVE); + + m_xBasicBox->connect_editing(LINK(this, ObjectPage, EditingEntryHdl), + LINK(this, ObjectPage, EditedEntryHdl)); + + m_xBasicBox->SetMode( nMode ); + m_xBasicBox->ScanAllEntries(); + + m_xEditButton->grab_focus(); + CheckButtons(); +} + +ObjectPage::~ObjectPage() +{ +} + +void ObjectPage::ActivatePage() +{ + m_xBasicBox->UpdateEntries(); + CheckButtons(); +} + +void ObjectPage::CheckButtons() +{ + // enable/disable edit button + std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator()); + if (!m_xBasicBox->get_cursor(xCurEntry.get())) + xCurEntry.reset(); + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(xCurEntry.get()); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + const OUString& aLibName( aDesc.GetLibName() ); + const OUString& aLibSubName( aDesc.GetLibSubName() ); + bool bVBAEnabled = aDocument.isInVBAMode(); + BrowseMode nMode = m_xBasicBox->GetMode(); + + sal_uInt16 nDepth = xCurEntry ? m_xBasicBox->get_iter_depth(*xCurEntry) : 0; + if ( nDepth >= 2 ) + { + if( bVBAEnabled && ( nMode & BrowseMode::Modules ) && ( nDepth == 2 ) ) + m_xEditButton->set_sensitive(false); + else + m_xEditButton->set_sensitive(true); + } + else + m_xEditButton->set_sensitive(false); + + // enable/disable new module/dialog buttons + LibraryLocation eLocation( aDesc.GetLocation() ); + bool bReadOnly = false; + if ( nDepth > 0 ) + { + Reference< script::XLibraryContainer2 > xModLibContainer( aDocument.getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + Reference< script::XLibraryContainer2 > xDlgLibContainer( aDocument.getLibraryContainer( E_DIALOGS ), UNO_QUERY ); + if ( ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && xModLibContainer->isLibraryReadOnly( aLibName ) ) || + ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && xDlgLibContainer->isLibraryReadOnly( aLibName ) ) ) + { + bReadOnly = true; + } + } + if ( bReadOnly || eLocation == LIBRARY_LOCATION_SHARE ) + { + m_xNewModButton->set_sensitive(false); + m_xNewDlgButton->set_sensitive(false); + } + else + { + m_xNewModButton->set_sensitive(true); + m_xNewDlgButton->set_sensitive(true); + } + + // enable/disable delete button + if ( nDepth >= 2 && !bReadOnly && eLocation != LIBRARY_LOCATION_SHARE ) + { + if( bVBAEnabled && ( nMode & BrowseMode::Modules ) && ( ( nDepth == 2 ) || aLibSubName == IDEResId(RID_STR_DOCUMENT_OBJECTS) ) ) + m_xDelButton->set_sensitive(false); + else + m_xDelButton->set_sensitive(true); + } + else + m_xDelButton->set_sensitive(false); +} + +IMPL_LINK_NOARG(ObjectPage, BasicBoxHighlightHdl, weld::TreeView&, void) +{ + CheckButtons(); +} + +IMPL_LINK(ObjectPage, ButtonHdl, weld::Button&, rButton, void) +{ + if (&rButton == m_xEditButton.get()) + { + SfxAllItemSet aArgs( SfxGetpApp()->GetPool() ); + SfxRequest aRequest( SID_BASICIDE_APPEAR, SfxCallMode::SYNCHRON, aArgs ); + SfxGetpApp()->ExecuteSlot( aRequest ); + + SfxDispatcher* pDispatcher = GetDispatcher(); + + std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator()); + if (!m_xBasicBox->get_cursor(xCurEntry.get())) + return; + if (m_xBasicBox->get_iter_depth(*xCurEntry) >= 2) + { + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(xCurEntry.get()); + if ( pDispatcher ) + { + OUString aModName( aDesc.GetName() ); + // extract the module name from the string like "Sheet1 (Example1)" + if( aDesc.GetLibSubName() == IDEResId(RID_STR_DOCUMENT_OBJECTS) ) + { + aModName = aModName.getToken( 0, ' ' ); + } + SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, aDesc.GetDocument(), aDesc.GetLibName(), + aModName, SbTreeListBox::ConvertType( aDesc.GetType() ) ); + pDispatcher->ExecuteList(SID_BASICIDE_SHOWSBX, + SfxCallMode::SYNCHRON, { &aSbxItem }); + } + } + else // only Lib selected + { + DBG_ASSERT( m_xBasicBox->get_iter_depth(*xCurEntry) == 1, "No LibEntry?!" ); + ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() ); + std::unique_ptr<weld::TreeIter> xParentEntry(m_xBasicBox->make_iterator(xCurEntry.get())); + if (m_xBasicBox->iter_parent(*xParentEntry)) + { + DocumentEntry* pDocumentEntry = weld::fromId<DocumentEntry*>(m_xBasicBox->get_id(*xParentEntry)); + if (pDocumentEntry) + aDocument = pDocumentEntry->GetDocument(); + } + SfxUnoAnyItem aDocItem( SID_BASICIDE_ARG_DOCUMENT_MODEL, Any( aDocument.getDocumentOrNull() ) ); + OUString aLibName(m_xBasicBox->get_text(*xCurEntry)); + SfxStringItem aLibNameItem( SID_BASICIDE_ARG_LIBNAME, aLibName ); + if ( pDispatcher ) + { + pDispatcher->ExecuteList(SID_BASICIDE_LIBSELECTED, + SfxCallMode::ASYNCHRON, { &aDocItem, &aLibNameItem }); + } + } + EndTabDialog(); + } + else if (&rButton == m_xNewModButton.get()) + NewModule(); + else if (&rButton == m_xNewDlgButton.get()) + NewDialog(); + else if (&rButton == m_xDelButton.get()) + DeleteCurrent(); +} + +bool ObjectPage::GetSelection( ScriptDocument& rDocument, OUString& rLibName ) +{ + bool bRet = false; + + std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator()); + if (!m_xBasicBox->get_cursor(xCurEntry.get())) + xCurEntry.reset(); + EntryDescriptor aDesc = m_xBasicBox->GetEntryDescriptor(xCurEntry.get()); + rDocument = aDesc.GetDocument(); + rLibName = aDesc.GetLibName(); + if ( rLibName.isEmpty() ) + rLibName = "Standard" ; + + DBG_ASSERT( rDocument.isAlive(), "ObjectPage::GetSelection: no or dead ScriptDocument in the selection!" ); + if ( !rDocument.isAlive() ) + return false; + + // check if the module library is loaded + bool bOK = true; + OUString aLibName( rLibName ); + Reference< script::XLibraryContainer > xModLibContainer( rDocument.getLibraryContainer( E_SCRIPTS ) ); + if ( xModLibContainer.is() && xModLibContainer->hasByName( aLibName ) && !xModLibContainer->isLibraryLoaded( aLibName ) ) + { + // check password + Reference< script::XLibraryContainerPassword > xPasswd( xModLibContainer, UNO_QUERY ); + if ( xPasswd.is() && xPasswd->isLibraryPasswordProtected( aLibName ) && !xPasswd->isLibraryPasswordVerified( aLibName ) ) + { + OUString aPassword; + bOK = QueryPassword(m_pDialog->getDialog(), xModLibContainer, rLibName, aPassword); + } + + // load library + if ( bOK ) + xModLibContainer->loadLibrary( aLibName ); + } + + // check if the dialog library is loaded + Reference< script::XLibraryContainer > xDlgLibContainer( rDocument.getLibraryContainer( E_DIALOGS ) ); + if ( xDlgLibContainer.is() && xDlgLibContainer->hasByName( aLibName ) && !xDlgLibContainer->isLibraryLoaded( aLibName ) ) + { + // load library + if ( bOK ) + xDlgLibContainer->loadLibrary( aLibName ); + } + + if ( bOK ) + bRet = true; + + return bRet; +} + +void ObjectPage::NewModule() +{ + ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() ); + OUString aLibName; + + if ( GetSelection( aDocument, aLibName ) ) + { + createModImpl(m_pDialog->getDialog(), aDocument, + *m_xBasicBox, aLibName, OUString(), true); + } +} + +void ObjectPage::NewDialog() +{ + ScriptDocument aDocument( ScriptDocument::getApplicationScriptDocument() ); + OUString aLibName; + + if ( !GetSelection( aDocument, aLibName ) ) + return; + + aDocument.getOrCreateLibrary( E_DIALOGS, aLibName ); + + NewObjectDialog aNewDlg(m_pDialog->getDialog(), ObjectMode::Dialog, true); + aNewDlg.SetObjectName(aDocument.createObjectName(E_DIALOGS, aLibName)); + + if (aNewDlg.run() == RET_CANCEL) + return; + + OUString aDlgName = aNewDlg.GetObjectName(); + if (aDlgName.isEmpty()) + aDlgName = aDocument.createObjectName( E_DIALOGS, aLibName); + + if ( aDocument.hasDialog( aLibName, aDlgName ) ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(m_pDialog->getDialog(), + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2))); + xError->run(); + } + else + { + Reference< io::XInputStreamProvider > xISP; + if ( !aDocument.createDialog( aLibName, aDlgName, xISP ) ) + return; + + SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, aDocument, aLibName, aDlgName, TYPE_DIALOG ); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + { + pDispatcher->ExecuteList( SID_BASICIDE_SBXINSERTED, + SfxCallMode::SYNCHRON, { &aSbxItem }); + } + LibraryLocation eLocation = aDocument.getLibraryLocation( aLibName ); + std::unique_ptr<weld::TreeIter> xIter(m_xBasicBox->make_iterator()); + bool bRootEntry = m_xBasicBox->FindRootEntry(aDocument, eLocation, *xIter); + if (bRootEntry) + { + if (!m_xBasicBox->get_row_expanded(*xIter)) + m_xBasicBox->expand_row(*xIter); + bool bLibEntry = m_xBasicBox->FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xIter); + DBG_ASSERT( bLibEntry, "LibEntry not found!" ); + if (bLibEntry) + { + if (!m_xBasicBox->get_row_expanded(*xIter)) + m_xBasicBox->expand_row(*xIter); + std::unique_ptr<weld::TreeIter> xSubRootEntry(m_xBasicBox->make_iterator(xIter.get())); + bool bDlgEntry = m_xBasicBox->FindEntry(aDlgName, OBJ_TYPE_DIALOG, *xIter); + if (!bDlgEntry) + { + m_xBasicBox->AddEntry(aDlgName, RID_BMP_DIALOG, xSubRootEntry.get(), false, + std::make_unique<Entry>(OBJ_TYPE_DIALOG), xIter.get()); + assert(xIter && "Insert entry failed!"); + } + m_xBasicBox->set_cursor(*xIter); + m_xBasicBox->select(*xIter); + } + } + } +} + +void ObjectPage::DeleteCurrent() +{ + std::unique_ptr<weld::TreeIter> xCurEntry(m_xBasicBox->make_iterator()); + if (!m_xBasicBox->get_cursor(xCurEntry.get())) + xCurEntry.reset(); + DBG_ASSERT( xCurEntry, "No current entry!" ); + if (!xCurEntry) + return; + EntryDescriptor aDesc( m_xBasicBox->GetEntryDescriptor( xCurEntry.get() ) ); + const ScriptDocument& aDocument( aDesc.GetDocument() ); + DBG_ASSERT( aDocument.isAlive(), "ObjectPage::DeleteCurrent: no document!" ); + if ( !aDocument.isAlive() ) + return; + const OUString& aLibName( aDesc.GetLibName() ); + const OUString& aName( aDesc.GetName() ); + EntryType eType = aDesc.GetType(); + + if ( !(( eType == OBJ_TYPE_MODULE && QueryDelModule(aName, m_pDialog->getDialog()) ) || + ( eType == OBJ_TYPE_DIALOG && QueryDelDialog(aName, m_pDialog->getDialog()) )) ) + return; + + m_xBasicBox->remove(*xCurEntry); + if (m_xBasicBox->get_cursor(xCurEntry.get())) + m_xBasicBox->select(*xCurEntry); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + { + SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, aDocument, aLibName, aName, SbTreeListBox::ConvertType( eType ) ); + pDispatcher->ExecuteList( SID_BASICIDE_SBXDELETED, + SfxCallMode::SYNCHRON, { &aSbxItem }); + } + + try + { + bool bSuccess = false; + if ( eType == OBJ_TYPE_MODULE ) + bSuccess = aDocument.removeModule( aLibName, aName ); + else if ( eType == OBJ_TYPE_DIALOG ) + bSuccess = RemoveDialog( aDocument, aLibName, aName ); + + if ( bSuccess ) + MarkDocumentModified( aDocument ); + } + catch (const container::NoSuchElementException& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } +} + +void ObjectPage::EndTabDialog() +{ + m_pDialog->response(RET_OK); +} + +LibDialog::LibDialog(weld::Window* pParent) + : GenericDialogController(pParent, "modules/BasicIDE/ui/importlibdialog.ui", "ImportLibDialog") + , m_xStorageFrame(m_xBuilder->weld_frame("storageframe")) + , m_xLibBox(m_xBuilder->weld_tree_view("entries")) + , m_xReferenceBox(m_xBuilder->weld_check_button("ref")) + , m_xReplaceBox(m_xBuilder->weld_check_button("replace")) +{ + m_xLibBox->set_size_request(m_xLibBox->get_approximate_digit_width() * 28, + m_xLibBox->get_height_rows(8)); + m_xLibBox->enable_toggle_buttons(weld::ColumnToggleType::Check); + // tdf#93476 The libraries should be listed alphabetically + m_xLibBox->make_sorted(); +} + +LibDialog::~LibDialog() +{ +} + +void LibDialog::SetStorageName( std::u16string_view rName ) +{ + OUString aName = IDEResId(RID_STR_FILENAME) + rName; + m_xStorageFrame->set_label(aName); +} + +// Helper function +SbModule* createModImpl(weld::Window* pWin, const ScriptDocument& rDocument, + SbTreeListBox& rBasicBox, const OUString& rLibName, const OUString& _aModName, bool bMain ) +{ + OSL_ENSURE( rDocument.isAlive(), "createModImpl: invalid document!" ); + if ( !rDocument.isAlive() ) + return nullptr; + + SbModule* pModule = nullptr; + + OUString aLibName( rLibName ); + if ( aLibName.isEmpty() ) + aLibName = "Standard" ; + rDocument.getOrCreateLibrary( E_SCRIPTS, aLibName ); + OUString aModName = _aModName; + if ( aModName.isEmpty() ) + aModName = rDocument.createObjectName( E_SCRIPTS, aLibName ); + + NewObjectDialog aNewDlg(pWin, ObjectMode::Module, true); + aNewDlg.SetObjectName(aModName); + + if (aNewDlg.run() != RET_CANCEL) + { + if (!aNewDlg.GetObjectName().isEmpty()) + aModName = aNewDlg.GetObjectName(); + + try + { + OUString sModuleCode; + // the module has existed + if( rDocument.hasModule( aLibName, aModName ) ) + return nullptr; + rDocument.createModule( aLibName, aModName, bMain, sModuleCode ); + BasicManager* pBasMgr = rDocument.getBasicManager(); + StarBASIC* pBasic = pBasMgr? pBasMgr->GetLib( aLibName ) : nullptr; + if ( pBasic ) + pModule = pBasic->FindModule( aModName ); + SbxItem aSbxItem( SID_BASICIDE_ARG_SBX, rDocument, aLibName, aModName, TYPE_MODULE ); + if (SfxDispatcher* pDispatcher = GetDispatcher()) + { + pDispatcher->ExecuteList( SID_BASICIDE_SBXINSERTED, + SfxCallMode::SYNCHRON, { &aSbxItem }); + } + LibraryLocation eLocation = rDocument.getLibraryLocation( aLibName ); + std::unique_ptr<weld::TreeIter> xIter(rBasicBox.make_iterator()); + bool bRootEntry = rBasicBox.FindRootEntry(rDocument, eLocation, *xIter); + if (bRootEntry) + { + if (!rBasicBox.get_row_expanded(*xIter)) + rBasicBox.expand_row(*xIter); + bool bLibEntry = rBasicBox.FindEntry(aLibName, OBJ_TYPE_LIBRARY, *xIter); + DBG_ASSERT( bLibEntry, "LibEntry not found!" ); + if (bLibEntry) + { + if (!rBasicBox.get_row_expanded(*xIter)) + rBasicBox.expand_row(*xIter); + std::unique_ptr<weld::TreeIter> xSubRootEntry(rBasicBox.make_iterator(xIter.get())); + if (pBasic && rDocument.isInVBAMode()) + { + // add the new module in the "Modules" entry + std::unique_ptr<weld::TreeIter> xLibSubEntry(rBasicBox.make_iterator(xIter.get())); + bool bLibSubEntry = rBasicBox.FindEntry(IDEResId(RID_STR_NORMAL_MODULES) , OBJ_TYPE_NORMAL_MODULES, *xLibSubEntry); + if (bLibSubEntry) + { + if (!rBasicBox.get_row_expanded(*xLibSubEntry)) + rBasicBox.expand_row(*xLibSubEntry); + rBasicBox.copy_iterator(*xLibSubEntry, *xSubRootEntry); + } + } + + std::unique_ptr<weld::TreeIter> xEntry(rBasicBox.make_iterator(xSubRootEntry.get())); + bool bEntry = rBasicBox.FindEntry(aModName, OBJ_TYPE_MODULE, *xEntry); + if (!bEntry) + { + rBasicBox.AddEntry(aModName, RID_BMP_MODULE, xSubRootEntry.get(), false, + std::make_unique<Entry>(OBJ_TYPE_MODULE), xEntry.get()); + } + rBasicBox.set_cursor(*xEntry); + rBasicBox.select(*xEntry); + } + } + } + catch (const container::ElementExistException& ) + { + std::unique_ptr<weld::MessageDialog> xError(Application::CreateMessageDialog(pWin, + VclMessageType::Warning, VclButtonsType::Ok, IDEResId(RID_STR_SBXNAMEALLREADYUSED2))); + xError->run(); + } + catch (const container::NoSuchElementException& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + return pModule; +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/moduldlg.hxx b/basctl/source/basicide/moduldlg.hxx new file mode 100644 index 0000000000..4f4cbcbda3 --- /dev/null +++ b/basctl/source/basicide/moduldlg.hxx @@ -0,0 +1,226 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#include <bastype2.hxx> +#include <vcl/weld.hxx> +#include <com/sun/star/task/XInteractionHandler.hpp> + +class SvxPasswordDialog; + +namespace basctl +{ + +enum class ObjectMode +{ + Library = 1, + Module = 2, + Dialog = 3, +}; + +class NewObjectDialog : public weld::GenericDialogController +{ +private: + std::unique_ptr<weld::Entry> m_xEdit; + std::unique_ptr<weld::Button> m_xOKButton; + bool m_bCheckName; + + DECL_LINK(OkButtonHandler, weld::Button&, void); +public: + NewObjectDialog(weld::Window* pParent, ObjectMode, bool bCheckName = false); + OUString GetObjectName() const { return m_xEdit->get_text(); } + void SetObjectName(const OUString& rName) + { + m_xEdit->set_text(rName); + m_xEdit->select_region(0, -1); + } +}; + +class GotoLineDialog : public weld::GenericDialogController +{ + std::unique_ptr<weld::Entry> m_xEdit; + std::unique_ptr<weld::Button> m_xOKButton; + DECL_LINK(OkButtonHandler, weld::Button&, void); +public: + explicit GotoLineDialog(weld::Window* pParent); + virtual ~GotoLineDialog() override; + sal_Int32 GetLineNumber() const; +}; + +class ExportDialog : public weld::GenericDialogController +{ +private: + bool m_bExportAsPackage; + + std::unique_ptr<weld::RadioButton> m_xExportAsPackageButton; + std::unique_ptr<weld::Button> m_xOKButton; + + DECL_LINK(OkButtonHandler, weld::Button&, void); + +public: + explicit ExportDialog(weld::Window * pParent); + virtual ~ExportDialog() override; + + bool isExportAsPackage () const { return m_bExportAsPackage; } +}; + +class LibDialog : public weld::GenericDialogController +{ +private: + std::unique_ptr<weld::Frame> m_xStorageFrame; + std::unique_ptr<weld::TreeView> m_xLibBox; + std::unique_ptr<weld::CheckButton> m_xReferenceBox; + std::unique_ptr<weld::CheckButton> m_xReplaceBox; + +public: + explicit LibDialog(weld::Window* pParent); + virtual ~LibDialog() override; + + void SetStorageName( std::u16string_view rName ); + + weld::TreeView& GetLibBox() { return *m_xLibBox; } + bool IsReference() const { return m_xReferenceBox->get_active(); } + bool IsReplace() const { return m_xReplaceBox->get_active(); } + + void EnableReference (bool b) { m_xReferenceBox->set_sensitive(b); } +}; + +class OrganizeDialog; + +class OrganizePage +{ +protected: + OrganizeDialog* m_pDialog; + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + + OrganizePage(weld::Container* pParent, const OUString& rUIFile, const OUString &rName, OrganizeDialog* pDialog); + virtual ~OrganizePage(); + +public: + virtual void ActivatePage() = 0; +}; + +class SbTreeListBoxDropTarget; + +class ObjectPage final : public OrganizePage +{ + std::unique_ptr<SbTreeListBox> m_xBasicBox; + std::unique_ptr<weld::Button> m_xEditButton; + std::unique_ptr<weld::Button> m_xNewModButton; + std::unique_ptr<weld::Button> m_xNewDlgButton; + std::unique_ptr<weld::Button> m_xDelButton; + std::unique_ptr<SbTreeListBoxDropTarget> m_xDropTarget; + + DECL_LINK( BasicBoxHighlightHdl, weld::TreeView&, void ); + DECL_LINK( ButtonHdl, weld::Button&, void ); + DECL_LINK( EditingEntryHdl, const weld::TreeIter&, bool ); + typedef std::pair<const weld::TreeIter&, OUString> IterString; + DECL_LINK( EditedEntryHdl, const IterString&, bool ); + + void CheckButtons(); + bool GetSelection( ScriptDocument& rDocument, OUString& rLibName ); + void DeleteCurrent(); + void NewModule(); + void NewDialog(); + void EndTabDialog(); + +public: + ObjectPage(weld::Container* pParent, const OUString& rName, BrowseMode nMode, OrganizeDialog* pDialog); + virtual ~ObjectPage() override; + + void SetCurrentEntry(const EntryDescriptor& rDesc) { m_xBasicBox->SetCurrentEntry(rDesc); } + + virtual void ActivatePage() override; +}; + +class LibPage final : public OrganizePage +{ + std::unique_ptr<weld::ComboBox> m_xBasicsBox; + std::unique_ptr<weld::TreeView> m_xLibBox; + std::unique_ptr<weld::Button> m_xEditButton; + std::unique_ptr<weld::Button> m_xPasswordButton; + std::unique_ptr<weld::Button> m_xNewLibButton; + std::unique_ptr<weld::Button> m_xInsertLibButton; + std::unique_ptr<weld::Button> m_xExportButton; + std::unique_ptr<weld::Button> m_xDelButton; + + ScriptDocument m_aCurDocument; + LibraryLocation m_eCurLocation; + + DECL_LINK( TreeListHighlightHdl, weld::TreeView&, void ); + DECL_LINK( BasicSelectHdl, weld::ComboBox&, void ); + DECL_LINK( ButtonHdl, weld::Button&, void ); + DECL_LINK( CheckPasswordHdl, SvxPasswordDialog *, bool ); + DECL_LINK( EditingEntryHdl, const weld::TreeIter&, bool ); + typedef std::pair<const weld::TreeIter&, OUString> IterString; + DECL_LINK( EditedEntryHdl, const IterString&, bool ); + + void CheckButtons(); + void DeleteCurrent(); + void NewLib(); + void InsertLib(); + void implExportLib( const OUString& aLibName, const OUString& aTargetURL, + const css::uno::Reference< css::task::XInteractionHandler >& Handler ); + void Export(); + void ExportAsPackage( const OUString& aLibName ); + void ExportAsBasic( const OUString& aLibName ); + void EndTabDialog(); + void FillListBox(); + void InsertListBoxEntry( const ScriptDocument& rDocument, LibraryLocation eLocation ); + void SetCurLib(); + void ImpInsertLibEntry( const OUString& rLibName, int nPos ); + +public: + explicit LibPage(weld::Container* pParent, OrganizeDialog* pDialog); + virtual ~LibPage() override; + virtual void ActivatePage() override; +}; + +class OrganizeDialog : public weld::GenericDialogController +{ +private: + std::unique_ptr<weld::Notebook> m_xTabCtrl; + std::unique_ptr<ObjectPage> m_xModulePage; + std::unique_ptr<ObjectPage> m_xDialogPage; + std::unique_ptr<LibPage> m_xLibPage; + + DECL_LINK(ActivatePageHdl, const OUString&, void); + + void SetCurrentEntry(const css::uno::Reference<css::frame::XFrame>& xDocFrame); + +public: + OrganizeDialog(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, sal_Int16 tabId); + virtual ~OrganizeDialog() override; +}; + +// Helper functions +SbModule* createModImpl(weld::Window* pWin, const ScriptDocument& rDocument, + SbTreeListBox& rBasicBox, const OUString& rLibName, const OUString& aModName, bool bMain); +void createLibImpl(weld::Window* pWin, const ScriptDocument& rDocument, + weld::TreeView* pLibBox, SbTreeListBox* pBasicBox); + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/sbxitem.cxx b/basctl/source/basicide/sbxitem.cxx new file mode 100644 index 0000000000..39c86b1d08 --- /dev/null +++ b/basctl/source/basicide/sbxitem.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 <sbxitem.hxx> +#include <sal/log.hxx> +#include <utility> + +namespace basctl +{ +SfxPoolItem* SbxItem::CreateDefault() { SAL_WARN( "basctl.basicide", "No SbxItem factory available"); return nullptr; } +SbxItem::SbxItem ( + sal_uInt16 nWhichItem, + ScriptDocument aDocument, + OUString aLibName, + OUString aName, + ItemType eType +) : + SfxPoolItem(nWhichItem), + m_aDocument(std::move(aDocument)), + m_aLibName(std::move(aLibName)), + m_aName(std::move(aName)), + m_eType(eType) +{ } + +SbxItem::SbxItem ( + sal_uInt16 nWhichItem, + ScriptDocument aDocument, + OUString aLibName, + OUString aName, + OUString aMethodName, + ItemType eType +) : + SfxPoolItem(nWhichItem), + m_aDocument(std::move(aDocument)), + m_aLibName(std::move(aLibName)), + m_aName(std::move(aName)), + m_aMethodName(std::move(aMethodName)), + m_eType(eType) +{ } + +SbxItem* SbxItem::Clone(SfxItemPool*) const +{ + return new SbxItem(*this); +} + +bool SbxItem::operator==(const SfxPoolItem& rCmp) const +{ + SbxItem const* pSbxItem = static_cast<SbxItem const*>(&rCmp); + return + SfxPoolItem::operator==(rCmp) && + m_aDocument == pSbxItem->m_aDocument && + m_aLibName == pSbxItem->m_aLibName && + m_aName == pSbxItem->m_aName && + m_aMethodName == pSbxItem->m_aMethodName && + m_eType == pSbxItem->m_eType; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/scriptdocument.cxx b/basctl/source/basicide/scriptdocument.cxx new file mode 100644 index 0000000000..c435d7a57d --- /dev/null +++ b/basctl/source/basicide/scriptdocument.cxx @@ -0,0 +1,1505 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include <scriptdocument.hxx> +#include <basobj.hxx> +#include <strings.hrc> +#include <iderid.hxx> +#include <dlgeddef.hxx> +#include <doceventnotifier.hxx> +#include "documentenumeration.hxx" + +#include <com/sun/star/ucb/ContentCreationException.hpp> +#include <com/sun/star/uri/UriReferenceFactory.hpp> +#include <com/sun/star/util/theMacroExpander.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/document/XEmbeddedScripts.hpp> +#include <com/sun/star/script/vba/XVBACompatibility.hpp> +#include <com/sun/star/script/vba/XVBAModuleInfo.hpp> +#include <com/sun/star/script/ModuleInfo.hpp> +#include <com/sun/star/script/ModuleType.hpp> + +#include <sfx2/app.hxx> +#include <sfx2/objsh.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/docfile.hxx> + +#include <basic/basicmanagerrepository.hxx> + +#include <xmlscript/xmldlg_imexp.hxx> + +#include <i18nlangtag/languagetag.hxx> + +#include <comphelper/diagnose_ex.hxx> +#include <config_folders.h> +#include <tools/debug.hxx> + +#include <comphelper/documentinfo.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/propertysequence.hxx> +#include <comphelper/string.hxx> + +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> + +#include <osl/file.hxx> +#include <rtl/uri.hxx> +#include <set> + + +namespace basctl +{ + using ::com::sun::star::uno::Sequence; + using ::com::sun::star::uno::Reference; + using ::com::sun::star::frame::XModel; + using ::com::sun::star::beans::XPropertySet; + using ::com::sun::star::script::XLibraryContainer; + 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::container::XNameContainer; + using ::com::sun::star::container::NoSuchElementException; + using ::com::sun::star::uno::UNO_QUERY; + using ::com::sun::star::task::XStatusIndicator; + using ::com::sun::star::uno::Any; + using ::com::sun::star::script::XLibraryContainer2; + using ::com::sun::star::uri::UriReferenceFactory; + using ::com::sun::star::uri::XUriReferenceFactory; + using ::com::sun::star::uri::XUriReference; + using ::com::sun::star::uno::XComponentContext; + using ::com::sun::star::util::XMacroExpander; + using ::com::sun::star::util::theMacroExpander; + using ::com::sun::star::io::XInputStreamProvider; + using ::com::sun::star::uno::Any; + using ::com::sun::star::io::XInputStream; + using ::com::sun::star::frame::XStorable; + using ::com::sun::star::util::XModifiable; + using ::com::sun::star::frame::XController; + using ::com::sun::star::frame::XFrame; + using ::com::sun::star::util::URL; + using ::com::sun::star::frame::XDispatchProvider; + using ::com::sun::star::frame::XDispatch; + using ::com::sun::star::beans::PropertyValue; + using ::com::sun::star::awt::XWindow2; + using ::com::sun::star::document::XEmbeddedScripts; + using ::com::sun::star::script::ModuleInfo; + using ::com::sun::star::script::vba::XVBACompatibility; + using ::com::sun::star::script::vba::XVBAModuleInfo; + + namespace FrameSearchFlag = ::com::sun::star::frame::FrameSearchFlag; + + + namespace + { + class FilterDocuments : public docs::IDocumentDescriptorFilter + { + public: + explicit FilterDocuments(bool _bFilterInvisible) + : m_bFilterInvisible(_bFilterInvisible) + { + } + + virtual ~FilterDocuments() {} + + virtual bool includeDocument( const docs::DocumentDescriptor& _rDocument ) const override; + + private: + static bool impl_isDocumentVisible_nothrow( const docs::DocumentDescriptor& _rDocument ); + + private: + bool m_bFilterInvisible; + }; + + bool FilterDocuments::impl_isDocumentVisible_nothrow( const docs::DocumentDescriptor& _rDocument ) + { + try + { + for (auto const& controller : _rDocument.aControllers) + { + Reference< XFrame > xFrame( controller->getFrame(), UNO_SET_THROW ); + Reference< XWindow2 > xContainer( xFrame->getContainerWindow(), UNO_QUERY_THROW ); + if ( xContainer->isVisible() ) + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + bool FilterDocuments::includeDocument( const docs::DocumentDescriptor& _rDocument ) const + { + Reference< XEmbeddedScripts > xScripts( _rDocument.xModel, UNO_QUERY ); + if ( !xScripts.is() ) + return false; + return !m_bFilterInvisible || impl_isDocumentVisible_nothrow( _rDocument ); + } + + void lcl_getAllModels_throw( docs::Documents& _out_rModels, bool _bVisibleOnly ) + { + _out_rModels.clear(); + + FilterDocuments aFilter( _bVisibleOnly ); + docs::DocumentEnumeration aEnum( + comphelper::getProcessComponentContext(), &aFilter ); + + aEnum.getDocuments( _out_rModels ); + } + } + + class ScriptDocument::Impl : public DocumentEventListener + { + private: + bool m_bIsApplication; + bool m_bValid; + bool m_bDocumentClosed; + Reference< XModel > m_xDocument; + Reference< XModifiable > m_xDocModify; + Reference< XEmbeddedScripts > m_xScriptAccess; + std::unique_ptr< DocumentEventNotifier > m_pDocListener; + + public: + Impl (); + explicit Impl(Reference<XModel> const& rxDocument); + virtual ~Impl() override; + + /** determines whether the instance refers to a valid "document" with script and + dialog libraries + */ + bool isValid() const { return m_bValid; } + /** determines whether the instance refers to a non-closed document + */ + bool isAlive() const { return m_bValid && ( m_bIsApplication || !m_bDocumentClosed ); } + /// determines whether the "document" refers to the application in real + bool isApplication() const { return m_bValid && m_bIsApplication; } + /// determines whether the document refers to a real document (instead of the application) + bool isDocument() const { return m_bValid && !m_bIsApplication; } + + /** invalidates the instance + */ + void invalidate(); + + const Reference< XModel >& + getDocumentRef() const { return m_xDocument; } + + /// returns a library container belonging to the document + Reference< XLibraryContainer > + getLibraryContainer( LibraryContainerType _eType ) const; + + /// determines whether a given library is part of the shared installation + bool isLibraryShared( const OUString& _rLibName, LibraryContainerType _eType ); + + /** returns the current frame of the document + + To be called for documents only, not for the application. + + If <FALSE/> is returned, an assertion will be raised in non-product builds. + */ + bool getCurrentFrame( Reference< XFrame >& _out_rxFrame ) const; + + // versions with the same signature/semantics as in ScriptDocument itself + bool isReadOnly() const; + bool isInVBAMode() const; + BasicManager* + getBasicManager() const; + Reference< XModel > + getDocument() const; + void setDocumentModified() const; + bool isDocumentModified() const; + void saveDocument( const Reference< XStatusIndicator >& _rxStatusIndicator ) const; + + OUString getTitle() const; + OUString getURL() const; + + bool allowMacros() const; + + Reference< XNameContainer > + getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const; + bool hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const; + Reference< XNameContainer > + getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const; + + void loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary ); + + bool removeModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModuleName ); + bool hasModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModName ) const; + bool getModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rObjectName, Any& _out_rModuleOrDialog ); + bool renameModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName, const Reference< XNameContainer >& _rxExistingDialogModel ); + bool createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const; + bool insertModuleOrDialog( LibraryContainerType _eType, const OUString& _rObjectName, const OUString& _rModName, const Any& _rElement ) const; + bool updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const; + bool createDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const; + + protected: + // DocumentEventListener + virtual void onDocumentCreated( const ScriptDocument& _rDocument ) override; + virtual void onDocumentOpened( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSave( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveDone( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveAs( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveAsDone( const ScriptDocument& _rDocument ) override; + virtual void onDocumentClosed( const ScriptDocument& _rDocument ) override; + virtual void onDocumentTitleChanged( const ScriptDocument& _rDocument ) override; + virtual void onDocumentModeChanged( const ScriptDocument& _rDocument ) override; + + private: + bool impl_initDocument_nothrow( const Reference< XModel >& _rxModel ); + }; + + + ScriptDocument::Impl::Impl() + :m_bIsApplication( true ) + ,m_bValid( true ) + ,m_bDocumentClosed( false ) + { + } + + ScriptDocument::Impl::Impl( const Reference< XModel >& _rxDocument ) + :m_bIsApplication( false ) + ,m_bValid( false ) + ,m_bDocumentClosed( false ) + { + if ( _rxDocument.is() ) + impl_initDocument_nothrow( _rxDocument ); + } + + ScriptDocument::Impl::~Impl() + { + invalidate(); + } + + void ScriptDocument::Impl::invalidate() + { + m_bIsApplication = false; + m_bValid = false; + m_bDocumentClosed = false; + + m_xDocument.clear(); + m_xDocModify.clear(); + m_xScriptAccess.clear(); + + if (m_pDocListener) + m_pDocListener->dispose(); + } + + bool ScriptDocument::Impl::impl_initDocument_nothrow( const Reference< XModel >& _rxModel ) + { + try + { + m_xDocument.set ( _rxModel, UNO_SET_THROW ); + m_xDocModify.set ( _rxModel, UNO_QUERY_THROW ); + m_xScriptAccess.set ( _rxModel, UNO_QUERY ); + + m_bValid = m_xScriptAccess.is(); + + if ( m_bValid ) + m_pDocListener.reset( new DocumentEventNotifier( *this, _rxModel ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + m_bValid = false; + } + + if ( !m_bValid ) + { + invalidate(); + } + + return m_bValid; + } + + Reference< XLibraryContainer > ScriptDocument::Impl::getLibraryContainer( LibraryContainerType _eType ) const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getLibraryContainer: invalid!" ); + + Reference< XLibraryContainer > xContainer; + if ( !isValid() ) + return xContainer; + + try + { + if ( isApplication() ) + xContainer.set( _eType == E_SCRIPTS ? SfxGetpApp()->GetBasicContainer() : SfxGetpApp()->GetDialogContainer(), UNO_QUERY_THROW ); + else + { + xContainer.set( + _eType == E_SCRIPTS ? m_xScriptAccess->getBasicLibraries() : m_xScriptAccess->getDialogLibraries(), + UNO_QUERY_THROW ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return xContainer; + } + + bool ScriptDocument::Impl::isReadOnly() const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::isReadOnly: invalid state!" ); + OSL_ENSURE( !isApplication(), "ScriptDocument::Impl::isReadOnly: not allowed to be called for the application!" ); + + bool bIsReadOnly = true; + if ( isValid() && !isApplication() ) + { + try + { + // note that XStorable is required by the OfficeDocument service + Reference< XStorable > xDocStorable( m_xDocument, UNO_QUERY_THROW ); + bIsReadOnly = xDocStorable->isReadonly(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + return bIsReadOnly; + } + + bool ScriptDocument::Impl::isInVBAMode() const + { + bool bResult = false; + if ( !isApplication() ) + { + Reference< XVBACompatibility > xVBACompat( getLibraryContainer( E_SCRIPTS ), UNO_QUERY ); + if ( xVBACompat.is() ) + bResult = xVBACompat->getVBACompatibilityMode(); + } + return bResult; + } + + BasicManager* ScriptDocument::Impl::getBasicManager() const + { + try + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getBasicManager: invalid state!" ); + if ( !isValid() ) + return nullptr; + + if ( isApplication() ) + return SfxApplication::GetBasicManager(); + + return ::basic::BasicManagerRepository::getDocumentBasicManager( m_xDocument ); + } + catch (const css::ucb::ContentCreationException&) + { + TOOLS_WARN_EXCEPTION( "basctl.basicide", "ScriptDocument::getBasicManager" ); + } + return nullptr; + } + + Reference< XModel > ScriptDocument::Impl::getDocument() const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getDocument: invalid state!" ); + OSL_ENSURE( isDocument(), "ScriptDocument::Impl::getDocument: for documents only!" ); + if ( !isValid() || !isDocument() ) + return nullptr; + + return m_xDocument; + } + + + Reference< XNameContainer > ScriptDocument::Impl::getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getLibrary: invalid state!" ); + + Reference< XNameContainer > xContainer; + try + { + Reference< XLibraryContainer > xLibContainer = getLibraryContainer( _eType ); + if ( isValid() && xLibContainer.is() ) + xContainer.set( xLibContainer->getByName( _rLibName ), UNO_QUERY_THROW ); + + if ( !xContainer.is() ) + throw NoSuchElementException(); + + // load library + if ( _bLoadLibrary && !xLibContainer->isLibraryLoaded( _rLibName ) ) + xLibContainer->loadLibrary( _rLibName ); + } + catch( const NoSuchElementException& ) + { + throw; // allowed to leave + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + return xContainer; + } + + + bool ScriptDocument::Impl::hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const + { + bool bHas = false; + try + { + Reference< XLibraryContainer > xLibContainer = getLibraryContainer( _eType ); + bHas = xLibContainer.is() && xLibContainer->hasByName( _rLibName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return bHas; + } + + + Reference< XNameContainer > ScriptDocument::Impl::getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const + { + Reference< XNameContainer > xLibrary; + try + { + Reference< XLibraryContainer > xLibContainer( getLibraryContainer( _eType ), UNO_SET_THROW ); + if ( xLibContainer->hasByName( _rLibName ) ) + xLibrary.set( xLibContainer->getByName( _rLibName ), UNO_QUERY_THROW ); + else + xLibrary.set( xLibContainer->createLibrary( _rLibName ), UNO_SET_THROW ); + + if ( !xLibContainer->isLibraryLoaded( _rLibName ) ) + xLibContainer->loadLibrary( _rLibName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return xLibrary; + } + + + void ScriptDocument::Impl::loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary ) + { + try + { + Reference< XLibraryContainer > xLibContainer( getLibraryContainer( _eType ) ); + if ( xLibContainer.is() && xLibContainer->hasByName( _rLibrary ) && !xLibContainer->isLibraryLoaded( _rLibrary ) ) + xLibContainer->loadLibrary( _rLibrary ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + + + bool ScriptDocument::Impl::removeModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModuleName ) + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::removeModuleOrDialog: invalid!" ); + if ( !isValid() ) + return false; + try + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ) ); + if ( xLib.is() ) + { + xLib->removeByName( _rModuleName ); + Reference< XVBAModuleInfo > xVBAModuleInfo(xLib, UNO_QUERY); + if(xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo(_rModuleName)) + xVBAModuleInfo->removeModuleInfo(_rModuleName); + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::hasModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rModName ) const + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::hasModuleOrDialog: invalid!" ); + if ( !isValid() ) + return false; + + try + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ) ); + if ( xLib.is() ) + return xLib->hasByName( _rModName ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::getModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rObjectName, Any& _out_rModuleOrDialog ) + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::getModuleOrDialog: invalid!" ); + if ( !isValid() ) + return false; + + _out_rModuleOrDialog.clear(); + try + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ), UNO_SET_THROW ); + if ( xLib->hasByName( _rObjectName ) ) + { + _out_rModuleOrDialog = xLib->getByName( _rObjectName ); + return true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::renameModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, + const OUString& _rOldName, const OUString& _rNewName, const Reference< XNameContainer >& _rxExistingDialogModel ) + { + OSL_ENSURE( isValid(), "ScriptDocument::Impl::renameModuleOrDialog: invalid!" ); + if ( !isValid() ) + return false; + + try + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, true ), UNO_SET_THROW ); + + // get element + Any aElement( xLib->getByName( _rOldName ) ); + + // remove element from container + xLib->removeByName( _rOldName ); + + // if it's a dialog, import and export, to reflect the new name + if ( _eType == E_DIALOGS ) + { + // create dialog model + Reference< XComponentContext > aContext( + comphelper::getProcessComponentContext() ); + Reference< XNameContainer > xDialogModel; + if ( _rxExistingDialogModel.is() ) + xDialogModel = _rxExistingDialogModel; + else + xDialogModel.set( + ( aContext->getServiceManager()-> + createInstanceWithContext( + "com.sun.star.awt.UnoControlDialogModel", + aContext ) ), + UNO_QUERY_THROW ); + + // import dialog model + Reference< XInputStreamProvider > xISP( aElement, UNO_QUERY_THROW ); + if ( !_rxExistingDialogModel.is() ) + { + Reference< XInputStream > xInput( xISP->createInputStream(), UNO_SET_THROW ); + ::xmlscript::importDialogModel( xInput, xDialogModel, aContext, isDocument() ? getDocument() : Reference< XModel >() ); + } + + // set new name as property + Reference< XPropertySet > xDlgPSet( xDialogModel, UNO_QUERY_THROW ); + xDlgPSet->setPropertyValue( DLGED_PROP_NAME, Any( _rNewName ) ); + + // export dialog model + xISP = ::xmlscript::exportDialogModel( xDialogModel, aContext, isDocument() ? getDocument() : Reference< XModel >() ); + aElement <<= xISP; + } + + // insert element by new name in container + if ( _eType == E_SCRIPTS ) + { + Reference< XVBAModuleInfo > xVBAModuleInfo( xLib, UNO_QUERY ); + if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo( _rOldName ) ) + { + ModuleInfo sModuleInfo = xVBAModuleInfo->getModuleInfo( _rOldName ); + xVBAModuleInfo->removeModuleInfo( _rOldName ); + xVBAModuleInfo->insertModuleInfo( _rNewName, sModuleInfo ); + } + } + xLib->insertByName( _rNewName, aElement ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const + { + _out_rNewModuleCode.clear(); + try + { + Reference< XNameContainer > xLib( getLibrary( E_SCRIPTS, _rLibName, true ) ); + if ( !xLib.is() || xLib->hasByName( _rModName ) ) + return false; + + // create new module + _out_rNewModuleCode = "REM ***** BASIC *****\n\n" ; + if ( _bCreateMain ) + _out_rNewModuleCode += "Sub Main\n\nEnd Sub\n" ; + + Reference< XVBAModuleInfo > xVBAModuleInfo(xLib, UNO_QUERY); + if (xVBAModuleInfo.is()) + { + css::script::ModuleInfo aModuleInfo; + aModuleInfo.ModuleType = css::script::ModuleType::NORMAL; + xVBAModuleInfo->insertModuleInfo(_rModName, aModuleInfo); + } + + // insert module into library + xLib->insertByName( _rModName, Any( _out_rNewModuleCode ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + return false; + } + + return true; + } + + + bool ScriptDocument::Impl::insertModuleOrDialog( LibraryContainerType _eType, const OUString& _rLibName, const OUString& _rObjectName, const Any& _rElement ) const + { + try + { + Reference< XNameContainer > xLib( getOrCreateLibrary( _eType, _rLibName ), UNO_SET_THROW ); + if ( xLib->hasByName( _rObjectName ) ) + return false; + + xLib->insertByName( _rObjectName, _rElement ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const + { + try + { + Reference< XNameContainer > xLib( getOrCreateLibrary( E_SCRIPTS, _rLibName ), UNO_SET_THROW ); + if ( !xLib->hasByName( _rModName ) ) + return false; + xLib->replaceByName( _rModName, Any( _rModuleCode ) ); + return true; + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return false; + } + + + bool ScriptDocument::Impl::createDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const + { + try + { + Reference< XNameContainer > xLib( getLibrary( E_DIALOGS, _rLibName, true ), UNO_SET_THROW ); + + // create dialog + _out_rDialogProvider.clear(); + if ( xLib->hasByName( _rDialogName ) ) + return false; + + // create new dialog model + Reference< XComponentContext > aContext( + comphelper::getProcessComponentContext() ); + Reference< XNameContainer > xDialogModel( + aContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.awt.UnoControlDialogModel", aContext ), + UNO_QUERY_THROW ); + + // set name property + Reference< XPropertySet > xDlgPSet( xDialogModel, UNO_QUERY_THROW ); + xDlgPSet->setPropertyValue( DLGED_PROP_NAME, Any( _rDialogName ) ); + + // export dialog model + _out_rDialogProvider = ::xmlscript::exportDialogModel( xDialogModel, aContext, isDocument() ? getDocument() : Reference< XModel >() ); + + // insert dialog into library + xLib->insertByName( _rDialogName, Any( _out_rDialogProvider ) ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + return _out_rDialogProvider.is(); + } + + + void ScriptDocument::Impl::setDocumentModified() const + { + OSL_ENSURE( isValid() && isDocument(), "ScriptDocument::Impl::setDocumentModified: only to be called for real documents!" ); + if ( isValid() && isDocument() ) + { + try + { + m_xDocModify->setModified( true ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + } + + + bool ScriptDocument::Impl::isDocumentModified() const + { + OSL_ENSURE( isValid() && isDocument(), "ScriptDocument::Impl::isDocumentModified: only to be called for real documents!" ); + bool bIsModified = false; + if ( isValid() && isDocument() ) + { + try + { + bIsModified = m_xDocModify->isModified(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + return bIsModified; + } + + + void ScriptDocument::Impl::saveDocument( const Reference< XStatusIndicator >& _rxStatusIndicator ) const + { + Reference< XFrame > xFrame; + if ( !getCurrentFrame( xFrame ) ) + return; + + Sequence< PropertyValue > aArgs; + if ( _rxStatusIndicator.is() ) + { + aArgs = ::comphelper::InitPropertySequence({ + { "StatusIndicator", Any(_rxStatusIndicator) } + }); + } + + try + { + URL aURL; + aURL.Complete = ".uno:Save" ; + aURL.Main = aURL.Complete; + aURL.Protocol = ".uno:" ; + aURL.Path = "Save" ; + + Reference< XDispatchProvider > xDispProv( xFrame, UNO_QUERY_THROW ); + Reference< XDispatch > xDispatch( + xDispProv->queryDispatch( aURL, "_self", FrameSearchFlag::AUTO ), + UNO_SET_THROW ); + + xDispatch->dispatch( aURL, aArgs ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + + + OUString ScriptDocument::Impl::getTitle() const + { + OSL_PRECOND( isValid() && isDocument(), "ScriptDocument::Impl::getTitle: for documents only!" ); + + OUString sTitle; + if ( isValid() && isDocument() ) + { + sTitle = ::comphelper::DocumentInfo::getDocumentTitle( m_xDocument ); + } + return sTitle; + } + + + OUString ScriptDocument::Impl::getURL() const + { + OSL_PRECOND( isValid() && isDocument(), "ScriptDocument::Impl::getURL: for documents only!" ); + + OUString sURL; + if ( isValid() && isDocument() ) + { + try + { + sURL = m_xDocument->getURL(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + return sURL; + } + + + bool ScriptDocument::Impl::allowMacros() const + { + OSL_ENSURE( isValid() && isDocument(), "ScriptDocument::Impl::allowMacros: for documents only!" ); + bool bAllow = false; + if ( isValid() && isDocument() ) + { + try + { + bAllow = m_xScriptAccess->getAllowMacroExecution(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + } + return bAllow; + } + + + bool ScriptDocument::Impl::getCurrentFrame( Reference< XFrame >& _out_rxFrame ) const + { + _out_rxFrame.clear(); + OSL_PRECOND( isValid() && isDocument(), "ScriptDocument::Impl::getCurrentFrame: documents only!" ); + if ( !isValid() || !isDocument() ) + return false; + + try + { + Reference< XModel > xDocument( m_xDocument, UNO_SET_THROW ); + Reference< XController > xController( xDocument->getCurrentController(), UNO_SET_THROW ); + _out_rxFrame.set( xController->getFrame(), UNO_SET_THROW ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + return _out_rxFrame.is(); + } + + + bool ScriptDocument::Impl::isLibraryShared( const OUString& _rLibName, LibraryContainerType _eType ) + { + bool bIsShared = false; + try + { + Reference< XLibraryContainer2 > xLibContainer( getLibraryContainer( _eType ), UNO_QUERY_THROW ); + + if ( !xLibContainer->hasByName( _rLibName ) || !xLibContainer->isLibraryLink( _rLibName ) ) + return false; + OUString aFileURL; + Reference< XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + Reference< XUriReferenceFactory > xUriFac = UriReferenceFactory::create(xContext); + + OUString aLinkURL( xLibContainer->getLibraryLinkURL( _rLibName ) ); + Reference< XUriReference > xUriRef( xUriFac->parse( aLinkURL ), UNO_SET_THROW ); + + OUString aScheme = xUriRef->getScheme(); + if ( aScheme.equalsIgnoreAsciiCase("file") ) + { + aFileURL = aLinkURL; + } + else if ( aScheme.equalsIgnoreAsciiCase("vnd.sun.star.pkg") ) + { + OUString aDecodedURL = xUriRef->getAuthority(); + if (aDecodedURL.startsWithIgnoreAsciiCase("vnd.sun.star.expand:", &aDecodedURL)) + { + aDecodedURL = ::rtl::Uri::decode( aDecodedURL, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); + Reference< XMacroExpander > xMacroExpander = theMacroExpander::get(xContext); + aFileURL = xMacroExpander->expandMacros( aDecodedURL ); + } + } + + if ( !aFileURL.isEmpty() ) + { + ::osl::DirectoryItem aFileItem; + ::osl::FileStatus aFileStatus( osl_FileStatus_Mask_FileURL ); + OSL_VERIFY( ::osl::DirectoryItem::get( aFileURL, aFileItem ) == ::osl::FileBase::E_None ); + OSL_VERIFY( aFileItem.getFileStatus( aFileStatus ) == ::osl::FileBase::E_None ); + OUString aCanonicalFileURL( aFileStatus.getFileURL() ); + + if( aCanonicalFileURL.indexOf( LIBO_SHARE_FOLDER "/basic" ) >= 0 || + aCanonicalFileURL.indexOf( LIBO_SHARE_FOLDER "/uno_packages" ) >= 0 || + aCanonicalFileURL.indexOf( LIBO_SHARE_FOLDER "/extensions" ) >= 0 ) + bIsShared = true; + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + return bIsShared; + } + + + void ScriptDocument::Impl::onDocumentCreated( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentOpened( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentSave( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentSaveDone( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentSaveAs( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentSaveAsDone( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentClosed( const ScriptDocument& _rDocument ) + { + DBG_TESTSOLARMUTEX(); + OSL_PRECOND( isValid(), "ScriptDocument::Impl::onDocumentClosed: should not be listening if I'm not valid!" ); + + bool bMyDocument = m_xDocument == _rDocument.getDocument(); + OSL_PRECOND( bMyDocument, "ScriptDocument::Impl::onDocumentClosed: didn't want to know *this*!" ); + if ( bMyDocument ) + { + m_bDocumentClosed = true; + } + } + + + void ScriptDocument::Impl::onDocumentTitleChanged( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + void ScriptDocument::Impl::onDocumentModeChanged( const ScriptDocument& /*_rDocument*/ ) + { + // not interested in + } + + + ScriptDocument::ScriptDocument() + :m_pImpl(std::make_shared<Impl>()) + { } + + + ScriptDocument::ScriptDocument( ScriptDocument::SpecialDocument _eType ) + :m_pImpl( std::make_shared<Impl>( Reference< XModel >() ) ) + { + OSL_ENSURE( _eType == NoDocument, "ScriptDocument::ScriptDocument: unknown SpecialDocument type!" ); + } + + + ScriptDocument::ScriptDocument( const Reference< XModel >& _rxDocument ) + :m_pImpl( std::make_shared<Impl>( _rxDocument ) ) + { + OSL_ENSURE( _rxDocument.is(), "ScriptDocument::ScriptDocument: document must not be NULL!" ); + // a NULL document results in an uninitialized instance, and for this + // purpose, there is a dedicated constructor + } + + + const ScriptDocument& ScriptDocument::getApplicationScriptDocument() + { + static ScriptDocument s_aApplicationScripts; + return s_aApplicationScripts; + } + + + ScriptDocument ScriptDocument::getDocumentForBasicManager( const BasicManager* _pManager ) + { + if ( _pManager == SfxApplication::GetBasicManager() ) + return getApplicationScriptDocument(); + + docs::Documents aDocuments; + lcl_getAllModels_throw( aDocuments, false ); + + for (auto const& doc : aDocuments) + { + const BasicManager* pDocBasicManager = ::basic::BasicManagerRepository::getDocumentBasicManager( doc.xModel ); + if ( ( pDocBasicManager != SfxApplication::GetBasicManager() ) + && ( pDocBasicManager == _pManager ) + ) + { + return ScriptDocument( doc.xModel ); + } + } + + OSL_FAIL( "ScriptDocument::getDocumentForBasicManager: did not find a document for this manager!" ); + return ScriptDocument( NoDocument ); + } + + + ScriptDocument ScriptDocument::getDocumentWithURLOrCaption( std::u16string_view _rUrlOrCaption ) + { + ScriptDocument aDocument( getApplicationScriptDocument() ); + if ( _rUrlOrCaption.empty() ) + return aDocument; + + docs::Documents aDocuments; + lcl_getAllModels_throw( aDocuments, false ); + + for (auto const& doc : aDocuments) + { + const ScriptDocument aCheck( doc.xModel ); + if ( _rUrlOrCaption == aCheck.getTitle() + || _rUrlOrCaption == aCheck.m_pImpl->getURL() + ) + { + aDocument = aCheck; + break; + } + } + + return aDocument; + } + + ScriptDocuments ScriptDocument::getAllScriptDocuments( ScriptDocument::ScriptDocumentList _eListType ) + { + ScriptDocuments aScriptDocs; + + // include application? + if ( _eListType == AllWithApplication ) + aScriptDocs.push_back( getApplicationScriptDocument() ); + + // obtain documents + try + { + docs::Documents aDocuments; + lcl_getAllModels_throw( aDocuments, true /* exclude invisible */ ); + + for (auto const& doc : aDocuments) + { + // exclude documents without script/library containers + ScriptDocument aDoc( doc.xModel ); + if ( !aDoc.isValid() ) + continue; + + aScriptDocs.push_back( aDoc ); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + // sort document list by doc title? + if ( _eListType == DocumentsSorted ) + { + auto const sort = comphelper::string::NaturalStringSorter( + comphelper::getProcessComponentContext(), + Application::GetSettings().GetUILanguageTag().getLocale()); + std::sort(aScriptDocs.begin(), aScriptDocs.end(), + [&sort](const ScriptDocument& rLHS, const ScriptDocument& rRHS) { + return sort.compare(rLHS.getTitle(), rRHS.getTitle()) < 0; + }); + } + + return aScriptDocs; + } + + + bool ScriptDocument::operator==( const ScriptDocument& _rhs ) const + { + return m_pImpl->getDocumentRef() == _rhs.m_pImpl->getDocumentRef(); + } + + + sal_Int32 ScriptDocument::hashCode() const + { + return sal::static_int_cast<sal_Int32>(reinterpret_cast< sal_IntPtr >( m_pImpl->getDocumentRef().get() )); + } + + + bool ScriptDocument::isValid() const + { + return m_pImpl->isValid(); + } + + + bool ScriptDocument::isAlive() const + { + return m_pImpl->isAlive(); + } + + + Reference< XLibraryContainer > ScriptDocument::getLibraryContainer( LibraryContainerType _eType ) const + { + return m_pImpl->getLibraryContainer( _eType ); + } + + + Reference< XNameContainer > ScriptDocument::getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const + { + return m_pImpl->getLibrary( _eType, _rLibName, _bLoadLibrary ); + } + + + bool ScriptDocument::hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const + { + return m_pImpl->hasLibrary( _eType, _rLibName ); + } + + + Reference< XNameContainer > ScriptDocument::getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const + { + return m_pImpl->getOrCreateLibrary( _eType, _rLibName ); + } + + + void ScriptDocument::loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary ) + { + m_pImpl->loadLibraryIfExists( _eType, _rLibrary ); + } + + + Sequence< OUString > ScriptDocument::getObjectNames( LibraryContainerType _eType, const OUString& _rLibName ) const + { + Sequence< OUString > aModuleNames; + + try + { + if ( hasLibrary( _eType, _rLibName ) ) + { + Reference< XNameContainer > xLib( getLibrary( _eType, _rLibName, false ) ); + if ( xLib.is() ) + aModuleNames = xLib->getElementNames(); + } + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + + // sort + auto const sort = comphelper::string::NaturalStringSorter( + comphelper::getProcessComponentContext(), + Application::GetSettings().GetUILanguageTag().getLocale()); + auto [begin, end] = asNonConstRange(aModuleNames); + std::sort(begin, end, + [&sort](const OUString& rLHS, const OUString& rRHS) { + return sort.compare(rLHS, rRHS) < 0; + }); + return aModuleNames; + } + + + OUString ScriptDocument::createObjectName( LibraryContainerType _eType, const OUString& _rLibName ) const + { + OUString aObjectName; + + OUString aBaseName = _eType == E_SCRIPTS ? OUString("Module") : OUString("Dialog"); + + const Sequence< OUString > aUsedNames( getObjectNames( _eType, _rLibName ) ); + std::set< OUString > aUsedNamesCheck( aUsedNames.begin(), aUsedNames.end() ); + + bool bValid = false; + sal_Int32 i = 1; + while ( !bValid ) + { + aObjectName = aBaseName + + OUString::number( i ); + + if ( aUsedNamesCheck.find( aObjectName ) == aUsedNamesCheck.end() ) + bValid = true; + + ++i; + } + + return aObjectName; + } + + + Sequence< OUString > ScriptDocument::getLibraryNames() const + { + return GetMergedLibraryNames( getLibraryContainer( E_SCRIPTS ), getLibraryContainer( E_DIALOGS ) ); + } + + + bool ScriptDocument::isReadOnly() const + { + return m_pImpl->isReadOnly(); + } + + + bool ScriptDocument::isApplication() const + { + return m_pImpl->isApplication(); + } + + bool ScriptDocument::isInVBAMode() const + { + return m_pImpl->isInVBAMode(); + } + + + BasicManager* ScriptDocument::getBasicManager() const + { + return m_pImpl->getBasicManager(); + } + + + Reference< XModel > ScriptDocument::getDocument() const + { + return m_pImpl->getDocument(); + } + + + Reference< XModel > ScriptDocument::getDocumentOrNull() const + { + if ( isDocument() ) + return m_pImpl->getDocument(); + return nullptr; + } + + + bool ScriptDocument::removeModule( const OUString& _rLibName, const OUString& _rModuleName ) const + { + return m_pImpl->removeModuleOrDialog( E_SCRIPTS, _rLibName, _rModuleName ); + } + + + bool ScriptDocument::hasModule( const OUString& _rLibName, const OUString& _rModuleName ) const + { + return m_pImpl->hasModuleOrDialog( E_SCRIPTS, _rLibName, _rModuleName ); + } + + + bool ScriptDocument::getModule( const OUString& _rLibName, const OUString& _rModName, OUString& _out_rModuleSource ) const + { + Any aCode; + if ( !m_pImpl->getModuleOrDialog( E_SCRIPTS, _rLibName, _rModName, aCode ) ) + return false; + OSL_VERIFY( aCode >>= _out_rModuleSource ); + return true; + } + + + bool ScriptDocument::renameModule( const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName ) const + { + return m_pImpl->renameModuleOrDialog( E_SCRIPTS, _rLibName, _rOldName, _rNewName, nullptr ); + } + + + bool ScriptDocument::createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const + { + if ( !m_pImpl->createModule( _rLibName, _rModName, _bCreateMain, _out_rNewModuleCode ) ) + return false; + + // doc shell modified + MarkDocumentModified( *const_cast< ScriptDocument* >( this ) ); // here? + return true; + } + + + bool ScriptDocument::insertModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const + { + return m_pImpl->insertModuleOrDialog( E_SCRIPTS, _rLibName, _rModName, Any( _rModuleCode ) ); + } + + + bool ScriptDocument::updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const + { + return m_pImpl->updateModule( _rLibName, _rModName, _rModuleCode ); + } + + + bool ScriptDocument::removeDialog( const OUString& _rLibName, const OUString& _rDialogName ) const + { + return m_pImpl->removeModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName ); + } + + + bool ScriptDocument::hasDialog( const OUString& _rLibName, const OUString& _rDialogName ) const + { + return m_pImpl->hasModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName ); + } + + + bool ScriptDocument::getDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const + { + Any aCode; + if ( !m_pImpl->getModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName, aCode ) ) + return false; + OSL_VERIFY( aCode >>= _out_rDialogProvider ); + return _out_rDialogProvider.is(); + } + + + bool ScriptDocument::renameDialog( const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName, const Reference< XNameContainer >& _rxExistingDialogModel ) const + { + return m_pImpl->renameModuleOrDialog( E_DIALOGS, _rLibName, _rOldName, _rNewName, _rxExistingDialogModel ); + } + + + bool ScriptDocument::createDialog( const OUString& _rLibName, const OUString& _rDialogName, Reference< XInputStreamProvider >& _out_rDialogProvider ) const + { + if ( !m_pImpl->createDialog( _rLibName, _rDialogName, _out_rDialogProvider ) ) + return false; + + MarkDocumentModified( *const_cast< ScriptDocument* >( this ) ); // here? + return true; + } + + + bool ScriptDocument::insertDialog( const OUString& _rLibName, const OUString& _rDialogName, const Reference< XInputStreamProvider >& _rxDialogProvider ) const + { + return m_pImpl->insertModuleOrDialog( E_DIALOGS, _rLibName, _rDialogName, Any( _rxDialogProvider ) ); + } + + + void ScriptDocument::setDocumentModified() const + { + m_pImpl->setDocumentModified(); + } + + + bool ScriptDocument::isDocumentModified() const + { + return m_pImpl->isDocumentModified(); + } + + + void ScriptDocument::saveDocument( const Reference< XStatusIndicator >& _rxStatusIndicator ) const + { + m_pImpl->saveDocument( _rxStatusIndicator ); + } + + + LibraryLocation ScriptDocument::getLibraryLocation( const OUString& _rLibName ) const + { + LibraryLocation eLocation = LIBRARY_LOCATION_UNKNOWN; + if ( !_rLibName.isEmpty() ) + { + if ( isDocument() ) + { + eLocation = LIBRARY_LOCATION_DOCUMENT; + } + else + { + if ( ( hasLibrary( E_SCRIPTS, _rLibName ) && !m_pImpl->isLibraryShared( _rLibName, E_SCRIPTS ) ) + || ( hasLibrary( E_DIALOGS, _rLibName ) && !m_pImpl->isLibraryShared( _rLibName, E_DIALOGS ) ) + ) + { + eLocation = LIBRARY_LOCATION_USER; + } + else + { + eLocation = LIBRARY_LOCATION_SHARE; + } + } + } + + return eLocation; + } + + + OUString ScriptDocument::getTitle( LibraryLocation _eLocation, LibraryType _eType ) const + { + OUString aTitle; + + switch ( _eLocation ) + { + case LIBRARY_LOCATION_USER: + { + switch ( _eType ) + { + case LibraryType::Module: aTitle = IDEResId(RID_STR_USERMACROS); break; + case LibraryType::Dialog: aTitle = IDEResId(RID_STR_USERDIALOGS); break; + case LibraryType::All: aTitle = IDEResId(RID_STR_USERMACROSDIALOGS); break; + default: + break; + } + } + break; + case LIBRARY_LOCATION_SHARE: + { + switch ( _eType ) + { + case LibraryType::Module: aTitle = IDEResId(RID_STR_SHAREMACROS); break; + case LibraryType::Dialog: aTitle = IDEResId(RID_STR_SHAREDIALOGS); break; + case LibraryType::All: aTitle = IDEResId(RID_STR_SHAREMACROSDIALOGS); break; + default: + break; + } + } + break; + case LIBRARY_LOCATION_DOCUMENT: + aTitle = getTitle(); + break; + default: + break; + } + + return aTitle; + } + + + OUString ScriptDocument::getTitle() const + { + return m_pImpl->getTitle(); + } + + + bool ScriptDocument::isActive() const + { + bool bIsActive( false ); + try + { + Reference< XFrame > xFrame; + if ( m_pImpl->getCurrentFrame( xFrame ) ) + bIsActive = xFrame->isActive(); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl.basicide"); + } + return bIsActive; + } + + + bool ScriptDocument::allowMacros() const + { + return m_pImpl->allowMacros(); + } + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/textwindowpeer.cxx b/basctl/source/basicide/textwindowpeer.cxx new file mode 100644 index 0000000000..421468a279 --- /dev/null +++ b/basctl/source/basicide/textwindowpeer.cxx @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <vcl/svtaccessiblefactory.hxx> +#include <vcl/accessiblefactory.hxx> + +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <toolkit/awt/vclxwindow.hxx> +#include <vcl/texteng.hxx> +#include <vcl/textview.hxx> +#include <vcl/window.hxx> +#include "textwindowpeer.hxx" + +namespace { + +class TextWindowPeer final : public VCLXWindow { +public: + explicit TextWindowPeer(TextView & view); + + TextWindowPeer(const TextWindowPeer&) = delete; + TextWindowPeer& operator=(const TextWindowPeer&) = delete; + +private: + virtual css::uno::Reference<css::accessibility::XAccessibleContext> + CreateAccessibleContext() override; + + TextEngine & m_rEngine; + TextView & m_rView; + vcl::AccessibleFactoryAccess m_aFactoryAccess; +}; + +TextWindowPeer::TextWindowPeer(TextView & view): + m_rEngine(*view.GetTextEngine()), m_rView(view) +{ + SetWindow(view.GetWindow()); +} + +css::uno::Reference<css::accessibility::XAccessibleContext> +TextWindowPeer::CreateAccessibleContext() { + return m_aFactoryAccess.getFactory().createAccessibleTextWindowContext( + this, m_rEngine, m_rView); +} + +} + +css::uno::Reference<css::awt::XVclWindowPeer> basctl::createTextWindowPeer( + TextView & view) +{ + return new TextWindowPeer(view); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/textwindowpeer.hxx b/basctl/source/basicide/textwindowpeer.hxx new file mode 100644 index 0000000000..e29c4a412d --- /dev/null +++ b/basctl/source/basicide/textwindowpeer.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 <sal/config.h> + +#include <com/sun/star/uno/Reference.hxx> + +namespace com::sun::star::awt +{ +class XVclWindowPeer; +} +class TextView; + +namespace basctl +{ +css::uno::Reference<css::awt::XVclWindowPeer> createTextWindowPeer(TextView& view); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/uiobject.cxx b/basctl/source/basicide/uiobject.cxx new file mode 100644 index 0000000000..b875b1eced --- /dev/null +++ b/basctl/source/basicide/uiobject.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 <memory> +#include "uiobject.hxx" +#include <vcl/xtextedt.hxx> + +namespace basctl +{ +EditorWindowUIObject::EditorWindowUIObject(const VclPtr<basctl::EditorWindow>& xEditorWindow) + : WindowUIObject(xEditorWindow) + , mxEditorWindow(xEditorWindow) +{ +} + +StringMap EditorWindowUIObject::get_state() +{ + StringMap aMap = WindowUIObject::get_state(); + + ExtTextEngine* pEditEngine = mxEditorWindow->GetEditEngine(); + sal_Int32 i, nParas; + OUStringBuffer aRes; + for (i = 0, nParas = pEditEngine->GetParagraphCount(); i < nParas; ++i) + { + aRes.append(pEditEngine->GetText(i) + "\n"); + } + + aMap["Text"] = aRes.makeStringAndClear(); + + return aMap; +} + +std::unique_ptr<UIObject> EditorWindowUIObject::create(vcl::Window* pWindow) +{ + basctl::EditorWindow* pEditorWindow = dynamic_cast<basctl::EditorWindow*>(pWindow); + assert(pEditorWindow); + return std::unique_ptr<UIObject>(new EditorWindowUIObject(pEditorWindow)); +} + +OUString EditorWindowUIObject::get_name() const { return "EditorWindowUIObject"; } + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/uiobject.hxx b/basctl/source/basicide/uiobject.hxx new file mode 100644 index 0000000000..f3a1e5ec88 --- /dev/null +++ b/basctl/source/basicide/uiobject.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/. + */ + +#include <memory> +#include <vcl/uitest/uiobject.hxx> +#include "baside2.hxx" + +namespace basctl +{ +class EditorWindow; + +class EditorWindowUIObject : public WindowUIObject +{ + VclPtr<basctl::EditorWindow> mxEditorWindow; + +public: + EditorWindowUIObject(const VclPtr<basctl::EditorWindow>& xEditorWindow); + + virtual StringMap get_state() override; + + static std::unique_ptr<UIObject> create(vcl::Window* pWindow); + +protected: + virtual OUString get_name() const override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/unomodel.cxx b/basctl/source/basicide/unomodel.cxx new file mode 100644 index 0000000000..5d3946b426 --- /dev/null +++ b/basctl/source/basicide/unomodel.cxx @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include "basdoc.hxx" +#include <iderdll.hxx> +#include <com/sun/star/io/IOException.hpp> +#include <comphelper/sequence.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <sfx2/objsh.hxx> +#include <vcl/svapp.hxx> + +#include "unomodel.hxx" + +namespace basctl +{ + +using namespace ::cppu; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + +SIDEModel::SIDEModel( SfxObjectShell *pObjSh ) +: SfxBaseModel(pObjSh) +{ +} + +SIDEModel::~SIDEModel() +{ +} + +uno::Any SAL_CALL SIDEModel::queryInterface( const uno::Type& rType ) +{ + uno::Any aRet = ::cppu::queryInterface ( rType, + // OWeakObject interfaces + static_cast< XInterface* >( static_cast< OWeakObject* >( this ) ), + static_cast< XWeak* > ( this ), + static_cast< XServiceInfo* > ( this ) ); + if (!aRet.hasValue()) + aRet = SfxBaseModel::queryInterface ( rType ); + return aRet; +} + +void SAL_CALL SIDEModel::acquire() noexcept +{ + SolarMutexGuard aGuard; + OWeakObject::acquire(); +} + +void SAL_CALL SIDEModel::release() noexcept +{ + SolarMutexGuard aGuard; + OWeakObject::release(); +} + +uno::Sequence< uno::Type > SAL_CALL SIDEModel::getTypes( ) +{ + return comphelper::concatSequences( + SfxBaseModel::getTypes(), + uno::Sequence { cppu::UnoType<XServiceInfo>::get() }); +} + +OUString SIDEModel::getImplementationName() +{ + return "com.sun.star.comp.basic.BasicIDE"; +} + +sal_Bool SIDEModel::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence< OUString > SIDEModel::getSupportedServiceNames() +{ + return { "com.sun.star.script.BasicIDE" }; +} + +// XStorable +void SAL_CALL SIDEModel::store() +{ + notImplemented(); +} + +void SAL_CALL SIDEModel::storeAsURL( const OUString&, const uno::Sequence< beans::PropertyValue >& ) +{ + notImplemented(); +} + +void SAL_CALL SIDEModel::storeToURL( const OUString&, + const uno::Sequence< beans::PropertyValue >& ) +{ + notImplemented(); +} + +void SIDEModel::notImplemented() +{ + throw io::IOException("Can't store IDE model" ); +} + +} // namespace basctl + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +com_sun_star_comp_basic_BasicID_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + SolarMutexGuard aGuard; + basctl::EnsureIde(); + SfxObjectShell* pShell = new basctl::DocShell(); + auto pModel = pShell->GetModel(); + pModel->acquire(); + return pModel.get(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/basicide/unomodel.hxx b/basctl/source/basicide/unomodel.hxx new file mode 100644 index 0000000000..b478730056 --- /dev/null +++ b/basctl/source/basicide/unomodel.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 <com/sun/star/lang/XServiceInfo.hpp> +#include <sfx2/sfxbasemodel.hxx> + +namespace basctl +{ + +class SIDEModel : public SfxBaseModel, + public com::sun::star::lang::XServiceInfo +{ + /// @throws css::io::IOException + static void notImplemented(); +public: + explicit SIDEModel(SfxObjectShell *pObjSh); + virtual ~SIDEModel() override; + + //XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override; + virtual void SAL_CALL acquire( ) noexcept override; + virtual void SAL_CALL release( ) noexcept override; + + //XTypeProvider + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) 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; + // XStorable2 + virtual void SAL_CALL storeSelf( const css::uno::Sequence< css::beans::PropertyValue >& ) override { notImplemented(); } + // XStorable + virtual void SAL_CALL store() override; + virtual void SAL_CALL storeAsURL( const OUString& sURL, + const css::uno::Sequence< css::beans::PropertyValue >& seqArguments ) override; + virtual void SAL_CALL storeToURL( const OUString& sURL, + const css::uno::Sequence< css::beans::PropertyValue >& seqArguments ) override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/dlged.cxx b/basctl/source/dlged/dlged.cxx new file mode 100644 index 0000000000..2eb099718b --- /dev/null +++ b/basctl/source/dlged/dlged.cxx @@ -0,0 +1,1236 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <dlged.hxx> +#include <dlgedclip.hxx> +#include <dlgeddef.hxx> +#include <dlgedfac.hxx> +#include <dlgedfunc.hxx> +#include <dlgedmod.hxx> +#include <dlgedobj.hxx> +#include <dlgedpage.hxx> +#include <dlgedview.hxx> +#include <localizationmgr.hxx> +#include <baside3.hxx> + +#include <com/sun/star/awt/Toolkit.hpp> +#include <com/sun/star/awt/UnoControlDialog.hpp> +#include <com/sun/star/awt/XVclWindowPeer.hpp> +#include <com/sun/star/resource/StringResource.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/util/NumberFormatsSupplier.hpp> +#include <comphelper/types.hxx> +#include <comphelper/processfactory.hxx> +#include <tools/debug.hxx> +#include <svl/itempool.hxx> +#include <svx/sdrpaintwindow.hxx> +#include <svx/svdpagv.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/print.hxx> +#include <vcl/svapp.hxx> +#include <xmlscript/xml_helper.hxx> +#include <xmlscript/xmldlg_imexp.hxx> +#include <osl/diagnose.h> + +namespace basctl +{ + +using namespace comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::io; + +constexpr OUString aResourceResolverPropName = u"ResourceResolver"_ustr; +constexpr OUString aDecorationPropName = u"Decoration"_ustr; + + +// DlgEdHint + + +DlgEdHint::DlgEdHint(Kind eHint) + : eKind(eHint) + , pDlgEdObj(nullptr) +{ +} + +DlgEdHint::DlgEdHint(Kind eHint, DlgEdObj* pObj) + : eKind(eHint) + , pDlgEdObj(pObj) +{ +} + +DlgEdHint::~DlgEdHint() +{ +} + + +// DlgEditor + + +void DlgEditor::ShowDialog() +{ + uno::Reference< uno::XComponentContext > xContext = getProcessComponentContext(); + + // create a dialog + uno::Reference< awt::XUnoControlDialog > xDlg = awt::UnoControlDialog::create( xContext ); + + // clone the dialog model + uno::Reference< util::XCloneable > xC( m_xUnoControlDialogModel, uno::UNO_QUERY ); + uno::Reference< util::XCloneable > xNew = xC->createClone(); + uno::Reference< awt::XControlModel > xDlgMod( xNew, uno::UNO_QUERY ); + + uno::Reference< beans::XPropertySet > xSrcDlgModPropSet( m_xUnoControlDialogModel, uno::UNO_QUERY ); + uno::Reference< beans::XPropertySet > xNewDlgModPropSet( xDlgMod, uno::UNO_QUERY ); + if( xNewDlgModPropSet.is() ) + { + if( xSrcDlgModPropSet.is() ) + { + try + { + Any aResourceResolver = xSrcDlgModPropSet->getPropertyValue( aResourceResolverPropName ); + xNewDlgModPropSet->setPropertyValue( aResourceResolverPropName, aResourceResolver ); + } + catch(const UnknownPropertyException& ) + { + OSL_FAIL( "DlgEditor::ShowDialog(): No ResourceResolver property" ); + } + } + + // Disable decoration + try + { + bool bDecoration = true; + + Any aDecorationAny = xSrcDlgModPropSet->getPropertyValue( aDecorationPropName ); + aDecorationAny >>= bDecoration; + if( !bDecoration ) + { + xNewDlgModPropSet->setPropertyValue( aDecorationPropName, Any( true ) ); + xNewDlgModPropSet->setPropertyValue( "Title", Any( OUString() ) ); + } + } + catch(const UnknownPropertyException& ) + {} + } + + // set the model + xDlg->setModel( xDlgMod ); + + // create a peer + uno::Reference< awt::XToolkit> xToolkit = awt::Toolkit::create( xContext ); + xDlg->createPeer( xToolkit, rWindow.GetComponentInterface() ); + + xDlg->execute(); + + // need to cast because of multiple inheritance + Reference<awt::XControl>(xDlg)->dispose(); +} + + +bool DlgEditor::UnmarkDialog() +{ + SdrObject* pDlgObj = pDlgEdModel->GetPage(0)->GetObj(0); + SdrPageView* pPgView = pDlgEdView->GetSdrPageView(); + + bool bWasMarked = pDlgEdView->IsObjMarked( pDlgObj ); + + if( bWasMarked ) + pDlgEdView->MarkObj( pDlgObj, pPgView, true ); + + return bWasMarked; +} + + +bool DlgEditor::RemarkDialog() +{ + SdrObject* pDlgObj = pDlgEdModel->GetPage(0)->GetObj(0); + SdrPageView* pPgView = pDlgEdView->GetSdrPageView(); + + bool bWasMarked = pDlgEdView->IsObjMarked( pDlgObj ); + + if( !bWasMarked ) + pDlgEdView->MarkObj( pDlgObj, pPgView ); + + return bWasMarked; +} + + +DlgEditor::DlgEditor ( + vcl::Window& rWindow_, DialogWindowLayout& rLayout_, + css::uno::Reference<css::frame::XModel> const& xModel, + css::uno::Reference<css::container::XNameContainer> const & xDialogModel +) + :pHScroll(nullptr) + ,pVScroll(nullptr) + ,pDlgEdModel(new DlgEdModel()) + ,pDlgEdPage(new DlgEdPage(*pDlgEdModel)) + // set clipboard data flavors + ,m_ClipboardDataFlavors{ { /* MimeType */ "application/vnd.sun.xml.dialog", + /* HumanPresentableName */ "Dialog 6.0", + /* DataType */ cppu::UnoType<Sequence< sal_Int8 >>::get() } } + ,m_ClipboardDataFlavorsResource{ m_ClipboardDataFlavors[0], + { /* MimeType */ "application/vnd.sun.xml.dialogwithresource", + /* HumanPresentableName */ "Dialog 8.0", + /* DataType */ cppu::UnoType<Sequence< sal_Int8 >>::get() } } + ,pObjFac(new DlgEdFactory(xModel)) + ,rWindow(rWindow_) + ,pFunc(new DlgEdFuncSelect(*this)) + ,rLayout(rLayout_) + ,eMode( DlgEditor::SELECT ) + ,eActObj( SdrObjKind::BasicDialogPushButton ) + ,bFirstDraw(false) + ,bCreateOK(true) + ,bDialogModelChanged(false) + ,aMarkIdle("basctl DlgEditor Mark") + ,mnPaintGuard(0) + ,m_xDocument( xModel ) +{ + pDlgEdModel->GetItemPool().FreezeIdRanges(); + pDlgEdView.reset(new DlgEdView(*pDlgEdModel, *rWindow_.GetOutDev(), *this)); + pDlgEdModel->SetScaleUnit( MapUnit::Map100thMM ); + + SdrLayerAdmin& rAdmin = pDlgEdModel->GetLayerAdmin(); + rAdmin.NewLayer( rAdmin.GetControlLayerName() ); + rAdmin.NewLayer( "HiddenLayer" ); + + pDlgEdModel->InsertPage(pDlgEdPage); + + aMarkIdle.SetInvokeHandler( LINK( this, DlgEditor, MarkTimeout ) ); + + rWindow.SetMapMode( MapMode( MapUnit::Map100thMM ) ); + pDlgEdPage->SetSize( rWindow.PixelToLogic( Size(DLGED_PAGE_WIDTH_MIN, DLGED_PAGE_HEIGHT_MIN) ) ); + + pDlgEdView->ShowSdrPage(pDlgEdView->GetModel().GetPage(0)); + pDlgEdView->SetLayerVisible( "HiddenLayer", false ); + pDlgEdView->SetMoveSnapOnlyTopLeft(true); + pDlgEdView->SetWorkArea( tools::Rectangle( Point( 0, 0 ), pDlgEdPage->GetSize() ) ); + + Size aGridSize( 100, 100 ); // 100TH_MM + pDlgEdView->SetGridCoarse( aGridSize ); + pDlgEdView->SetSnapGridWidth(Fraction(aGridSize.Width(), 1), Fraction(aGridSize.Height(), 1)); + pDlgEdView->SetGridSnap( true ); + pDlgEdView->SetGridVisible( false ); + pDlgEdView->SetDragStripes(false); + + pDlgEdView->SetDesignMode(); + + ::comphelper::disposeComponent( m_xControlContainer ); + + SetDialog(xDialogModel); +} + +DlgEditor::~DlgEditor() +{ + aMarkIdle.Stop(); + + ::comphelper::disposeComponent( m_xControlContainer ); +} + +Reference< awt::XControlContainer > const & DlgEditor::GetWindowControlContainer() +{ + if (!m_xControlContainer.is()) + m_xControlContainer = VCLUnoHelper::CreateControlContainer(&rWindow); + return m_xControlContainer; +} + +void DlgEditor::SetScrollBars(ScrollAdaptor* pHS, ScrollAdaptor* pVS) +{ + pHScroll = pHS; + pVScroll = pVS; + + InitScrollBars(); +} + +void DlgEditor::InitScrollBars() +{ + DBG_ASSERT( pHScroll, "DlgEditor::InitScrollBars: no horizontal scroll bar!" ); + DBG_ASSERT( pVScroll, "DlgEditor::InitScrollBars: no vertical scroll bar!" ); + if ( !pHScroll || !pVScroll ) + return; + + Size aOutSize = rWindow.GetOutDev()->GetOutputSize(); + Size aPgSize = pDlgEdPage->GetSize(); + + pHScroll->SetRange( Range( 0, aPgSize.Width() )); + pVScroll->SetRange( Range( 0, aPgSize.Height() )); + pHScroll->SetVisibleSize( aOutSize.Width() ); + pVScroll->SetVisibleSize( aOutSize.Height() ); + + pHScroll->SetLineSize( aOutSize.Width() / 10 ); + pVScroll->SetLineSize( aOutSize.Height() / 10 ); + pHScroll->SetPageSize( aOutSize.Width() / 2 ); + pVScroll->SetPageSize( aOutSize.Height() / 2 ); + + DoScroll(); +} + + +void DlgEditor::DoScroll() +{ + if( !pHScroll || !pVScroll ) + return; + + MapMode aMap = rWindow.GetMapMode(); + Point aOrg = aMap.GetOrigin(); + + Size aScrollPos( pHScroll->GetThumbPos(), pVScroll->GetThumbPos() ); + aScrollPos = rWindow.LogicToPixel( aScrollPos ); + aScrollPos = rWindow.PixelToLogic( aScrollPos ); + + tools::Long nX = aScrollPos.Width() + aOrg.X(); + tools::Long nY = aScrollPos.Height() + aOrg.Y(); + + if( !nX && !nY ) + return; + + rWindow.PaintImmediately(); + + // #i31562# + // When scrolling, someone was rescuing the Wallpaper and forced the window scroll to + // be done without background refresh. I do not know why, but that causes the repaint + // problems. Taking that out. + // Wallpaper aOldBackground = rWindow.GetBackground(); + // rWindow.SetBackground(); + + // #i74769# children should be scrolled + rWindow.Scroll( -nX, -nY, ScrollFlags::Children); + aMap.SetOrigin( Point( -aScrollPos.Width(), -aScrollPos.Height() ) ); + rWindow.SetMapMode( aMap ); + rWindow.PaintImmediately(); + + DlgEdHint aHint( DlgEdHint::WINDOWSCROLLED ); + Broadcast( aHint ); +} + + +void DlgEditor::UpdateScrollBars() +{ + MapMode aMap = rWindow.GetMapMode(); + Point aOrg = aMap.GetOrigin(); + + if ( pHScroll ) + pHScroll->SetThumbPos( -aOrg.X() ); + + if ( pVScroll ) + pVScroll->SetThumbPos( -aOrg.Y() ); +} + + +void DlgEditor::SetDialog( const uno::Reference< container::XNameContainer >& xUnoControlDialogModel ) +{ + // set dialog model + m_xUnoControlDialogModel = xUnoControlDialogModel; + + // create dialog form + pDlgEdForm = new DlgEdForm(*pDlgEdModel, *this); + uno::Reference< awt::XControlModel > xDlgMod( m_xUnoControlDialogModel , uno::UNO_QUERY ); + pDlgEdForm->SetUnoControlModel(xDlgMod); + static_cast<DlgEdPage*>(pDlgEdModel->GetPage(0))->SetDlgEdForm( pDlgEdForm.get() ); + pDlgEdModel->GetPage(0)->InsertObject( pDlgEdForm.get() ); + AdjustPageSize(); + pDlgEdForm->SetRectFromProps(); + pDlgEdForm->UpdateTabIndices(); // for backward compatibility + pDlgEdForm->StartListening(); + + // create controls + if ( m_xUnoControlDialogModel.is() ) + { + // get sequence of control names + Sequence< OUString > aNames = m_xUnoControlDialogModel->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + sal_Int32 nCtrls = aNames.getLength(); + + // create a map of tab indices and control names, sorted by tab index + IndexToNameMap aIndexToNameMap; + for ( sal_Int32 i = 0; i < nCtrls; ++i ) + { + // get name + OUString aName( pNames[i] ); + + // get tab index + sal_Int16 nTabIndex = -1; + Any aCtrl = m_xUnoControlDialogModel->getByName( aName ); + Reference< css::beans::XPropertySet > xPSet; + aCtrl >>= xPSet; + if ( xPSet.is() ) + xPSet->getPropertyValue( DLGED_PROP_TABINDEX ) >>= nTabIndex; + + // insert into map + aIndexToNameMap.emplace( nTabIndex, aName ); + } + + // create controls and insert them into drawing page + for (auto const& indexToName : aIndexToNameMap) + { + Any aCtrl = m_xUnoControlDialogModel->getByName( indexToName.second ); + Reference< css::awt::XControlModel > xCtrlModel; + aCtrl >>= xCtrlModel; + rtl::Reference<DlgEdObj> pCtrlObj = new DlgEdObj(*pDlgEdModel); + pCtrlObj->SetUnoControlModel( xCtrlModel ); + pCtrlObj->SetDlgEdForm( pDlgEdForm.get() ); + pDlgEdForm->AddChild( pCtrlObj.get() ); + pDlgEdModel->GetPage(0)->InsertObject( pCtrlObj.get() ); + pCtrlObj->SetRectFromProps(); + pCtrlObj->UpdateStep(); + pCtrlObj->StartListening(); + } + } + + bFirstDraw = true; + + pDlgEdModel->SetChanged(false); +} + +void DlgEditor::ResetDialog () +{ + DlgEdForm* pOldDlgEdForm = pDlgEdForm.get(); + DlgEdPage* pPage = static_cast<DlgEdPage*>(pDlgEdModel->GetPage(0)); + SdrPageView* pPgView = pDlgEdView->GetSdrPageView(); + bool bWasMarked = pDlgEdView->IsObjMarked( pOldDlgEdForm ); + pDlgEdView->UnmarkAll(); + + // clear SdrObjects with broadcasting + pPage->ClearSdrObjList(); + + pPage->SetDlgEdForm( nullptr ); + SetDialog( m_xUnoControlDialogModel ); + if( bWasMarked ) + pDlgEdView->MarkObj( pDlgEdForm.get(), pPgView ); +} + + +Reference< util::XNumberFormatsSupplier > const & DlgEditor::GetNumberFormatsSupplier() +{ + if ( !m_xSupplier.is() ) + { + Reference< uno::XComponentContext > xContext = ::comphelper::getProcessComponentContext(); + Reference< util::XNumberFormatsSupplier > xSupplier( util::NumberFormatsSupplier::createWithDefaultLocale(xContext) ); + + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if ( !m_xSupplier.is() ) + { + m_xSupplier = xSupplier; + } + } + return m_xSupplier; +} + + +void DlgEditor::MouseButtonDown( const MouseEvent& rMEvt ) +{ + rWindow.GrabFocus(); + pFunc->MouseButtonDown( rMEvt ); +} + + +void DlgEditor::MouseButtonUp( const MouseEvent& rMEvt ) +{ + bool bRet = pFunc->MouseButtonUp( rMEvt ); + + if( eMode == DlgEditor::INSERT ) + bCreateOK = bRet; +} + + +void DlgEditor::MouseMove( const MouseEvent& rMEvt ) +{ + pFunc->MouseMove( rMEvt ); +} + + +bool DlgEditor::KeyInput( const KeyEvent& rKEvt ) +{ + return pFunc->KeyInput( rKEvt ); +} + + +void DlgEditor::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) +{ + aPaintRect = rRect; + mnPaintGuard++; + + if (bFirstDraw && rWindow.IsVisible() && (rRenderContext.GetOutputSize() != Size())) + { + bFirstDraw = false; + + // get property set + css::uno::Reference<css::beans::XPropertySet> xPSet(pDlgEdForm->GetUnoControlModel(), css::uno::UNO_QUERY); + + if (xPSet.is()) + { + // get dialog size from properties + sal_Int32 nWidth = 0, nHeight = 0; + xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidth; + xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeight; + + if (nWidth == 0 && nHeight == 0) + { + Size aSize = rRenderContext.PixelToLogic( Size( 400, 300 ) ); + + // align with grid + Size aGridSize_(tools::Long(pDlgEdView->GetSnapGridWidthX()), tools::Long(pDlgEdView->GetSnapGridWidthY())); + aSize.AdjustWidth( -(aSize.Width() % aGridSize_.Width()) ); + aSize.AdjustHeight( -(aSize.Height() % aGridSize_.Height()) ); + + Point aPos; + Size aOutSize = rRenderContext.GetOutputSize(); + aPos.setX( (aOutSize.Width()>>1) - (aSize.Width()>>1) ); + aPos.setY( (aOutSize.Height()>>1) - (aSize.Height()>>1) ); + + // align with grid + aPos.AdjustX( -(aPos.X() % aGridSize_.Width()) ); + aPos.AdjustY( -(aPos.Y() % aGridSize_.Height()) ); + + // don't put in the corner + Point aMinPos = rRenderContext.PixelToLogic( Point( 30, 20 ) ); + if( (aPos.X() < aMinPos.X()) || (aPos.Y() < aMinPos.Y()) ) + { + aPos = aMinPos; + aPos.AdjustX( -(aPos.X() % aGridSize_.Width()) ); + aPos.AdjustY( -(aPos.Y() % aGridSize_.Height()) ); + } + + // set dialog position and size + pDlgEdForm->SetSnapRect( tools::Rectangle( aPos, aSize ) ); + pDlgEdForm->EndListening(false); + pDlgEdForm->SetPropsFromRect(); + pDlgEdForm->GetDlgEditor().SetDialogModelChanged(); + pDlgEdForm->StartListening(); + + // set position and size of controls + for (const rtl::Reference<SdrObject>& pObj : *pDlgEdPage) + { + if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get())) + { + if (!dynamic_cast<DlgEdForm*>(pDlgEdObj)) + { + pDlgEdObj->SetRectFromProps(); + } + } + } + } + } + } + + // repaint, get PageView and prepare Region + SdrPageView* pPgView = pDlgEdView->GetSdrPageView(); + const vcl::Region aPaintRectRegion(aPaintRect); + + // #i74769# + SdrPaintWindow* pTargetPaintWindow = nullptr; + + // mark repaint start + if (pPgView) + { + pTargetPaintWindow = pPgView->GetView().BeginDrawLayers(&rRenderContext, aPaintRectRegion); + OSL_ENSURE(pTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)"); + } + + // draw background self using wallpaper + // #i79128# ...and use correct OutDev for that + if (pTargetPaintWindow) + { + Color maBackColor = rRenderContext.GetSettings().GetStyleSettings().GetLightColor(); + OutputDevice& rTargetOutDev = pTargetPaintWindow->GetTargetOutputDevice(); + rTargetOutDev.DrawWallpaper(aPaintRect, Wallpaper(maBackColor)); + } + + // do paint (unbuffered) and mark repaint end + if (pPgView) + { + // paint of control layer is done in EndDrawLayers anyway... + pPgView->GetView().EndDrawLayers(*pTargetPaintWindow, true); + } + + mnPaintGuard--; +} + + +IMPL_LINK_NOARG(DlgEditor, MarkTimeout, Timer *, void) +{ + rLayout.UpdatePropertyBrowser(); +} + + +void DlgEditor::SetMode (Mode eNewMode ) +{ + if ( eNewMode != eMode ) + { + if ( eNewMode == INSERT ) + pFunc.reset(new DlgEdFuncInsert(*this)); + else + pFunc.reset(new DlgEdFuncSelect(*this)); + + if ( eNewMode == READONLY ) + pDlgEdModel->SetReadOnly( true ); + else + pDlgEdModel->SetReadOnly( false ); + } + + if ( eNewMode == TEST ) + ShowDialog(); + + eMode = eNewMode; +} + + +void DlgEditor::SetInsertObj(SdrObjKind eObj) +{ + eActObj = eObj; + + pDlgEdView->SetCurrentObj( eActObj, SdrInventor::BasicDialog ); +} + +void DlgEditor::CreateDefaultObject() +{ + // create object by factory + rtl::Reference<SdrObject> pObj = SdrObjFactory::MakeNewObject( + *pDlgEdModel, + pDlgEdView->GetCurrentObjInventor(), + pDlgEdView->GetCurrentObjIdentifier()); + + DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get()); + if (!pDlgEdObj) + return; + + // set position and size + Size aSize = rWindow.PixelToLogic( Size( 96, 24 ) ); + Point aPoint = pDlgEdForm->GetSnapRect().Center(); + aPoint.AdjustX( -(aSize.Width() / 2) ); + aPoint.AdjustY( -(aSize.Height() / 2) ); + pDlgEdObj->SetSnapRect( tools::Rectangle( aPoint, aSize ) ); + + // set default property values + pDlgEdObj->SetDefaults(); + + // insert object into drawing page + SdrPageView* pPageView = pDlgEdView->GetSdrPageView(); + if (pDlgEdView->InsertObjectAtView(pDlgEdObj, *pPageView)) + { + // start listening + pDlgEdObj->StartListening(); + } +} + +void DlgEditor::Cut() +{ + Copy(); + Delete(); +} + +static void implCopyStreamToByteSequence( const Reference< XInputStream >& xStream, + Sequence< sal_Int8 >& bytes ) +{ + xStream->readBytes( bytes, xStream->available() ); + for (;;) + { + Sequence< sal_Int8 > readBytes; + sal_Int32 nRead = xStream->readBytes( readBytes, 1024 ); + if (! nRead) + break; + + sal_Int32 nPos = bytes.getLength(); + bytes.realloc( nPos + nRead ); + memcpy( bytes.getArray() + nPos, readBytes.getConstArray(), static_cast<sal_uInt32>(nRead) ); + } +} + +void DlgEditor::Copy() +{ + if( !pDlgEdView->AreObjectsMarked() ) + return; + + // stop all drawing actions + pDlgEdView->BrkAction(); + + // create an empty clipboard dialog model + Reference< util::XCloneable > xClone( m_xUnoControlDialogModel, UNO_QUERY ); + Reference< util::XCloneable > xNewClone = xClone->createClone(); + Reference< container::XNameContainer > xClipDialogModel( xNewClone, UNO_QUERY ); + + if ( xClipDialogModel.is() ) + { + Sequence< OUString > aNames = xClipDialogModel->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + sal_uInt32 nCtrls = aNames.getLength(); + + for ( sal_uInt32 n = 0; n < nCtrls; n++ ) + { + xClipDialogModel->removeByName( pNames[n] ); + } + } + + // insert control models of marked objects into clipboard dialog model + const size_t nMark = pDlgEdView->GetMarkedObjectList().GetMarkCount(); + for( size_t i = 0; i < nMark; ++i ) + { + SdrObject* pObj = pDlgEdView->GetMarkedObjectList().GetMark(i)->GetMarkedSdrObj(); + DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj); + + if (pDlgEdObj && !dynamic_cast<DlgEdForm*>(pDlgEdObj)) + { + OUString aName; + Reference< beans::XPropertySet > xMarkPSet(pDlgEdObj->GetUnoControlModel(), uno::UNO_QUERY); + if (xMarkPSet.is()) + { + xMarkPSet->getPropertyValue( DLGED_PROP_NAME ) >>= aName; + } + + if ( m_xUnoControlDialogModel.is() && m_xUnoControlDialogModel->hasByName(aName) ) + { + Any aCtrl = m_xUnoControlDialogModel->getByName( aName ); + + // clone control model + Reference< util::XCloneable > xCtrl; + aCtrl >>= xCtrl; + Reference< util::XCloneable > xNewCtrl = xCtrl->createClone(); + Any aNewCtrl; + aNewCtrl <<= xNewCtrl; + + if (xClipDialogModel.is()) + xClipDialogModel->insertByName( aName , aNewCtrl ); + } + } + } + + // export clipboard dialog model to xml + Reference< XComponentContext > xContext( + comphelper::getProcessComponentContext() ); + Reference< XInputStreamProvider > xISP = ::xmlscript::exportDialogModel( xClipDialogModel, xContext, m_xDocument ); + Reference< XInputStream > xStream( xISP->createInputStream() ); + Sequence< sal_Int8 > DialogModelBytes; + implCopyStreamToByteSequence( xStream, DialogModelBytes ); + xStream->closeInput(); + + // set clipboard content + Reference< datatransfer::clipboard::XClipboard > xClipboard = GetWindow().GetClipboard(); + if ( !xClipboard.is() ) + return; + + // With resource? + uno::Reference< beans::XPropertySet > xDialogModelPropSet( m_xUnoControlDialogModel, uno::UNO_QUERY ); + uno::Reference< resource::XStringResourcePersistence > xStringResourcePersistence; + if( xDialogModelPropSet.is() ) + { + try + { + Any aResourceResolver = xDialogModelPropSet->getPropertyValue( aResourceResolverPropName ); + aResourceResolver >>= xStringResourcePersistence; + } + catch(const UnknownPropertyException& ) + {} + } + + rtl::Reference<DlgEdTransferableImpl> pTrans; + if( xStringResourcePersistence.is() ) + { + // With resource, support old and new format + + // Export xClipDialogModel another time with ids replaced by current language string + LocalizationMgr::resetResourceForDialog( xClipDialogModel, xStringResourcePersistence ); + Reference< XInputStreamProvider > xISP2 = ::xmlscript::exportDialogModel( xClipDialogModel, xContext, m_xDocument ); + Reference< XInputStream > xStream2( xISP2->createInputStream() ); + Sequence< sal_Int8 > NoResourceDialogModelBytes; + implCopyStreamToByteSequence( xStream2, NoResourceDialogModelBytes ); + xStream2->closeInput(); + + // Old format contains dialog with replaced ids + Any aNoResourceDialogModelBytesAny; + aNoResourceDialogModelBytesAny <<= NoResourceDialogModelBytes; + + // New format contains dialog and resource + Sequence< sal_Int8 > aResData = xStringResourcePersistence->exportBinary(); + + // Create sequence for combined dialog and resource + sal_Int32 nDialogDataLen = DialogModelBytes.getLength(); + sal_Int32 nResDataLen = aResData.getLength(); + + // Combined data = 4 Bytes 32Bit Offset to begin of resource data, lowest byte first + // + nDialogDataLen bytes dialog data + nResDataLen resource data + sal_Int32 nTotalLen = 4 + nDialogDataLen + nResDataLen; + sal_Int32 nResOffset = 4 + nDialogDataLen; + Sequence< sal_Int8 > aCombinedData( nTotalLen ); + sal_Int8* pCombinedData = aCombinedData.getArray(); + + // Write offset + sal_Int32 n = nResOffset; + for( sal_Int16 i = 0 ; i < 4 ; i++ ) + { + pCombinedData[i] = sal_Int8( n & 0xff ); + n >>= 8; + } + memcpy( pCombinedData + 4, DialogModelBytes.getConstArray(), nDialogDataLen ); + memcpy( pCombinedData + nResOffset, aResData.getConstArray(), nResDataLen ); + + Sequence< Any > aSeqData + { + aNoResourceDialogModelBytesAny, + Any(aCombinedData) + }; + + pTrans = new DlgEdTransferableImpl( m_ClipboardDataFlavorsResource, aSeqData ); + } + else + { + // No resource, support only old format + pTrans = new DlgEdTransferableImpl( m_ClipboardDataFlavors , { Any(DialogModelBytes) } ); + } + SolarMutexReleaser aReleaser; + xClipboard->setContents( pTrans , pTrans ); +} + + +void DlgEditor::Paste() +{ + // stop all drawing actions + pDlgEdView->BrkAction(); + + // unmark all objects + pDlgEdView->UnmarkAll(); + + // get clipboard + Reference< datatransfer::clipboard::XClipboard > xClipboard = GetWindow().GetClipboard(); + if ( !xClipboard.is() ) + return; + + Reference< datatransfer::XTransferable > xTransf; + { + SolarMutexReleaser aReleaser; + // get clipboard content + xTransf = xClipboard->getContents(); + } + if ( !xTransf.is() ) + return; + + // Is target dialog (library) localized? + uno::Reference< beans::XPropertySet > xDialogModelPropSet( m_xUnoControlDialogModel, uno::UNO_QUERY ); + uno::Reference< resource::XStringResourceManager > xStringResourceManager; + if( xDialogModelPropSet.is() ) + { + try + { + Any aResourceResolver = xDialogModelPropSet->getPropertyValue( aResourceResolverPropName ); + aResourceResolver >>= xStringResourceManager; + } + catch(const UnknownPropertyException& ) + {} + } + bool bLocalized = false; + if( xStringResourceManager.is() ) + bLocalized = xStringResourceManager->getLocales().hasElements(); + + if ( !xTransf->isDataFlavorSupported( m_ClipboardDataFlavors[0] ) ) + return; + + // create clipboard dialog model from xml + Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); + Reference< container::XNameContainer > xClipDialogModel( xContext->getServiceManager()->createInstanceWithContext( + "com.sun.star.awt.UnoControlDialogModel", xContext ), uno::UNO_QUERY ); + + bool bSourceIsLocalized = false; + Sequence< sal_Int8 > DialogModelBytes; + Sequence< sal_Int8 > aResData; + if( bLocalized && xTransf->isDataFlavorSupported( m_ClipboardDataFlavorsResource[1] ) ) + { + bSourceIsLocalized = true; + + Any aCombinedDataAny = xTransf->getTransferData( m_ClipboardDataFlavorsResource[1] ); + Sequence< sal_Int8 > aCombinedData; + aCombinedDataAny >>= aCombinedData; + const sal_Int8* pCombinedData = aCombinedData.getConstArray(); + + sal_Int32 nTotalLen = aCombinedData.getLength(); + + // Reading offset + sal_Int32 nResOffset = 0; + sal_Int32 nFactor = 1; + for( sal_Int16 i = 0; i < 4; i++ ) + { + nResOffset += nFactor * sal_uInt8( pCombinedData[i] ); + nFactor *= 256; + } + + sal_Int32 nResDataLen = nTotalLen - nResOffset; + sal_Int32 nDialogDataLen = nTotalLen - nResDataLen - 4; + + DialogModelBytes.realloc( nDialogDataLen ); + memcpy( DialogModelBytes.getArray(), pCombinedData + 4, nDialogDataLen ); + + aResData.realloc( nResDataLen ); + memcpy( aResData.getArray(), pCombinedData + nResOffset, nResDataLen ); + } + else + { + Any aAny = xTransf->getTransferData( m_ClipboardDataFlavors[0] ); + aAny >>= DialogModelBytes; + } + + if ( xClipDialogModel.is() ) + { + Reference<XInputStream> xIn = ::xmlscript::createInputStream( DialogModelBytes.getConstArray(), DialogModelBytes.getLength() ); + ::xmlscript::importDialogModel( xIn , xClipDialogModel, xContext, m_xDocument ); + } + + // get control models from clipboard dialog model + if ( !xClipDialogModel.is() ) + return; + + Sequence< OUString > aNames = xClipDialogModel->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + sal_uInt32 nCtrls = aNames.getLength(); + + Reference< resource::XStringResourcePersistence > xStringResourcePersistence; + if( nCtrls > 0 && bSourceIsLocalized ) + { + xStringResourcePersistence = css::resource::StringResource::create( getProcessComponentContext() ); + xStringResourcePersistence->importBinary( aResData ); + } + for( sal_uInt32 n = 0; n < nCtrls; n++ ) + { + Any aA = xClipDialogModel->getByName( pNames[n] ); + Reference< css::awt::XControlModel > xCM; + aA >>= xCM; + + // clone the control model + Reference< util::XCloneable > xClone( xCM, uno::UNO_QUERY ); + Reference< awt::XControlModel > xCtrlModel( xClone->createClone(), uno::UNO_QUERY ); + + rtl::Reference<DlgEdObj> pCtrlObj = new DlgEdObj(*pDlgEdModel); + pCtrlObj->SetDlgEdForm(pDlgEdForm.get()); // set parent form + pDlgEdForm->AddChild(pCtrlObj.get()); // add child to parent form + pCtrlObj->SetUnoControlModel( xCtrlModel ); // set control model + + // set new name + OUString aOUniqueName( pCtrlObj->GetUniqueName() ); + Reference< beans::XPropertySet > xPSet( xCtrlModel , UNO_QUERY ); + xPSet->setPropertyValue( DLGED_PROP_NAME, Any(aOUniqueName) ); + + // set tabindex + Sequence< OUString > aNames_ = m_xUnoControlDialogModel->getElementNames(); + xPSet->setPropertyValue( DLGED_PROP_TABINDEX, Any(static_cast<sal_Int16>(aNames_.getLength())) ); + + if( bLocalized ) + { + Any aControlAny; + aControlAny <<= xCtrlModel; + if( bSourceIsLocalized && xStringResourcePersistence.is() ) + { + LocalizationMgr::copyResourcesForPastedEditorObject( this, + aControlAny, aOUniqueName, xStringResourcePersistence ); + } + else + { + LocalizationMgr::setControlResourceIDsForNewEditorObject + ( this, aControlAny, aOUniqueName ); + } + } + + // insert control model in editor dialog model + Any aCtrlModel; + aCtrlModel <<= xCtrlModel; + m_xUnoControlDialogModel->insertByName( aOUniqueName , aCtrlModel ); + + // insert object into drawing page + pDlgEdModel->GetPage(0)->InsertObject( pCtrlObj.get() ); + pCtrlObj->SetRectFromProps(); + pCtrlObj->UpdateStep(); + pDlgEdForm->UpdateTabOrderAndGroups(); + pCtrlObj->StartListening(); // start listening + + // mark object + SdrPageView* pPgView = pDlgEdView->GetSdrPageView(); + pDlgEdView->MarkObj( pCtrlObj.get(), pPgView, false, true); + } + + // center marked objects in dialog editor form + Point aMarkCenter = pDlgEdView->GetMarkedObjRect().Center(); + Point aFormCenter = pDlgEdForm->GetSnapRect().Center(); + Point aPoint = aFormCenter - aMarkCenter; + Size aSize( aPoint.X() , aPoint.Y() ); + pDlgEdView->MoveMarkedObj( aSize ); // update of control model properties (position + size) in NbcMove + pDlgEdView->MarkListHasChanged(); + + // dialog model changed + SetDialogModelChanged(); +} + + +void DlgEditor::Delete() +{ + if( !pDlgEdView->AreObjectsMarked() ) + return; + + // remove control models of marked objects from dialog model + const size_t nMark = pDlgEdView->GetMarkedObjectList().GetMarkCount(); + + for( size_t i = 0; i < nMark; ++i ) + { + SdrObject* pObj = pDlgEdView->GetMarkedObjectList().GetMark(i)->GetMarkedSdrObj(); + DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj); + + if ( pDlgEdObj && !dynamic_cast<DlgEdForm*>(pDlgEdObj) ) + { + // get name from property + OUString aName; + uno::Reference< beans::XPropertySet > xPSet(pDlgEdObj->GetUnoControlModel(), uno::UNO_QUERY); + if (xPSet.is()) + { + xPSet->getPropertyValue( DLGED_PROP_NAME ) >>= aName; + } + + // remove control from dialog model + Reference< css::container::XNameAccess > xNameAcc(pDlgEdObj->GetDlgEdForm()->GetUnoControlModel(), UNO_QUERY ); + if ( xNameAcc.is() && xNameAcc->hasByName(aName) ) + { + Reference< css::container::XNameContainer > xCont(xNameAcc, UNO_QUERY ); + if ( xCont.is() ) + { + if( xCont->hasByName( aName ) ) + { + Any aAny = xCont->getByName( aName ); + LocalizationMgr::deleteControlResourceIDsForDeletedEditorObject( this, aAny, aName ); + } + xCont->removeByName( aName ); + } + } + + // remove child from parent form + pDlgEdForm->RemoveChild( pDlgEdObj ); + } + } + + // update tab indices + pDlgEdForm->UpdateTabIndices(); + + pDlgEdView->BrkAction(); + + bool const bDlgMarked = UnmarkDialog(); + pDlgEdView->DeleteMarked(); + if( bDlgMarked ) + RemarkDialog(); +} + + +bool DlgEditor::IsPasteAllowed() +{ + // get clipboard + Reference< datatransfer::clipboard::XClipboard > xClipboard = GetWindow().GetClipboard(); + if ( xClipboard.is() ) + { + Reference< datatransfer::XTransferable > xTransf; + { + SolarMutexReleaser aReleaser; + // get clipboard content + xTransf = xClipboard->getContents(); + } + if (xTransf.is()) + return xTransf->isDataFlavorSupported(m_ClipboardDataFlavors[0]); + } + return false; +} + + +void DlgEditor::ShowProperties() +{ + rLayout.ShowPropertyBrowser(); +} + + +void DlgEditor::UpdatePropertyBrowserDelayed() +{ + aMarkIdle.Start(); +} + + +bool DlgEditor::IsModified() const +{ + return pDlgEdModel->IsChanged() || bDialogModelChanged; +} + + +void DlgEditor::ClearModifyFlag() +{ + pDlgEdModel->SetChanged(false); + bDialogModelChanged = false; +} + + +namespace Print +{ + tools::Long const nLeftMargin = 1700; + tools::Long const nRightMargin = 900; + tools::Long const nTopMargin = 2000; + tools::Long const nBottomMargin = 1000; + tools::Long const nBorder = 300; +} + +static void lcl_PrintHeader( Printer* pPrinter, const OUString& rTitle ) // not working yet +{ + + pPrinter->Push(); + + Size const aSz = pPrinter->GetOutputSize(); + + pPrinter->SetLineColor( COL_BLACK ); + pPrinter->SetFillColor(); + + vcl::Font aFont( pPrinter->GetFont() ); + aFont.SetWeight( WEIGHT_BOLD ); + aFont.SetAlignment( ALIGN_BOTTOM ); + pPrinter->SetFont( aFont ); + + tools::Long const nFontHeight = pPrinter->GetTextHeight(); + + // 1st border => line, 2+3 border = free space + tools::Long const nYTop = Print::nTopMargin - 3*Print::nBorder - nFontHeight; + + tools::Long const nXLeft = Print::nLeftMargin - Print::nBorder; + tools::Long const nXRight = aSz.Width() - Print::nRightMargin + Print::nBorder; + + pPrinter->DrawRect(tools::Rectangle( + Point(nXLeft, nYTop), + Size(nXRight - nXLeft, aSz.Height() - nYTop - Print::nBottomMargin + Print::nBorder) + )); + + tools::Long nY = Print::nTopMargin - 2*Print::nBorder; + Point aPos(Print::nLeftMargin, nY); + pPrinter->DrawText( aPos, rTitle ); + + nY = Print::nTopMargin - Print::nBorder; + pPrinter->DrawLine( Point( nXLeft, nY ), Point( nXRight, nY ) ); + + pPrinter->Pop(); +} + + +void DlgEditor::printPage( sal_Int32 nPage, Printer* pPrinter, const OUString& rTitle ) +{ + if( nPage == 0 ) + Print( pPrinter, rTitle ); +} + + +void DlgEditor::Print( Printer* pPrinter, const OUString& rTitle ) // not working yet +{ + MapMode aOldMap( pPrinter->GetMapMode()); + vcl::Font aOldFont( pPrinter->GetFont() ); + + MapMode aMap( MapUnit::Map100thMM ); + pPrinter->SetMapMode( aMap ); + vcl::Font aFont; + aFont.SetAlignment( ALIGN_BOTTOM ); + aFont.SetFontSize( Size( 0, 360 )); + pPrinter->SetFont( aFont ); + + Size aPaperSz = pPrinter->GetOutputSize(); + aPaperSz.AdjustWidth( -(Print::nLeftMargin + Print::nRightMargin) ); + aPaperSz.AdjustHeight( -(Print::nTopMargin + Print::nBottomMargin) ); + + lcl_PrintHeader( pPrinter, rTitle ); + + BitmapEx aDlgEx; + Size aBmpSz( pPrinter->PixelToLogic( aDlgEx.GetSizePixel() ) ); + double nPaperSzWidth = aPaperSz.Width(); + double nPaperSzHeight = aPaperSz.Height(); + double nBmpSzWidth = aBmpSz.Width(); + double nBmpSzHeight = aBmpSz.Height(); + double nScaleX = nPaperSzWidth / nBmpSzWidth; + double nScaleY = nPaperSzHeight / nBmpSzHeight; + + Size aOutputSz; + if( nBmpSzHeight * nScaleX <= nPaperSzHeight ) + { + aOutputSz.setWidth( static_cast<tools::Long>(nBmpSzWidth * nScaleX) ); + aOutputSz.setHeight( static_cast<tools::Long>(nBmpSzHeight * nScaleX) ); + } + else + { + aOutputSz.setWidth( static_cast<tools::Long>(nBmpSzWidth * nScaleY) ); + aOutputSz.setHeight( static_cast<tools::Long>(nBmpSzHeight * nScaleY) ); + } + + Point aPosOffs( + (aPaperSz.Width() / 2) - (aOutputSz.Width() / 2), + (aPaperSz.Height()/ 2) - (aOutputSz.Height() / 2)); + + aPosOffs.AdjustX(Print::nLeftMargin ); + aPosOffs.AdjustY(Print::nTopMargin ); + + pPrinter->DrawBitmapEx( aPosOffs, aOutputSz, aDlgEx ); + + pPrinter->SetMapMode( aOldMap ); + pPrinter->SetFont( aOldFont ); +} + + +bool DlgEditor::AdjustPageSize() +{ + bool bAdjustedPageSize = false; + Reference< beans::XPropertySet > xPSet( m_xUnoControlDialogModel, UNO_QUERY ); + if ( xPSet.is() ) + { + sal_Int32 nFormXIn = 0, nFormYIn = 0, nFormWidthIn = 0, nFormHeightIn = 0; + xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nFormXIn; + xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nFormYIn; + xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nFormWidthIn; + xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nFormHeightIn; + + sal_Int32 nFormX, nFormY, nFormWidth, nFormHeight; + if ( pDlgEdForm && pDlgEdForm->TransformFormToSdrCoordinates( nFormXIn, nFormYIn, nFormWidthIn, nFormHeightIn, nFormX, nFormY, nFormWidth, nFormHeight ) ) + { + Size aPageSizeDelta( 400, 300 ); + aPageSizeDelta = rWindow.PixelToLogic( aPageSizeDelta, MapMode( MapUnit::Map100thMM ) ); + + sal_Int32 nNewPageWidth = nFormX + nFormWidth + aPageSizeDelta.Width(); + sal_Int32 nNewPageHeight = nFormY + nFormHeight + aPageSizeDelta.Height(); + + Size aPageSizeMin( DLGED_PAGE_WIDTH_MIN, DLGED_PAGE_HEIGHT_MIN ); + aPageSizeMin = rWindow.PixelToLogic( aPageSizeMin, MapMode( MapUnit::Map100thMM ) ); + sal_Int32 nPageWidthMin = aPageSizeMin.Width(); + sal_Int32 nPageHeightMin = aPageSizeMin.Height(); + + if ( nNewPageWidth < nPageWidthMin ) + nNewPageWidth = nPageWidthMin; + + if ( nNewPageHeight < nPageHeightMin ) + nNewPageHeight = nPageHeightMin; + + if ( pDlgEdPage ) + { + Size aPageSize = pDlgEdPage->GetSize(); + if ( nNewPageWidth != aPageSize.Width() || nNewPageHeight != aPageSize.Height() ) + { + Size aNewPageSize( nNewPageWidth, nNewPageHeight ); + pDlgEdPage->SetSize( aNewPageSize ); + pDlgEdView->SetWorkArea( tools::Rectangle( Point( 0, 0 ), aNewPageSize ) ); + bAdjustedPageSize = true; + } + } + } + } + + return bAdjustedPageSize; +} + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/dlgedclip.cxx b/basctl/source/dlged/dlgedclip.cxx new file mode 100644 index 0000000000..931f10afe5 --- /dev/null +++ b/basctl/source/dlged/dlgedclip.cxx @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <dlgedclip.hxx> +#include <vcl/svapp.hxx> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp> +#include <com/sun/star/datatransfer/XMimeContentType.hpp> +#include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp> + +namespace basctl +{ + +using namespace comphelper; +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::datatransfer; +using namespace ::com::sun::star::datatransfer::clipboard; +DlgEdTransferableImpl::DlgEdTransferableImpl( const Sequence< DataFlavor >& aSeqFlavors, const Sequence< Any >& aSeqData ) +{ + m_SeqFlavors = aSeqFlavors; + m_SeqData = aSeqData; +} +DlgEdTransferableImpl::~DlgEdTransferableImpl() +{ +} +bool DlgEdTransferableImpl::compareDataFlavors( const DataFlavor& lFlavor, const DataFlavor& rFlavor ) +{ + // compare mime content types + Reference< uno::XComponentContext > xContext = getProcessComponentContext(); + Reference< datatransfer::XMimeContentTypeFactory > + xMCntTypeFactory = MimeContentTypeFactory::create(xContext); + + // compare full media types + Reference< datatransfer::XMimeContentType > xLType = xMCntTypeFactory->createMimeContentType( lFlavor.MimeType ); + Reference< datatransfer::XMimeContentType > xRType = xMCntTypeFactory->createMimeContentType( rFlavor.MimeType ); + + OUString aLFullMediaType = xLType->getFullMediaType(); + OUString aRFullMediaType = xRType->getFullMediaType(); + + bool bRet = aLFullMediaType.equalsIgnoreAsciiCase( aRFullMediaType ); + + return bRet; +} + +// XTransferable +Any SAL_CALL DlgEdTransferableImpl::getTransferData( const DataFlavor& rFlavor ) +{ + const SolarMutexGuard aGuard; + + if ( !isDataFlavorSupported( rFlavor ) ) + throw UnsupportedFlavorException(); + + Any aData; + + for ( sal_Int32 i = 0; i < m_SeqFlavors.getLength(); i++ ) + { + if ( compareDataFlavors( m_SeqFlavors[i] , rFlavor ) ) + { + aData = m_SeqData[i]; + break; + } + } + + return aData; +} +Sequence< DataFlavor > SAL_CALL DlgEdTransferableImpl::getTransferDataFlavors( ) +{ + const SolarMutexGuard aGuard; + + return m_SeqFlavors; +} +sal_Bool SAL_CALL DlgEdTransferableImpl::isDataFlavorSupported( const DataFlavor& rFlavor ) +{ + const SolarMutexGuard aGuard; + + for ( auto const & i : std::as_const(m_SeqFlavors) ) + if ( compareDataFlavors( i, rFlavor ) ) + return true; + return false; +} + +// XClipboardOwner +void SAL_CALL DlgEdTransferableImpl::lostOwnership( const Reference< XClipboard >&, const Reference< XTransferable >& ) +{ + const SolarMutexGuard aGuard; + + m_SeqFlavors = Sequence< DataFlavor >(); + m_SeqData = Sequence< Any >(); +} +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/dlgedfac.cxx b/basctl/source/dlged/dlgedfac.cxx new file mode 100644 index 0000000000..65e2965491 --- /dev/null +++ b/basctl/source/dlged/dlgedfac.cxx @@ -0,0 +1,229 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <dlgedfac.hxx> +#include <dlgedobj.hxx> +#include <dlgeddef.hxx> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/ScrollBarOrientation.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <comphelper/processfactory.hxx> +#include <utility> + +namespace basctl +{ + +using namespace ::com::sun::star; + + +DlgEdFactory::DlgEdFactory( css::uno::Reference< css::frame::XModel > xModel ) : mxModel(std::move( xModel )) +{ + SdrObjFactory::InsertMakeObjectHdl( LINK(this, DlgEdFactory, MakeObject) ); +} + + +DlgEdFactory::~DlgEdFactory() COVERITY_NOEXCEPT_FALSE +{ + SdrObjFactory::RemoveMakeObjectHdl( LINK(this, DlgEdFactory, MakeObject) ); +} + + +IMPL_LINK( DlgEdFactory, MakeObject, SdrObjCreatorParams, aParams, rtl::Reference<SdrObject> ) +{ + static const uno::Reference<lang::XMultiServiceFactory> xDialogSFact = [] { + uno::Reference<lang::XMultiServiceFactory> xFact; + uno::Reference< uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext(); + uno::Reference< container::XNameContainer > xC( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.awt.UnoControlDialogModel", xContext ), uno::UNO_QUERY ); + if (xC.is()) + xFact.set(xC, uno::UNO_QUERY); + return xFact; + }(); + + rtl::Reference<SdrObject> pNewObj; + if( (aParams.nInventor == SdrInventor::BasicDialog) && + (aParams.nObjIdentifier >= SdrObjKind::BasicDialogPushButton) && + (aParams.nObjIdentifier <= SdrObjKind::BasicDialogFormHorizontalScroll) ) + { + switch( aParams.nObjIdentifier ) + { + case SdrObjKind::BasicDialogPushButton: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlButtonModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogRadioButton: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlRadioButtonModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogFormRadio: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.RadioButton", xDialogSFact ); + static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel ); + break; + case SdrObjKind::BasicDialogCheckbox: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlCheckBoxModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogFormCheck: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.CheckBox", xDialogSFact ); + static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel ); + break; + case SdrObjKind::BasicDialogListbox: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlListBoxModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogFormList: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.ListBox", xDialogSFact ); + static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel ); + break; + case SdrObjKind::BasicDialogFormCombo: + case SdrObjKind::BasicDialogCombobox: + { + rtl::Reference<DlgEdObj> pNew; + if ( aParams.nObjIdentifier == SdrObjKind::BasicDialogCombobox ) + pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlComboBoxModel", xDialogSFact ); + else + { + pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.ComboBox", xDialogSFact ); + pNew->MakeDataAware( mxModel ); + } + pNewObj = pNew; + try + { + uno::Reference< beans::XPropertySet > xPSet(pNew->GetUnoControlModel(), uno::UNO_QUERY); + if (xPSet.is()) + { + xPSet->setPropertyValue( DLGED_PROP_DROPDOWN, uno::Any(true)); + } + } + catch(...) + { + } + } + break; + case SdrObjKind::BasicDialogGroupBox: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlGroupBoxModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogEdit: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlEditModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogFixedText: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFixedTextModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogImageControl: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlImageControlModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogProgressbar: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlProgressBarModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogHorizontalScrollbar: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlScrollBarModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogFormHorizontalScroll: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.ScrollBar", xDialogSFact ); + static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel ); + break; + case SdrObjKind::BasicDialogFormVerticalScroll: + case SdrObjKind::BasicDialogVerticalScrollbar: + { + rtl::Reference<DlgEdObj> pNew; + if ( aParams.nObjIdentifier == SdrObjKind::BasicDialogVerticalScrollbar ) + pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlScrollBarModel", xDialogSFact ); + else + { + pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.ScrollBar", xDialogSFact ); + pNew->MakeDataAware( mxModel ); + } + pNewObj = pNew; + // set vertical orientation + try + { + uno::Reference< beans::XPropertySet > xPSet(pNew->GetUnoControlModel(), uno::UNO_QUERY); + if (xPSet.is()) + { + xPSet->setPropertyValue( DLGED_PROP_ORIENTATION, uno::Any(sal_Int32(css::awt::ScrollBarOrientation::VERTICAL)) ); + } + } + catch(...) + { + } + } break; + case SdrObjKind::BasicDialogHorizontalFixedLine: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFixedLineModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogVerticalFixedLine: + { + rtl::Reference<DlgEdObj> pNew = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFixedLineModel", xDialogSFact ); + pNewObj = pNew; + // set vertical orientation + try + { + uno::Reference< beans::XPropertySet > xPSet(pNew->GetUnoControlModel(), uno::UNO_QUERY); + if (xPSet.is()) + { + xPSet->setPropertyValue( DLGED_PROP_ORIENTATION, uno::Any(sal_Int32(1)) ); + } + } + catch(...) + { + } + } break; + case SdrObjKind::BasicDialogDateField: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlDateFieldModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogTimeField: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlTimeFieldModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogNumericField: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlNumericFieldModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogCurencyField: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlCurrencyFieldModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogFormattedField: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFormattedFieldModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogPatternField: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlPatternFieldModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogFileControl: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFileControlModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogSpinButton: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlSpinButtonModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogFormSpin: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.form.component.SpinButton", xDialogSFact ); + static_cast< DlgEdObj* >( pNewObj.get() )->MakeDataAware( mxModel ); + break; + case SdrObjKind::BasicDialogTreeControl: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.tree.TreeControlModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogGridControl: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.grid.UnoControlGridModel", xDialogSFact ); + break; + case SdrObjKind::BasicDialogHyperlinkControl: + pNewObj = new DlgEdObj(aParams.rSdrModel, "com.sun.star.awt.UnoControlFixedHyperlinkModel", xDialogSFact ); + break; + default: + break; + + } + } + return pNewObj; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/dlgedfunc.cxx b/basctl/source/dlged/dlgedfunc.cxx new file mode 100644 index 0000000000..7f1a0388ee --- /dev/null +++ b/basctl/source/dlged/dlgedfunc.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 <svtools/scrolladaptor.hxx> +#include <svx/svdview.hxx> +#include <dlgedfunc.hxx> +#include <dlged.hxx> +#include <dlgedview.hxx> +#include <vcl/seleng.hxx> + +namespace basctl +{ + +IMPL_LINK_NOARG( DlgEdFunc, ScrollTimeout, Timer *, void ) +{ + vcl::Window& rWindow = rParent.GetWindow(); + Point aPos = rWindow.ScreenToOutputPixel( rWindow.GetPointerPosPixel() ); + aPos = rWindow.PixelToLogic( aPos ); + ForceScroll( aPos ); +} + +void DlgEdFunc::ForceScroll( const Point& rPos ) +{ + aScrollTimer.Stop(); + + vcl::Window& rWindow = rParent.GetWindow(); + + static const Point aDefPoint; + tools::Rectangle aOutRect( aDefPoint, rWindow.GetOutputSizePixel() ); + aOutRect = rWindow.PixelToLogic( aOutRect ); + + ScrollAdaptor* pHScroll = rParent.GetHScroll(); + ScrollAdaptor* pVScroll = rParent.GetVScroll(); + tools::Long nDeltaX = pHScroll->GetLineSize(); + tools::Long nDeltaY = pVScroll->GetLineSize(); + + if( !aOutRect.Contains( rPos ) ) + { + if( rPos.X() < aOutRect.Left() ) + nDeltaX = -nDeltaX; + else if( rPos.X() <= aOutRect.Right() ) + nDeltaX = 0; + + if( rPos.Y() < aOutRect.Top() ) + nDeltaY = -nDeltaY; + else if( rPos.Y() <= aOutRect.Bottom() ) + nDeltaY = 0; + + if( nDeltaX ) + pHScroll->SetThumbPos( pHScroll->GetThumbPos() + nDeltaX ); + if( nDeltaY ) + pVScroll->SetThumbPos( pVScroll->GetThumbPos() + nDeltaY ); + + if( nDeltaX ) + rParent.DoScroll(); + if( nDeltaY ) + rParent.DoScroll(); + } + + aScrollTimer.Start(); +} + +DlgEdFunc::DlgEdFunc (DlgEditor& rParent_) : + rParent(rParent_), aScrollTimer("basctl DlgEdFunc aScrollTimer") +{ + aScrollTimer.SetInvokeHandler( LINK( this, DlgEdFunc, ScrollTimeout ) ); + aScrollTimer.SetTimeout( SELENG_AUTOREPEAT_INTERVAL ); +} + +DlgEdFunc::~DlgEdFunc() +{ +} + +void DlgEdFunc::MouseButtonDown( const MouseEvent& ) +{ +} + +bool DlgEdFunc::MouseButtonUp( const MouseEvent& ) +{ + aScrollTimer.Stop(); + return true; +} + +void DlgEdFunc::MouseMove( const MouseEvent& ) +{ +} + +bool DlgEdFunc::KeyInput( const KeyEvent& rKEvt ) +{ + bool bReturn = false; + + SdrView& rView = rParent.GetView(); + vcl::Window& rWindow = rParent.GetWindow(); + + vcl::KeyCode aCode = rKEvt.GetKeyCode(); + sal_uInt16 nCode = aCode.GetCode(); + + switch ( nCode ) + { + case KEY_ESCAPE: + { + if ( rView.IsAction() ) + { + rView.BrkAction(); + bReturn = true; + } + else if ( rView.AreObjectsMarked() ) + { + const SdrHdlList& rHdlList = rView.GetHdlList(); + SdrHdl* pHdl = rHdlList.GetFocusHdl(); + if ( pHdl ) + const_cast<SdrHdlList&>(rHdlList).ResetFocusHdl(); + else + rView.UnmarkAll(); + + bReturn = true; + } + } + break; + case KEY_TAB: + { + if ( !aCode.IsMod1() && !aCode.IsMod2() ) + { + // mark next object + if ( !rView.MarkNextObj( !aCode.IsShift() ) ) + { + // if no next object, mark first/last + rView.UnmarkAllObj(); + rView.MarkNextObj( !aCode.IsShift() ); + } + + if ( rView.AreObjectsMarked() ) + rView.MakeVisible( rView.GetAllMarkedRect(), rWindow ); + + bReturn = true; + } + else if ( aCode.IsMod1() ) + { + // selected handle + const SdrHdlList& rHdlList = rView.GetHdlList(); + const_cast<SdrHdlList&>(rHdlList).TravelFocusHdl( !aCode.IsShift() ); + + // guarantee visibility of focused handle + if (SdrHdl* pHdl = rHdlList.GetFocusHdl()) + { + Point aHdlPosition( pHdl->GetPos() ); + tools::Rectangle aVisRect( aHdlPosition - Point( 100, 100 ), Size( 200, 200 ) ); + rView.MakeVisible( aVisRect, rWindow ); + } + + bReturn = true; + } + } + break; + case KEY_UP: + case KEY_DOWN: + case KEY_LEFT: + case KEY_RIGHT: + { + tools::Long nX = 0; + tools::Long nY = 0; + + if ( nCode == KEY_UP ) + { + // scroll up + nX = 0; + nY = -1; + } + else if ( nCode == KEY_DOWN ) + { + // scroll down + nX = 0; + nY = 1; + } + else if ( nCode == KEY_LEFT ) + { + // scroll left + nX = -1; + nY = 0; + } + else if ( nCode == KEY_RIGHT ) + { + // scroll right + nX = 1; + nY = 0; + } + + if ( rView.AreObjectsMarked() && !aCode.IsMod1() ) + { + if ( aCode.IsMod2() ) + { + // move in 1 pixel distance + Size aPixelSize = rWindow.PixelToLogic(Size(1, 1)); + nX *= aPixelSize.Width(); + nY *= aPixelSize.Height(); + } + else + { + // move in 1 mm distance + nX *= 100; + nY *= 100; + } + + const SdrHdlList& rHdlList = rView.GetHdlList(); + SdrHdl* pHdl = rHdlList.GetFocusHdl(); + + if ( pHdl == nullptr ) + { + // no handle selected + if ( rView.IsMoveAllowed() ) + { + // restrict movement to work area + const tools::Rectangle& rWorkArea = rView.GetWorkArea(); + + if ( !rWorkArea.IsEmpty() ) + { + tools::Rectangle aMarkRect( rView.GetMarkedObjRect() ); + aMarkRect.Move( nX, nY ); + + if ( !rWorkArea.Contains( aMarkRect ) ) + { + if ( aMarkRect.Left() < rWorkArea.Left() ) + nX += rWorkArea.Left() - aMarkRect.Left(); + + if ( aMarkRect.Right() > rWorkArea.Right() ) + nX -= aMarkRect.Right() - rWorkArea.Right(); + + if ( aMarkRect.Top() < rWorkArea.Top() ) + nY += rWorkArea.Top() - aMarkRect.Top(); + + if ( aMarkRect.Bottom() > rWorkArea.Bottom() ) + nY -= aMarkRect.Bottom() - rWorkArea.Bottom(); + } + } + + if ( nX != 0 || nY != 0 ) + { + rView.MoveAllMarked( Size( nX, nY ) ); + rView.MakeVisible( rView.GetAllMarkedRect(), rWindow ); + } + } + } + else if (nX || nY) + { + Point aStartPoint(pHdl->GetPos()); + Point aEndPoint(pHdl->GetPos() + Point(nX, nY)); + const SdrDragStat& rDragStat = rView.GetDragStat(); + + // start dragging + rView.BegDragObj(aStartPoint, nullptr, pHdl, 0); + + if (rView.IsDragObj()) + { + bool const bWasNoSnap = rDragStat.IsNoSnap(); + bool const bWasSnapEnabled = rView.IsSnapEnabled(); + + // switch snapping off + if (!bWasNoSnap) + const_cast<SdrDragStat&>(rDragStat).SetNoSnap(); + if (bWasSnapEnabled) + rView.SetSnapEnabled(false); + + rView.MovAction(aEndPoint); + rView.EndDragObj(); + + // restore snap + if (!bWasNoSnap) + const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap); + if (bWasSnapEnabled) + rView.SetSnapEnabled(bWasSnapEnabled); + } + + // make moved handle visible + tools::Rectangle aVisRect(aEndPoint - Point(100, 100), Size(200, 200)); + rView.MakeVisible(aVisRect, rWindow); + } + } + else + { + // scroll page + ScrollAdaptor* pScrollBar = ( nX != 0 ) ? rParent.GetHScroll() : rParent.GetVScroll(); + if ( pScrollBar ) + { + tools::Long nRangeMin = pScrollBar->GetRangeMin(); + tools::Long nRangeMax = pScrollBar->GetRangeMax(); + tools::Long nThumbPos = pScrollBar->GetThumbPos() + ( ( nX != 0 ) ? nX : nY ) * pScrollBar->GetLineSize(); + if ( nThumbPos < nRangeMin ) + nThumbPos = nRangeMin; + if ( nThumbPos > nRangeMax ) + nThumbPos = nRangeMax; + pScrollBar->SetThumbPos( nThumbPos ); + rParent.DoScroll(); + } + } + + bReturn = true; + } + break; + default: + { + } + break; + } + + if ( bReturn ) + rWindow.ReleaseMouse(); + + return bReturn; +} + +DlgEdFuncInsert::DlgEdFuncInsert (DlgEditor& rParent_) : + DlgEdFunc(rParent_) +{ + rParent.GetView().SetCreateMode(); +} + +DlgEdFuncInsert::~DlgEdFuncInsert() +{ + rParent.GetView().SetEditMode(); +} + +void DlgEdFuncInsert::MouseButtonDown( const MouseEvent& rMEvt ) +{ + if( !rMEvt.IsLeft() ) + return; + + SdrView& rView = rParent.GetView(); + vcl::Window& rWindow = rParent.GetWindow(); + rView.SetActualWin(rWindow.GetOutDev()); + + Point aPos = rWindow.PixelToLogic( rMEvt.GetPosPixel() ); + sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width()); + sal_uInt16 nDrgLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width()); + + rWindow.CaptureMouse(); + + if ( rMEvt.IsLeft() && rMEvt.GetClicks() == 1 ) + { + SdrHdl* pHdl = rView.PickHandle(aPos); + + // if selected object was hit, drag object + if ( pHdl!=nullptr || rView.IsMarkedHit(aPos, nHitLog) ) + rView.BegDragObj(aPos, nullptr, pHdl, nDrgLog); + else if ( rView.AreObjectsMarked() ) + rView.UnmarkAll(); + + // if no action, create object + if ( !rView.IsAction() ) + rView.BegCreateObj(aPos); + } + else if ( rMEvt.IsLeft() && rMEvt.GetClicks() == 2 ) + { + // if object was hit, show property browser + if ( rView.IsMarkedHit(aPos, nHitLog) && rParent.GetMode() != DlgEditor::READONLY ) + rParent.ShowProperties(); + } +} + +bool DlgEdFuncInsert::MouseButtonUp( const MouseEvent& rMEvt ) +{ + DlgEdFunc::MouseButtonUp( rMEvt ); + + SdrView& rView = rParent.GetView(); + vcl::Window& rWindow = rParent.GetWindow(); + rView.SetActualWin(rWindow.GetOutDev()); + + rWindow.ReleaseMouse(); + + // object creation active? + if ( rView.IsCreateObj() ) + { + rView.EndCreateObj(SdrCreateCmd::ForceEnd); + + if ( !rView.AreObjectsMarked() ) + { + sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width()); + Point aPos( rWindow.PixelToLogic( rMEvt.GetPosPixel() ) ); + rView.MarkObj(aPos, nHitLog); + } + + return rView.AreObjectsMarked(); + } + else + { + if ( rView.IsDragObj() ) + rView.EndDragObj( rMEvt.IsMod1() ); + return true; + } +} + +void DlgEdFuncInsert::MouseMove( const MouseEvent& rMEvt ) +{ + SdrView& rView = rParent.GetView(); + vcl::Window& rWindow = rParent.GetWindow(); + rView.SetActualWin(rWindow.GetOutDev()); + + Point aPos = rWindow.PixelToLogic(rMEvt.GetPosPixel()); + sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width()); + + if (rView.IsAction()) + { + ForceScroll(aPos); + rView.MovAction(aPos); + } + + rWindow.SetPointer( rView.GetPreferredPointer( aPos, rWindow.GetOutDev(), nHitLog ) ); +} + +DlgEdFuncSelect::DlgEdFuncSelect (DlgEditor& rParent_) : + DlgEdFunc(rParent_) +{ +} + +DlgEdFuncSelect::~DlgEdFuncSelect() +{ +} + +void DlgEdFuncSelect::MouseButtonDown( const MouseEvent& rMEvt ) +{ + // get view from parent + SdrView& rView = rParent.GetView(); + vcl::Window& rWindow = rParent.GetWindow(); + rView.SetActualWin(rWindow.GetOutDev()); + + sal_uInt16 nDrgLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width()); + sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width()); + Point aMDPos = rWindow.PixelToLogic(rMEvt.GetPosPixel()); + + if ( rMEvt.IsLeft() && rMEvt.GetClicks() == 1 ) + { + SdrHdl* pHdl = rView.PickHandle(aMDPos); + + // hit selected object? + if ( pHdl!=nullptr || rView.IsMarkedHit(aMDPos, nHitLog) ) + { + rView.BegDragObj(aMDPos, nullptr, pHdl, nDrgLog); + } + else + { + // if not multi selection, unmark all + if ( !rMEvt.IsShift() ) + rView.UnmarkAll(); + else + { + SdrPageView* pPV; + SdrObject* pObj = rView.PickObj(aMDPos, nHitLog, pPV); + if (pObj) + { + //if (dynamic_cast<DlgEdForm*>(pObj)) + // rView.UnmarkAll(); + //else + // rParent.UnmarkDialog(); + } + } + + if ( rView.MarkObj(aMDPos, nHitLog) ) + { + // drag object + pHdl = rView.PickHandle(aMDPos); + rView.BegDragObj(aMDPos, nullptr, pHdl, nDrgLog); + } + else + { + // select object + rView.BegMarkObj(aMDPos); + } + } + } + else if ( rMEvt.IsLeft() && rMEvt.GetClicks() == 2 ) + { + // if object was hit, show property browser + if ( rView.IsMarkedHit(aMDPos, nHitLog) && rParent.GetMode() != DlgEditor::READONLY ) + rParent.ShowProperties(); + } +} + +bool DlgEdFuncSelect::MouseButtonUp( const MouseEvent& rMEvt ) +{ + DlgEdFunc::MouseButtonUp( rMEvt ); + + // get view from parent + SdrView& rView = rParent.GetView(); + vcl::Window& rWindow = rParent.GetWindow(); + rView.SetActualWin(rWindow.GetOutDev()); + + Point aPnt = rWindow.PixelToLogic(rMEvt.GetPosPixel()); + sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width()); + + if ( rMEvt.IsLeft() ) + { + if (rView.IsDragObj()) + { + // object was dragged + rView.EndDragObj( rMEvt.IsMod1() ); + rView.ForceMarkedToAnotherPage(); + } + else if (rView.IsAction()) + { + rView.EndAction(); + } + } + + rWindow.SetPointer( rView.GetPreferredPointer( aPnt, rWindow.GetOutDev(), nHitLog ) ); + rWindow.ReleaseMouse(); + + return true; +} + +void DlgEdFuncSelect::MouseMove( const MouseEvent& rMEvt ) +{ + SdrView& rView = rParent.GetView(); + vcl::Window& rWindow = rParent.GetWindow(); + rView.SetActualWin(rWindow.GetOutDev()); + + Point aPnt = rWindow.PixelToLogic(rMEvt.GetPosPixel()); + sal_uInt16 nHitLog = static_cast<sal_uInt16>(rWindow.PixelToLogic(Size(3, 0)).Width()); + + if ( rView.IsAction() ) + { + Point aPix = rMEvt.GetPosPixel(); + Point aPnt_ = rWindow.PixelToLogic(aPix); + + ForceScroll(aPnt_); + rView.MovAction(aPnt_); + } + + rWindow.SetPointer( rView.GetPreferredPointer( aPnt, rWindow.GetOutDev(), nHitLog ) ); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/dlgedlist.cxx b/basctl/source/dlged/dlgedlist.cxx new file mode 100644 index 0000000000..6b9cebfe89 --- /dev/null +++ b/basctl/source/dlged/dlgedlist.cxx @@ -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 . + */ + +#include <dlgedlist.hxx> +#include <dlgedobj.hxx> + +namespace basctl +{ + +// DlgEdPropListenerImpl +DlgEdPropListenerImpl::DlgEdPropListenerImpl (DlgEdObj& rObj) : + rDlgEdObj(rObj) +{ +} + +DlgEdPropListenerImpl::~DlgEdPropListenerImpl() +{ +} + +// XEventListener +void SAL_CALL DlgEdPropListenerImpl::disposing( const css::lang::EventObject& ) +{ +} + +// XPropertyChangeListener +void SAL_CALL DlgEdPropListenerImpl::propertyChange( const css::beans::PropertyChangeEvent& evt ) +{ + rDlgEdObj._propertyChange( evt ); +} + +// DlgEdEvtContListenerImpl +DlgEdEvtContListenerImpl::DlgEdEvtContListenerImpl (DlgEdObj& rObj) : + rDlgEdObj(rObj) +{ +} + +DlgEdEvtContListenerImpl::~DlgEdEvtContListenerImpl() +{ +} + +// XEventListener +void SAL_CALL DlgEdEvtContListenerImpl::disposing( const css::lang::EventObject& ) +{ +} + +// XContainerListener +void SAL_CALL DlgEdEvtContListenerImpl::elementInserted(const css::container::ContainerEvent& /*Event*/) +{ + rDlgEdObj._elementInserted(); +} + +void SAL_CALL DlgEdEvtContListenerImpl::elementReplaced(const css::container::ContainerEvent& /*Event*/) +{ + rDlgEdObj._elementReplaced(); +} + +void SAL_CALL DlgEdEvtContListenerImpl::elementRemoved(const css::container::ContainerEvent& /*Event*/) +{ + rDlgEdObj._elementRemoved(); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/dlgedmod.cxx b/basctl/source/dlged/dlgedmod.cxx new file mode 100644 index 0000000000..017e4b16c7 --- /dev/null +++ b/basctl/source/dlged/dlgedmod.cxx @@ -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 . + */ + +#include <dlgedmod.hxx> +#include <dlgedpage.hxx> + +namespace basctl +{ +DlgEdModel::DlgEdModel() {} + +DlgEdModel::~DlgEdModel() {} + +rtl::Reference<SdrPage> DlgEdModel::AllocPage(bool bMasterPage) +{ + return new DlgEdPage(*this, bMasterPage); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/dlgedobj.cxx b/basctl/source/dlged/dlgedobj.cxx new file mode 100644 index 0000000000..5b87393e51 --- /dev/null +++ b/basctl/source/dlged/dlgedobj.cxx @@ -0,0 +1,1705 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <sal/log.hxx> + +#include <cassert> + +#include <dlged.hxx> +#include <dlgeddef.hxx> +#include <dlgedlist.hxx> +#include <dlgedobj.hxx> +#include <dlgedpage.hxx> +#include <dlgedview.hxx> +#include <localizationmgr.hxx> +#include <strings.hxx> + +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/form/binding/XBindableValue.hpp> +#include <com/sun/star/form/binding/XValueBinding.hpp> +#include <com/sun/star/form/binding/XListEntrySink.hpp> +#include <com/sun/star/awt/XUnoControlContainer.hpp> +#include <com/sun/star/awt/XVclContainerPeer.hpp> +#include <com/sun/star/container/XContainer.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/script/XScriptEventsSupplier.hpp> +#include <com/sun/star/table/CellAddress.hpp> +#include <com/sun/star/table/CellRangeAddress.hpp> +#include <cppuhelper/exc_hlp.hxx> +#include <o3tl/functional.hxx> +#include <svx/svdpagv.hxx> +#include <unotools/sharedunocomponent.hxx> +#include <vcl/svapp.hxx> +#include <tools/debug.hxx> + +namespace basctl +{ + +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::script; + + +DlgEditor& DlgEdObj::GetDialogEditor () +{ + if (DlgEdForm* pFormThis = dynamic_cast<DlgEdForm*>(this)) + return pFormThis->GetDlgEditor(); + else + return pDlgEdForm->GetDlgEditor(); +} + +DlgEdObj::DlgEdObj(SdrModel& rSdrModel) +: SdrUnoObj(rSdrModel, OUString()) + ,bIsListening(false) +{ +} + +DlgEdObj::DlgEdObj(SdrModel& rSdrModel, DlgEdObj const & rSource) +: SdrUnoObj(rSdrModel, rSource) + ,bIsListening(false) +{ + // set parent form + pDlgEdForm = rSource.pDlgEdForm; + + // add child to parent form + pDlgEdForm->AddChild( this ); + + Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY ); + if ( xPSet.is() ) + { + // set new name + OUString aOUniqueName( GetUniqueName() ); + Any aUniqueName; + aUniqueName <<= aOUniqueName; + xPSet->setPropertyValue( DLGED_PROP_NAME, aUniqueName ); + + Reference< container::XNameContainer > xCont( GetDlgEdForm()->GetUnoControlModel() , UNO_QUERY ); + if ( xCont.is() ) + { + // set tabindex + Sequence< OUString > aNames = xCont->getElementNames(); + xPSet->setPropertyValue( DLGED_PROP_TABINDEX, Any(static_cast<sal_Int16>(aNames.getLength())) ); + + // insert control model in dialog model + Reference< awt::XControlModel > xCtrl( xPSet , UNO_QUERY ); + xCont->insertByName( aOUniqueName, Any(xCtrl) ); + + pDlgEdForm->UpdateTabOrderAndGroups(); + } + } + + // start listening + StartListening(); +} + +DlgEdObj::DlgEdObj( + SdrModel& rSdrModel, + const OUString& rModelName, + const css::uno::Reference< css::lang::XMultiServiceFactory >& rxSFac) +: SdrUnoObj(rSdrModel, rModelName, rxSFac) + ,bIsListening(false) +{ +} + +DlgEdObj::~DlgEdObj() +{ + if ( isListening() ) + EndListening(true); +} + +namespace +{ + /* returns the DlgEdForm which the given DlgEdObj belongs to + (which might in fact be the object itself) + + Failure to obtain the form will be reported with an assertion in the non-product + version. + */ + bool lcl_getDlgEdForm( DlgEdObj* _pObject, DlgEdForm*& _out_pDlgEdForm ) + { + _out_pDlgEdForm = dynamic_cast< DlgEdForm* >( _pObject ); + if ( !_out_pDlgEdForm ) + _out_pDlgEdForm = _pObject->GetDlgEdForm(); + DBG_ASSERT( _out_pDlgEdForm, "lcl_getDlgEdForm: no form!" ); + return ( _out_pDlgEdForm != nullptr ); + } +} + +uno::Reference< awt::XControl > DlgEdObj::GetControl() const +{ + uno::Reference< awt::XControl > xControl; + if (DlgEdForm const* pForm = GetDlgEdForm()) + { + DlgEditor const& rEditor = pForm->GetDlgEditor(); + xControl = GetUnoControl(rEditor.GetView(), *rEditor.GetWindow().GetOutDev()); + } + return xControl; +} + +bool DlgEdObj::TransformSdrToControlCoordinates( + sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn, + sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut ) +{ + // input position and size + Size aPos( nXIn, nYIn ); + Size aSize( nWidthIn, nHeightIn ); + + // form position + DlgEdForm* pForm = nullptr; + if ( !lcl_getDlgEdForm( this, pForm ) ) + return false; + tools::Rectangle aFormRect = pForm->GetSnapRect(); + Size aFormPos( aFormRect.Left(), aFormRect.Top() ); + + // convert 100th_mm to pixel + OutputDevice* pDevice = Application::GetDefaultDevice(); + DBG_ASSERT( pDevice, "DlgEdObj::TransformSdrToControlCoordinates: missing default device!" ); + if ( !pDevice ) + return false; + aPos = pDevice->LogicToPixel( aPos, MapMode( MapUnit::Map100thMM ) ); + aSize = pDevice->LogicToPixel( aSize, MapMode( MapUnit::Map100thMM ) ); + aFormPos = pDevice->LogicToPixel( aFormPos, MapMode( MapUnit::Map100thMM ) ); + + // subtract form position + aPos.AdjustWidth( -(aFormPos.Width()) ); + aPos.AdjustHeight( -(aFormPos.Height()) ); + + // take window borders into account + Reference< beans::XPropertySet > xPSetForm( pForm->GetUnoControlModel(), UNO_QUERY ); + DBG_ASSERT( xPSetForm.is(), "DlgEdObj::TransformFormToSdrCoordinates: no form property set!" ); + if ( !xPSetForm.is() ) + return false; + bool bDecoration = true; + xPSetForm->getPropertyValue( DLGED_PROP_DECORATION ) >>= bDecoration; + if( bDecoration ) + { + awt::DeviceInfo aDeviceInfo = pForm->getDeviceInfo(); + aPos.AdjustWidth( -(aDeviceInfo.LeftInset) ); + aPos.AdjustHeight( -(aDeviceInfo.TopInset) ); + } + + // convert pixel to logic units + aPos = pDevice->PixelToLogic(aPos, MapMode(MapUnit::MapAppFont)); + aSize = pDevice->PixelToLogic(aSize, MapMode(MapUnit::MapAppFont)); + + // set out parameters + nXOut = aPos.Width(); + nYOut = aPos.Height(); + nWidthOut = aSize.Width(); + nHeightOut = aSize.Height(); + + return true; +} + +bool DlgEdObj::TransformSdrToFormCoordinates( + sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn, + sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut ) +{ + // input position and size + Size aPos( nXIn, nYIn ); + Size aSize( nWidthIn, nHeightIn ); + + // convert 100th_mm to pixel + OutputDevice* pDevice = Application::GetDefaultDevice(); + DBG_ASSERT( pDevice, "DlgEdObj::TransformSdrToFormCoordinates: missing default device!" ); + if ( !pDevice ) + return false; + aPos = pDevice->LogicToPixel( aPos, MapMode( MapUnit::Map100thMM ) ); + aSize = pDevice->LogicToPixel( aSize, MapMode( MapUnit::Map100thMM ) ); + + // take window borders into account + DlgEdForm* pForm = nullptr; + if ( !lcl_getDlgEdForm( this, pForm ) ) + return false; + + // take window borders into account + Reference< beans::XPropertySet > xPSetForm( pForm->GetUnoControlModel(), UNO_QUERY ); + DBG_ASSERT( xPSetForm.is(), "DlgEdObj::TransformFormToSdrCoordinates: no form property set!" ); + if ( !xPSetForm.is() ) + return false; + bool bDecoration = true; + xPSetForm->getPropertyValue( DLGED_PROP_DECORATION ) >>= bDecoration; + if( bDecoration ) + { + awt::DeviceInfo aDeviceInfo = pForm->getDeviceInfo(); + aSize.AdjustWidth( -(aDeviceInfo.LeftInset + aDeviceInfo.RightInset) ); + aSize.AdjustHeight( -(aDeviceInfo.TopInset + aDeviceInfo.BottomInset) ); + } + // convert pixel to logic units + aPos = pDevice->PixelToLogic(aPos, MapMode(MapUnit::MapAppFont)); + aSize = pDevice->PixelToLogic(aSize, MapMode(MapUnit::MapAppFont)); + + // set out parameters + nXOut = aPos.Width(); + nYOut = aPos.Height(); + nWidthOut = aSize.Width(); + nHeightOut = aSize.Height(); + + return true; +} + +bool DlgEdObj::TransformControlToSdrCoordinates( + sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn, + sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut ) +{ + // input position and size + Size aPos( nXIn, nYIn ); + Size aSize( nWidthIn, nHeightIn ); + + // form position + DlgEdForm* pForm = nullptr; + if ( !lcl_getDlgEdForm( this, pForm ) ) + return false; + + Reference< beans::XPropertySet > xPSetForm( pForm->GetUnoControlModel(), UNO_QUERY ); + DBG_ASSERT( xPSetForm.is(), "DlgEdObj::TransformControlToSdrCoordinates: no form property set!" ); + if ( !xPSetForm.is() ) + return false; + sal_Int32 nFormX = 0, nFormY = 0; + xPSetForm->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nFormX; + xPSetForm->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nFormY; + Size aFormPos( nFormX, nFormY ); + + // convert logic units to pixel + OutputDevice* pDevice = Application::GetDefaultDevice(); + DBG_ASSERT( pDevice, "DlgEdObj::TransformControlToSdrCoordinates: missing default device!" ); + if ( !pDevice ) + return false; + aPos = pDevice->LogicToPixel(aPos, MapMode(MapUnit::MapAppFont)); + aSize = pDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont)); + aFormPos = pDevice->LogicToPixel(aFormPos, MapMode(MapUnit::MapAppFont)); + + // add form position + aPos.AdjustWidth(aFormPos.Width() ); + aPos.AdjustHeight(aFormPos.Height() ); + + // take window borders into account + bool bDecoration = true; + xPSetForm->getPropertyValue( DLGED_PROP_DECORATION ) >>= bDecoration; + if( bDecoration ) + { + awt::DeviceInfo aDeviceInfo = pForm->getDeviceInfo(); + aPos.AdjustWidth(aDeviceInfo.LeftInset ); + aPos.AdjustHeight(aDeviceInfo.TopInset ); + } + + // convert pixel to 100th_mm + aPos = pDevice->PixelToLogic( aPos, MapMode( MapUnit::Map100thMM ) ); + aSize = pDevice->PixelToLogic( aSize, MapMode( MapUnit::Map100thMM ) ); + + // set out parameters + nXOut = aPos.Width(); + nYOut = aPos.Height(); + nWidthOut = aSize.Width(); + nHeightOut = aSize.Height(); + + return true; +} + +bool DlgEdObj::TransformFormToSdrCoordinates( + sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn, + sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut ) +{ + // input position and size + Size aPos( nXIn, nYIn ); + Size aSize( nWidthIn, nHeightIn ); + + // convert logic units to pixel + OutputDevice* pDevice = Application::GetDefaultDevice(); + DBG_ASSERT( pDevice, "DlgEdObj::TransformFormToSdrCoordinates: missing default device!" ); + if ( !pDevice ) + return false; + + // take window borders into account + DlgEdForm* pForm = nullptr; + if ( !lcl_getDlgEdForm( this, pForm ) ) + return false; + + aPos = pDevice->LogicToPixel(aPos, MapMode(MapUnit::MapAppFont)); + aSize = pDevice->LogicToPixel(aSize, MapMode(MapUnit::MapAppFont)); + + // take window borders into account + Reference< beans::XPropertySet > xPSetForm( pForm->GetUnoControlModel(), UNO_QUERY ); + DBG_ASSERT( xPSetForm.is(), "DlgEdObj::TransformFormToSdrCoordinates: no form property set!" ); + if ( !xPSetForm.is() ) + return false; + bool bDecoration = true; + xPSetForm->getPropertyValue( DLGED_PROP_DECORATION ) >>= bDecoration; + if( bDecoration ) + { + awt::DeviceInfo aDeviceInfo = pForm->getDeviceInfo(); + aSize.AdjustWidth(aDeviceInfo.LeftInset + aDeviceInfo.RightInset ); + aSize.AdjustHeight(aDeviceInfo.TopInset + aDeviceInfo.BottomInset ); + } + + // convert pixel to 100th_mm + aPos = pDevice->PixelToLogic( aPos, MapMode( MapUnit::Map100thMM ) ); + aSize = pDevice->PixelToLogic( aSize, MapMode( MapUnit::Map100thMM ) ); + + // set out parameters + nXOut = aPos.Width(); + nYOut = aPos.Height(); + nWidthOut = aSize.Width(); + nHeightOut = aSize.Height(); + + return true; +} + +void DlgEdObj::SetRectFromProps() +{ + // get control position and size from properties + Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY ); + if ( !xPSet.is() ) + return; + + sal_Int32 nXIn = 0, nYIn = 0, nWidthIn = 0, nHeightIn = 0; + xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nXIn; + xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nYIn; + xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidthIn; + xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeightIn; + + // transform coordinates + sal_Int32 nXOut, nYOut, nWidthOut, nHeightOut; + if ( TransformControlToSdrCoordinates( nXIn, nYIn, nWidthIn, nHeightIn, nXOut, nYOut, nWidthOut, nHeightOut ) ) + { + // set rectangle position and size + Point aPoint( nXOut, nYOut ); + Size aSize( nWidthOut, nHeightOut ); + SetSnapRect( tools::Rectangle( aPoint, aSize ) ); + } +} + +void DlgEdObj::SetPropsFromRect() +{ + // get control position and size from rectangle + tools::Rectangle aRect_ = GetSnapRect(); + sal_Int32 nXIn = aRect_.Left(); + sal_Int32 nYIn = aRect_.Top(); + sal_Int32 nWidthIn = aRect_.GetWidth(); + sal_Int32 nHeightIn = aRect_.GetHeight(); + + // transform coordinates + sal_Int32 nXOut, nYOut, nWidthOut, nHeightOut; + if ( TransformSdrToControlCoordinates( nXIn, nYIn, nWidthIn, nHeightIn, nXOut, nYOut, nWidthOut, nHeightOut ) ) + { + // set properties + Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY ); + if ( xPSet.is() ) + { + xPSet->setPropertyValue( DLGED_PROP_POSITIONX, Any(nXOut) ); + xPSet->setPropertyValue( DLGED_PROP_POSITIONY, Any(nYOut) ); + xPSet->setPropertyValue( DLGED_PROP_WIDTH, Any(nWidthOut) ); + xPSet->setPropertyValue( DLGED_PROP_HEIGHT, Any(nHeightOut) ); + } + } +} + +void DlgEdObj::PositionAndSizeChange( const beans::PropertyChangeEvent& evt ) +{ + DBG_ASSERT( pDlgEdForm, "DlgEdObj::PositionAndSizeChange: no form!" ); + DlgEdPage& rPage = pDlgEdForm->GetDlgEditor().GetPage(); + { + Size aPageSize = rPage.GetSize(); + sal_Int32 nPageWidthIn = aPageSize.Width(); + sal_Int32 nPageHeightIn = aPageSize.Height(); + sal_Int32 nPageX, nPageY, nPageWidth, nPageHeight; + if ( TransformSdrToControlCoordinates( 0/*nPageXIn*/, 0/*nPageYIn*/, nPageWidthIn, nPageHeightIn, nPageX, nPageY, nPageWidth, nPageHeight ) ) + { + Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY ); + if ( xPSet.is() ) + { + sal_Int32 nX = 0, nY = 0, nWidth = 0, nHeight = 0; + xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nX; + xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nY; + xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidth; + xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeight; + + sal_Int32 nValue = 0; + evt.NewValue >>= nValue; + sal_Int32 nNewValue = nValue; + + if ( evt.PropertyName == DLGED_PROP_POSITIONX ) + { + if ( nNewValue + nWidth > nPageX + nPageWidth ) + nNewValue = nPageX + nPageWidth - nWidth; + if ( nNewValue < nPageX ) + nNewValue = nPageX; + } + else if ( evt.PropertyName == DLGED_PROP_POSITIONY ) + { + if ( nNewValue + nHeight > nPageY + nPageHeight ) + nNewValue = nPageY + nPageHeight - nHeight; + if ( nNewValue < nPageY ) + nNewValue = nPageY; + } + else if ( evt.PropertyName == DLGED_PROP_WIDTH ) + { + if ( nX + nNewValue > nPageX + nPageWidth ) + nNewValue = nPageX + nPageWidth - nX; + if ( nNewValue < 1 ) + nNewValue = 1; + } + else if ( evt.PropertyName == DLGED_PROP_HEIGHT ) + { + if ( nY + nNewValue > nPageY + nPageHeight ) + nNewValue = nPageY + nPageHeight - nY; + if ( nNewValue < 1 ) + nNewValue = 1; + } + + if ( nNewValue != nValue ) + { + EndListening( false ); + xPSet->setPropertyValue( evt.PropertyName, Any(nNewValue) ); + StartListening(); + } + } + } + } + + SetRectFromProps(); +} + +void DlgEdObj::NameChange( const css::beans::PropertyChangeEvent& evt ) +{ + // get old name + OUString aOldName; + evt.OldValue >>= aOldName; + + // get new name + OUString aNewName; + evt.NewValue >>= aNewName; + + if ( aNewName == aOldName ) + return; + + Reference< container::XNameAccess > xNameAcc((GetDlgEdForm()->GetUnoControlModel()), UNO_QUERY); + if ( !(xNameAcc.is() && xNameAcc->hasByName(aOldName)) ) + return; + + if (!xNameAcc->hasByName(aNewName) && !aNewName.isEmpty()) + { + // remove the control by the old name and insert the control by the new name in the container + Reference< container::XNameContainer > xCont(xNameAcc, UNO_QUERY ); + if ( xCont.is() ) + { + Reference< awt::XControlModel > xCtrl = GetUnoControlModel(); + Any aAny; + aAny <<= xCtrl; + xCont->removeByName( aOldName ); + xCont->insertByName( aNewName , aAny ); + + LocalizationMgr::renameControlResourceIDsForEditorObject( + &GetDialogEditor(), aAny, aNewName + ); + } + } + else + { + // set old name property + EndListening(false); + Reference< beans::XPropertySet > xPSet(GetUnoControlModel(), UNO_QUERY); + xPSet->setPropertyValue( DLGED_PROP_NAME, Any(aOldName) ); + StartListening(); + } +} + +sal_Int32 DlgEdObj::GetStep() const +{ + // get step property + sal_Int32 nStep = 0; + uno::Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), uno::UNO_QUERY ); + if (xPSet.is()) + { + xPSet->getPropertyValue( DLGED_PROP_STEP ) >>= nStep; + } + return nStep; +} + +void DlgEdObj::UpdateStep() +{ + sal_Int32 nCurStep = GetDlgEdForm()->GetStep(); + sal_Int32 nStep = GetStep(); + + SdrLayerAdmin& rLayerAdmin(getSdrModelFromSdrObject().GetLayerAdmin()); + SdrLayerID nHiddenLayerId = rLayerAdmin.GetLayerID( "HiddenLayer" ); + SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID( rLayerAdmin.GetControlLayerName() ); + + if( nCurStep ) + { + if ( nStep && (nStep != nCurStep) ) + { + SetLayer( nHiddenLayerId ); + } + else + { + SetLayer( nControlLayerId ); + } + } + else + { + SetLayer( nControlLayerId ); + } +} + +void DlgEdObj::TabIndexChange( const beans::PropertyChangeEvent& evt ) +{ + DlgEdForm* pForm = GetDlgEdForm(); + if ( !pForm ) + return; + + // stop listening with all children + std::vector<DlgEdObj*> aChildList = pForm->GetChildren(); + for (auto const& child : aChildList) + { + child->EndListening( false ); + } + + Reference< container::XNameAccess > xNameAcc( pForm->GetUnoControlModel() , UNO_QUERY ); + if ( xNameAcc.is() ) + { + // get sequence of control names + Sequence< OUString > aNames = xNameAcc->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + sal_Int32 nCtrls = aNames.getLength(); + + // create a map of tab indices and control names, sorted by tab index + IndexToNameMap aIndexToNameMap; + for ( sal_Int32 i = 0; i < nCtrls; ++i ) + { + // get control name + OUString aName( pNames[i] ); + + // get tab index + sal_Int16 nTabIndex = -1; + Any aCtrl = xNameAcc->getByName( aName ); + Reference< beans::XPropertySet > xPSet; + aCtrl >>= xPSet; + if ( xPSet.is() && xPSet == Reference< beans::XPropertySet >( evt.Source, UNO_QUERY ) ) + evt.OldValue >>= nTabIndex; + else if ( xPSet.is() ) + xPSet->getPropertyValue( DLGED_PROP_TABINDEX ) >>= nTabIndex; + + // insert into map + aIndexToNameMap.emplace( nTabIndex, aName ); + } + + // create a helper list of control names, sorted by tab index + std::vector< OUString > aNameList( aIndexToNameMap.size() ); + std::transform( + aIndexToNameMap.begin(), aIndexToNameMap.end(), + aNameList.begin(), + ::o3tl::select2nd< IndexToNameMap::value_type >( ) + ); + + // check tab index + sal_Int16 nOldTabIndex = 0; + evt.OldValue >>= nOldTabIndex; + sal_Int16 nNewTabIndex = 0; + evt.NewValue >>= nNewTabIndex; + if ( nNewTabIndex < 0 ) + nNewTabIndex = 0; + else if ( nNewTabIndex > nCtrls - 1 ) + nNewTabIndex = sal::static_int_cast<sal_Int16>( nCtrls - 1 ); + + // reorder helper list + OUString aCtrlName = aNameList[nOldTabIndex]; + aNameList.erase( aNameList.begin() + nOldTabIndex ); + aNameList.insert( aNameList.begin() + nNewTabIndex , aCtrlName ); + + // set new tab indices + for ( sal_Int32 i = 0; i < nCtrls; ++i ) + { + Any aCtrl = xNameAcc->getByName( aNameList[i] ); + Reference< beans::XPropertySet > xPSet; + aCtrl >>= xPSet; + if ( xPSet.is() ) + { + assert(i >= SAL_MIN_INT16); + if (i > SAL_MAX_INT16) + { + SAL_WARN("basctl", "tab " << i << " > SAL_MAX_INT16"); + continue; + } + xPSet->setPropertyValue( DLGED_PROP_TABINDEX, Any(static_cast<sal_Int16>(i)) ); + } + } + + // reorder objects in drawing page + getSdrModelFromSdrObject().GetPage(0)->SetObjectOrdNum( nOldTabIndex + 1, nNewTabIndex + 1 ); + + pForm->UpdateTabOrderAndGroups(); + } + + // start listening with all children + for (auto const& child : aChildList) + { + child->StartListening(); + } +} + +bool DlgEdObj::supportsService( OUString const & serviceName ) const +{ + bool bSupports = false; + + Reference< lang::XServiceInfo > xServiceInfo( GetUnoControlModel() , UNO_QUERY ); + // TODO: cache xServiceInfo as member? + if ( xServiceInfo.is() ) + bSupports = xServiceInfo->supportsService( serviceName ); + + return bSupports; +} + +OUString DlgEdObj::GetDefaultName() const +{ + OUString sResId; + OUString aDefaultName; + if ( supportsService( "com.sun.star.awt.UnoControlDialogModel" ) ) + { + sResId = RID_STR_CLASS_DIALOG; + } + else if ( supportsService( "com.sun.star.awt.UnoControlButtonModel" ) ) + { + sResId = RID_STR_CLASS_BUTTON; + } + else if ( supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" ) ) + { + sResId = RID_STR_CLASS_RADIOBUTTON; + } + else if ( supportsService( "com.sun.star.awt.UnoControlCheckBoxModel" ) ) + { + sResId = RID_STR_CLASS_CHECKBOX; + } + else if ( supportsService( "com.sun.star.awt.UnoControlListBoxModel" ) ) + { + sResId = RID_STR_CLASS_LISTBOX; + } + else if ( supportsService( "com.sun.star.awt.UnoControlComboBoxModel" ) ) + { + sResId = RID_STR_CLASS_COMBOBOX; + } + else if ( supportsService( "com.sun.star.awt.UnoControlGroupBoxModel" ) ) + { + sResId = RID_STR_CLASS_GROUPBOX; + } + else if ( supportsService( "com.sun.star.awt.UnoControlEditModel" ) ) + { + sResId = RID_STR_CLASS_EDIT; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFixedTextModel" ) ) + { + sResId = RID_STR_CLASS_FIXEDTEXT; + } + else if ( supportsService( "com.sun.star.awt.UnoControlImageControlModel" ) ) + { + sResId = RID_STR_CLASS_IMAGECONTROL; + } + else if ( supportsService( "com.sun.star.awt.UnoControlProgressBarModel" ) ) + { + sResId = RID_STR_CLASS_PROGRESSBAR; + } + else if ( supportsService( "com.sun.star.awt.UnoControlScrollBarModel" ) ) + { + sResId = RID_STR_CLASS_SCROLLBAR; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFixedLineModel" ) ) + { + sResId = RID_STR_CLASS_FIXEDLINE; + } + else if ( supportsService( "com.sun.star.awt.UnoControlDateFieldModel" ) ) + { + sResId = RID_STR_CLASS_DATEFIELD; + } + else if ( supportsService( "com.sun.star.awt.UnoControlTimeFieldModel" ) ) + { + sResId = RID_STR_CLASS_TIMEFIELD; + } + else if ( supportsService( "com.sun.star.awt.UnoControlNumericFieldModel" ) ) + { + sResId = RID_STR_CLASS_NUMERICFIELD; + } + else if ( supportsService( "com.sun.star.awt.UnoControlCurrencyFieldModel" ) ) + { + sResId = RID_STR_CLASS_CURRENCYFIELD; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFormattedFieldModel" ) ) + { + sResId = RID_STR_CLASS_FORMATTEDFIELD; + } + else if ( supportsService( "com.sun.star.awt.UnoControlPatternFieldModel" ) ) + { + sResId = RID_STR_CLASS_PATTERNFIELD; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFileControlModel" ) ) + { + sResId = RID_STR_CLASS_FILECONTROL; + } + else if ( supportsService( "com.sun.star.awt.tree.TreeControlModel" ) ) + { + sResId = RID_STR_CLASS_TREECONTROL; + } + else if ( supportsService( "com.sun.star.awt.grid.UnoControlGridModel" ) ) + { + sResId = RID_STR_CLASS_GRIDCONTROL; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFixedHyperlinkModel" ) ) + { + sResId = RID_STR_CLASS_HYPERLINKCONTROL; + } + else if ( supportsService( "com.sun.star.awt.UnoControlSpinButtonModel" ) ) + { + sResId = RID_STR_CLASS_SPINCONTROL; + } + else + { + sResId = RID_STR_CLASS_CONTROL; + } + + if (!sResId.isEmpty()) + aDefaultName = sResId; + + return aDefaultName; +} + +OUString DlgEdObj::GetUniqueName() const +{ + OUString aUniqueName; + uno::Reference< container::XNameAccess > xNameAcc((GetDlgEdForm()->GetUnoControlModel()), uno::UNO_QUERY); + + if ( xNameAcc.is() ) + { + sal_Int32 n = 0; + OUString aDefaultName = GetDefaultName(); + + do + { + aUniqueName = aDefaultName + OUString::number(++n); + } while (xNameAcc->hasByName(aUniqueName)); + } + + return aUniqueName; +} + +SdrInventor DlgEdObj::GetObjInventor() const +{ + return SdrInventor::BasicDialog; +} + +SdrObjKind DlgEdObj::GetObjIdentifier() const +{ + if ( supportsService( "com.sun.star.awt.UnoControlDialogModel" )) + { + return SdrObjKind::BasicDialogDialog; + } + else if ( supportsService( "com.sun.star.awt.UnoControlButtonModel" )) + { + return SdrObjKind::BasicDialogPushButton; + } + else if ( supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" )) + { + return SdrObjKind::BasicDialogRadioButton; + } + else if ( supportsService( "com.sun.star.awt.UnoControlCheckBoxModel" )) + { + return SdrObjKind::BasicDialogCheckbox; + } + else if ( supportsService( "com.sun.star.awt.UnoControlListBoxModel" )) + { + return SdrObjKind::BasicDialogListbox; + } + else if ( supportsService( "com.sun.star.awt.UnoControlComboBoxModel" )) + { + return SdrObjKind::BasicDialogCombobox; + } + else if ( supportsService( "com.sun.star.awt.UnoControlGroupBoxModel" )) + { + return SdrObjKind::BasicDialogGroupBox; + } + else if ( supportsService( "com.sun.star.awt.UnoControlEditModel" )) + { + return SdrObjKind::BasicDialogEdit; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFixedTextModel" )) + { + return SdrObjKind::BasicDialogFixedText; + } + else if ( supportsService( "com.sun.star.awt.UnoControlImageControlModel" )) + { + return SdrObjKind::BasicDialogImageControl; + } + else if ( supportsService( "com.sun.star.awt.UnoControlProgressBarModel" )) + { + return SdrObjKind::BasicDialogProgressbar; + } + else if ( supportsService( "com.sun.star.awt.UnoControlScrollBarModel" )) + { + return SdrObjKind::BasicDialogHorizontalScrollbar; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFixedLineModel" )) + { + return SdrObjKind::BasicDialogHorizontalFixedLine; + } + else if ( supportsService( "com.sun.star.awt.UnoControlDateFieldModel" )) + { + return SdrObjKind::BasicDialogDateField; + } + else if ( supportsService( "com.sun.star.awt.UnoControlTimeFieldModel" )) + { + return SdrObjKind::BasicDialogTimeField; + } + else if ( supportsService( "com.sun.star.awt.UnoControlNumericFieldModel" )) + { + return SdrObjKind::BasicDialogNumericField; + } + else if ( supportsService( "com.sun.star.awt.UnoControlCurrencyFieldModel" )) + { + return SdrObjKind::BasicDialogCurencyField; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFormattedFieldModel" )) + { + return SdrObjKind::BasicDialogFormattedField; + } + else if ( supportsService( "com.sun.star.awt.UnoControlPatternFieldModel" )) + { + return SdrObjKind::BasicDialogPatternField; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFileControlModel" )) + { + return SdrObjKind::BasicDialogFileControl; + } + else if ( supportsService( "com.sun.star.awt.tree.TreeControlModel" )) + { + return SdrObjKind::BasicDialogTreeControl; + } + else if ( supportsService( "com.sun.star.awt.grid.UnoControlGridModel" )) + { + return SdrObjKind::BasicDialogGridControl; + } + else if ( supportsService( "com.sun.star.awt.UnoControlFixedHyperlinkModel" )) + { + return SdrObjKind::BasicDialogHyperlinkControl; + } + else + { + return SdrObjKind::BasicDialogControl; + } +} + +rtl::Reference<SdrObject> DlgEdObj::CloneSdrObject(SdrModel& rTargetModel) const +{ + return new DlgEdObj(rTargetModel, *this); +} + +rtl::Reference<SdrObject> DlgEdObj::getFullDragClone() const +{ + // no need to really add the clone for dragging, it's a temporary + // object + return rtl::Reference<SdrObject>(new SdrUnoObj(getSdrModelFromSdrObject(), *this)); +} + +void DlgEdObj::NbcMove( const Size& rSize ) +{ + SdrUnoObj::NbcMove( rSize ); + + // stop listening + EndListening(false); + + // set geometry properties + SetPropsFromRect(); + + // start listening + StartListening(); + + // dialog model changed + GetDlgEdForm()->GetDlgEditor().SetDialogModelChanged(); +} + +void DlgEdObj::NbcResize(const Point& rRef, const Fraction& xFract, const Fraction& yFract) +{ + SdrUnoObj::NbcResize( rRef, xFract, yFract ); + + // stop listening + EndListening(false); + + // set geometry properties + SetPropsFromRect(); + + // start listening + StartListening(); + + // dialog model changed + GetDlgEdForm()->GetDlgEditor().SetDialogModelChanged(); +} + +bool DlgEdObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) +{ + bool bResult = SdrUnoObj::EndCreate(rStat, eCmd); + + // tdf#120674 after interactive creation, the SdrObject (this) has no SdrPage yet + // due to not being inserted. Usually this should be handled in a ::handlePageChange + // implementation. For historical reasons, the SdrPage (which is the DlgEdPage) was + // already set. For now, get it from the SdrDragStat and use it to access and set + // the local pDlgEdForm + if(!pDlgEdForm && nullptr != rStat.GetPageView()) + { + const DlgEdPage* pDlgEdPage(dynamic_cast<const DlgEdPage*>(rStat.GetPageView()->GetPage())); + + if(nullptr != pDlgEdPage) + { + // set parent form + pDlgEdForm = pDlgEdPage->GetDlgEdForm(); + } + } + + SetDefaults(); + StartListening(); + + return bResult; +} + +void DlgEdObj::SetDefaults() +{ + if ( !pDlgEdForm ) + return; + + // add child to parent form + pDlgEdForm->AddChild( this ); + + Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY ); + if ( xPSet.is() ) + { + // get unique name + OUString aOUniqueName( GetUniqueName() ); + + // set name property + xPSet->setPropertyValue( DLGED_PROP_NAME, Any(aOUniqueName) ); + + // set labels + if ( supportsService( "com.sun.star.awt.UnoControlButtonModel" ) || + supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" ) || + supportsService( "com.sun.star.awt.UnoControlCheckBoxModel" ) || + supportsService( "com.sun.star.awt.UnoControlGroupBoxModel" ) || + supportsService( "com.sun.star.awt.UnoControlFixedTextModel" ) ) + { + xPSet->setPropertyValue( DLGED_PROP_LABEL, Any(aOUniqueName) ); + } + + // set number formats supplier for formatted field + if ( supportsService( "com.sun.star.awt.UnoControlFormattedFieldModel" ) ) + { + Reference< util::XNumberFormatsSupplier > xSupplier = GetDlgEdForm()->GetDlgEditor().GetNumberFormatsSupplier(); + if ( xSupplier.is() ) + { + xPSet->setPropertyValue( DLGED_PROP_FORMATSSUPPLIER, Any(xSupplier) ); + } + } + + // set geometry properties + SetPropsFromRect(); + + Reference< container::XNameContainer > xCont( GetDlgEdForm()->GetUnoControlModel() , UNO_QUERY ); + if ( xCont.is() ) + { + // set tabindex + Sequence< OUString > aNames = xCont->getElementNames(); + uno::Any aTabIndex; + aTabIndex <<= static_cast<sal_Int16>(aNames.getLength()); + xPSet->setPropertyValue( DLGED_PROP_TABINDEX, aTabIndex ); + + // set step + Reference< beans::XPropertySet > xPSetForm( xCont, UNO_QUERY ); + if ( xPSetForm.is() ) + { + Any aStep = xPSetForm->getPropertyValue( DLGED_PROP_STEP ); + xPSet->setPropertyValue( DLGED_PROP_STEP, aStep ); + } + + // insert control model in dialog model + Reference< awt::XControlModel > xCtrl( xPSet , UNO_QUERY ); + Any aAny; + aAny <<= xCtrl; + xCont->insertByName( aOUniqueName , aAny ); + + LocalizationMgr::setControlResourceIDsForNewEditorObject( + &GetDialogEditor(), aAny, aOUniqueName + ); + + pDlgEdForm->UpdateTabOrderAndGroups(); + } + } + + // dialog model changed + pDlgEdForm->GetDlgEditor().SetDialogModelChanged(); +} + +void DlgEdObj::StartListening() +{ + DBG_ASSERT(!isListening(), "DlgEdObj::StartListening: already listening!"); + + if (isListening()) + return; + + bIsListening = true; + + // XPropertyChangeListener + Reference< XPropertySet > xControlModel( GetUnoControlModel() , UNO_QUERY ); + if (!m_xPropertyChangeListener.is() && xControlModel.is()) + { + // create listener + m_xPropertyChangeListener = new DlgEdPropListenerImpl(*this); + + // register listener to properties + xControlModel->addPropertyChangeListener( OUString() , m_xPropertyChangeListener ); + } + + // XContainerListener + Reference< XScriptEventsSupplier > xEventsSupplier( GetUnoControlModel() , UNO_QUERY ); + if( !m_xContainerListener.is() && xEventsSupplier.is() ) + { + // create listener + m_xContainerListener = new DlgEdEvtContListenerImpl(*this); + + // register listener to script event container + Reference< XNameContainer > xEventCont = xEventsSupplier->getEvents(); + DBG_ASSERT(xEventCont.is(), "DlgEdObj::StartListening: control model has no script event container!"); + Reference< XContainer > xCont( xEventCont , UNO_QUERY ); + if (xCont.is()) + xCont->addContainerListener( m_xContainerListener ); + } +} + +void DlgEdObj::EndListening(bool bRemoveListener) +{ + DBG_ASSERT(isListening(), "DlgEdObj::EndListening: not listening currently!"); + + if (!isListening()) + return; + + bIsListening = false; + + if (!bRemoveListener) + return; + + // XPropertyChangeListener + Reference< XPropertySet > xControlModel(GetUnoControlModel(), UNO_QUERY); + if ( m_xPropertyChangeListener.is() && xControlModel.is() ) + { + // remove listener + xControlModel->removePropertyChangeListener( OUString() , m_xPropertyChangeListener ); + } + m_xPropertyChangeListener.clear(); + + // XContainerListener + Reference< XScriptEventsSupplier > xEventsSupplier( GetUnoControlModel() , UNO_QUERY ); + if( m_xContainerListener.is() && xEventsSupplier.is() ) + { + // remove listener + Reference< XNameContainer > xEventCont = xEventsSupplier->getEvents(); + DBG_ASSERT(xEventCont.is(), "DlgEdObj::EndListening: control model has no script event container!"); + Reference< XContainer > xCont( xEventCont , UNO_QUERY ); + if (xCont.is()) + xCont->removeContainerListener( m_xContainerListener ); + } + m_xContainerListener.clear(); +} + +void DlgEdObj::_propertyChange( const css::beans::PropertyChangeEvent& evt ) +{ + if (!isListening()) + return; + + DlgEdForm* pRealDlgEdForm = dynamic_cast<DlgEdForm*>(this); + if (!pRealDlgEdForm) + pRealDlgEdForm = GetDlgEdForm(); + if (!pRealDlgEdForm) + return; + DlgEditor& rDlgEditor = pRealDlgEdForm->GetDlgEditor(); + if (rDlgEditor.isInPaint()) + return; + + // dialog model changed + rDlgEditor.SetDialogModelChanged(); + + // update position and size + if ( evt.PropertyName == DLGED_PROP_POSITIONX || evt.PropertyName == DLGED_PROP_POSITIONY || + evt.PropertyName == DLGED_PROP_WIDTH || evt.PropertyName == DLGED_PROP_HEIGHT || + evt.PropertyName == DLGED_PROP_DECORATION ) + { + PositionAndSizeChange( evt ); + + if ( evt.PropertyName == DLGED_PROP_DECORATION ) + GetDialogEditor().ResetDialog(); + } + // change name of control in dialog model + else if ( evt.PropertyName == DLGED_PROP_NAME ) + { + if (!dynamic_cast<DlgEdForm*>(this)) + { + try + { + NameChange(evt); + } + catch (container::NoSuchElementException const&) + { + css::uno::Any anyEx = cppu::getCaughtException(); + throw lang::WrappedTargetRuntimeException("", nullptr, + anyEx); + } + } + } + // update step + else if ( evt.PropertyName == DLGED_PROP_STEP ) + { + UpdateStep(); + } + // change tabindex + else if ( evt.PropertyName == DLGED_PROP_TABINDEX ) + { + if (!dynamic_cast<DlgEdForm*>(this)) + TabIndexChange(evt); + } +} + +void DlgEdObj::_elementInserted() +{ + if (isListening()) + { + // dialog model changed + GetDialogEditor().SetDialogModelChanged(); + } +} + +void DlgEdObj::_elementReplaced() +{ + if (isListening()) + { + // dialog model changed + GetDialogEditor().SetDialogModelChanged(); + } +} + +void DlgEdObj::_elementRemoved() +{ + if (isListening()) + { + // dialog model changed + GetDialogEditor().SetDialogModelChanged(); + } +} + +void DlgEdObj::SetLayer(SdrLayerID nLayer) +{ + SdrLayerID nOldLayer = GetLayer(); + + if ( nLayer != nOldLayer ) + { + SdrUnoObj::SetLayer( nLayer ); + + DlgEdHint aHint( DlgEdHint::LAYERCHANGED, this ); + GetDlgEdForm()->GetDlgEditor().Broadcast( aHint ); + } +} + +DlgEdForm::DlgEdForm( + SdrModel& rSdrModel, + DlgEditor& rDlgEditor_) +: DlgEdObj(rSdrModel), + rDlgEditor(rDlgEditor_) +{ +} + +DlgEdForm::~DlgEdForm() +{ +} + +void DlgEdForm::SetRectFromProps() +{ + // get form position and size from properties + Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY ); + if ( !xPSet.is() ) + return; + + sal_Int32 nXIn = 0, nYIn = 0, nWidthIn = 0, nHeightIn = 0; + xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nXIn; + xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nYIn; + xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidthIn; + xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeightIn; + + // transform coordinates + sal_Int32 nXOut, nYOut, nWidthOut, nHeightOut; + if ( TransformFormToSdrCoordinates( nXIn, nYIn, nWidthIn, nHeightIn, nXOut, nYOut, nWidthOut, nHeightOut ) ) + { + // set rectangle position and size + Point aPoint( nXOut, nYOut ); + Size aSize( nWidthOut, nHeightOut ); + SetSnapRect( tools::Rectangle( aPoint, aSize ) ); + } +} + +void DlgEdForm::SetPropsFromRect() +{ + // get form position and size from rectangle + tools::Rectangle aRect_ = GetSnapRect(); + sal_Int32 nXIn = aRect_.Left(); + sal_Int32 nYIn = aRect_.Top(); + sal_Int32 nWidthIn = aRect_.GetWidth(); + sal_Int32 nHeightIn = aRect_.GetHeight(); + + // transform coordinates + sal_Int32 nXOut, nYOut, nWidthOut, nHeightOut; + if ( TransformSdrToFormCoordinates( nXIn, nYIn, nWidthIn, nHeightIn, nXOut, nYOut, nWidthOut, nHeightOut ) ) + { + // set properties + Reference< beans::XPropertySet > xPSet( GetUnoControlModel(), UNO_QUERY ); + if ( xPSet.is() ) + { + xPSet->setPropertyValue( DLGED_PROP_POSITIONX, Any(nXOut) ); + xPSet->setPropertyValue( DLGED_PROP_POSITIONY, Any(nYOut) ); + xPSet->setPropertyValue( DLGED_PROP_WIDTH, Any(nWidthOut) ); + xPSet->setPropertyValue( DLGED_PROP_HEIGHT, Any(nHeightOut) ); + } + } +} + +void DlgEdForm::AddChild( DlgEdObj* pDlgEdObj ) +{ + pChildren.push_back( pDlgEdObj ); +} + +void DlgEdForm::RemoveChild( DlgEdObj* pDlgEdObj ) +{ + std::erase(pChildren, pDlgEdObj); +} + +void DlgEdForm::PositionAndSizeChange( const beans::PropertyChangeEvent& evt ) +{ + DlgEditor& rEditor = GetDlgEditor(); + DlgEdPage& rPage = rEditor.GetPage(); + + sal_Int32 nPageXIn = 0; + sal_Int32 nPageYIn = 0; + Size aPageSize = rPage.GetSize(); + sal_Int32 nPageWidthIn = aPageSize.Width(); + sal_Int32 nPageHeightIn = aPageSize.Height(); + sal_Int32 nPageX, nPageY, nPageWidth, nPageHeight; + if ( TransformSdrToFormCoordinates( nPageXIn, nPageYIn, nPageWidthIn, nPageHeightIn, nPageX, nPageY, nPageWidth, nPageHeight ) ) + { + Reference< beans::XPropertySet > xPSetForm( GetUnoControlModel(), UNO_QUERY ); + if ( xPSetForm.is() ) + { + sal_Int32 nValue = 0; + evt.NewValue >>= nValue; + sal_Int32 nNewValue = nValue; + + if ( evt.PropertyName == DLGED_PROP_POSITIONX ) + { + if ( nNewValue < nPageX ) + nNewValue = nPageX; + } + else if ( evt.PropertyName == DLGED_PROP_POSITIONY ) + { + if ( nNewValue < nPageY ) + nNewValue = nPageY; + } + else if ( evt.PropertyName == DLGED_PROP_WIDTH ) + { + if ( nNewValue < 1 ) + nNewValue = 1; + } + else if ( evt.PropertyName == DLGED_PROP_HEIGHT ) + { + if ( nNewValue < 1 ) + nNewValue = 1; + } + + if ( nNewValue != nValue ) + { + EndListening( false ); + xPSetForm->setPropertyValue( evt.PropertyName, Any(nNewValue) ); + StartListening(); + } + } + } + + bool bAdjustedPageSize = rEditor.AdjustPageSize(); + SetRectFromProps(); + std::vector<DlgEdObj*> const& aChildList = GetChildren(); + + if ( bAdjustedPageSize ) + { + rEditor.InitScrollBars(); + aPageSize = rPage.GetSize(); + nPageWidthIn = aPageSize.Width(); + nPageHeightIn = aPageSize.Height(); + if ( TransformSdrToControlCoordinates( nPageXIn, nPageYIn, nPageWidthIn, nPageHeightIn, nPageX, nPageY, nPageWidth, nPageHeight ) ) + { + for (auto const& child : aChildList) + { + Reference< beans::XPropertySet > xPSet( child->GetUnoControlModel(), UNO_QUERY ); + if ( xPSet.is() ) + { + sal_Int32 nX = 0, nY = 0, nWidth = 0, nHeight = 0; + xPSet->getPropertyValue( DLGED_PROP_POSITIONX ) >>= nX; + xPSet->getPropertyValue( DLGED_PROP_POSITIONY ) >>= nY; + xPSet->getPropertyValue( DLGED_PROP_WIDTH ) >>= nWidth; + xPSet->getPropertyValue( DLGED_PROP_HEIGHT ) >>= nHeight; + + sal_Int32 nNewX = nX; + if ( nX + nWidth > nPageX + nPageWidth ) + { + nNewX = nPageX + nPageWidth - nWidth; + if ( nNewX < nPageX ) + nNewX = nPageX; + } + if ( nNewX != nX ) + { + EndListening( false ); + xPSet->setPropertyValue( DLGED_PROP_POSITIONX, Any(nNewX) ); + StartListening(); + } + + sal_Int32 nNewY = nY; + if ( nY + nHeight > nPageY + nPageHeight ) + { + nNewY = nPageY + nPageHeight - nHeight; + if ( nNewY < nPageY ) + nNewY = nPageY; + } + if ( nNewY != nY ) + { + EndListening( false ); + xPSet->setPropertyValue( DLGED_PROP_POSITIONY, Any(nNewY) ); + StartListening(); + } + } + } + } + } + + for (auto const& child : aChildList) + child->SetRectFromProps(); +} + +void DlgEdForm::UpdateStep() +{ + SdrPage* pSdrPage = getSdrPageFromSdrObject(); + + if ( pSdrPage ) + { + for (const rtl::Reference<SdrObject>& pObj : *pSdrPage) + { + DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pObj.get()); + if (pDlgEdObj && !dynamic_cast<DlgEdForm*>(pDlgEdObj)) + pDlgEdObj->UpdateStep(); + } + } +} + +void DlgEdForm::UpdateTabIndices() +{ + // stop listening with all children + for (auto const& child : pChildren) + { + child->EndListening( false ); + } + + Reference< css::container::XNameAccess > xNameAcc( GetUnoControlModel() , UNO_QUERY ); + if ( xNameAcc.is() ) + { + // get sequence of control names + Sequence< OUString > aNames = xNameAcc->getElementNames(); + const OUString* pNames = aNames.getConstArray(); + sal_Int32 nCtrls = aNames.getLength(); + + // create a map of tab indices and control names, sorted by tab index + IndexToNameMap aIndexToNameMap; + for ( sal_Int32 i = 0; i < nCtrls; ++i ) + { + // get name + OUString aName( pNames[i] ); + + // get tab index + sal_Int16 nTabIndex = -1; + Any aCtrl = xNameAcc->getByName( aName ); + Reference< css::beans::XPropertySet > xPSet; + aCtrl >>= xPSet; + if ( xPSet.is() ) + xPSet->getPropertyValue( DLGED_PROP_TABINDEX ) >>= nTabIndex; + + // insert into map + aIndexToNameMap.emplace( nTabIndex, aName ); + } + + // set new tab indices + sal_Int16 nNewTabIndex = 0; + for (auto const& indexToName : aIndexToNameMap) + { + Any aCtrl = xNameAcc->getByName( indexToName.second ); + Reference< beans::XPropertySet > xPSet; + aCtrl >>= xPSet; + if ( xPSet.is() ) + { + xPSet->setPropertyValue( DLGED_PROP_TABINDEX, Any(nNewTabIndex) ); + nNewTabIndex++; + } + } + + UpdateTabOrderAndGroups(); + } + + // start listening with all children + for (auto const& child : pChildren) + { + child->StartListening(); + } +} + +void DlgEdForm::UpdateTabOrder() +{ + // When the tabindex of a control model changes, the dialog control is + // notified about those changes. Due to #109067# (bad performance of + // dialog editor) the dialog control doesn't activate the tab order + // in design mode. When the dialog editor has reordered all + // tabindices, this method allows to activate the taborder afterwards. + + Reference< awt::XUnoControlContainer > xCont( GetControl(), UNO_QUERY ); + if ( xCont.is() ) + { + Sequence< Reference< awt::XTabController > > aSeqTabCtrls = xCont->getTabControllers(); + const Reference< awt::XTabController >* pTabCtrls = aSeqTabCtrls.getConstArray(); + sal_Int32 nCount = aSeqTabCtrls.getLength(); + for ( sal_Int32 i = 0; i < nCount; ++i ) + pTabCtrls[i]->activateTabOrder(); + } +} + +void DlgEdForm::UpdateGroups() +{ + // The grouping of radio buttons in a dialog is done by vcl. + // In the dialog editor we have two views (=controls) for one + // radio button model. One control is owned by the dialog control, + // but not visible in design mode. The other control is owned by + // the drawing layer object. Whereas the grouping of the first + // control is done by vcl, the grouping of the control in the + // drawing layer has to be done here. + + Reference< awt::XTabControllerModel > xTabModel( GetUnoControlModel() , UNO_QUERY ); + if ( !xTabModel.is() ) + return; + + // create a global list of controls that belong to the dialog + std::vector<DlgEdObj*> aChildList = GetChildren(); + sal_uInt32 nSize = aChildList.size(); + Sequence< Reference< awt::XControl > > aSeqControls( nSize ); + for ( sal_uInt32 i = 0; i < nSize; ++i ) + aSeqControls.getArray()[i] = aChildList[i]->GetControl(); + + sal_Int32 nGroupCount = xTabModel->getGroupCount(); + for ( sal_Int32 nGroup = 0; nGroup < nGroupCount; ++nGroup ) + { + // get a list of control models that belong to this group + OUString aName; + Sequence< Reference< awt::XControlModel > > aSeqModels; + xTabModel->getGroup( nGroup, aSeqModels, aName ); + const Reference< awt::XControlModel >* pModels = aSeqModels.getConstArray(); + sal_Int32 nModelCount = aSeqModels.getLength(); + + // create a list of peers that belong to this group + Sequence< Reference< awt::XWindow > > aSeqPeers( nModelCount ); + for ( sal_Int32 nModel = 0; nModel < nModelCount; ++nModel ) + { + // for each control model find the corresponding control in the global list + const Reference< awt::XControl >* pControls = aSeqControls.getConstArray(); + sal_Int32 nControlCount = aSeqControls.getLength(); + for ( sal_Int32 nControl = 0; nControl < nControlCount; ++nControl ) + { + const Reference< awt::XControl > xCtrl( pControls[nControl] ); + if ( xCtrl.is() ) + { + Reference< awt::XControlModel > xCtrlModel( xCtrl->getModel() ); + if ( xCtrlModel.get() == pModels[nModel].get() ) + { + // get the control peer and insert into the list of peers + aSeqPeers.getArray()[ nModel ].set( xCtrl->getPeer(), UNO_QUERY ); + break; + } + } + } + } + + // set the group at the dialog peer + Reference< awt::XControl > xDlg = GetControl(); + if ( xDlg.is() ) + { + Reference< awt::XVclContainerPeer > xDlgPeer( xDlg->getPeer(), UNO_QUERY ); + if ( xDlgPeer.is() ) + xDlgPeer->setGroup( aSeqPeers ); + } + } +} + +void DlgEdForm::UpdateTabOrderAndGroups() +{ + UpdateTabOrder(); + UpdateGroups(); +} + +void DlgEdForm::NbcMove( const Size& rSize ) +{ + SdrUnoObj::NbcMove( rSize ); + + // set geometry properties of form + EndListening(false); + SetPropsFromRect(); + StartListening(); + + // set geometry properties of all children + for (auto const& child : pChildren) + { + child->EndListening(false); + child->SetPropsFromRect(); + child->StartListening(); + } + + // dialog model changed + GetDlgEditor().SetDialogModelChanged(); +} + +void DlgEdForm::NbcResize(const Point& rRef, const Fraction& xFract, const Fraction& yFract) +{ + SdrUnoObj::NbcResize( rRef, xFract, yFract ); + + // set geometry properties of form + EndListening(false); + SetPropsFromRect(); + StartListening(); + + // set geometry properties of all children + for (auto const& child : pChildren) + { + child->EndListening(false); + child->SetPropsFromRect(); + child->StartListening(); + } + + // dialog model changed + GetDlgEditor().SetDialogModelChanged(); +} + +bool DlgEdForm::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) +{ + bool bResult = SdrUnoObj::EndCreate(rStat, eCmd); + + // stop listening + EndListening(false); + + // set geometry properties + SetPropsFromRect(); + + // dialog model changed + GetDlgEditor().SetDialogModelChanged(); + + // start listening + StartListening(); + + return bResult; +} + +awt::DeviceInfo DlgEdForm::getDeviceInfo() const +{ + awt::DeviceInfo aDeviceInfo; + + DlgEditor& rEditor = GetDlgEditor(); + vcl::Window& rWindow = rEditor.GetWindow(); + + // obtain an XControl + ::utl::SharedUNOComponent< awt::XControl > xDialogControl; // ensures auto-disposal, if needed + xDialogControl.reset( GetControl(), ::utl::SharedUNOComponent< awt::XControl >::NoTakeOwnership ); + if ( !xDialogControl.is() ) + { + // don't create a temporary control all the time, this method here is called + // way too often. Instead, use a cached DeviceInfo. + // #i74065# + if ( !!mpDeviceInfo ) + return *mpDeviceInfo; + + Reference< awt::XControlContainer > xEditorControlContainer( rEditor.GetWindowControlContainer() ); + xDialogControl.reset( + GetTemporaryControlForWindow(rWindow, xEditorControlContainer), + utl::SharedUNOComponent< awt::XControl >::TakeOwnership + ); + } + + Reference< awt::XDevice > xDialogDevice; + if ( xDialogControl.is() ) + xDialogDevice.set( xDialogControl->getPeer(), UNO_QUERY ); + DBG_ASSERT( xDialogDevice.is(), "DlgEdForm::getDeviceInfo: no device!" ); + if ( xDialogDevice.is() ) + aDeviceInfo = xDialogDevice->getInfo(); + + mpDeviceInfo = aDeviceInfo; + + return aDeviceInfo; +} +void DlgEdObj::MakeDataAware( const Reference< frame::XModel >& xModel ) +{ + // Need to flesh this out, currently we will only support data-aware controls for calc + // and only handle a subset of functionality e.g. linked-cell and cell range data source. Of course later + // we need to disambiguate for writer ( and others ? ) and also support the generic form (db) bindings + // we need some more work in xmlscript to be able to handle that + Reference< lang::XMultiServiceFactory > xFac( xModel, UNO_QUERY ); + Reference< form::binding::XBindableValue > xBindable( GetUnoControlModel(), UNO_QUERY ); + Reference< form::binding::XListEntrySink > xListEntrySink( GetUnoControlModel(), UNO_QUERY ); + if ( !xFac.is() ) + return; + + //tdf#90361 and tdf#104011 CellValueBinding and CellRangeListSource are unusable + //without being initialized, so use createInstanceWithArguments with a + //dummy BoundCell and CellRange instead of createInstance. This at least results in + //the dialog editor not falling. + css::beans::NamedValue aCellValue; + aCellValue.Name = "BoundCell"; + css::table::CellAddress aCellAddress; + aCellValue.Value <<= aCellAddress; + + css::beans::NamedValue aCellRange; + aCellRange.Name = "CellRange"; + css::table::CellRangeAddress aRangeAddress; + aCellRange.Value <<= aRangeAddress; + + Sequence< Any > aArgs{ Any(aCellValue), Any(aCellRange) }; + + if ( xBindable.is() ) + { + Reference< form::binding::XValueBinding > xBinding( xFac->createInstanceWithArguments( "com.sun.star.table.CellValueBinding", aArgs ), UNO_QUERY ); + xBindable->setValueBinding( xBinding ); + } + if ( xListEntrySink.is() ) + { + Reference< form::binding::XListEntrySource > xSource( xFac->createInstanceWithArguments( "com.sun.star.table.CellRangeListSource", aArgs ), UNO_QUERY ); + xListEntrySink->setListEntrySource( xSource ); + } +} +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/dlgedpage.cxx b/basctl/source/dlged/dlgedpage.cxx new file mode 100644 index 0000000000..760f885276 --- /dev/null +++ b/basctl/source/dlged/dlgedpage.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 <dlgedpage.hxx> +#include <dlged.hxx> +#include <dlgedmod.hxx> +#include <dlgedobj.hxx> + +namespace basctl +{ + + +DlgEdPage::DlgEdPage(DlgEdModel& rModel, bool bMasterPage) +: SdrPage(rModel, bMasterPage) + ,pDlgEdForm(nullptr) +{ +} + +DlgEdPage::~DlgEdPage() +{ + // clear SdrObjects with broadcasting + ClearSdrObjList(); +} + +rtl::Reference<SdrPage> DlgEdPage::CloneSdrPage(SdrModel& rTargetModel) const +{ + DlgEdModel& rDlgEdModel(static_cast< DlgEdModel& >(rTargetModel)); + rtl::Reference<DlgEdPage> pClonedDlgEdPage = + new DlgEdPage( + rDlgEdModel, + IsMasterPage()); + pClonedDlgEdPage->SdrPage::lateInit(*this); + return pClonedDlgEdPage; +} + + +SdrObject* DlgEdPage::SetObjectOrdNum(size_t nOldObjNum, size_t nNewObjNum) +{ + SdrObject* pObj = SdrPage::SetObjectOrdNum( nOldObjNum, nNewObjNum ); + + DlgEdHint aHint( DlgEdHint::OBJORDERCHANGED ); + if ( pDlgEdForm ) + pDlgEdForm->GetDlgEditor().Broadcast( aHint ); + + return pObj; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/dlgedview.cxx b/basctl/source/dlged/dlgedview.cxx new file mode 100644 index 0000000000..81271d38f8 --- /dev/null +++ b/basctl/source/dlged/dlgedview.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 <dlgedview.hxx> +#include <dlged.hxx> +#include <dlgedpage.hxx> + +#include <svtools/scrolladaptor.hxx> +#include <vcl/canvastools.hxx> + +#include <dlgedobj.hxx> + +namespace basctl +{ + +DlgEdView::DlgEdView( + SdrModel& rSdrModel, + OutputDevice& rOut, + DlgEditor& rEditor) +: SdrView(rSdrModel, &rOut), + rDlgEditor(rEditor) +{ + SetBufferedOutputAllowed(true); + SetBufferedOverlayAllowed(true); +} + +DlgEdView::~DlgEdView() +{ +} + +void DlgEdView::MarkListHasChanged() +{ + SdrView::MarkListHasChanged(); + + DlgEdHint aHint( DlgEdHint::SELECTIONCHANGED ); + rDlgEditor.Broadcast( aHint ); + rDlgEditor.UpdatePropertyBrowserDelayed(); +} + +void DlgEdView::MakeVisible( const tools::Rectangle& rRect, vcl::Window& rWin ) +{ + // visible area + MapMode aMap( rWin.GetMapMode() ); + Point aOrg( aMap.GetOrigin() ); + Size aVisSize( rWin.GetOutDev()->GetOutputSize() ); + tools::Rectangle RectTmp( Point(-aOrg.X(),-aOrg.Y()), aVisSize ); + tools::Rectangle aVisRect( RectTmp ); + + // check, if rectangle is inside visible area + if ( aVisRect.Contains( rRect ) ) + return; + + // calculate scroll distance; the rectangle must be inside the visible area + sal_Int32 nScrollX = 0, nScrollY = 0; + + sal_Int32 nVisLeft = aVisRect.Left(); + sal_Int32 nVisRight = aVisRect.Right(); + sal_Int32 nVisTop = aVisRect.Top(); + sal_Int32 nVisBottom = aVisRect.Bottom(); + + sal_Int32 nDeltaX = rDlgEditor.GetHScroll()->GetLineSize(); + sal_Int32 nDeltaY = rDlgEditor.GetVScroll()->GetLineSize(); + + while ( rRect.Right() > nVisRight + nScrollX ) + nScrollX += nDeltaX; + + while ( rRect.Left() < nVisLeft + nScrollX ) + nScrollX -= nDeltaX; + + while ( rRect.Bottom() > nVisBottom + nScrollY ) + nScrollY += nDeltaY; + + while ( rRect.Top() < nVisTop + nScrollY ) + nScrollY -= nDeltaY; + + // don't scroll beyond the page size + Size aPageSize = rDlgEditor.GetPage().GetSize(); + sal_Int32 nPageWidth = aPageSize.Width(); + sal_Int32 nPageHeight = aPageSize.Height(); + + if ( nVisRight + nScrollX > nPageWidth ) + nScrollX = nPageWidth - nVisRight; + + if ( nVisLeft + nScrollX < 0 ) + nScrollX = -nVisLeft; + + if ( nVisBottom + nScrollY > nPageHeight ) + nScrollY = nPageHeight - nVisBottom; + + if ( nVisTop + nScrollY < 0 ) + nScrollY = -nVisTop; + + // scroll window + rWin.PaintImmediately(); + rWin.Scroll( -nScrollX, -nScrollY ); + aMap.SetOrigin( Point( aOrg.X() - nScrollX, aOrg.Y() - nScrollY ) ); + rWin.SetMapMode( aMap ); + rWin.Invalidate(); + + // update scroll bars + rDlgEditor.UpdateScrollBars(); + + DlgEdHint aHint( DlgEdHint::WINDOWSCROLLED ); + rDlgEditor.Broadcast( aHint ); +} + +static SdrObject* impLocalHitCorrection(SdrObject* pRetval, const Point& rPnt, sal_uInt16 nTol) +{ + DlgEdObj* pDlgEdObj = dynamic_cast< DlgEdObj* >(pRetval); + + if(pDlgEdObj) + { + bool bExcludeInner(false); + + if(dynamic_cast< DlgEdForm* >(pRetval) != nullptr) + { + // from DlgEdForm::CheckHit; exclude inner for DlgEdForm + bExcludeInner = true; + } + else if(pDlgEdObj->supportsService("com.sun.star.awt.UnoControlGroupBoxModel")) + { + // from DlgEdObj::CheckHit; exclude inner for group shapes + bExcludeInner = true; + } + + if(bExcludeInner) + { + // use direct model data; it's a DlgEdObj, so GetLastBoundRect() + // will access aOutRect directly + const tools::Rectangle aOuterRectangle(pDlgEdObj->GetLastBoundRect()); + + if(!aOuterRectangle.IsEmpty()) + { + basegfx::B2DRange aOuterRange = vcl::unotools::b2DRectangleFromRectangle(aOuterRectangle); + + if(nTol) + { + aOuterRange.grow(-1.0 * nTol); + } + + if(aOuterRange.isInside(basegfx::B2DPoint(rPnt.X(), rPnt.Y()))) + { + pRetval = nullptr; + } + } + } + } + + return pRetval; +} + +SdrObject* DlgEdView::CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const +{ + // call parent + SdrObject* pRetval = SdrView::CheckSingleSdrObjectHit(rPnt, nTol, pObj, pPV, nOptions, pMVisLay); + + if(pRetval) + { + // check hit object locally + pRetval = impLocalHitCorrection(pRetval, rPnt, nTol); + } + + return pRetval; +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/managelang.cxx b/basctl/source/dlged/managelang.cxx new file mode 100644 index 0000000000..69f366ed66 --- /dev/null +++ b/basctl/source/dlged/managelang.cxx @@ -0,0 +1,318 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <basidesh.hxx> +#include <basobj.hxx> +#include <iderdll.hxx> +#include <iderid.hxx> +#include <localizationmgr.hxx> +#include <managelang.hxx> + +#include <strings.hrc> + +#include <comphelper/sequence.hxx> +#include <sfx2/bindings.hxx> +#include <sfx2/sfxsids.hrc> +#include <svtools/langtab.hxx> +#include <svx/langbox.hxx> +#include <utility> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <vcl/settings.hxx> +#include <tools/debug.hxx> + +namespace basctl +{ + +using namespace ::com::sun::star::i18n; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::resource; +using namespace ::com::sun::star::uno; + +bool localesAreEqual( const Locale& rLocaleLeft, const Locale& rLocaleRight ) +{ + bool bRet = ( rLocaleLeft.Language == rLocaleRight.Language && + rLocaleLeft.Country == rLocaleRight.Country && + rLocaleLeft.Variant == rLocaleRight.Variant ); + return bRet; +} + +ManageLanguageDialog::ManageLanguageDialog(weld::Window* pParent, std::shared_ptr<LocalizationMgr> xLMgr) + : GenericDialogController(pParent, "modules/BasicIDE/ui/managelanguages.ui", "ManageLanguagesDialog") + , m_xLocalizationMgr(std::move(xLMgr)) + , m_sDefLangStr(IDEResId(RID_STR_DEF_LANG)) + , m_sCreateLangStr(IDEResId(RID_STR_CREATE_LANG)) + , m_xLanguageLB(m_xBuilder->weld_tree_view("treeview")) + , m_xAddPB(m_xBuilder->weld_button("add")) + , m_xDeletePB(m_xBuilder->weld_button("delete")) + , m_xMakeDefPB(m_xBuilder->weld_button("default")) +{ + m_xLanguageLB->set_size_request(m_xLanguageLB->get_approximate_digit_width() * 42, + m_xLanguageLB->get_height_rows(10)); + + Init(); + FillLanguageBox(); + SelectHdl( *m_xLanguageLB ); +} + +ManageLanguageDialog::~ManageLanguageDialog() +{ + ClearLanguageBox(); +} + +void ManageLanguageDialog::Init() +{ + // get current IDE + Shell* pShell = GetShell(); + const OUString& sLibName = pShell->GetCurLibName(); + // set dialog title with library name + OUString sText = m_xDialog->get_title(); + sText = sText.replaceAll("$1", sLibName); + m_xDialog->set_title(sText); + // set handler + m_xAddPB->connect_clicked( LINK( this, ManageLanguageDialog, AddHdl ) ); + m_xDeletePB->connect_clicked( LINK( this, ManageLanguageDialog, DeleteHdl ) ); + m_xMakeDefPB->connect_clicked( LINK( this, ManageLanguageDialog, MakeDefHdl ) ); + m_xLanguageLB->connect_changed( LINK( this, ManageLanguageDialog, SelectHdl ) ); + + m_xLanguageLB->set_selection_mode(SelectionMode::Multiple); +} + +void ManageLanguageDialog::FillLanguageBox() +{ + DBG_ASSERT( m_xLocalizationMgr, "ManageLanguageDialog::FillLanguageBox(): no localization manager" ); + + if ( m_xLocalizationMgr->isLibraryLocalized() ) + { + Locale aDefaultLocale = m_xLocalizationMgr->getStringResourceManager()->getDefaultLocale(); + Sequence< Locale > aLocaleSeq = m_xLocalizationMgr->getStringResourceManager()->getLocales(); + const Locale* pLocale = aLocaleSeq.getConstArray(); + sal_Int32 i, nCount = aLocaleSeq.getLength(); + for ( i = 0; i < nCount; ++i ) + { + bool bIsDefault = localesAreEqual( aDefaultLocale, pLocale[i] ); + LanguageType eLangType = LanguageTag::convertToLanguageType( pLocale[i] ); + OUString sLanguage = SvtLanguageTable::GetLanguageString( eLangType ); + if ( bIsDefault ) + { + sLanguage += " " + m_sDefLangStr; + } + LanguageEntry* pEntry = new LanguageEntry(pLocale[i], bIsDefault); + m_xLanguageLB->append(weld::toId(pEntry), sLanguage); + } + } + else + m_xLanguageLB->append_text(m_sCreateLangStr); +} + +void ManageLanguageDialog::ClearLanguageBox() +{ + const sal_Int32 nCount = m_xLanguageLB->n_children(); + for (sal_Int32 i = 0; i < nCount; ++i) + { + LanguageEntry* pEntry = weld::fromId<LanguageEntry*>(m_xLanguageLB->get_id(i)); + delete pEntry; + } + m_xLanguageLB->clear(); +} + +IMPL_LINK_NOARG(ManageLanguageDialog, AddHdl, weld::Button&, void) +{ + auto xDlg = std::make_shared<SetDefaultLanguageDialog>(m_xDialog.get(), m_xLocalizationMgr); + weld::DialogController::runAsync(xDlg, [xDlg,this](sal_Int32 nResult) + { + if (!nResult ) + return; + // add new locales + Sequence< Locale > aLocaleSeq = xDlg->GetLocales(); + m_xLocalizationMgr->handleAddLocales( aLocaleSeq ); + // update listbox + ClearLanguageBox(); + FillLanguageBox(); + + if (SfxBindings* pBindings = GetBindingsPtr()) + pBindings->Invalidate( SID_BASICIDE_CURRENT_LANG ); + }); +} + +IMPL_LINK_NOARG(ManageLanguageDialog, DeleteHdl, weld::Button&, void) +{ + std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xDialog.get(), "modules/BasicIDE/ui/deletelangdialog.ui")); + std::unique_ptr<weld::MessageDialog> xQBox(xBuilder->weld_message_dialog("DeleteLangDialog")); + if (xQBox->run() != RET_OK) + return; + + std::vector<int> aSelection = m_xLanguageLB->get_selected_rows(); + int nCount = aSelection.size(); + int nPos = m_xLanguageLB->get_selected_index(); + // remove locales + Sequence< Locale > aLocaleSeq( nCount ); + auto aLocaleSeqRange = asNonConstRange(aLocaleSeq); + for (int i = 0; i < nCount; ++i) + { + const sal_Int32 nSelPos = aSelection[i]; + LanguageEntry* pEntry = weld::fromId<LanguageEntry*>(m_xLanguageLB->get_id(nSelPos)); + if ( pEntry ) + aLocaleSeqRange[i] = pEntry->m_aLocale; + } + m_xLocalizationMgr->handleRemoveLocales( aLocaleSeq ); + // update listbox + ClearLanguageBox(); + FillLanguageBox(); + // reset selection + nCount = m_xLanguageLB->n_children(); + if (nCount <= nPos) + nPos = nCount - 1; + m_xLanguageLB->select(nPos); + SelectHdl( *m_xLanguageLB ); +} + +IMPL_LINK_NOARG(ManageLanguageDialog, MakeDefHdl, weld::Button&, void) +{ + const sal_Int32 nPos = m_xLanguageLB->get_selected_index(); + LanguageEntry* pSelectEntry = weld::fromId<LanguageEntry*>(m_xLanguageLB->get_id(nPos)); + if (pSelectEntry && !pSelectEntry->m_bIsDefault) + { + // set new default entry + m_xLocalizationMgr->handleSetDefaultLocale( pSelectEntry->m_aLocale ); + // update Listbox + ClearLanguageBox(); + FillLanguageBox(); + // reset selection + m_xLanguageLB->select(nPos); + SelectHdl( *m_xLanguageLB ); + } +} + +IMPL_LINK_NOARG(ManageLanguageDialog, SelectHdl, weld::TreeView&, void) +{ + const sal_Int32 nCount = m_xLanguageLB->n_children(); + bool bEmpty = ( !nCount || + m_xLanguageLB->find_text(m_sCreateLangStr) != -1 ); + bool bSelect = ( m_xLanguageLB->get_selected_index() != -1 ); + bool bEnable = !bEmpty && bSelect; + + m_xDeletePB->set_sensitive(bEnable); + m_xMakeDefPB->set_sensitive(bEnable && nCount > 1 && m_xLanguageLB->count_selected_rows() == 1); +} + +// class SetDefaultLanguageDialog ----------------------------------------------- + +SetDefaultLanguageDialog::SetDefaultLanguageDialog(weld::Window* pParent, std::shared_ptr<LocalizationMgr> xLMgr) + : GenericDialogController(pParent, "modules/BasicIDE/ui/defaultlanguage.ui", "DefaultLanguageDialog") + , m_xLocalizationMgr(std::move(xLMgr)) + , m_xLanguageFT(m_xBuilder->weld_label("defaultlabel")) + , m_xLanguageLB(m_xBuilder->weld_tree_view("entries")) + , m_xCheckLangFT(m_xBuilder->weld_label("checkedlabel")) + , m_xCheckLangLB(m_xBuilder->weld_tree_view("checkedentries")) + , m_xDefinedFT(m_xBuilder->weld_label("defined")) + , m_xAddedFT(m_xBuilder->weld_label("added")) + , m_xAltTitle(m_xBuilder->weld_label("alttitle")) + , m_xLanguageCB(new SvxLanguageBox(m_xBuilder->weld_combo_box("hidden"))) +{ + m_xLanguageLB->set_size_request(-1, m_xLanguageLB->get_height_rows(10)); + m_xCheckLangLB->set_size_request(-1, m_xCheckLangLB->get_height_rows(10)); + m_xCheckLangLB->enable_toggle_buttons(weld::ColumnToggleType::Check); + + if (m_xLocalizationMgr->isLibraryLocalized()) + { + // change to "Add Interface Language" mode + m_xLanguageLB->hide(); + m_xCheckLangLB->show(); + m_xDialog->set_title(m_xAltTitle->get_label()); + m_xLanguageFT->hide(); + m_xCheckLangFT->show(); + m_xDefinedFT->hide(); + m_xAddedFT->show(); + } + + FillLanguageBox(); +} + +SetDefaultLanguageDialog::~SetDefaultLanguageDialog() +{ +} + +void SetDefaultLanguageDialog::FillLanguageBox() +{ + // fill list with all languages + m_xLanguageCB->SetLanguageList(SvxLanguageListFlags::ALL, false); + + if (m_xLocalizationMgr->isLibraryLocalized()) + { + // remove the already localized languages + Sequence< Locale > aLocaleSeq = m_xLocalizationMgr->getStringResourceManager()->getLocales(); + const Locale* pLocale = aLocaleSeq.getConstArray(); + const sal_Int32 nCountLoc = aLocaleSeq.getLength(); + for ( sal_Int32 i = 0; i < nCountLoc; ++i ) + m_xLanguageCB->remove_id(LanguageTag::convertToLanguageType(pLocale[i])); + + // fill checklistbox if not in default mode + const sal_Int32 nCountLang = m_xLanguageCB->get_count(); + for (sal_Int32 j = 0; j < nCountLang; ++j) + { + LanguageType eLang = m_xLanguageCB->get_id(j); + m_xCheckLangLB->append(); + const int nRow = m_xCheckLangLB->n_children() - 1; + m_xCheckLangLB->set_toggle(nRow, TRISTATE_FALSE); + m_xCheckLangLB->set_text(nRow, m_xLanguageCB->get_text(j), 0); + m_xCheckLangLB->set_id(nRow, OUString::number(eLang.get())); + } + m_xLanguageCB.reset(); + m_xLanguageLB.reset(); + } + else + { + const sal_Int32 nCountLang = m_xLanguageCB->get_count(); + for (sal_Int32 j = 0; j < nCountLang; ++j) + { + LanguageType eLang = m_xLanguageCB->get_id(j); + m_xLanguageLB->append(OUString::number(eLang.get()), m_xLanguageCB->get_text(j)); + } + m_xLanguageCB.reset(); + + // preselect current UI language + m_xLanguageLB->select_id(OUString::number(Application::GetSettings().GetUILanguageTag().getLanguageType().get())); + } +} + +Sequence< Locale > SetDefaultLanguageDialog::GetLocales() const +{ + bool bNotLocalized = !m_xLocalizationMgr->isLibraryLocalized(); + if (bNotLocalized) + { + LanguageType eType(m_xLanguageLB->get_selected_id().toUInt32()); + return {LanguageTag(eType).getLocale()}; + } + std::vector<Locale> aLocaleSeq; + const sal_Int32 nCount = m_xCheckLangLB->n_children(); + for (sal_Int32 i = 0; i < nCount; ++i) + { + if (m_xCheckLangLB->get_toggle(i) == TRISTATE_TRUE) + { + LanguageType eType(m_xCheckLangLB->get_id(i).toUInt32()); + aLocaleSeq.push_back(LanguageTag::convertToLocale(eType)); + } + } + return comphelper::containerToSequence(aLocaleSeq); +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/dlged/propbrw.cxx b/basctl/source/dlged/propbrw.cxx new file mode 100644 index 0000000000..bb45d5f13e --- /dev/null +++ b/basctl/source/dlged/propbrw.cxx @@ -0,0 +1,506 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <propbrw.hxx> +#include <basidesh.hxx> +#include <dlgedobj.hxx> +#include <iderid.hxx> +#include <baside3.hxx> +#include <strings.hrc> + +#include <strings.hxx> + +#include <com/sun/star/frame/Frame.hpp> +#include <com/sun/star/inspection/XObjectInspector.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <comphelper/types.hxx> +#include <comphelper/processfactory.hxx> +#include <cppuhelper/component_context.hxx> +#include <tools/debug.hxx> +#include <svx/svditer.hxx> +#include <svx/svdview.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <vcl/layout.hxx> +#include <vcl/stdtext.hxx> +#include <vcl/weld.hxx> + +#include <memory> + +namespace basctl +{ + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::frame; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::comphelper; + + +void PropBrw::Update( const SfxViewShell* pShell ) +{ + Shell const* pIdeShell = dynamic_cast<Shell const*>(pShell); + OSL_ENSURE( pIdeShell || !pShell, "PropBrw::Update: invalid shell!" ); + if (pIdeShell) + ImplUpdate(pIdeShell->GetCurrentDocument(), pIdeShell->GetCurDlgView()); + else if (pShell) + ImplUpdate(nullptr, pShell->GetDrawView()); + else + ImplUpdate(nullptr, nullptr); +} + + +namespace +{ + +const tools::Long STD_WIN_SIZE_X = 300; +const tools::Long STD_WIN_SIZE_Y = 350; + +const tools::Long STD_MIN_SIZE_X = 250; +const tools::Long STD_MIN_SIZE_Y = 250; + +const tools::Long WIN_BORDER = 2; + +} // namespace + +PropBrw::PropBrw (DialogWindowLayout& rLayout_): + DockingWindow(&rLayout_), + m_xContentArea(VclPtr<VclVBox>::Create(this)), + m_bInitialStateChange(true), + m_xContextDocument(SfxViewShell::Current() ? SfxViewShell::Current()->GetCurrentDocument() : Reference<XModel>()), + pView(nullptr) +{ + Size aPropWinSize(STD_WIN_SIZE_X,STD_WIN_SIZE_Y); + SetMinOutputSizePixel(Size(STD_MIN_SIZE_X,STD_MIN_SIZE_Y)); + SetOutputSizePixel(aPropWinSize); + + // turn off WB_CLIPCHILDREN otherwise the bg won't extend "under" + // transparent children of the widget + m_xContentArea->SetControlBackground(m_xContentArea->GetSettings().GetStyleSettings().GetWindowColor()); + m_xContentArea->SetBackground(m_xContentArea->GetControlBackground()); + m_xContentArea->SetStyle(m_xContentArea->GetStyle() & ~WB_CLIPCHILDREN); + m_xContentArea->Show(); + + try + { + // create a frame wrapper for myself + m_xMeAsFrame = frame::Frame::create( comphelper::getProcessComponentContext() ); + m_xMeAsFrame->initialize(VCLUnoHelper::GetInterface(m_xContentArea)); + m_xMeAsFrame->setName( "form property browser" ); // change name! + } + catch (const Exception&) + { + OSL_FAIL("PropBrw::PropBrw: could not create/initialize my frame!"); + m_xMeAsFrame.clear(); + } + + ImplReCreateController(); +} + + +void PropBrw::ImplReCreateController() +{ + OSL_PRECOND( m_xMeAsFrame.is(), "PropBrw::ImplCreateController: no frame for myself!" ); + if ( !m_xMeAsFrame.is() ) + return; + + if ( m_xBrowserController.is() ) + ImplDestroyController(); + + try + { + Reference< XComponentContext > xOwnContext = comphelper::getProcessComponentContext(); + + // a ComponentContext for the + ::cppu::ContextEntry_Init aHandlerContextInfo[] = + { + ::cppu::ContextEntry_Init( "DialogParentWindow", Any(VCLUnoHelper::GetInterface(this))), + ::cppu::ContextEntry_Init( "ContextDocument", Any( m_xContextDocument ) ) + }; + Reference< XComponentContext > xInspectorContext( + ::cppu::createComponentContext( aHandlerContextInfo, std::size( aHandlerContextInfo ), xOwnContext ) ); + + // create a property browser controller + Reference< XMultiComponentFactory > xFactory( xInspectorContext->getServiceManager(), UNO_SET_THROW ); + static constexpr OUString s_sControllerServiceName = u"com.sun.star.awt.PropertyBrowserController"_ustr; + m_xBrowserController.set( xFactory->createInstanceWithContext( s_sControllerServiceName, xInspectorContext ), UNO_QUERY ); + if ( !m_xBrowserController.is() ) + { + vcl::Window* pWin = GetParent(); + ShowServiceNotAvailableError(pWin ? pWin->GetFrameWeld() : nullptr, s_sControllerServiceName, true); + } + else + { + Reference< XController > xAsXController( m_xBrowserController, UNO_QUERY ); + DBG_ASSERT(xAsXController.is(), "PropBrw::PropBrw: invalid controller object!"); + if (!xAsXController.is()) + { + ::comphelper::disposeComponent(m_xBrowserController); + m_xBrowserController.clear(); + } + else + { + xAsXController->attachFrame( Reference<XFrame>(m_xMeAsFrame,UNO_QUERY_THROW) ); + } + } + + Point aPropWinPos( WIN_BORDER, WIN_BORDER ); + Size aPropWinSize(STD_WIN_SIZE_X,STD_WIN_SIZE_Y); + aPropWinSize.AdjustWidth( -(2*WIN_BORDER) ); + aPropWinSize.AdjustHeight( -(2*WIN_BORDER) ); + + VclContainer::setLayoutAllocation(*m_xContentArea, aPropWinPos, aPropWinSize); + m_xContentArea->Show(); + } + catch (const Exception&) + { + OSL_FAIL("PropBrw::PropBrw: could not create/initialize the browser controller!"); + try + { + ::comphelper::disposeComponent(m_xBrowserController); + } + catch(const Exception&) + { + } + + m_xBrowserController.clear(); + } + Resize(); +} + +PropBrw::~PropBrw() +{ + disposeOnce(); +} + +void PropBrw::dispose() +{ + if ( m_xBrowserController.is() ) + ImplDestroyController(); + m_xContentArea.disposeAndClear(); + DockingWindow::dispose(); +} + + +void PropBrw::ImplDestroyController() +{ + implSetNewObject( Reference< XPropertySet >() ); + + if ( m_xMeAsFrame.is() ) + m_xMeAsFrame->setComponent( nullptr, nullptr ); + + Reference< XController > xAsXController( m_xBrowserController, UNO_QUERY ); + if ( xAsXController.is() ) + xAsXController->attachFrame( nullptr ); + + try + { + ::comphelper::disposeComponent( m_xBrowserController ); + } + catch( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl"); + } + + m_xBrowserController.clear(); +} + +bool PropBrw::Close() +{ + ImplDestroyController(); + + return DockingWindow::Close(); +} + +Sequence< Reference< XInterface > > + PropBrw::CreateMultiSelectionSequence( const SdrMarkList& _rMarkList ) +{ + Sequence< Reference< XInterface > > aSeq; + InterfaceArray aInterfaces; + + const size_t nMarkCount = _rMarkList.GetMarkCount(); + for( size_t i = 0 ; i < nMarkCount ; ++i ) + { + SdrObject* pCurrent = _rMarkList.GetMark(i)->GetMarkedSdrObj(); + + std::optional<SdrObjListIter> oGroupIterator; + if (pCurrent->IsGroupObject()) + { + oGroupIterator.emplace(pCurrent->GetSubList()); + pCurrent = oGroupIterator->IsMore() ? oGroupIterator->Next() : nullptr; + } + + while (pCurrent) + { + if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(pCurrent)) + { + Reference< XInterface > xControlInterface(pDlgEdObj->GetUnoControlModel(), UNO_QUERY); + if (xControlInterface.is()) + aInterfaces.push_back(xControlInterface); + } + + // next element + pCurrent = oGroupIterator && oGroupIterator->IsMore() ? oGroupIterator->Next() : nullptr; + } + } + + sal_Int32 nCount = aInterfaces.size(); + aSeq.realloc( nCount ); + Reference< XInterface >* pInterfaces = aSeq.getArray(); + for( sal_Int32 i = 0 ; i < nCount ; i++ ) + pInterfaces[i] = aInterfaces[i]; + + return aSeq; +} + + +void PropBrw::implSetNewObjectSequence + ( const Sequence< Reference< XInterface > >& _rObjectSeq ) +{ + Reference< inspection::XObjectInspector > xObjectInspector(m_xBrowserController, UNO_QUERY); + if ( xObjectInspector.is() ) + { + xObjectInspector->inspect( _rObjectSeq ); + + OUString aText = IDEResId(RID_STR_BRWTITLE_PROPERTIES) + + IDEResId(RID_STR_BRWTITLE_MULTISELECT); + SetText( aText ); + } +} + + +void PropBrw::implSetNewObject( const Reference< XPropertySet >& _rxObject ) +{ + if ( m_xBrowserController.is() ) + { + m_xBrowserController->setPropertyValue( "IntrospectedObject", + Any( _rxObject ) + ); + + // set the new title according to the selected object + SetText( GetHeadlineName( _rxObject ) ); + } +} + + +OUString PropBrw::GetHeadlineName( const Reference< XPropertySet >& _rxObject ) +{ + OUString aName; + Reference< lang::XServiceInfo > xServiceInfo( _rxObject, UNO_QUERY ); + + if (xServiceInfo.is()) // single selection + { + OUString sResId; + aName = IDEResId(RID_STR_BRWTITLE_PROPERTIES); + + if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlDialogModel" ) ) + { + sResId = RID_STR_CLASS_DIALOG; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlButtonModel" ) ) + { + sResId = RID_STR_CLASS_BUTTON; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlRadioButtonModel" ) ) + { + sResId = RID_STR_CLASS_RADIOBUTTON; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlCheckBoxModel" ) ) + { + sResId = RID_STR_CLASS_CHECKBOX; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlListBoxModel" ) ) + { + sResId = RID_STR_CLASS_LISTBOX; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlComboBoxModel" ) ) + { + sResId = RID_STR_CLASS_COMBOBOX; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlGroupBoxModel" ) ) + { + sResId = RID_STR_CLASS_GROUPBOX; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlEditModel" ) ) + { + sResId = RID_STR_CLASS_EDIT; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFixedTextModel" ) ) + { + sResId = RID_STR_CLASS_FIXEDTEXT; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlImageControlModel" ) ) + { + sResId = RID_STR_CLASS_IMAGECONTROL; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlProgressBarModel" ) ) + { + sResId = RID_STR_CLASS_PROGRESSBAR; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlScrollBarModel" ) ) + { + sResId = RID_STR_CLASS_SCROLLBAR; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFixedLineModel" ) ) + { + sResId = RID_STR_CLASS_FIXEDLINE; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlDateFieldModel" ) ) + { + sResId = RID_STR_CLASS_DATEFIELD; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlTimeFieldModel" ) ) + { + sResId = RID_STR_CLASS_TIMEFIELD; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlNumericFieldModel" ) ) + { + sResId = RID_STR_CLASS_NUMERICFIELD; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlCurrencyFieldModel" ) ) + { + sResId = RID_STR_CLASS_CURRENCYFIELD; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFormattedFieldModel" ) ) + { + sResId = RID_STR_CLASS_FORMATTEDFIELD; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlPatternFieldModel" ) ) + { + sResId = RID_STR_CLASS_PATTERNFIELD; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFileControlModel" ) ) + { + sResId = RID_STR_CLASS_FILECONTROL; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.tree.TreeControlModel" ) ) + { + sResId = RID_STR_CLASS_TREECONTROL; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.grid.UnoControlGridModel" ) ) + { + sResId = RID_STR_CLASS_GRIDCONTROL; + } + else if ( xServiceInfo->supportsService( "com.sun.star.awt.UnoControlFixedHyperlinkModel" ) ) + { + sResId = RID_STR_CLASS_HYPERLINKCONTROL; + } + else + { + sResId = RID_STR_CLASS_CONTROL; + } + + if (!sResId.isEmpty()) + { + aName += sResId; + } + } + else if (!_rxObject.is()) // no properties + { + aName = IDEResId(RID_STR_BRWTITLE_NO_PROPERTIES); + } + + return aName; +} + +void PropBrw::ImplUpdate( const Reference< XModel >& _rxContextDocument, SdrView* pNewView ) +{ + Reference< XModel > xContextDocument( _rxContextDocument ); + + // if we should simply "empty" ourself, assume the context document didn't change + if ( !pNewView ) + { + OSL_ENSURE( !_rxContextDocument.is(), "PropBrw::ImplUpdate: no view, but a document?!" ); + xContextDocument = m_xContextDocument; + } + + if ( xContextDocument != m_xContextDocument ) + { + m_xContextDocument = xContextDocument; + ImplReCreateController(); + } + + try + { + if ( pView ) + { + EndListening(pView->GetModel()); + pView = nullptr; + } + + if ( !pNewView ) + return; + + pView = pNewView; + + // set focus on initialization + if ( m_bInitialStateChange ) + { + m_xContentArea->GrabFocus(); + m_bInitialStateChange = false; + } + + const SdrMarkList& rMarkList = pView->GetMarkedObjectList(); + const size_t nMarkCount = rMarkList.GetMarkCount(); + + if ( nMarkCount == 0 ) + { + EndListening(pView->GetModel()); + pView = nullptr; + implSetNewObject( nullptr ); + return; + } + + Reference< XPropertySet > xNewObject; + Sequence< Reference< XInterface > > aNewObjects; + if ( nMarkCount == 1 ) + { + if (DlgEdObj* pDlgEdObj = dynamic_cast<DlgEdObj*>(rMarkList.GetMark(0)->GetMarkedSdrObj())) + { + if ( pDlgEdObj->IsGroupObject() ) // group object + aNewObjects = CreateMultiSelectionSequence( rMarkList ); + else // single selection + xNewObject.set(pDlgEdObj->GetUnoControlModel(), css::uno::UNO_QUERY); + } + } + else if ( nMarkCount > 1 ) // multiple selection + { + aNewObjects = CreateMultiSelectionSequence( rMarkList ); + } + + if ( aNewObjects.hasElements() ) + implSetNewObjectSequence( aNewObjects ); + else + implSetNewObject( xNewObject ); + + StartListening(pView->GetModel()); + } + catch ( const PropertyVetoException& ) { /* silence */ } + catch ( const Exception& ) + { + DBG_UNHANDLED_EXCEPTION("basctl"); + } +} + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/IDEComboBox.hxx b/basctl/source/inc/IDEComboBox.hxx new file mode 100644 index 0000000000..a5e7008a42 --- /dev/null +++ b/basctl/source/inc/IDEComboBox.hxx @@ -0,0 +1,271 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <svl/stritem.hxx> +#include <sfx2/tbxctrl.hxx> +#include <vcl/InterimItemWindow.hxx> + +#include "doceventnotifier.hxx" +#include "scriptdocument.hxx" + +namespace basctl +{ +/*! + * @brief Manage states of macro and dialog Library ComboBox + * + * @see LibBox Class + */ +class LibBoxControl : public SfxToolBoxControl +{ +public: + /*! + * Macro for registering two methods + * + * @code + * static SfxToolBoxControl* CreateImpl(sal_uInt16 nSlotId, sal_uInt16 nId, ToolBox& rTbx) + * static void RegisterControl(sal_uInt16 nSlotId = 0, SfxModule* pMod=nullptr) + * @endcode + * @see Macro SFX_IMPL_TOOLBOX_CONTROL + */ + SFX_DECL_TOOLBOX_CONTROL(); + + /*! + * @param nSlotId -- the slot as internal operation number + * @param nId -- this item's unique id in ToolBox + * @param rTbx -- the ToolBox which contains this ComboBox + */ + LibBoxControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx); + + /*! + * Triggered if state was changed + * + * @param nSlotID -- the slot as internal operation number (not used in this place) + * @param eState -- enum value which contains ComboBox state + * @param pState -- + */ + virtual void StateChangedAtToolBoxControl(sal_uInt16 nSlotID, SfxItemState eState, + const SfxPoolItem* pState) override; + /*! + * Create combobox of Macro and Dialog Library + * + * @param pParent -- parent window + * @return ComboBox of macro and dialog Library + */ + virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override; +}; + +/*! + * @brief Base class for all ComboBox elements. + * + * Base class for ComboBoxes which need to update their content according + * to the list of open documents. + */ +class DocListenerBox : public InterimItemWindow, public DocumentEventListener +{ +private: + DECL_LINK(SelectHdl, weld::ComboBox&, void); + DECL_LINK(KeyInputHdl, const KeyEvent&, bool); + +protected: + std::unique_ptr<weld::ComboBox> m_xWidget; + + /// @param pParent -- parent window + DocListenerBox(vcl::Window* pParent); + virtual ~DocListenerBox() override; + virtual void dispose() override; + + virtual void Select() = 0; + virtual void FillBox() = 0; + + /// key strokes the ComboBox receives + virtual bool HandleKeyInput(const KeyEvent& rKEvt); + +private: + // DocumentEventListener + virtual void onDocumentCreated(const ScriptDocument& _rDoc) override; + virtual void onDocumentOpened(const ScriptDocument& _rDoc) override; + virtual void onDocumentSave(const ScriptDocument& _rDoc) override; + virtual void onDocumentSaveDone(const ScriptDocument& _rDoc) override; + virtual void onDocumentSaveAs(const ScriptDocument& _rDoc) override; + virtual void onDocumentSaveAsDone(const ScriptDocument& _rDoc) override; + virtual void onDocumentClosed(const ScriptDocument& _rDoc) override; + virtual void onDocumentTitleChanged(const ScriptDocument& _rDoc) override; + virtual void onDocumentModeChanged(const ScriptDocument& _rDoc) override; + + DocumentEventNotifier maNotifier; + +public: + void set_sensitive(bool bSensitive); +}; + +/*! + * @brief Macros and Dialogs Library ComboBox + * + * @see LibBoxControl Class + */ +class LibBox : public DocListenerBox +{ +public: + /// @param pParent + LibBox(vcl::Window* pParent); + virtual ~LibBox() override; + virtual void dispose() override; + + /*! + * Update selection in ComboBox of macro and dialog Library + * + * @param pItem -- string that was selected + */ + void Update(const SfxStringItem* pItem); + +protected: + /// Called for setting language when user selects a language in ComboBox + virtual void Select() override; + +private: + static void ReleaseFocus(); + + /*! + * Insert name library in specified position + * + * @param rDocument -- macro or dialog + * @param eLocation -- enum value of Locations + */ + void InsertEntries(const ScriptDocument& rDocument, LibraryLocation eLocation); + + void ClearBox(); + void NotifyIDE(); + + /// Fill up the combobox + virtual void FillBox() override; + + /*! + * Handle keystrokes + * + * @param rKEvt represents key event + * @return a bool value: true if was handled, and false if there was nothing handled + */ + virtual bool HandleKeyInput(const KeyEvent& rKEvt) override; + + DECL_LINK(FocusInHdl, weld::Widget&, void); + DECL_LINK(FocusOutHdl, weld::Widget&, void); + + OUString maCurrentText; + bool mbIgnoreSelect; + bool mbFillBox; ///< If true, when FillBox() is called +}; + +/*! + * @brief Manage stats of Language ComboBox + * + * @see LanguageBox Class + */ +class LanguageBoxControl : public SfxToolBoxControl +{ +public: + /*! Macro for registering two methods + * + * @code + * static SfxToolBoxControl* CreateImpl(sal_uInt16 nSlotId, sal_uInt16 nId, ToolBox& rTbx) + * static void RegisterControl(sal_uInt16 nSlotId = 0, SfxModule* pMod=nullptr) + * @endcode + * @see Macro SFX_IMPL_TOOLBOX_CONTROL + */ + SFX_DECL_TOOLBOX_CONTROL(); + + /*! + * @param nSlotId -- the slot as internal operation number + * @param nId -- this item's unique id in ToolBox + * @param rTbx -- the ToolBox which contains this ComboBox + */ + LanguageBoxControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx); + + /*! + * Triggered if state was changed + * + * @param nSlotID -- the slot as internal operation number (not used in this place) + * @param eState -- enum value which contains ComboBox state + * @param pState -- + */ + virtual void StateChangedAtToolBoxControl(sal_uInt16 nSID, SfxItemState eState, + const SfxPoolItem* pState) override; + /*! + * Create ComboBox of Language + * + * @param pParent + * @return LanguageBox ComboBox + */ + virtual VclPtr<InterimItemWindow> CreateItemWindow(vcl::Window* pParent) override; +}; + +/*! + * @brief Class language ComboBox + * + * @see LanguageBoxControl Class + */ +class LanguageBox : public DocListenerBox +{ +public: + /*! + * @param pParent + */ + LanguageBox(vcl::Window* pParent); + virtual ~LanguageBox() override; + virtual void dispose() override; + + /*! + * Update selection in ComboBox of macro and dialog Library + * + * @param pItem -- string that was selected + */ + void Update(const SfxStringItem* pItem); + +protected: + /// Called for setting language when user selects a language in ComboBox + virtual void Select() override; + + /*! + * Handle keystrokes + * + * @param rKEvt represents key event + * @return a bool value: true if was handled, and false if there was nothing handled + */ + virtual bool HandleKeyInput(const KeyEvent& rKEvt) override; + +private: + /// Delete all languages from ComboBox + void ClearBox(); + /// Switch interface of dialog to selected language + void SetLanguage(); + + /// Fill up the language combobox + virtual void FillBox() override; + + OUString msNotLocalizedStr; + OUString msDefaultLanguageStr; + OUString msCurrentText; + + bool mbIgnoreSelect; ///< do not use in this class +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/ObjectCatalog.hxx b/basctl/source/inc/ObjectCatalog.hxx new file mode 100644 index 0000000000..a5b63eef42 --- /dev/null +++ b/basctl/source/inc/ObjectCatalog.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 "bastype2.hxx" +#include "bastypes.hxx" + +#include <vcl/weld.hxx> + +namespace basctl +{ +/*! + * @brief A docking window that contains a tree of the currently loaded macros + * + * The class creates Object Catalog window with the currently loaded macros + * in a tree structure which allows user to quickly select the necessary + * macro in BasicIDE. + */ +class ObjectCatalog : public DockingWindow +{ +public: + explicit ObjectCatalog(vcl::Window* pParent); + virtual ~ObjectCatalog() override; + virtual void dispose() override; + + /// Update the entries of Object Catalog Treelist + void UpdateEntries() { m_xTree->UpdateEntries(); } + void SetCurrentEntry(BaseWindow* pCurWin); + +private: + std::unique_ptr<weld::Label> m_xTitle; ///< Title of the Object Catalog window + std::unique_ptr<SbTreeListBox> m_xTree; ///< The Treelist of the objects in window + + /*! + * Function for resize by DockingWindow. + * It is called by DockingWindow when IsFloatingMode() changes. + */ + virtual void ToggleFloatingMode() override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/accessibledialogcontrolshape.hxx b/basctl/source/inc/accessibledialogcontrolshape.hxx new file mode 100644 index 0000000000..3af6e3da90 --- /dev/null +++ b/basctl/source/inc/accessibledialogcontrolshape.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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <comphelper/accessiblecomponenthelper.hxx> +#include <cppuhelper/implbase.hxx> +#include <vcl/vclptr.hxx> + +namespace vcl { class Window; } + +namespace basctl +{ + +class DlgEdObj; +class DialogWindow; + + + +class AccessibleDialogControlShape final : public cppu::ImplInheritanceHelper< + comphelper::OAccessibleExtendedComponentHelper, + css::accessibility::XAccessible, + css::lang::XServiceInfo, + css::beans::XPropertyChangeListener> +{ + friend class AccessibleDialogWindow; + +private: + VclPtr<DialogWindow> m_pDialogWindow; + DlgEdObj* m_pDlgEdObj; + bool m_bFocused; + bool m_bSelected; + + css::awt::Rectangle m_aBounds; + css::uno::Reference< css::beans::XPropertySet > m_xControlModel; + + bool IsFocused() const; + bool IsSelected() const; + + void SetFocused (bool bFocused); + void SetSelected (bool bSelected); + + css::awt::Rectangle GetBounds() const; + void SetBounds( const css::awt::Rectangle& aBounds ); + + vcl::Window* GetWindow() const; + + OUString GetModelStringProperty( OUString const & pPropertyName ); + + void FillAccessibleStateSet( sal_Int64& rStateSet ); + + // OCommonAccessibleComponent + virtual css::awt::Rectangle implGetBounds() override; + + // XComponent + virtual void SAL_CALL disposing() override; + +public: + AccessibleDialogControlShape (DialogWindow*, DlgEdObj*); + virtual ~AccessibleDialogControlShape() override; + + // XEventListener + virtual void SAL_CALL disposing( const css::lang::EventObject& rSource ) override; + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& rEvent ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int64 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 i ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override; + virtual sal_Int64 SAL_CALL getAccessibleIndexInParent( ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole( ) override; + virtual OUString SAL_CALL getAccessibleDescription( ) override; + virtual OUString SAL_CALL getAccessibleName( ) override; + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override; + virtual sal_Int64 SAL_CALL getAccessibleStateSet( ) override; + virtual css::lang::Locale SAL_CALL getLocale( ) override; + + // XAccessibleComponent + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + virtual void SAL_CALL grabFocus( ) override; + virtual sal_Int32 SAL_CALL getForeground( ) override; + virtual sal_Int32 SAL_CALL getBackground( ) override; + + // XAccessibleExtendedComponent + virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont( ) override; + virtual OUString SAL_CALL getTitledBorderText( ) override; + virtual OUString SAL_CALL getToolTipText( ) override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/accessibledialogwindow.hxx b/basctl/source/inc/accessibledialogwindow.hxx new file mode 100644 index 0000000000..0332b98a41 --- /dev/null +++ b/basctl/source/inc/accessibledialogwindow.hxx @@ -0,0 +1,143 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <comphelper/accessiblecomponenthelper.hxx> +#include <cppuhelper/implbase.hxx> +#include <svl/lstner.hxx> +#include <tools/link.hxx> +#include <vcl/vclptr.hxx> + +class VclSimpleEvent; +class VclWindowEvent; + +namespace basctl +{ + +class DialogWindow; +class DlgEditor; +class DlgEdModel; +class DlgEdObj; +class AccessibleDialogControlShape; + + +class AccessibleDialogWindow final : public cppu::ImplInheritanceHelper< + comphelper::OAccessibleExtendedComponentHelper, + css::accessibility::XAccessible, + css::accessibility::XAccessibleSelection, + css::lang::XServiceInfo>, + public SfxListener +{ +private: + + class ChildDescriptor + { + public: + DlgEdObj* pDlgEdObj; + rtl::Reference< AccessibleDialogControlShape > mxAccessible; + + ChildDescriptor( DlgEdObj* _pDlgEdObj ); + + bool operator==( const ChildDescriptor& rDesc ); + bool operator<( const ChildDescriptor& rDesc ) const; + }; + + typedef std::vector< ChildDescriptor > AccessibleChildren; + + AccessibleChildren m_aAccessibleChildren; + VclPtr<basctl::DialogWindow> m_pDialogWindow; + DlgEdModel* m_pDlgEdModel; + + void UpdateFocused(); + void UpdateSelected(); + void UpdateBounds(); + + bool IsChildVisible( const ChildDescriptor& rDesc ); + + void InsertChild( const ChildDescriptor& rDesc ); + void RemoveChild( const ChildDescriptor& rDesc ); + void UpdateChild( const ChildDescriptor& rDesc ); + void UpdateChildren(); + void SortChildren(); + + DECL_LINK( WindowEventListener, VclWindowEvent&, void ); + + void ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent ); + void FillAccessibleStateSet( sal_Int64& rStateSet ); + + // OCommonAccessibleComponent + virtual css::awt::Rectangle implGetBounds( ) override; + + // XComponent + virtual void SAL_CALL disposing() override; + +public: + AccessibleDialogWindow (basctl::DialogWindow*); + virtual ~AccessibleDialogWindow() override; + + // SfxListener + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& rServiceName ) override; + virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XAccessible + virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override; + + // XAccessibleContext + virtual sal_Int64 SAL_CALL getAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int64 i ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override; + virtual sal_Int64 SAL_CALL getAccessibleIndexInParent( ) override; + virtual sal_Int16 SAL_CALL getAccessibleRole( ) override; + virtual OUString SAL_CALL getAccessibleDescription( ) override; + virtual OUString SAL_CALL getAccessibleName( ) override; + virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override; + virtual sal_Int64 SAL_CALL getAccessibleStateSet( ) override; + virtual css::lang::Locale SAL_CALL getLocale( ) override; + + // XAccessibleComponent + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override; + virtual void SAL_CALL grabFocus( ) override; + virtual sal_Int32 SAL_CALL getForeground( ) override; + virtual sal_Int32 SAL_CALL getBackground( ) override; + + // XAccessibleExtendedComponent + virtual css::uno::Reference< css::awt::XFont > SAL_CALL getFont( ) override; + virtual OUString SAL_CALL getTitledBorderText( ) override; + virtual OUString SAL_CALL getToolTipText( ) override; + + // XAccessibleSelection + virtual void SAL_CALL selectAccessibleChild( sal_Int64 nChildIndex ) override; + virtual sal_Bool SAL_CALL isAccessibleChildSelected( sal_Int64 nChildIndex ) override; + virtual void SAL_CALL clearAccessibleSelection() override; + virtual void SAL_CALL selectAllAccessibleChildren( ) override; + virtual sal_Int64 SAL_CALL getSelectedAccessibleChildCount( ) override; + virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( sal_Int64 nSelectedChildIndex ) override; + virtual void SAL_CALL deselectAccessibleChild( sal_Int64 nChildIndex ) override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/baside3.hxx b/basctl/source/inc/baside3.hxx new file mode 100644 index 0000000000..14fc68f079 --- /dev/null +++ b/basctl/source/inc/baside3.hxx @@ -0,0 +1,154 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "dlged.hxx" +#include "layout.hxx" +#include "bastypes.hxx" +#include "propbrw.hxx" +#include <svl/undo.hxx> +#include <memory> + +class Printer; +class StarBASIC; +class SfxItemSet; +class SfxUndoManager; +class SdrUndoAction; + +namespace basctl +{ + +class DlgEditor; +class DlgEdModel; +class DlgEdPage; +class DlgEdView; + +class DialogWindowLayout; +class ObjectCatalog; + +bool implImportDialog(weld::Window* pWin, const ScriptDocument& rDocument, const OUString& rLibName); + +class DialogWindow: public BaseWindow +{ +private: + DialogWindowLayout& m_rLayout; + std::unique_ptr<DlgEditor> m_pEditor; + std::unique_ptr<SfxUndoManager> m_pUndoMgr; // never nullptr + sal_uInt16 m_nControlSlotId; + +protected: + virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override; + virtual void Resize() override; + virtual void dispose() override; + + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void MouseButtonUp( const MouseEvent& rMEvt ) override; + virtual void MouseMove( const MouseEvent& rMEvt ) override; + virtual void KeyInput( const KeyEvent& rKEvt ) override; + virtual void Command( const CommandEvent& rCEvt ) override; + virtual void LoseFocus() override; + + static void NotifyUndoActionHdl( std::unique_ptr<SdrUndoAction> ); + virtual void DoInit() override; + virtual void DoScroll( Scrollable* pCurScrollBar ) override; + virtual void DataChanged( const DataChangedEvent& rDCEvt ) override; + void InitSettings(); + +public: + DialogWindow (DialogWindowLayout* pParent, ScriptDocument const& rDocument, const OUString& aLibName, const OUString& aName, css::uno::Reference<css::container::XNameContainer> const& xDialogModel); + + virtual void ExecuteCommand( SfxRequest& rReq ) override; + virtual void GetState( SfxItemSet& ) override; + DlgEditor& GetEditor() const { return *m_pEditor; } + css::uno::Reference< css::container::XNameContainer > const & GetDialog() const; + DlgEdModel& GetModel() const; + DlgEdPage& GetPage() const; + DlgEdView& GetView() const; + bool RenameDialog( const OUString& rNewName ); + void DisableBrowser(); + void UpdateBrowser(); + void SaveDialog(); + void ImportDialog(); + + virtual OUString GetTitle() override; + virtual EntryDescriptor CreateEntryDescriptor() override; + virtual void SetReadOnly (bool bReadOnly) override; + virtual bool IsReadOnly() override; + + virtual void StoreData() override; + virtual bool IsModified() override; + bool IsPasteAllowed(); + + virtual SfxUndoManager* GetUndoManager() override; + // return number of pages to be printed + virtual sal_Int32 countPages( Printer* pPrinter ) override; + // print page + virtual void printPage (sal_Int32 nPage, Printer*) override; + + virtual void Activating () override; + virtual void Deactivating () override; + + virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override; + + virtual OUString GetHid () const override; + virtual ItemType GetType () const override; +}; + + +// DialogWindowLayout + +class DialogWindowLayout : public Layout +{ +public: + DialogWindowLayout (vcl::Window* pParent, ObjectCatalog&); + virtual ~DialogWindowLayout() override; + virtual void dispose() override; +public: + void ShowPropertyBrowser (); + void UpdatePropertyBrowser (); + void DisablePropertyBrowser (); +public: + // Layout: + virtual void Activating (BaseWindow&) override; + virtual void Deactivating () override; + virtual void ExecuteGlobal (SfxRequest&) override; + virtual void GetState (SfxItemSet&, unsigned nWhich) override; + virtual void UpdateDebug (bool) override {}; +protected: + // Layout: + virtual void OnFirstSize (tools::Long nWidth, tools::Long nHeight) override; + +private: + // dockable windows: + // object catalog (owned by Shell) + ObjectCatalog& rObjectCatalog; + // property browser (created by this, deleted by toolkit) + VclPtr<PropBrw> pPropertyBrowser; + +private: + void AddPropertyBrowser (); +private: + friend class DialogWindow; +}; + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/basidectrlr.hxx b/basctl/source/inc/basidectrlr.hxx new file mode 100644 index 0000000000..a32e1ffd94 --- /dev/null +++ b/basctl/source/inc/basidectrlr.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 <comphelper/broadcasthelper.hxx> +#include <comphelper/propertycontainer.hxx> +#include <comphelper/proparrhlp.hxx> +#include <sfx2/sfxbasecontroller.hxx> + +namespace basctl +{ + +class Shell; + +class Controller : + public comphelper::OMutexAndBroadcastHelper, + public comphelper::OPropertyContainer, + public comphelper::OPropertyArrayUsageHelper<Controller>, + public SfxBaseController +{ +private: + // properties + sal_Int32 m_nIconId; + +public: + Controller (Shell* pViewShell); + virtual ~Controller() override; + + // XInterface + virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override; + virtual void SAL_CALL acquire() noexcept override; + virtual void SAL_CALL release() noexcept override; + + // XTypeProvider ( ::SfxBaseController ) + virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override; + virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + + // XPropertySet + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override; + + // OPropertySetHelper + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + +protected: + // OPropertyArrayUsageHelper + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/basidesh.hxx b/basctl/source/inc/basidesh.hxx new file mode 100644 index 0000000000..f907abe6f2 --- /dev/null +++ b/basctl/source/inc/basidesh.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 "doceventnotifier.hxx" +#include "sbxitem.hxx" +#include "ObjectCatalog.hxx" + +#include <com/sun/star/container/XContainerListener.hpp> +#include <sfx2/viewsh.hxx> +#include <svx/ifaceids.hxx> +#include <svl/srchitem.hxx> +#include <svtools/scrolladaptor.hxx> +#include <map> +#include <memory> +#include <string_view> + +class SfxViewFactory; +class SdrView; +class TabBar; +class SbxObject; +class SbModule; +class StarBASIC; + +namespace basctl +{ + +// Used to control zoom level +constexpr sal_uInt16 MIN_ZOOM_LEVEL = 50; +constexpr sal_uInt16 DEFAULT_ZOOM_LEVEL = 100; +constexpr sal_uInt16 MAX_ZOOM_LEVEL = 400; + +class Layout; +class ModulWindow; +class ModulWindowLayout; +class DialogWindow; +class DialogWindowLayout; +class TabBar; +class BaseWindow; +class LocalizationMgr; + +class Shell : + public SfxViewShell, + public DocumentEventListener +{ +public: + typedef std::map<sal_uInt16, VclPtr<BaseWindow> > WindowTable; + +private: + friend class JavaDebuggingListenerImpl; + friend class LocalizationMgr; + friend bool implImportDialog(weld::Window* pWin, const ScriptDocument& rDocument, const OUString& rLibName); // defined in baside3.cxx + + WindowTable aWindowTable; + sal_uInt16 nCurKey; + VclPtr<BaseWindow> pCurWin; + ScriptDocument m_aCurDocument; + OUString m_aCurLibName; + std::shared_ptr<LocalizationMgr> m_pCurLocalizationMgr; + + // Current value of the zoom slider + sal_uInt16 m_nCurrentZoomSliderValue; + VclPtr<ScrollAdaptor> aHScrollBar; + VclPtr<ScrollAdaptor> aVScrollBar; + VclPtr<TabBar> pTabBar; // basctl::TabBar + bool bCreatingWindow; + + // layout windows + VclPtr<ModulWindowLayout> pModulLayout; + VclPtr<DialogWindowLayout> pDialogLayout; + VclPtr<Layout> pLayout; // the active layout window + // common object catalog window + VclPtr<ObjectCatalog> aObjectCatalog; + + bool m_bAppBasicModified; + bool mbJustOpened = false; + + DocumentEventNotifier m_aNotifier; + + friend class ContainerListenerImpl; + css::uno::Reference< css::container::XContainerListener > m_xLibListener; + std::unique_ptr<SvxSearchItem> mpSearchItem; + + void Init(); + void InitTabBar(); + void InitScrollBars(); + void InitZoomLevel(); + void CheckWindows(); + void RemoveWindows( const ScriptDocument& rDocument, std::u16string_view rLibName ); + void UpdateWindows(); + static void InvalidateBasicIDESlots(); + void StoreAllWindowData( bool bPersistent = true ); + void SetMDITitle(); + void SetCurLib( const ScriptDocument& rDocument, const OUString& aLibName, bool bUpdateWindows = true , bool bCheck = true ); + void SetCurLibForLocalization( const ScriptDocument& rDocument, const OUString& aLibName ); + + DECL_LINK( TabBarHdl, ::TabBar*, void ); + + static unsigned nShellCount; + +private: + void AdjustPosSizePixel( const Point &rPos, const Size &rSize ); + virtual void OuterResizePixel( const Point &rPos, const Size &rSize ) override; + sal_uInt16 InsertWindowInTable (BaseWindow* pNewWin); + virtual bool PrepareClose( bool bUI = true ) override; + + void SetCurWindow (BaseWindow* pNewWin, bool bUpdateTabBar = false, bool bRememberAsCurrent = true); + void ManageToolbars(); + + VclPtr<ModulWindow> CreateBasWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName ); + VclPtr<DialogWindow> CreateDlgWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rDlgName ); + + VclPtr<ModulWindow> ShowActiveModuleWindow( StarBASIC const * pBasic ); + + virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override; + + virtual void Activate(bool bMDI) override; + virtual void Deactivate(bool bMDI) override; + + virtual void Move() override; + virtual void ShowCursor( bool bOn = true ) override; + + // DocumentEventListener + virtual void onDocumentCreated( const ScriptDocument& _rDocument ) override; + virtual void onDocumentOpened( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSave( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveDone( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveAs( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveAsDone( const ScriptDocument& _rDocument ) override; + virtual void onDocumentClosed( const ScriptDocument& _rDocument ) override; + virtual void onDocumentTitleChanged( const ScriptDocument& _rDocument ) override; + virtual void onDocumentModeChanged( const ScriptDocument& _rDocument ) override; + +public: + SFX_DECL_INTERFACE( SVX_INTERFACE_BASIDE_VIEWSH ) + SFX_DECL_VIEWFACTORY(Shell); + +private: + /// SfxInterface initializer. + static void InitInterface_Impl(); + +public: + Shell(SfxViewFrame& rFrame, SfxViewShell *pOldSh); + virtual ~Shell() override; + + BaseWindow* GetCurWindow() const { return pCurWin; } + OUString const& GetCurLibName() const { return m_aCurLibName; } + const std::shared_ptr<LocalizationMgr>& GetCurLocalizationMgr() const { return m_pCurLocalizationMgr; } + + TabBar& GetTabBar() { return *pTabBar; } + WindowTable& GetWindowTable() { return aWindowTable; } + sal_uInt16 GetWindowId (BaseWindow const* pWin) const; + + SdrView* GetCurDlgView() const; + + SfxUndoManager* GetUndoManager() override; + + void SetGlobalEditorZoomLevel(sal_uInt16 nNewZoomLevel); + sal_uInt16 GetCurrentZoomSliderValue() { return m_nCurrentZoomSliderValue; } + static sal_uInt16 GetMinZoom() { return MIN_ZOOM_LEVEL; } + static sal_uInt16 GetMaxZoom() { return MAX_ZOOM_LEVEL; } + + virtual css::uno::Reference< css::view::XRenderable > GetRenderable() override; + + // virtual sal_uInt16 Print( SfxProgress &rProgress, sal_Bool bIsAPI, PrintDialog *pPrintDialog = 0 ); + virtual SfxPrinter* GetPrinter( bool bCreate = false ) override; + virtual sal_uInt16 SetPrinter( SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL ) override; + virtual OUString GetSelectionText( bool bCompleteWords = false, bool bOnlyASample = false ) override; + virtual bool HasSelection( bool bText = true ) const override; + + void GetState( SfxItemSet& ); + void ExecuteGlobal( SfxRequest& rReq ); + void ExecuteSearch( SfxRequest& rReq ); + void ExecuteCurrent( SfxRequest& rReq ); + void ExecuteBasic( SfxRequest& rReq ); + void ExecuteDialog( SfxRequest& rReq ); + + virtual bool HasUIFeature(SfxShellFeature nFeature) const override; + + bool CallBasicErrorHdl( StarBASIC const * pBasic ); + BasicDebugFlags CallBasicBreakHdl( StarBASIC const * pBasic ); + + VclPtr<BaseWindow> FindWindow( const ScriptDocument& rDocument, std::u16string_view rLibName, std::u16string_view rName, ItemType nType, bool bFindSuspended = false ); + VclPtr<DialogWindow> FindDlgWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rName, bool bCreateIfNotExist = false, bool bFindSuspended = false ); + VclPtr<ModulWindow> FindBasWin( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName, bool bCreateIfNotExist = false, bool bFindSuspended = false ); + VclPtr<BaseWindow> FindApplicationWindow(); + bool NextPage( bool bPrev ); + + bool IsAppBasicModified () const { return m_bAppBasicModified; } + void SetAppBasicModified (bool bModified) { m_bAppBasicModified = bModified; } + + // For Dialog Drag&Drop in Dialog Organizer: + // (defined in moduldlg.cxx) + static void CopyDialogResources( + css::uno::Reference< css::io::XInputStreamProvider >& io_xISP, + const ScriptDocument& rSourceDoc, const OUString& rSourceLibName, const ScriptDocument& rDestDoc, + const OUString& rDestLibName, std::u16string_view rDlgName ); + + static void InvalidateControlSlots(); + + virtual css::uno::Reference< css::frame::XModel > + GetCurrentDocument() const override; + + void UpdateObjectCatalog () { aObjectCatalog->UpdateEntries(); } + + void RemoveWindow (BaseWindow* pWindow, bool bDestroy, bool bAllowChangeCurWindow = true); +}; + +} // namespace basctl + +// This typedef helps baside.sdi, +// because I don't know how to use nested names in it. +typedef basctl::Shell basctl_Shell; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/basobj.hxx b/basctl/source/inc/basobj.hxx new file mode 100644 index 0000000000..70c603d454 --- /dev/null +++ b/basctl/source/inc/basobj.hxx @@ -0,0 +1,105 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "scriptdocument.hxx" +#include <tools/long.hxx> + +class SbMethod; +class SbModule; +class SbxVariable; +class StarBASIC; +class SfxUInt16Item; +class SfxBindings; +class SfxDispatcher; +namespace weld { class Widget; class Window; } + +namespace basctl +{ + void Organize(weld::Window* pParent, const css::uno::Reference<css::frame::XFrame>& xDocFrame, sal_Int16 tabId); + + // help methods for the general use: + SbMethod* CreateMacro( SbModule* pModule, const OUString& rMacroName ); + void RunMethod( SbMethod const * pMethod ); + + StarBASIC* FindBasic( const SbxVariable* pVar ); + void StopBasic(); + tools::Long HandleBasicError( StarBASIC const * pBasic ); + void BasicStopped( bool* pbAppWindowDisabled = nullptr, bool* pbDispatcherLocked = nullptr, sal_uInt16* pnWaitCount = nullptr, + SfxUInt16Item** ppSWActionCount = nullptr, SfxUInt16Item** ppSWLockViewCount = nullptr ); + + bool IsValidSbxName( std::u16string_view rName ); + + BasicManager* FindBasicManager( StarBASIC const * pLib ); + + SfxBindings* GetBindingsPtr(); + + SfxDispatcher* GetDispatcher (); + + void InvalidateDebuggerSlots(); + + // libraries + + css::uno::Sequence< OUString > GetMergedLibraryNames( + const css::uno::Reference< css::script::XLibraryContainer >& xModLibContainer, + const css::uno::Reference< css::script::XLibraryContainer >& xDlgLibContainer ); + + /** renames a module + + Will show an error message when renaming fails because the new name is already used. + */ + bool RenameModule( + weld::Widget* pErrorParent, const ScriptDocument& rDocument, + const OUString& rLibName, const OUString& rOldName, const OUString& rNewName ); + + // new methods for macros + + OUString ChooseMacro(weld::Window* pParent, + const css::uno::Reference< css::frame::XModel >& rxLimitToDocument, const css::uno::Reference< css::frame::XFrame >& xDocFrame, + bool bChooseOnly ); + inline OUString ChooseMacro(weld::Window* pParent, const css::uno::Reference<css::frame::XModel>& rLimitToDocument) + { return ChooseMacro(pParent, rLimitToDocument, css::uno::Reference< css::frame::XFrame >(), false/*bChooseOnly*/); } + + /// @throws css::container::NoSuchElementException + /// @throws css::uno::RuntimeException + css::uno::Sequence< OUString > GetMethodNames( + const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName ); + + bool HasMethod( + const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rModName, const OUString& rMethName ); + + // new methods for dialogs + + /** renames a dialog + + Will show an error message when renaming fails because the new name is already used. + + @throws css::container::ElementExistException + @throws css::container::NoSuchElementException + @throws css::uno::RuntimeException + */ + bool RenameDialog(weld::Widget* pErrorParent, const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rOldName, const OUString& rNewName); + + bool RemoveDialog( const ScriptDocument& rDocument, const OUString& rLibName, const OUString& rDlgName ); + + void MarkDocumentModified( const ScriptDocument& rDocument ); + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/bastype2.hxx b/basctl/source/inc/bastype2.hxx new file mode 100644 index 0000000000..0161797f16 --- /dev/null +++ b/basctl/source/inc/bastype2.hxx @@ -0,0 +1,278 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <memory> + +#include "doceventnotifier.hxx" + +#include <vcl/weld.hxx> +#include "sbxitem.hxx" +#include <o3tl/typed_flags_set.hxx> + +class SbModule; +class SbxVariable; + +enum class BrowseMode +{ + Modules = 0x01, + Subs = 0x02, + Dialogs = 0x04, + All = Modules | Subs | Dialogs, +}; +namespace o3tl { + template<> struct typed_flags<BrowseMode> : is_typed_flags<BrowseMode, 0x7> {}; +} + +namespace basctl +{ +using namespace ::com::sun::star::uno; + +enum EntryType +{ + OBJ_TYPE_UNKNOWN, + OBJ_TYPE_DOCUMENT, + OBJ_TYPE_LIBRARY, + OBJ_TYPE_MODULE, + OBJ_TYPE_DIALOG, + OBJ_TYPE_METHOD, + OBJ_TYPE_DOCUMENT_OBJECTS, + OBJ_TYPE_USERFORMS, + OBJ_TYPE_NORMAL_MODULES, + OBJ_TYPE_CLASS_MODULES +}; + +class Entry +{ +private: + EntryType m_eType; + +public: + explicit Entry(EntryType eType) + : m_eType(eType) + { + } + + virtual ~Entry(); + + Entry(Entry const &) = default; + Entry(Entry &&) = default; + Entry & operator =(Entry const &) = default; + Entry & operator =(Entry &&) = default; + + EntryType GetType () const { return m_eType; } +}; + +class DocumentEntry : public Entry +{ +private: + ScriptDocument m_aDocument; + LibraryLocation m_eLocation; + +public: + DocumentEntry ( + ScriptDocument aDocument, + LibraryLocation eLocation, + EntryType eType = OBJ_TYPE_DOCUMENT + ); + virtual ~DocumentEntry () override; + + ScriptDocument const& GetDocument() const { return m_aDocument; } + LibraryLocation GetLocation() const { return m_eLocation; } +}; + +class LibEntry : public DocumentEntry +{ +private: + OUString m_aLibName; + +public: + LibEntry ( + ScriptDocument const& rDocument, + LibraryLocation eLocation, + OUString aLibName + ); + virtual ~LibEntry () override; + + OUString const& GetLibName () const { return m_aLibName; } +}; + +class EntryDescriptor +{ + ScriptDocument m_aDocument; + LibraryLocation m_eLocation; + OUString m_aLibName; + OUString m_aLibSubName; // for vba entry: Document Objects, Class Modules, Forms and Normal Modules + OUString m_aName; + OUString m_aMethodName; + EntryType m_eType; + +public: + EntryDescriptor (); + EntryDescriptor ( + ScriptDocument aDocument, + LibraryLocation eLocation, + OUString aLibName, + OUString aLibSubName, + OUString aName, + EntryType eType + ); + EntryDescriptor ( + ScriptDocument aDocument, + LibraryLocation eLocation, + OUString aLibName, + OUString aLibSubName, + OUString aName, + OUString aMethodName, + EntryType eType + ); + + ScriptDocument const& GetDocument() const { return m_aDocument; } + LibraryLocation GetLocation() const { return m_eLocation; } + + const OUString& GetLibName() const { return m_aLibName; } + const OUString& GetLibSubName() const { return m_aLibSubName; } + const OUString& GetName() const { return m_aName; } + const OUString& GetMethodName() const { return m_aMethodName; } + void SetMethodName( const OUString& aMethodName ) { m_aMethodName = aMethodName; } + + EntryType GetType() const { return m_eType; } + void SetType( EntryType eType ) { m_eType = eType; } +}; + + +/* + Classification of types and pointers in the Entries: + + OBJ_TYPE_DOCUMENT DocumentEntry + OBJ_TYPE_LIBRARY Entry + OBJ_TYPE_MODULE Entry + OBJ_TYPE_DIALOG Entry + OBJ_TYPE_METHOD Entry + +*/ + +class SbTreeListBox : public DocumentEventListener +{ +private: + std::unique_ptr<weld::TreeView> m_xControl; + std::unique_ptr<weld::TreeIter> m_xScratchIter; + weld::Window* m_pTopLevel; + bool m_bFreezeOnFirstAddRemove; + BrowseMode nMode; + DocumentEventNotifier m_aNotifier; + void SetEntryBitmaps(const weld::TreeIter& rIter, const OUString& rImage); + +protected: + DECL_LINK(RequestingChildrenHdl, const weld::TreeIter&, bool); + DECL_LINK(OpenCurrentHdl, weld::TreeView&, bool); + void ImpCreateLibEntries(const weld::TreeIter& rShellRootEntry, const ScriptDocument& rDocument, LibraryLocation eLocation); + void ImpCreateLibSubEntries(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName); + void ImpCreateLibSubEntriesInVBAMode(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName ); + void ImpCreateLibSubSubEntriesInVBAMode(const weld::TreeIter& rLibRootEntry, const ScriptDocument& rDocument, const OUString& rLibName); + bool ImpFindEntry(weld::TreeIter& rIter, std::u16string_view rText); + + // DocumentEventListener + virtual void onDocumentCreated( const ScriptDocument& _rDocument ) override; + virtual void onDocumentOpened( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSave( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveDone( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveAs( const ScriptDocument& _rDocument ) override; + virtual void onDocumentSaveAsDone( const ScriptDocument& _rDocument ) override; + virtual void onDocumentClosed( const ScriptDocument& _rDocument ) override; + virtual void onDocumentTitleChanged( const ScriptDocument& _rDocument ) override; + virtual void onDocumentModeChanged( const ScriptDocument& _rDocument ) override; + +public: + SbTreeListBox(std::unique_ptr<weld::TreeView> xControl, weld::Window* pTopLevel); + virtual ~SbTreeListBox() override; + + void ScanEntry( const ScriptDocument& rDocument, LibraryLocation eLocation ); + void ScanAllEntries(); + void UpdateEntries(); + + bool IsEntryProtected(const weld::TreeIter* pEntry); + + void SetMode( BrowseMode nM ) { nMode = nM; } + BrowseMode GetMode() const { return nMode; } + + SbModule* FindModule(const weld::TreeIter* pEntry); + SbxVariable* FindVariable(const weld::TreeIter* pEntry); + bool FindRootEntry(const ScriptDocument& rDocument, LibraryLocation eLocation, weld::TreeIter& rIter); + bool FindEntry(std::u16string_view rText, EntryType eType, weld::TreeIter& rIter); + EntryDescriptor GetEntryDescriptor(const weld::TreeIter* pEntry); + + static ItemType ConvertType (EntryType eType); + bool IsValidEntry(const weld::TreeIter& rEntry); + void AddEntry(const OUString& rText, const OUString& rImage, + const weld::TreeIter* pParent, bool bChildrenOnDemand, + std::unique_ptr<Entry>&& rUserData, + weld::TreeIter* pRet = nullptr); + + void connect_changed(const Link<weld::TreeView&, void>& rLink) { m_xControl->connect_changed(rLink); } + std::unique_ptr<weld::TreeIter> make_iterator(const weld::TreeIter* pIter = nullptr) const { return m_xControl->make_iterator(pIter); } + void copy_iterator(const weld::TreeIter& rSource, weld::TreeIter& rDest) const { m_xControl->copy_iterator(rSource, rDest); } + bool get_selected(weld::TreeIter* pIter) const { return m_xControl->get_selected(pIter); } + void select(const weld::TreeIter& rIter) { m_xControl->select(rIter); } + void unselect(const weld::TreeIter& rIter) { m_xControl->unselect(rIter); } + void remove(const weld::TreeIter& rIter) { m_xControl->remove(rIter); } + bool get_cursor(weld::TreeIter* pIter) const { return m_xControl->get_cursor(pIter); } + void set_cursor(const weld::TreeIter& rIter) { m_xControl->set_cursor(rIter); } + OUString get_text(const weld::TreeIter& rIter) const { return m_xControl->get_text(rIter); } + void set_text(const weld::TreeIter& rIter, const OUString& rText) { m_xControl->set_text(rIter, rText); } + OUString get_id(const weld::TreeIter& rIter) const { return m_xControl->get_id(rIter); } + bool get_iter_first(weld::TreeIter& rIter) const { return m_xControl->get_iter_first(rIter); } + bool iter_next_sibling(weld::TreeIter& rIter) const { return m_xControl->iter_next_sibling(rIter); } + bool iter_children(weld::TreeIter& rIter) const { return m_xControl->iter_children(rIter); } + bool iter_parent(weld::TreeIter& rIter) const { return m_xControl->iter_parent(rIter); } + int get_iter_depth(const weld::TreeIter& rIter) const { return m_xControl->get_iter_depth(rIter); } + bool get_row_expanded(const weld::TreeIter& rIter) const { return m_xControl->get_row_expanded(rIter); } + void expand_row(const weld::TreeIter& rIter) { m_xControl->expand_row(rIter); } + void set_size_request(int nWidth, int nHeight) { m_xControl->set_size_request(nWidth, nHeight); } + float get_approximate_digit_width() const { return m_xControl->get_approximate_digit_width(); } + int get_height_rows(int nRows) const { return m_xControl->get_height_rows(nRows); } + int get_iter_index_in_parent(const weld::TreeIter& rIter) const { return m_xControl->get_iter_index_in_parent(rIter); } + void connect_editing(const Link<const weld::TreeIter&, bool>& rStartLink, + const Link<const std::pair<const weld::TreeIter&, OUString>&, bool>& rEndLink) + { + m_xControl->connect_editing(rStartLink, rEndLink); + } + + void make_sorted() { m_xControl->make_sorted(); }; + + void RemoveEntry(const weld::TreeIter& rIter); + void RemoveEntry(const ScriptDocument&); + + OUString GetRootEntryName(const ScriptDocument& rDocument, LibraryLocation eLocation) const; + static OUString GetRootEntryBitmaps(const ScriptDocument& rDocument); + + void SetCurrentEntry (EntryDescriptor const &); + + weld::TreeView& get_widget() { return *m_xControl; } + +private: + LibraryType GetLibraryType() const; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/bastypes.hxx b/basctl/source/inc/bastypes.hxx new file mode 100644 index 0000000000..513fbce3a4 --- /dev/null +++ b/basctl/source/inc/bastypes.hxx @@ -0,0 +1,316 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#pragma once + +#include "scriptdocument.hxx" + +#include "sbxitem.hxx" +#include <svtools/scrolladaptor.hxx> +#include <svtools/tabbar.hxx> +#include <basic/sbdef.hxx> +#include <vcl/dockwin.hxx> +#include <vcl/weld.hxx> + +#include <string_view> +#include <unordered_map> + +class SbModule; +class SfxItemSet; +class SfxRequest; +class SvxSearchItem; +class Printer; +enum class SearchOptionFlags; +class SfxUndoManager; + +namespace weld +{ + class Widget; +} + +namespace basctl +{ + +class Layout; +class ModulWindow; +class DialogWindow; + +constexpr auto LINE_SEP_CR = 0x0D; +constexpr auto LINE_SEP = 0x0A; + +// Implementation: baside2b.cxx +sal_Int32 searchEOL( std::u16string_view rStr, sal_Int32 fromIndex ); + +// Meaning of bToBeKilled: +// While being in a reschedule-loop, I may not destroy the window. +// It must first break from the reschedule-loop to self-destroy then. +// Does unfortunately not work that way: Destroying Window with living Child! + +struct BasicStatus +{ + bool bIsRunning : 1; + bool bError : 1; + bool bIsInReschedule : 1; + BasicDebugFlags nBasicFlags; + + BasicStatus(): + bIsRunning(false), + bError(false), + bIsInReschedule(false), + nBasicFlags(BasicDebugFlags::NONE) { } +}; + + +// basctl::DockingWindow -- special docking window for the Basic IDE +// Not to be confused with ::DockingWindow from vcl. + +class DockingWindow : public ResizableDockingWindow +{ +public: + DockingWindow(vcl::Window* pParent, const OUString& rUIXMLDescription, const OUString& rID); + DockingWindow(Layout* pParent); + virtual ~DockingWindow() override; + virtual void dispose() override; + void ResizeIfDocking (Point const&, Size const&); + void ResizeIfDocking (Size const&); + Size GetDockingSize () const { return aDockingRect.GetSize(); } + void SetLayoutWindow (Layout*); +public: + void Show (bool = true); + void Hide (); + +protected: + virtual bool Docking( const Point& rPos, tools::Rectangle& rRect ) override; + virtual void EndDocking( const tools::Rectangle& rRect, bool bFloatMode ) override; + virtual void ToggleFloatingMode() override; + virtual bool PrepareToggleFloatingMode() override; + virtual void StartDocking() override; + +protected: + std::unique_ptr<weld::Builder> m_xBuilder; + std::unique_ptr<weld::Container> m_xContainer; + +private: + // the position and the size of the floating window + tools::Rectangle aFloatingRect; + // the position and the size of the docking window + tools::Rectangle aDockingRect; + // the parent layout window (only when docking) + VclPtr<Layout> pLayout; + // > 0: shown, <= 0: hidden, ++ by Show() and -- by Hide() + int nShowCount; + + static WinBits const StyleBits; + +private: + void DockThis (); +}; + + +// basctl::TabBar +// Not to be confused with ::TabBar from svtools. + +class TabBar : public ::TabBar +{ +protected: + virtual void MouseButtonDown( const MouseEvent& rMEvt ) override; + virtual void Command( const CommandEvent& rCEvt ) override; + + virtual TabBarAllowRenamingReturnCode AllowRenaming() override; + virtual void EndRenaming() override; + +public: + TabBar (vcl::Window* pParent); + + void Sort(); +}; + +enum BasicWindowStatus +{ + BASWIN_RUNNINGBASIC = 0x01, + BASWIN_TOBEKILLED = 0x02, + BASWIN_SUSPENDED = 0x04, + BASWIN_INRESCHEDULE = 0x08 +}; + +class EntryDescriptor; + + +// BaseWindow -- the base of both ModulWindow and DialogWindow. + +class BaseWindow : public vcl::Window +{ +private: + VclPtr<ScrollAdaptor> pShellHScrollBar; + VclPtr<ScrollAdaptor> pShellVScrollBar; + + DECL_LINK( VertScrollHdl, weld::Scrollbar&, void ); + DECL_LINK( HorzScrollHdl, weld::Scrollbar&, void ); + int nStatus; + + ScriptDocument m_aDocument; + OUString m_aLibName; + OUString m_aName; + + friend class ModulWindow; + friend class DialogWindow; + +protected: + virtual void DoScroll(Scrollable* pCurScrollBar); + +public: + BaseWindow( vcl::Window* pParent, ScriptDocument aDocument, OUString aLibName, OUString aName ); + virtual ~BaseWindow() override; + virtual void dispose() override; + + void Init(); + virtual void DoInit(); + virtual void Activating () = 0; + virtual void Deactivating () = 0; + void GrabScrollBars(ScrollAdaptor* pHScroll, ScrollAdaptor* pVScroll); + + ScrollAdaptor* GetHScrollBar() const { return pShellHScrollBar.get(); } + ScrollAdaptor* GetVScrollBar() const { return pShellVScrollBar.get(); } + void ShowShellScrollBars(bool bVisible = true); + + virtual void ExecuteCommand (SfxRequest&); + virtual void ExecuteGlobal (SfxRequest&); + virtual void GetState (SfxItemSet&) = 0; + virtual bool EventNotify( NotifyEvent& rNEvt ) override; + + virtual void StoreData(); + virtual void UpdateData(); + + // return number of pages to be printed + virtual sal_Int32 countPages( Printer* pPrinter ) = 0; + // print page + virtual void printPage( sal_Int32 nPage, Printer* pPrinter ) = 0; + + virtual OUString GetTitle(); + OUString CreateQualifiedName(); + virtual EntryDescriptor CreateEntryDescriptor() = 0; + + virtual bool IsModified(); + + virtual bool AllowUndo(); + + virtual void SetReadOnly (bool bReadOnly); + virtual bool IsReadOnly(); + void ShowReadOnlyInfoBar(); + + int GetStatus() const { return nStatus; } + void SetStatus(int n) { nStatus = n; } + void AddStatus(int n) { nStatus |= n; } + void ClearStatus(int n) { nStatus &= ~n; } + + virtual SfxUndoManager* GetUndoManager (); + + virtual SearchOptionFlags GetSearchOptions(); + virtual sal_uInt16 StartSearchAndReplace (SvxSearchItem const&, bool bFromStart = false); + + virtual void BasicStarted(); + virtual void BasicStopped(); + + bool IsSuspended() const { return nStatus & BASWIN_SUSPENDED; } + + const ScriptDocument& + GetDocument() const { return m_aDocument; } + bool IsDocument( const ScriptDocument& rDocument ) const { return rDocument == m_aDocument; } + const OUString& GetLibName() const { return m_aLibName; } + + const OUString& GetName() const { return m_aName; } + void SetName( const OUString& aName ) { m_aName = aName; } + + virtual void OnNewDocument (); + virtual OUString GetHid () const = 0; + virtual ItemType GetType () const = 0; + void InsertLibInfo () const; + bool Is (ScriptDocument const&, std::u16string_view, std::u16string_view, ItemType, bool bFindSuspended); + virtual bool HasActiveEditor () const; +}; + +class LibInfo +{ +public: + class Item; +public: + LibInfo (); + ~LibInfo (); +public: + void InsertInfo (ScriptDocument const&, OUString const& rLibName, OUString const& rCurrentName, ItemType eCurrentType); + void RemoveInfoFor (ScriptDocument const&); + Item const* GetInfo (ScriptDocument const&, OUString const& rLibName); + +private: + class Key + { + private: + ScriptDocument m_aDocument; + OUString m_aLibName; + + public: + Key (ScriptDocument , OUString aLibName); + public: + bool operator == (Key const&) const; + struct Hash + { + size_t operator () (Key const&) const; + }; + public: + const ScriptDocument& GetDocument() const { return m_aDocument; } + }; +public: + class Item + { + private: + OUString m_aCurrentName; + ItemType m_eCurrentType; + + public: + Item (OUString aCurrentName, ItemType eCurrentType); + const OUString& GetCurrentName() const { return m_aCurrentName; } + ItemType GetCurrentType() const { return m_eCurrentType; } + }; +private: + typedef std::unordered_map<Key, Item, Key::Hash> Map; + Map m_aMap; +}; + +void CutLines( OUString& rStr, sal_Int32 nStartLine, sal_Int32 nLines ); +OUString CreateMgrAndLibStr( std::u16string_view rMgrName, std::u16string_view rLibName ); +sal_uInt32 CalcLineCount( SvStream& rStream ); + +bool QueryReplaceMacro( std::u16string_view rName, weld::Widget* pParent ); +bool QueryDelMacro( std::u16string_view rName, weld::Widget* pParent ); +bool QueryDelDialog( std::u16string_view rName, weld::Widget* pParent ); +bool QueryDelModule( std::u16string_view rName, weld::Widget* pParent ); +bool QueryDelLib( std::u16string_view rName, bool bRef, weld::Widget* pParent ); +bool QueryPassword(weld::Widget* pDialogParent, const css::uno::Reference< css::script::XLibraryContainer >& xLibContainer, const OUString& rLibName, OUString& rPassword, bool bRepeat = false, bool bNewTitle = false); + +class ModuleInfoHelper +{ + ModuleInfoHelper (const ModuleInfoHelper&) = delete; + ModuleInfoHelper& operator = (const ModuleInfoHelper&) = delete; +public: + static void getObjectName( const css::uno::Reference< css::container::XNameContainer >& rLib, const OUString& rModName, OUString& rObjName ); + static sal_Int32 getModuleType( const css::uno::Reference< css::container::XNameContainer >& rLib, const OUString& rModName ); +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlged.hxx b/basctl/source/inc/dlged.hxx new file mode 100644 index 0000000000..c50faf51b3 --- /dev/null +++ b/basctl/source/inc/dlged.hxx @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/awt/XControlContainer.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/datatransfer/DataFlavor.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/util/XNumberFormatsSupplier.hpp> +#include <o3tl/deleter.hxx> +#include <svl/SfxBroadcaster.hxx> +#include <svl/hint.hxx> +#include <svx/svdobjkind.hxx> +#include <tools/gen.hxx> +#include <vcl/timer.hxx> +#include <vcl/idle.hxx> +#include <vcl/vclptr.hxx> +#include <vcl/window.hxx> + +#include <memory> + +class ScrollAdaptor; +class Printer; +class KeyEvent; +class MouseEvent; +class Timer; +namespace vcl { class Window; } + +namespace basctl +{ + +class DialogWindowLayout; + +constexpr auto DLGED_PAGE_WIDTH_MIN = 1280; +constexpr auto DLGED_PAGE_HEIGHT_MIN = 1024; + +// DlgEdHint + + +class DlgEdObj; + +class DlgEdHint: public SfxHint +{ +public: + enum Kind { + UNKNOWN, + WINDOWSCROLLED, + LAYERCHANGED, + OBJORDERCHANGED, + SELECTIONCHANGED, + }; + +private: + Kind eKind; + DlgEdObj* pDlgEdObj; + +public: + DlgEdHint (Kind); + DlgEdHint (Kind, DlgEdObj* pObj); + virtual ~DlgEdHint() override; + + Kind GetKind() const { return eKind; } + DlgEdObj* GetObject() const { return pDlgEdObj; } +}; + + +// DlgEditor + + +class DlgEdModel; +class DlgEdPage; +class DlgEdView; +class DlgEdForm; +class DlgEdFactory; +class DlgEdFunc; + +class DlgEditor: public SfxBroadcaster +{ +public: + enum Mode { + INSERT, + SELECT, + TEST, + READONLY, + }; + +private: + DECL_LINK(MarkTimeout, Timer *, void); + + static void Print( Printer* pPrinter, const OUString& rTitle ); + +private: + VclPtr<ScrollAdaptor> pHScroll; + VclPtr<ScrollAdaptor> pVScroll; + std::unique_ptr<DlgEdModel> pDlgEdModel; // never nullptr + DlgEdPage* pDlgEdPage; // never nullptr + std::unique_ptr<DlgEdView> pDlgEdView; // never nullptr + rtl::Reference<DlgEdForm> pDlgEdForm; // never nullptr + css::uno::Reference< css::container::XNameContainer > m_xUnoControlDialogModel; + css::uno::Reference< css::awt::XControlContainer > m_xControlContainer; + css::uno::Sequence< css::datatransfer::DataFlavor > m_ClipboardDataFlavors; + css::uno::Sequence< css::datatransfer::DataFlavor > m_ClipboardDataFlavorsResource; + css::uno::Reference< css::util::XNumberFormatsSupplier > m_xSupplier; + std::unique_ptr<DlgEdFactory, o3tl::default_delete<DlgEdFactory>> pObjFac; // never nullptr + vcl::Window& rWindow; // DialogWindow + std::unique_ptr<DlgEdFunc> pFunc; + DialogWindowLayout& rLayout; + Mode eMode; + SdrObjKind eActObj; + bool bFirstDraw; + bool bCreateOK; + tools::Rectangle aPaintRect; + bool bDialogModelChanged; + Idle aMarkIdle; + tools::Long mnPaintGuard; + css::uno::Reference< css::frame::XModel > m_xDocument; + +public: + DlgEditor ( + vcl::Window&, DialogWindowLayout&, + css::uno::Reference<css::frame::XModel> const& xModel, + css::uno::Reference<css::container::XNameContainer> const & xDialogModel + ); + virtual ~DlgEditor() override; + + vcl::Window& GetWindow() const { return rWindow; } + + /** returns the control container associated with our window + @see GetWindow + @see SetWindow + */ + css::uno::Reference< css::awt::XControlContainer > const & + GetWindowControlContainer(); + + void SetScrollBars(ScrollAdaptor* pHScroll, ScrollAdaptor* pVScroll); + void InitScrollBars(); + ScrollAdaptor* GetHScroll() const { return pHScroll; } + ScrollAdaptor* GetVScroll() const { return pVScroll; } + void DoScroll(); + void UpdateScrollBars(); + + void SetDialog (const css::uno::Reference<css::container::XNameContainer>& xUnoControlDialogModel); + void ResetDialog (); + const css::uno::Reference< css::container::XNameContainer >& GetDialog() const + {return m_xUnoControlDialogModel;} + + css::uno::Reference< css::util::XNumberFormatsSupplier > const & GetNumberFormatsSupplier(); + + DlgEdModel& GetModel() const { return *pDlgEdModel; } + DlgEdView& GetView() const { return *pDlgEdView; } + DlgEdPage& GetPage() const { return *pDlgEdPage; } + + void ShowDialog(); + + bool UnmarkDialog(); + bool RemarkDialog(); + + void SetDialogModelChanged() { bDialogModelChanged = true; } + + bool IsModified () const; + void ClearModifyFlag(); + + void MouseButtonDown( const MouseEvent& rMEvt ); + void MouseButtonUp( const MouseEvent& rMEvt ); + void MouseMove( const MouseEvent& rMEvt ); + void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect); + bool KeyInput( const KeyEvent& rKEvt ); + + void SetMode (Mode eMode); + void SetInsertObj(SdrObjKind eObj); + void CreateDefaultObject(); + Mode GetMode() const { return eMode; } + bool IsCreateOK() const { return bCreateOK; } + + void Cut(); + void Copy(); + void Paste(); + void Delete(); + bool IsPasteAllowed(); + + void ShowProperties(); + void UpdatePropertyBrowserDelayed(); + + static void printPage( sal_Int32 nPage, Printer* pPrinter, const OUString& ); + + bool AdjustPageSize(); + + bool isInPaint() const { return mnPaintGuard > 0; } +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlgedclip.hxx b/basctl/source/inc/dlgedclip.hxx new file mode 100644 index 0000000000..0bb7a74161 --- /dev/null +++ b/basctl/source/inc/dlgedclip.hxx @@ -0,0 +1,53 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp> +#include <cppuhelper/implbase.hxx> + +namespace basctl +{ + + +class DlgEdTransferableImpl final : public ::cppu::WeakImplHelper< css::datatransfer::XTransferable, + css::datatransfer::clipboard::XClipboardOwner > +{ +private: + css::uno::Sequence< css::datatransfer::DataFlavor > m_SeqFlavors; + css::uno::Sequence< css::uno::Any > m_SeqData; + + static bool compareDataFlavors( const css::datatransfer::DataFlavor& lFlavor, const css::datatransfer::DataFlavor& rFlavor ); + +public: + DlgEdTransferableImpl( const css::uno::Sequence< css::datatransfer::DataFlavor >& aSeqFlavors, const css::uno::Sequence< css::uno::Any >& aSeqData ); + virtual ~DlgEdTransferableImpl() override; + + // XTransferable + virtual css::uno::Any SAL_CALL getTransferData( const css::datatransfer::DataFlavor& rFlavor ) override; + virtual css::uno::Sequence< css::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors() override; + virtual sal_Bool SAL_CALL isDataFlavorSupported( const css::datatransfer::DataFlavor& rFlavor ) override; + + // XClipboardOwner + virtual void SAL_CALL lostOwnership( const css::uno::Reference< css::datatransfer::clipboard::XClipboard >& xClipboard, const css::uno::Reference< css::datatransfer::XTransferable >& xTrans ) override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlgeddef.hxx b/basctl/source/inc/dlgeddef.hxx new file mode 100644 index 0000000000..c10ef16cd8 --- /dev/null +++ b/basctl/source/inc/dlgeddef.hxx @@ -0,0 +1,47 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <rtl/ustring.hxx> + +namespace basctl +{ + +// control properties +#define DLGED_PROP_BACKGROUNDCOLOR "BackgroundColor" +inline constexpr OUString DLGED_PROP_DROPDOWN = u"Dropdown"_ustr; +inline constexpr OUString DLGED_PROP_FORMATSSUPPLIER = u"FormatsSupplier"_ustr; +inline constexpr OUString DLGED_PROP_HEIGHT = u"Height"_ustr; +inline constexpr OUString DLGED_PROP_LABEL = u"Label"_ustr; +inline constexpr OUString DLGED_PROP_NAME = u"Name"_ustr; +inline constexpr OUString DLGED_PROP_ORIENTATION = u"Orientation"_ustr; +inline constexpr OUString DLGED_PROP_POSITIONX = u"PositionX"_ustr; +inline constexpr OUString DLGED_PROP_POSITIONY = u"PositionY"_ustr; +inline constexpr OUString DLGED_PROP_STEP = u"Step"_ustr; +inline constexpr OUString DLGED_PROP_TABINDEX = u"TabIndex"_ustr; +#define DLGED_PROP_TEXTCOLOR "TextColor" +#define DLGED_PROP_TEXTLINECOLOR "TextLineColor" +inline constexpr OUString DLGED_PROP_WIDTH = u"Width"_ustr; +inline constexpr OUString DLGED_PROP_DECORATION = u"Decoration"_ustr; + + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlgedfac.hxx b/basctl/source/inc/dlgedfac.hxx new file mode 100644 index 0000000000..5e583ada17 --- /dev/null +++ b/basctl/source/inc/dlgedfac.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 <svx/svdobj.hxx> +#include <tools/link.hxx> +#include <com/sun/star/frame/XModel.hpp> + +namespace basctl +{ +// DlgEdFactory + +class DlgEdFactory +{ + const css::uno::Reference<css::frame::XModel> mxModel; + +public: + DlgEdFactory(css::uno::Reference<css::frame::XModel> xModel); + ~DlgEdFactory() COVERITY_NOEXCEPT_FALSE; + + DECL_LINK(MakeObject, SdrObjCreatorParams, rtl::Reference<SdrObject>); +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlgedfunc.hxx b/basctl/source/inc/dlgedfunc.hxx new file mode 100644 index 0000000000..9e20f39015 --- /dev/null +++ b/basctl/source/inc/dlgedfunc.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 <vcl/event.hxx> +#include <vcl/timer.hxx> +#include <tools/link.hxx> +#include <tools/gen.hxx> + +namespace basctl +{ +class DlgEditor; + +// DlgEdFunc + +class DlgEdFunc /* : public LinkHdl */ +{ +protected: + DlgEditor& rParent; + Timer aScrollTimer; + + DECL_LINK(ScrollTimeout, Timer*, void); + void ForceScroll(const Point& rPos); + +public: + explicit DlgEdFunc(DlgEditor& rParent); + virtual ~DlgEdFunc(); + + virtual void MouseButtonDown(const MouseEvent& rMEvt); + virtual bool MouseButtonUp(const MouseEvent& rMEvt); + virtual void MouseMove(const MouseEvent& rMEvt); + bool KeyInput(const KeyEvent& rKEvt); +}; + +// DlgEdFuncInsert + +class DlgEdFuncInsert : public DlgEdFunc +{ +public: + explicit DlgEdFuncInsert(DlgEditor& rParent); + virtual ~DlgEdFuncInsert() override; + + virtual void MouseButtonDown(const MouseEvent& rMEvt) override; + virtual bool MouseButtonUp(const MouseEvent& rMEvt) override; + virtual void MouseMove(const MouseEvent& rMEvt) override; +}; + +// DlgEdFuncSelect + +class DlgEdFuncSelect : public DlgEdFunc +{ +public: + explicit DlgEdFuncSelect(DlgEditor& rParent); + virtual ~DlgEdFuncSelect() override; + + virtual void MouseButtonDown(const MouseEvent& rMEvt) override; + virtual bool MouseButtonUp(const MouseEvent& rMEvt) override; + virtual void MouseMove(const MouseEvent& rMEvt) override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlgedlist.hxx b/basctl/source/inc/dlgedlist.hxx new file mode 100644 index 0000000000..373f38b146 --- /dev/null +++ b/basctl/source/inc/dlgedlist.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 <cppuhelper/implbase.hxx> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/container/XContainerListener.hpp> + +namespace basctl +{ +class DlgEdObj; + +// DlgEdPropListenerImpl + +typedef ::cppu::WeakImplHelper<css::beans::XPropertyChangeListener> PropertyChangeListenerHelper; + +class DlgEdPropListenerImpl : public PropertyChangeListenerHelper +{ +private: + DlgEdObj& rDlgEdObj; + +public: + explicit DlgEdPropListenerImpl(DlgEdObj&); + virtual ~DlgEdPropListenerImpl() override; + + // XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + // XPropertyChangeListener + virtual void SAL_CALL propertyChange(const css::beans::PropertyChangeEvent& evt) override; +}; + +// DlgEdEvtContListenerImpl + +typedef ::cppu::WeakImplHelper<css::container::XContainerListener> ContainerListenerHelper; + +class DlgEdEvtContListenerImpl : public ContainerListenerHelper +{ +private: + DlgEdObj& rDlgEdObj; + +public: + explicit DlgEdEvtContListenerImpl(DlgEdObj&); + virtual ~DlgEdEvtContListenerImpl() override; + + // XEventListener + virtual void SAL_CALL disposing(const css::lang::EventObject& Source) override; + + // XContainerListener + virtual void SAL_CALL elementInserted(const css::container::ContainerEvent& Event) override; + virtual void SAL_CALL elementReplaced(const css::container::ContainerEvent& Event) override; + virtual void SAL_CALL elementRemoved(const css::container::ContainerEvent& Event) override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlgedmod.hxx b/basctl/source/inc/dlgedmod.hxx new file mode 100644 index 0000000000..24a97905b1 --- /dev/null +++ b/basctl/source/inc/dlgedmod.hxx @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <svx/svdmodel.hxx> + +namespace basctl +{ +// DlgEdModel + +class DlgEdModel : public SdrModel +{ + friend class DlgEdPage; + +private: + DlgEdModel(const DlgEdModel&) = delete; + void operator=(const DlgEdModel& rSrcModel) = delete; + +public: + DlgEdModel(); + virtual ~DlgEdModel() override; + + virtual rtl::Reference<SdrPage> AllocPage(bool bMasterPage) override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlgedobj.hxx b/basctl/source/inc/dlgedobj.hxx new file mode 100644 index 0000000000..a8c249adec --- /dev/null +++ b/basctl/source/inc/dlgedobj.hxx @@ -0,0 +1,195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/beans/XPropertyChangeListener.hpp> +#include <com/sun/star/container/XContainerListener.hpp> +#include <svx/svdouno.hxx> + +#include <optional> + +#include <map> + +namespace basctl +{ + +typedef std::multimap< sal_Int16, OUString > IndexToNameMap; + + +class DlgEdForm; +class DlgEditor; + + +// DlgEdObj + + +class DlgEdObj: public SdrUnoObj +{ + friend class DlgEditor; + friend class DlgEdFactory; + friend class DlgEdPropListenerImpl; + friend class DlgEdForm; + +private: + bool bIsListening; + rtl::Reference<DlgEdForm> pDlgEdForm; + css::uno::Reference< css::beans::XPropertyChangeListener> m_xPropertyChangeListener; + css::uno::Reference< css::container::XContainerListener> m_xContainerListener; + +private: + DlgEditor& GetDialogEditor (); + +protected: + DlgEdObj(SdrModel& rSdrModel); + // copy constructor + DlgEdObj(SdrModel& rSdrModel, DlgEdObj const & rSource); + DlgEdObj( + SdrModel& rSdrModel, + const OUString& rModelName, + const css::uno::Reference< css::lang::XMultiServiceFactory >& rxSFac); + + // protected destructor + virtual ~DlgEdObj() override; + + virtual void NbcMove( const Size& rSize ) override; + virtual void NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override; + virtual bool EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) override; + + using SfxListener::StartListening; + void StartListening(); + using SfxListener::EndListening; + void EndListening(bool bRemoveListener); + bool isListening() const { return bIsListening; } + + bool TransformSdrToControlCoordinates( + sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn, + sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut ); + bool TransformSdrToFormCoordinates( + sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn, + sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut ); + bool TransformControlToSdrCoordinates( + sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn, + sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut ); + bool TransformFormToSdrCoordinates( + sal_Int32 nXIn, sal_Int32 nYIn, sal_Int32 nWidthIn, sal_Int32 nHeightIn, + sal_Int32& nXOut, sal_Int32& nYOut, sal_Int32& nWidthOut, sal_Int32& nHeightOut ); + +public: + void SetDlgEdForm( DlgEdForm* pForm ) { pDlgEdForm = pForm; } + DlgEdForm* GetDlgEdForm() const { return pDlgEdForm.get(); } + + virtual SdrInventor GetObjInventor() const override; + virtual SdrObjKind GetObjIdentifier() const override; + + virtual rtl::Reference<SdrObject> CloneSdrObject(SdrModel& rTargetModel) const override; // not working yet + + // FullDrag support + virtual rtl::Reference<SdrObject> getFullDragClone() const override; + + bool supportsService( OUString const & serviceName ) const; + OUString GetDefaultName() const; + OUString GetUniqueName() const; + + sal_Int32 GetStep() const; + virtual void UpdateStep(); + + void SetDefaults(); + virtual void SetRectFromProps(); + virtual void SetPropsFromRect(); + + css::uno::Reference< css::awt::XControl > GetControl() const; + + virtual void PositionAndSizeChange( const css::beans::PropertyChangeEvent& evt ); + /// @throws css::container::NoSuchElementException + /// @throws css::uno::RuntimeException + void NameChange( const css::beans::PropertyChangeEvent& evt ); + /// @throws css::uno::RuntimeException + void TabIndexChange( const css::beans::PropertyChangeEvent& evt ); + + // PropertyChangeListener + /// @throws css::uno::RuntimeException + void _propertyChange(const css::beans::PropertyChangeEvent& evt); + + // ContainerListener + /// @throws css::uno::RuntimeException + void _elementInserted(); + /// @throws css::uno::RuntimeException + void _elementReplaced(); + /// @throws css::uno::RuntimeException + void _elementRemoved(); + + virtual void SetLayer(SdrLayerID nLayer) override; + void MakeDataAware( const css::uno::Reference< css::frame::XModel >& xModel ); +}; + + +// DlgEdForm + + +class DlgEdForm: public DlgEdObj +{ + friend class DlgEditor; + friend class DlgEdFactory; + +private: + DlgEditor& rDlgEditor; + std::vector<DlgEdObj*> pChildren; + + mutable ::std::optional< css::awt::DeviceInfo > mpDeviceInfo; + +private: + explicit DlgEdForm( + SdrModel& rSdrModel, + DlgEditor&); + +protected: + virtual void NbcMove( const Size& rSize ) override; + virtual void NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override; + virtual bool EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) override; + + // protected destructor + virtual ~DlgEdForm() override; + +public: + DlgEditor& GetDlgEditor () const { return rDlgEditor; } + + void AddChild( DlgEdObj* pDlgEdObj ); + void RemoveChild( DlgEdObj* pDlgEdObj ); + std::vector<DlgEdObj*> const& GetChildren() const { return pChildren; } + + virtual void UpdateStep() override; + + virtual void SetRectFromProps() override; + virtual void SetPropsFromRect() override; + + virtual void PositionAndSizeChange( const css::beans::PropertyChangeEvent& evt ) override; + + void UpdateTabIndices(); + void UpdateTabOrder(); + void UpdateGroups(); + void UpdateTabOrderAndGroups(); + + css::awt::DeviceInfo getDeviceInfo() const; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlgedpage.hxx b/basctl/source/inc/dlgedpage.hxx new file mode 100644 index 0000000000..91efc12edd --- /dev/null +++ b/basctl/source/inc/dlgedpage.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 <svx/svdpage.hxx> + +namespace basctl +{ +// DlgEdPage + +class DlgEdModel; +class DlgEdForm; + +class DlgEdPage final : public SdrPage +{ + DlgEdPage& operator=(const DlgEdPage&) = delete; + DlgEdPage(const DlgEdPage&) = delete; + + DlgEdForm* pDlgEdForm; + +public: + explicit DlgEdPage(DlgEdModel& rModel, bool bMasterPage = false); + virtual ~DlgEdPage() override; + + virtual rtl::Reference<SdrPage> CloneSdrPage(SdrModel& rTargetModel) const override; + + void SetDlgEdForm(DlgEdForm* pForm) { pDlgEdForm = pForm; } + DlgEdForm* GetDlgEdForm() const { return pDlgEdForm; } + + virtual SdrObject* SetObjectOrdNum(size_t nOldObjNum, size_t nNewObjNum) override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/dlgedview.hxx b/basctl/source/inc/dlgedview.hxx new file mode 100644 index 0000000000..195dee8403 --- /dev/null +++ b/basctl/source/inc/dlgedview.hxx @@ -0,0 +1,59 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#pragma once + +#include <svx/svdview.hxx> + +namespace basctl +{ + +class DlgEditor; + + +// DlgEdView + + +class DlgEdView : public SdrView +{ +private: + DlgEditor& rDlgEditor; + +public: + + DlgEdView( + SdrModel& rSdrModel, + OutputDevice& rOut, + DlgEditor& rEditor); + + virtual ~DlgEdView() override; + + virtual void MarkListHasChanged() override; + virtual void MakeVisible( const tools::Rectangle& rRect, vcl::Window& rWin ) override; + +protected: + /// override to handle HitTest for some objects specially + using SdrView::CheckSingleSdrObjectHit; + virtual SdrObject* CheckSingleSdrObjectHit(const Point& rPnt, sal_uInt16 nTol, SdrObject* pObj, SdrPageView* pPV, SdrSearchOptions nOptions, const SdrLayerIDSet* pMVisLay) const override; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/doceventnotifier.hxx b/basctl/source/inc/doceventnotifier.hxx new file mode 100644 index 0000000000..25fd2a7a84 --- /dev/null +++ b/basctl/source/inc/doceventnotifier.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 <com/sun/star/frame/XModel.hpp> + +#include <rtl/ref.hxx> + + +namespace basctl +{ + + + class ScriptDocument; + + + class SAL_NO_VTABLE DocumentEventListener + { + public: + DocumentEventListener(const DocumentEventListener&) = delete; + const DocumentEventListener& operator=(const DocumentEventListener&) = delete; + DocumentEventListener() = default; + + virtual void onDocumentCreated( const ScriptDocument& _rDocument ) = 0; + virtual void onDocumentOpened( const ScriptDocument& _rDocument ) = 0; + virtual void onDocumentSave( const ScriptDocument& _rDocument ) = 0; + virtual void onDocumentSaveDone( const ScriptDocument& _rDocument ) = 0; + virtual void onDocumentSaveAs( const ScriptDocument& _rDocument ) = 0; + virtual void onDocumentSaveAsDone( const ScriptDocument& _rDocument ) = 0; + virtual void onDocumentClosed( const ScriptDocument& _rDocument ) = 0; + virtual void onDocumentTitleChanged( const ScriptDocument& _rDocument ) = 0; + virtual void onDocumentModeChanged( const ScriptDocument& _rDocument ) = 0; + + virtual ~DocumentEventListener(); + }; + + + /** allows registering at theGlobalEventBroadcaster for global document events + */ + class DocumentEventNotifier + { + public: + /** create a notifier instance which notifies about events of all documents in the whole application + */ + DocumentEventNotifier (DocumentEventListener&); + + /** creates a notifier instance which notifies about events at a single document + */ + DocumentEventNotifier (DocumentEventListener&, css::uno::Reference<css::frame::XModel> const& rxDocument); + + ~DocumentEventNotifier(); + + public: + void dispose(); + + private: + class Impl; + rtl::Reference<Impl> m_pImpl; + }; + + +} // namespace basctl + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/docsignature.hxx b/basctl/source/inc/docsignature.hxx new file mode 100644 index 0000000000..1681807d39 --- /dev/null +++ b/basctl/source/inc/docsignature.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 <sfx2/signaturestate.hxx> +#include <vcl/weld.hxx> + +class SfxObjectShell; + +namespace basctl +{ + + + class ScriptDocument; + + /// encapsulates (actions on) the signature/state of a document + class DocumentSignature + { + public: + /** creates a DocumentSignature instance for the given document + + If the given ScriptDocument instance refers to the application, or to a document + which does not support being signed, the DocumentSignature instance is invalid afterwards. + */ + explicit DocumentSignature (ScriptDocument const&); + + /** determines whether the instance is valid + + An instance is valid if and only if it has been constructed with a document + which supports signatures. + */ + bool supportsSignatures() const; + + /** signs the scripting content inside the document + + @precond + isValid returns <TRUE/> + */ + void signScriptingContent(weld::Window* pDialogParent) const; + + /** retrieves the state of the signature of the scripting content inside the document + + If the instance is not valid, then SIGNATURESTATE_NOSIGNATURES is returned. + */ + SignatureState getScriptingSignatureState() const; + + private: + DocumentSignature() = delete; + + private: + SfxObjectShell* m_pShell; + }; + + +} // namespace basctl + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/iderid.hxx b/basctl/source/inc/iderid.hxx new file mode 100644 index 0000000000..83cbc3d0c4 --- /dev/null +++ b/basctl/source/inc/iderid.hxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <rtl/ustring.hxx> +#include <unotools/resmgr.hxx> + +namespace basctl +{ +OUString IDEResId(TranslateId aId); + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/layout.hxx b/basctl/source/inc/layout.hxx new file mode 100644 index 0000000000..29b44896b3 --- /dev/null +++ b/basctl/source/inc/layout.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 "bastypes.hxx" +#include <vcl/split.hxx> +#include <vcl/vclptr.hxx> + +#include <vector> + +class DockingWindow; +class SfxRequest; +class SfxItemSet; + +namespace basctl +{ +class DockingWindow; +class BaseWindow; + +// Layout -- the common base of ModulLayout and DialogLayout. +// Handles the splitting lines and the dockable windows. + +class Layout : public vcl::Window +{ +public: + void ArrangeWindows(); + + virtual void Activating(BaseWindow&); + virtual void Deactivating(); + virtual void ExecuteGlobal(SfxRequest&) {} + virtual void GetState(SfxItemSet&, unsigned nWhich) = 0; + virtual void UpdateDebug(bool bBasicStopped) = 0; + + virtual ~Layout() override; + virtual void dispose() override; + +protected: + explicit Layout(vcl::Window* pParent); + + void AddToLeft(DockingWindow* pWin, Size const& rSize) { aLeftSide.Add(pWin, rSize); } + void AddToBottom(DockingWindow* pWin, Size const& rSize) { aBottomSide.Add(pWin, rSize); } + void Remove(DockingWindow*); + bool HasSize() const { return !bFirstSize; } + + // Window: + virtual void Resize() override; + virtual void DataChanged(DataChangedEvent const& rDCEvt) override; + // new: + virtual void OnFirstSize(tools::Long nWidth, tools::Long nHeight) = 0; + +private: + // the main child window (either ModulWindow or DialogWindow) + VclPtr<BaseWindow> pChild; + + // when this window has at first (nonempty) size + bool bFirstSize; + + // horizontal or vertical split strip + class SplittedSide + { + public: + enum class Side + { + Left, + Bottom + }; + SplittedSide(Layout*, Side); + void Add(DockingWindow*, Size const&); + void Remove(DockingWindow*); + bool IsEmpty() const; + tools::Long GetSize() const; + void ArrangeIn(tools::Rectangle const&); + void dispose(); + + private: + // the layout window + Layout& rLayout; + // horizontal or vertical strip? + bool bVertical; + // lower (top or left) or higher (bottom or right) strip? + bool bLower; + // rectangle to move in + tools::Rectangle aRect; + // size (width or height) + tools::Long nSize; + // the main splitting line + VclPtr<Splitter> aSplitter; + // the dockable windows (and some data) + struct Item + { + // pointer to the dockable window + VclPtr<DockingWindow> pWin; + // starting and ending position in the strip + // They may be different from the actual window position, because + // the window may fill the space of the adjacent currently + // non-docking windows, but this change is not stored in these + // variables. These change only when the splitter lines are moved. + tools::Long nStartPos, nEndPos; + // splitter line window before the window + // (the first one is always nullptr) + VclPtr<Splitter> pSplit; + }; + std::vector<Item> vItems; + + Point MakePoint(tools::Long, tools::Long) const; + Size MakeSize(tools::Long, tools::Long) const; + static bool IsDocking(DockingWindow const&); + DECL_LINK(SplitHdl, Splitter*, void); + void CheckMarginsFor(Splitter*); + void InitSplitter(Splitter&); + } aLeftSide, aBottomSide; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/localizationmgr.hxx b/basctl/source/inc/localizationmgr.hxx new file mode 100644 index 0000000000..3e2ff0fc58 --- /dev/null +++ b/basctl/source/inc/localizationmgr.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 <sal/config.h> + +#include <string_view> + +#include "scriptdocument.hxx" + +#include <com/sun/star/resource/XStringResourceManager.hpp> + +namespace basctl +{ + +class Shell; +class DlgEditor; + +class LocalizationMgr +{ + css::uno::Reference< css::resource::XStringResourceManager > m_xStringResourceManager; + + Shell* m_pShell; + + ScriptDocument m_aDocument; + OUString m_aLibName; + + css::lang::Locale m_aLocaleBeforeBasicStart; + + enum HandleResourceMode + { + SET_IDS, + RESET_IDS, + RENAME_DIALOG_IDS, + RENAME_CONTROL_IDS, + REMOVE_IDS_FROM_RESOURCE, + MOVE_RESOURCES, + COPY_RESOURCES + }; + static sal_Int32 implHandleControlResourceProperties(const css::uno::Any& rControlAny, + std::u16string_view aDialogName, + std::u16string_view aCtrlName, + const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager, + const css::uno::Reference< css::resource::XStringResourceResolver >& xSourceStringResolver, + HandleResourceMode eMode ); + + void enableResourceForAllLibraryDialogs() + { + implEnableDisableResourceForAllLibraryDialogs( SET_IDS ); + } + void disableResourceForAllLibraryDialogs() + { + implEnableDisableResourceForAllLibraryDialogs( RESET_IDS ); + } + void implEnableDisableResourceForAllLibraryDialogs( HandleResourceMode eMode ); + +public: + LocalizationMgr(Shell*, ScriptDocument , OUString aLibName, + const css::uno::Reference < css::resource::XStringResourceManager >& xStringResourceManager ); + + const css::uno::Reference< css::resource::XStringResourceManager >& getStringResourceManager() const + { + return m_xStringResourceManager; + } + + bool isLibraryLocalized(); + + void handleTranslationbar(); + + void handleAddLocales( const css::uno::Sequence + < css::lang::Locale >& aLocaleSeq ); + + void handleRemoveLocales( const css::uno::Sequence + < css::lang::Locale >& aLocaleSeq ); + + void handleSetDefaultLocale(const css::lang::Locale& rLocale); + + void handleSetCurrentLocale(const css::lang::Locale& rLocale); + + void handleBasicStarted(); + + void handleBasicStopped(); + + static void setControlResourceIDsForNewEditorObject(DlgEditor const * pEditor, + const css::uno::Any& rControlAny, std::u16string_view aCtrlName); + + static void renameControlResourceIDsForEditorObject(DlgEditor const * pEditor, + const css::uno::Any& rControlAny, std::u16string_view aNewCtrlName); + + static void deleteControlResourceIDsForDeletedEditorObject(DlgEditor const * pEditor, + const css::uno::Any& rControlAny, std::u16string_view aCtrlName); + + static void setStringResourceAtDialog( const ScriptDocument& rDocument, const OUString& aLibName, std::u16string_view aDlgName, + const css::uno::Reference< css::container::XNameContainer >& xDialogModel ); + + static void renameStringResourceIDs( const ScriptDocument& rDocument, const OUString& aLibName, std::u16string_view aDlgName, + const css::uno::Reference< css::container::XNameContainer >& xDialogModel ); + + static void removeResourceForDialog( const ScriptDocument& rDocument, const OUString& aLibName, std::u16string_view aDlgName, + const css::uno::Reference< css::container::XNameContainer >& xDialogModel ); + + static css::uno::Reference< css::resource::XStringResourceManager > + getStringResourceFromDialogLibrary( const css::uno::Reference< css::container::XNameContainer >& xDialogLib ); + + // Clipboard / Drag & Drop + static void resetResourceForDialog( + const css::uno::Reference< css::container::XNameContainer >& xDialogModel, + const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager ); + + static void setResourceIDsForDialog( + const css::uno::Reference< css::container::XNameContainer >& xDialogModel, + const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager ); + + static void copyResourcesForPastedEditorObject( DlgEditor const * pEditor, + const css::uno::Any& rControlAny, std::u16string_view aCtrlName, + const css::uno::Reference< css::resource::XStringResourceResolver >& xSourceStringResolver ); + + static void copyResourceForDroppedDialog( + const css::uno::Reference< css::container::XNameContainer >& xDialogModel, + std::u16string_view aDialogName, + const css::uno::Reference< css::resource::XStringResourceManager >& xStringResourceManager, + const css::uno::Reference< css::resource::XStringResourceResolver >& xSourceStringResolver ); + + static void copyResourceForDialog( + const css::uno::Reference< css::container::XNameContainer >& xDialogModel, + const css::uno::Reference< css::resource:: + XStringResourceResolver >& xSourceStringResolver, + const css::uno::Reference< css::resource:: + XStringResourceManager >& xTargetStringResourceManager ); +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/managelang.hxx b/basctl/source/inc/managelang.hxx new file mode 100644 index 0000000000..58dd418905 --- /dev/null +++ b/basctl/source/inc/managelang.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 <utility> +#include <vcl/weld.hxx> + +class SvxLanguageBox; + +namespace basctl +{ + +class LocalizationMgr; + +struct LanguageEntry +{ + css::lang::Locale m_aLocale; + bool m_bIsDefault; + + LanguageEntry( css::lang::Locale _aLocale, + bool _bIsDefault ) : + m_aLocale(std::move( _aLocale )), + m_bIsDefault( _bIsDefault ) {} +}; + +extern bool localesAreEqual( const css::lang::Locale& rLocaleLeft, + const css::lang::Locale& rLocaleRight ); + +class ManageLanguageDialog : public weld::GenericDialogController +{ +private: + std::shared_ptr<LocalizationMgr> m_xLocalizationMgr; + + OUString m_sDefLangStr; + OUString m_sCreateLangStr; + + std::unique_ptr<weld::TreeView> m_xLanguageLB; + std::unique_ptr<weld::Button> m_xAddPB; + std::unique_ptr<weld::Button> m_xDeletePB; + std::unique_ptr<weld::Button> m_xMakeDefPB; + + void Init(); + void FillLanguageBox(); + void ClearLanguageBox(); + + DECL_LINK(AddHdl, weld::Button&, void); + DECL_LINK(DeleteHdl, weld::Button&, void); + DECL_LINK(MakeDefHdl, weld::Button&, void); + DECL_LINK(SelectHdl, weld::TreeView&, void); + +public: + ManageLanguageDialog(weld::Window* pParent, std::shared_ptr<LocalizationMgr> _pLMgr); + virtual ~ManageLanguageDialog() override; +}; + +class SetDefaultLanguageDialog : public weld::GenericDialogController +{ +private: + std::shared_ptr<LocalizationMgr> m_xLocalizationMgr; + + void FillLanguageBox(); + + std::unique_ptr<weld::Label> m_xLanguageFT; + std::unique_ptr<weld::TreeView> m_xLanguageLB; + std::unique_ptr<weld::Label> m_xCheckLangFT; + std::unique_ptr<weld::TreeView> m_xCheckLangLB; + std::unique_ptr<weld::Label> m_xDefinedFT; + std::unique_ptr<weld::Label> m_xAddedFT; + std::unique_ptr<weld::Label> m_xAltTitle; + std::unique_ptr<SvxLanguageBox> m_xLanguageCB; + +public: + SetDefaultLanguageDialog(weld::Window* pParent, std::shared_ptr<LocalizationMgr> xLMgr); + virtual ~SetDefaultLanguageDialog() override; + + css::uno::Sequence< css::lang::Locale > GetLocales() const; +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/propbrw.hxx b/basctl/source/inc/propbrw.hxx new file mode 100644 index 0000000000..c9ad803444 --- /dev/null +++ b/basctl/source/inc/propbrw.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 <sal/config.h> + +#include <vector> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XFrame2.hpp> +#include <svl/lstner.hxx> +#include <svl/SfxBroadcaster.hxx> +#include <svx/svdmark.hxx> +#include "bastypes.hxx" + +class SfxBindings; +class SdrView; +class SfxViewShell; + +namespace basctl +{ + +class DialogWindowLayout; + +class PropBrw final : public DockingWindow, public SfxListener, public SfxBroadcaster +{ +private: + VclPtr<vcl::Window> m_xContentArea; + bool m_bInitialStateChange; + + css::uno::Reference< css::frame::XFrame2 > + m_xMeAsFrame; + css::uno::Reference< css::beans::XPropertySet > + m_xBrowserController; + css::uno::Reference< css::frame::XModel > + m_xContextDocument; + + SdrView* pView; + virtual bool Close() override; + + typedef std::vector< css::uno::Reference< css::uno::XInterface> > InterfaceArray; + + static css::uno::Sequence< css::uno::Reference< css::uno::XInterface > > + CreateMultiSelectionSequence( const SdrMarkList& _rMarkList ); + void implSetNewObjectSequence( const css::uno::Sequence + < css::uno::Reference< css::uno::XInterface > >& _rObjectSeq ); + + void implSetNewObject( const css::uno::Reference< css::beans::XPropertySet >& _rxObject); + + static OUString GetHeadlineName( const css::uno::Reference< css::beans::XPropertySet >& _rxObject); + +public: + explicit PropBrw (DialogWindowLayout&); + virtual ~PropBrw() override; + virtual void dispose() override; + // note: changing the Context document to an instance other than the one given in the ctor is not supported + // currently + void Update( const SfxViewShell* pShell ); + +private: + void ImplUpdate( const css::uno::Reference< css::frame::XModel >& _rxContextDocument, SdrView* pView ); + void ImplDestroyController(); + void ImplReCreateController(); +}; + +} // namespace basctl + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/sbxitem.hxx b/basctl/source/inc/sbxitem.hxx new file mode 100644 index 0000000000..941ffd3e0e --- /dev/null +++ b/basctl/source/inc/sbxitem.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 "scriptdocument.hxx" +#include <svl/poolitem.hxx> + +namespace basctl +{ + +enum ItemType +{ + TYPE_UNKNOWN, + TYPE_SHELL, + TYPE_LIBRARY, + TYPE_MODULE, + TYPE_DIALOG, + TYPE_METHOD +}; + +class SbxItem : public SfxPoolItem +{ + const ScriptDocument m_aDocument; + const OUString m_aLibName; + const OUString m_aName; + const OUString m_aMethodName; + ItemType m_eType; + +public: + static SfxPoolItem* CreateDefault(); + SbxItem(sal_uInt16 nWhich, ScriptDocument aDocument, OUString aLibName, OUString aName, ItemType); + SbxItem(sal_uInt16 nWhich, ScriptDocument aDocument, OUString aLibName, OUString aName, OUString aMethodName, ItemType eType); + + virtual SbxItem* Clone(SfxItemPool *pPool = nullptr) const override; + virtual bool operator==(const SfxPoolItem&) const override; + + ScriptDocument const& GetDocument () const { return m_aDocument; } + OUString const& GetLibName () const { return m_aLibName; } + OUString const& GetName () const { return m_aName; } + OUString const& GetMethodName () const { return m_aMethodName; } + ItemType GetType () const { return m_eType; } +}; + +} // namespace basctl + +// For baside.sdi, because I don't know how to use nested names in it. +using basctl::SbxItem; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/source/inc/scriptdocument.hxx b/basctl/source/inc/scriptdocument.hxx new file mode 100644 index 0000000000..da7f2b50d3 --- /dev/null +++ b/basctl/source/inc/scriptdocument.hxx @@ -0,0 +1,481 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <com/sun/star/script/XLibraryContainer.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <com/sun/star/io/XInputStreamProvider.hpp> + +#include <memory> +#include <vector> + +class SfxListener; + +class BasicManager; + + +namespace basctl +{ + + enum LibraryContainerType + { + E_SCRIPTS, + E_DIALOGS + }; + + enum LibraryLocation + { + LIBRARY_LOCATION_UNKNOWN, + LIBRARY_LOCATION_USER, + LIBRARY_LOCATION_SHARE, + LIBRARY_LOCATION_DOCUMENT + }; + + enum class LibraryType + { + Module, + Dialog, + All + }; + + class ScriptDocument; + typedef std::vector< ScriptDocument > ScriptDocuments; + + /** encapsulates a document which contains Basic scripts and dialogs + */ + class ScriptDocument + { + private: + class Impl; + std::shared_ptr<Impl> m_pImpl; + + private: + /** creates a ScriptDocument instance which operates on the application-wide + scripts and dialogs + */ + ScriptDocument(); + + public: + enum SpecialDocument { NoDocument }; + /** creates a ScriptDocument instance which does refers to neither the application-wide, + nor a specific real document's scripts. + + This constructor might come handy when you need some kind of uninitialized + ScriptDocument, which you do not want to operate on (yet), but initialize later + by assignment. + + <member>isValid</member> will return <FALSE/> for a ScriptDocument constructed + this way. + */ + explicit ScriptDocument( SpecialDocument _eType ); + + /** creates a ScriptDocument instance which refers to a document given as + XModel + + @param _rxDocument + the document. Must not be <NULL/>. + */ + explicit ScriptDocument( const css::uno::Reference< css::frame::XModel >& _rxDocument ); + + /** returns a reference to a shared ScriptDocument instance which + operates on the application-wide scripts and dialogs + */ + static const ScriptDocument& + getApplicationScriptDocument(); + + /** returns a (newly created) ScriptDocument instance for the document to + which a given BasicManager belongs + + If the basic manager is the application's basic manager, then the (shared) + ScriptDocument instance which is responsible for the application is returned. + + @see getApplicationScriptDocument + */ + static ScriptDocument + getDocumentForBasicManager( const BasicManager* _pManager ); + + /** returns a (newly created) ScriptDocument instance for the document + with a given caption or URL + + If there is no document with the given caption, then the (shared) + ScriptDocument instance which is responsible for the application is returned. + + @see getApplicationScriptDocument + */ + static ScriptDocument + getDocumentWithURLOrCaption( std::u16string_view _rUrlOrCaption ); + + /** operation mode for getAllScriptDocuments + */ + enum ScriptDocumentList + { + /** all ScriptDocuments, including the dedicated one which represents + the application-wide scripts/dialogs. + */ + AllWithApplication, + /** real documents only, sorted lexicographically by their title (using the sys locale's default + collator) + */ + DocumentsSorted + }; + + /** returns the set of ScriptDocument instances, one for each open document which + contains Basic/Dialog containers; plus an additional instance for + the application, if desired + + Documents which are not visible - i.e. do not have a visible frame. + + @param _bIncludingApplication + <TRUE/> if the application-wide scripts/dialogs should also be represented + by a ScriptDocument + */ + static ScriptDocuments + getAllScriptDocuments( ScriptDocumentList _eListType ); + + // comparison + bool operator==( const ScriptDocument& _rhs ) const; + bool operator!=( const ScriptDocument& _rhs ) const { return !( *this == _rhs ); } + + /// retrieves a (pretty simple) hash code for the document + sal_Int32 hashCode() const; + + /** determines whether the document is actually able to contain Basic/Dialog libraries + + Note that validity does not automatically imply the document can be used for active + work. Instead, it is possible the document is closed already (or being closed currently). + In this case, isValid will return <TRUE/>, but isAlive will return <FALSE/>. + + @return + <TRUE/> if the instance refers to a document which contains Basic/Dialog libraries, + or the application as a whole, <FALSE/> otherwise. + + @see isAlive + */ + bool isValid() const; + + /** determines whether the document instance is alive + + If the instance is not valid, <FALSE/> is returned. + + If the instance refers to a real document, which is already closed, or just being closed, + the method returns <FALSE/>. + + If the instance refers to the application, <TRUE/> is returned. + + @see isValid + */ + bool isAlive() const; + + bool isInVBAMode() const; + /// returns the BasicManager associated with this instance + BasicManager* + getBasicManager() const; + + /** returns the UNO component representing the document which the instance operates on + + Must not be used when the instance operates on the application-wide + Basic/Dialog libraries. + */ + css::uno::Reference< css::frame::XModel > + getDocument() const; + + /** returns the UNO component representing the document which the instance operates on + + May be used when the instance operates on the application-wide + Basic/Dialog libraries, in this case it returns <NULL/>. + */ + css::uno::Reference< css::frame::XModel > + getDocumentOrNull() const; + + /** returns the Basic or Dialog library container of the document + + If the document is not valid, <NULL/> is returned. + */ + css::uno::Reference< css::script::XLibraryContainer > + getLibraryContainer( LibraryContainerType _eType ) const; + + /** determines whether there exists a library of the given type, with the given name + */ + bool hasLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const; + + /** returns a script or dialog library given by name + + @param _eType + the type of library to load + @param _rLibName + the name of the script library + @param _bLoadLibrary + <TRUE/> if and only if the library should be loaded. + + @throws NoSuchElementException + if there is no script library with the given name + */ + css::uno::Reference< css::container::XNameContainer > + getLibrary( LibraryContainerType _eType, const OUString& _rLibName, bool _bLoadLibrary ) const; + + /** creates a script or dialog library in the document, or returns an existing one + + If <code>_rLibName</code> denotes an existing library which does not need to be created, + then this library will automatically be loaded, and then returned. + */ + css::uno::Reference< css::container::XNameContainer > + getOrCreateLibrary( LibraryContainerType _eType, const OUString& _rLibName ) const; + + /** returns the names of the modules in a given script or dialog library of the document + */ + css::uno::Sequence< OUString > + getObjectNames( LibraryContainerType _eType, const OUString& _rLibName ) const; + + /** retrieves a name for a newly to be created module or dialog + */ + OUString createObjectName( LibraryContainerType _eType, const OUString& _rLibName ) const; + + /** loads a script or dialog library given by name, if there is such a library + */ + void loadLibraryIfExists( LibraryContainerType _eType, const OUString& _rLibrary ); + + /// retrieves the (combined) names of all script and dialog libraries + css::uno::Sequence< OUString > + getLibraryNames() const; + + /** removes a given script module from the document + + @return + <TRUE/> if and only if the removal was successful. When <FALSE/> is returned, + this will reported as assertion in a non-product build. + */ + bool removeModule( const OUString& _rLibName, const OUString& _rModuleName ) const; + + /** creates a module with the given name in the given library + @param _rLibName + the library name + @param _rModName + the name of the to-be-created module + @param _bCreateMain + determines whether or not a function Main should be created + @param _out_rNewModuleCode + the source code of the newly created module + @return + <TRUE/> if and only if the creation was successful + */ + bool createModule( const OUString& _rLibName, const OUString& _rModName, bool _bCreateMain, OUString& _out_rNewModuleCode ) const; + + /** inserts a given piece as code as module + @param _rLibName + the name of the library to insert the module into. If a library with this name does + not yet exist, it will be created. + @param _rModName + the name of the module to insert the code as. Must denote a name which is not yet + used in the module library. + @param _rModuleCode + the code of the new module + @return + <TRUE/> if and only if the insertion was successful. + */ + bool insertModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const; + + /** updates a given module with new code + @param _rLibName + the name of the library the modules lives in. Must denote an existing module library. + @param _rModName + the name of the module to update. Must denote an existing module in the given library. + @param _rModuleCode + the new module code. + @return + <TRUE/> if and only if the insertion was successful. + */ + bool updateModule( const OUString& _rLibName, const OUString& _rModName, const OUString& _rModuleCode ) const; + + /// determines whether a module with the given name exists in the given library + bool hasModule( const OUString& _rLibName, const OUString& _rModName ) const; + + /** retrieves a module's source + @param _rLibName + the library name where the module is located + @param _rModName + the module name + @param _out_rModuleSource + takes the module's source upon successful return + @return + <TRUE/> if and only if the code could be successfully retrieved, <FALSE/> otherwise + */ + bool getModule( const OUString& _rLibName, const OUString& _rModName, OUString& _rModuleSource ) const; + + /** renames a module + @param _rLibName + the library where the module lives in. Must denote an existing library. + @param _rOldName + the old module name. Must denote an existing module. + @param _rNewName + the new module name + @return + <TRUE/> if and only if renaming was successful. + */ + bool renameModule( const OUString& _rLibName, const OUString& _rOldName, const OUString& _rNewName ) const; + + /** removes a given dialog from the document + + @return + <TRUE/> if and only if the removal was successful. When <FALSE/> is returned, + this will reported as assertion in a non-product build. + */ + bool removeDialog( const OUString& _rLibName, const OUString& _rDialogName ) const; + + /// determines whether a dialog with the given name exists in the given library + bool hasDialog( const OUString& _rLibName, const OUString& _rDialogName ) const; + + /** retrieves a dialog + @param _rLibName + the library name where the module is located + @param _rDialogName + the dialog's name + @param _out_rDialogSource + takes the provider for the dialog's description, upon successful return + @return + <TRUE/> if and only if the dialog could be successfully retrieved, <FALSE/> otherwise + */ + bool getDialog( + const OUString& _rLibName, + const OUString& _rDialogName, + css::uno::Reference< css::io::XInputStreamProvider >& _out_rDialogProvider + ) const; + + /** renames a dialog + @param _rLibName + the library where the dialog lives in. Must denote an existing library. + @param _rOldName + the old dialog name. Must denote an existing dialog. + @param _rNewName + the new dialog name + @param _rxExistingDialogModel + the existing model of the dialog, if already loaded in the IDE + @return + <TRUE/> if and only if renaming was successful. + */ + bool renameDialog( + const OUString& _rLibName, + const OUString& _rOldName, + const OUString& _rNewName, + const css::uno::Reference< css::container::XNameContainer >& _rxExistingDialogModel + ) const; + + /** create a dialog + @param _rLibName + the library name where the module is located + @param _rDialogName + the dialog's name + @param _out_rDialogSource + takes the provider for the dialog's description, upon successful return + @return + <TRUE/> if and only if the dialog could be successfully retrieved, <FALSE/> otherwise + */ + bool createDialog( + const OUString& _rLibName, + const OUString& _rDialogName, + css::uno::Reference< css::io::XInputStreamProvider >& _out_rDialogProvider + ) const; + + /** inserts a given dialog into a given library + + @param _rLibName + the name of the library to insert the dialog into. If a library with this name does + not yet exist, it will be created. + @param _rModName + the name of the dialog to insert. Must denote a name which is not yet + used in the dialog library. + @param _rDialogProvider + the provider of the dialog's description + @return + <TRUE/> if and only if the insertion was successful. + */ + bool insertDialog( + const OUString& _rLibName, + const OUString& _rDialogName, + const css::uno::Reference< css::io::XInputStreamProvider >& _rDialogProvider + ) const; + + /** determines whether the document is read-only + + cannot be called if the document operates on the application-wide scripts + */ + bool isReadOnly() const; + + /** determines whether the ScriptDocument instance operates on the whole application, + as opposed to a real document + */ + bool isApplication() const; + + /** determines whether the ScriptDocument instance operates on a real document, + as opposed to the whole application + */ + bool isDocument() const { return isValid() && !isApplication(); } + + /** marks the document as modified + @precond + the instance operates on a real document, not on the application + @see isDocument + */ + void setDocumentModified() const; + + /** determines whether the document is modified + @precond + the instance operates on a real document, not on the application + @see isDocument + */ + bool isDocumentModified() const; + + /** saves the document, if the instance refers to a real document + @precond + <code>isApplication</code> returns <FALSE/> + */ + void saveDocument( + const css::uno::Reference< css::task::XStatusIndicator >& _rxStatusIndicator + ) const; + + /// returns the location of a library given by name + LibraryLocation + getLibraryLocation( const OUString& _rLibName ) const; + + /// returns the title for the document + OUString getTitle( LibraryLocation _eLocation, LibraryType _eType = LibraryType::All ) const; + + /** returns the title of the document + + to be used for valid documents only + */ + OUString getTitle() const; + + /** determines whether the document is currently the one-and-only application-wide active document + */ + bool isActive() const; + + /** determines whether macro execution for this document is allowed + + only to be called for real documents (->isDocument) + */ + bool allowMacros() const; + }; + + +} // namespace basctl + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/basctl/uiconfig/basicide/menubar/menubar.xml b/basctl/uiconfig/basicide/menubar/menubar.xml new file mode 100644 index 0000000000..fc510571e2 --- /dev/null +++ b/basctl/uiconfig/basicide/menubar/menubar.xml @@ -0,0 +1,179 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<menu:menubar xmlns:menu="http://openoffice.org/2001/menu" menu:id="menubar"> + <menu:menu menu:id=".uno:PickList"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:AddDirect"/> + <menu:menuitem menu:id=".uno:Open"/> + <menu:menuitem menu:id=".uno:OpenRemote"/> + <menu:menuitem menu:id=".uno:RecentFileList"/> + <menu:menuitem menu:id=".uno:CloseDoc"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:Save"/> + <menu:menuitem menu:id=".uno:SaveAll"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:CheckOut"/> + <menu:menuitem menu:id=".uno:CancelCheckOut"/> + <menu:menuitem menu:id=".uno:CheckIn"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:LoadBasic"/> + <menu:menuitem menu:id=".uno:SaveBasicAs"/> + <menu:menuitem menu:id=".uno:ImportDialog"/> + <menu:menuitem menu:id=".uno:ExportDialog"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:Print"/> + <menu:menuitem menu:id=".uno:PrinterSetup"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:Signature"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:Quit"/> + </menu:menupopup> + </menu:menu> + <menu:menu menu:id=".uno:EditMenu"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:Undo"/> + <menu:menuitem menu:id=".uno:Redo"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:Cut"/> + <menu:menuitem menu:id=".uno:Copy"/> + <menu:menuitem menu:id=".uno:Paste"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:SelectAll"/> + <menu:menuseparator/> + <menu:menuitem menu:id="vnd.sun.star.findbar:FocusToFindbar"/> + <menu:menuitem menu:id=".uno:SearchDialog"/> + <menu:menuitem menu:id=".uno:GotoLine"/> + </menu:menupopup> + </menu:menu> + <menu:menu menu:id=".uno:ViewMenu"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:AvailableToolbars"/> + <menu:menuitem menu:id=".uno:StatusBarVisible"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:ShowLines"/> + <menu:menuitem menu:id=".uno:ShowPropBrowser"/> + <menu:menuitem menu:id=".uno:ObjectCatalog"/> + <menu:menuitem menu:id=".uno:WatchWindow"/> + <menu:menuitem menu:id=".uno:StackWindow"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:FullScreen"/> + </menu:menupopup> + </menu:menu> + <menu:menu menu:id=".uno:RunMenu"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:RunBasic"/> + <menu:menuitem menu:id=".uno:BasicStop"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:BasicStepOver"/> + <menu:menuitem menu:id=".uno:BasicStepInto"/> + <menu:menuitem menu:id=".uno:BasicStepOut"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:ToggleBreakPoint"/> + <menu:menuitem menu:id=".uno:ManageBreakPoints"/> + <menu:menuitem menu:id=".uno:AddWatch"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:MatchGroup"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:CompileBasic"/> + </menu:menupopup> + </menu:menu> + <menu:menu menu:id=".uno:DialogMenu"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:MacroOrganizer?TabId:short=1"/> + <menu:menuitem menu:id=".uno:TestMode"/> + <menu:menuitem menu:id=".uno:ManageLanguage"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:SelectMode"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:InsertEdit"/> + <menu:menuitem menu:id=".uno:InsertFixedText"/> + <menu:menuitem menu:id=".uno:Checkbox"/> + <menu:menuitem menu:id=".uno:Radiobutton"/> + <menu:menuitem menu:id=".uno:InsertListbox"/> + <menu:menuitem menu:id=".uno:Combobox"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:InsertPushbutton"/> + <menu:menuitem menu:id=".uno:Imagebutton"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:InsertFormattedField"/> + <menu:menu menu:id=".uno:FormMoreFieldsMenu"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:AddDateField"/> + <menu:menuitem menu:id=".uno:InsertTimeField"/> + <menu:menuitem menu:id=".uno:InsertNumericField"/> + <menu:menuitem menu:id=".uno:InsertCurrencyField"/> + <menu:menuitem menu:id=".uno:InsertPatternField"/> + </menu:menupopup> + </menu:menu> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:Groupbox"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:InsertImageControl"/> + <menu:menuitem menu:id=".uno:InsertFileControl"/> + <menu:menuitem menu:id=".uno:InsertTreeControl"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:HFixedLine"/> + <menu:menuitem menu:id=".uno:VFixedLine"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:SpinButton"/> + <menu:menuitem menu:id=".uno:ProgressBar"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:VScrollbar"/> + <menu:menuitem menu:id=".uno:HScrollbar"/> + </menu:menupopup> + </menu:menu> + <menu:menu menu:id=".uno:ToolsMenu"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:ChooseMacro"/> + <menu:menuitem menu:id=".uno:ModuleDialog"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:MacroRecorder"/> + <menu:menuitem menu:id=".uno:ScriptOrganizer"/> + <menu:menuitem menu:id="service:com.sun.star.deployment.ui.PackageManagerDialog"/> + <menu:menuitem menu:id=".uno:ConfigureDialog"/> + <menu:menuitem menu:id=".uno:OptionsTreeDialog"/> + </menu:menupopup> + </menu:menu> + <menu:menu menu:id=".uno:WindowList"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:CloseWin"/> + <menu:menuseparator/> + </menu:menupopup> + </menu:menu> + <menu:menu menu:id=".uno:HelpMenu"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:HelpIndex"/> + <menu:menuitem menu:id=".uno:ExtendedHelp"/> + <menu:menuitem menu:id=".uno:Documentation"/> + <menu:menuitem menu:id=".uno:TipOfTheDay"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:QuestionAnswers"/> + <menu:menuitem menu:id=".uno:SendFeedback"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:SafeMode"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:GetInvolved"/> + <menu:menuitem menu:id=".uno:Donation"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:ShowLicense"/> + <menu:menuitem menu:id=".uno:About"/> + </menu:menupopup> + </menu:menu> +</menu:menubar> + diff --git a/basctl/uiconfig/basicide/popupmenu/dialog.xml b/basctl/uiconfig/basicide/popupmenu/dialog.xml new file mode 100644 index 0000000000..17f96b8740 --- /dev/null +++ b/basctl/uiconfig/basicide/popupmenu/dialog.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> +<menu:menupopup xmlns:menu="http://openoffice.org/2001/menu"> + <menu:menuitem menu:id=".uno:Cut"/> + <menu:menuitem menu:id=".uno:Copy"/> + <menu:menuitem menu:id=".uno:Paste"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:ShowPropBrowser"/> +</menu:menupopup> diff --git a/basctl/uiconfig/basicide/popupmenu/tabbar.xml b/basctl/uiconfig/basicide/popupmenu/tabbar.xml new file mode 100644 index 0000000000..1e0991f16a --- /dev/null +++ b/basctl/uiconfig/basicide/popupmenu/tabbar.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * +--> +<menu:menupopup xmlns:menu="http://openoffice.org/2001/menu"> + <menu:menu menu:id=".uno:InsertMenu"> + <menu:menupopup> + <menu:menuitem menu:id=".uno:NewModule"/> + <menu:menuitem menu:id=".uno:NewDialog"/> + </menu:menupopup> + </menu:menu> + <menu:menuitem menu:id=".uno:DeleteCurrent"/> + <menu:menuitem menu:id=".uno:RenameCurrent"/> + <menu:menuitem menu:id=".uno:HideCurPage"/> + <menu:menuseparator/> + <menu:menuitem menu:id=".uno:ModuleDialog"/> +</menu:menupopup> diff --git a/basctl/uiconfig/basicide/statusbar/statusbar.xml b/basctl/uiconfig/basicide/statusbar/statusbar.xml new file mode 100644 index 0000000000..a5bde3ad0a --- /dev/null +++ b/basctl/uiconfig/basicide/statusbar/statusbar.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE statusbar:statusbar PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "statusbar.dtd"> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<statusbar:statusbar xmlns:statusbar="http://openoffice.org/2001/statusbar" xmlns:xlink="http://www.w3.org/1999/xlink"> + <statusbar:statusbaritem xlink:href=".uno:StatusGetTitle" statusbar:align="left" statusbar:autosize="true" statusbar:width="240"/> + <statusbar:statusbaritem xlink:href=".uno:ModifiedStatus" statusbar:align="center" statusbar:ownerdraw="true" statusbar:width="9"/> + <statusbar:statusbaritem xlink:href=".uno:StatusGetPosition" statusbar:align="left" statusbar:width="120"/> + <statusbar:statusbaritem xlink:href=".uno:InsertMode" statusbar:align="center" statusbar:width="55"/> + <statusbar:statusbaritem xlink:href=".uno:Signature" statusbar:align="center" statusbar:ownerdraw="true" statusbar:width="16"/> + <statusbar:statusbaritem xlink:href=".uno:Size" statusbar:align="left" statusbar:autosize="true" statusbar:ownerdraw="true" statusbar:width="140"/> + <statusbar:statusbaritem xlink:href=".uno:ZoomSlider" statusbar:align="center" statusbar:ownerdraw="true" statusbar:mandatory="true" statusbar:width="130"/> + <statusbar:statusbaritem xlink:href=".uno:BasicIDEZoom" statusbar:align="center" statusbar:mandatory="true" statusbar:width="35"/> +</statusbar:statusbar> diff --git a/basctl/uiconfig/basicide/toolbar/dialogbar.xml b/basctl/uiconfig/basicide/toolbar/dialogbar.xml new file mode 100644 index 0000000000..fe15b8e38b --- /dev/null +++ b/basctl/uiconfig/basicide/toolbar/dialogbar.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE toolbar:toolbar PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "toolbar.dtd"> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink"> + <toolbar:toolbaritem xlink:href=".uno:LibSelector"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:ChooseControls"/> + <toolbar:toolbaritem xlink:href=".uno:ImportDialog"/> + <toolbar:toolbaritem xlink:href=".uno:ExportDialog"/> +</toolbar:toolbar>
\ No newline at end of file diff --git a/basctl/uiconfig/basicide/toolbar/findbar.xml b/basctl/uiconfig/basicide/toolbar/findbar.xml new file mode 100644 index 0000000000..35e6116962 --- /dev/null +++ b/basctl/uiconfig/basicide/toolbar/findbar.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE toolbar:toolbar PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "toolbar.dtd"> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink"> + <toolbar:toolbaritem xlink:href=".uno:ExitSearch"/> + <toolbar:toolbaritem xlink:href=".uno:FindText"/> + <toolbar:toolbaritem xlink:href=".uno:UpSearch"/> + <toolbar:toolbaritem xlink:href=".uno:DownSearch"/> + <toolbar:toolbaritem xlink:href=".uno:FindAll"/> + <toolbar:toolbaritem xlink:href=".uno:MatchCase"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:SearchDialog"/> +</toolbar:toolbar> diff --git a/basctl/uiconfig/basicide/toolbar/formcontrolsbar.xml b/basctl/uiconfig/basicide/toolbar/formcontrolsbar.xml new file mode 100644 index 0000000000..95e6549693 --- /dev/null +++ b/basctl/uiconfig/basicide/toolbar/formcontrolsbar.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE toolbar:toolbar PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "toolbar.dtd"> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + --> +<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink"> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertFormRadio"/> + <toolbar:toolbaritem xlink:href=".uno:InsertFormCheck"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertFormList"/> + <toolbar:toolbaritem xlink:href=".uno:InsertFormCombo"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertFormVScroll"/> + <toolbar:toolbaritem xlink:href=".uno:InsertFormHScroll"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertFormSpin"/> +</toolbar:toolbar> diff --git a/basctl/uiconfig/basicide/toolbar/fullscreenbar.xml b/basctl/uiconfig/basicide/toolbar/fullscreenbar.xml new file mode 100644 index 0000000000..bbb77f4386 --- /dev/null +++ b/basctl/uiconfig/basicide/toolbar/fullscreenbar.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE toolbar:toolbar PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "toolbar.dtd"> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink"> + <toolbar:toolbaritem xlink:href=".uno:FullScreen"/> +</toolbar:toolbar>
\ No newline at end of file diff --git a/basctl/uiconfig/basicide/toolbar/insertcontrolsbar.xml b/basctl/uiconfig/basicide/toolbar/insertcontrolsbar.xml new file mode 100644 index 0000000000..cdd0ae7a0f --- /dev/null +++ b/basctl/uiconfig/basicide/toolbar/insertcontrolsbar.xml @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE toolbar:toolbar PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "toolbar.dtd"> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink"> + <toolbar:toolbaritem xlink:href=".uno:SelectMode"/> + <toolbar:toolbaritem xlink:href=".uno:ManageLanguage"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:TestMode"/> + <toolbar:toolbaritem xlink:href=".uno:ShowPropBrowser"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertPushbutton"/> + <toolbar:toolbaritem xlink:href=".uno:InsertImageControl"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:Checkbox"/> + <toolbar:toolbaritem xlink:href=".uno:Radiobutton"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertFixedText"/> + <toolbar:toolbaritem xlink:href=".uno:InsertEdit"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertListbox"/> + <toolbar:toolbaritem xlink:href=".uno:Combobox"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:VScrollbar"/> + <toolbar:toolbaritem xlink:href=".uno:HScrollbar"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:Groupbox"/> + <toolbar:toolbaritem xlink:href=".uno:ProgressBar"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:HFixedLine"/> + <toolbar:toolbaritem xlink:href=".uno:VFixedLine"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:AddDateField"/> + <toolbar:toolbaritem xlink:href=".uno:InsertTimeField"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertNumericField"/> + <toolbar:toolbaritem xlink:href=".uno:InsertCurrencyField"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertFormattedField"/> + <toolbar:toolbaritem xlink:href=".uno:InsertPatternField"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertFileControl"/> + <toolbar:toolbaritem xlink:href=".uno:InsertTreeControl"/> + <toolbar:toolbarbreak/> + <toolbar:toolbaritem xlink:href=".uno:InsertGridControl"/> + <toolbar:toolbaritem xlink:href=".uno:InsertHyperlinkControl"/> + <toolbar:toolbaritem xlink:href=".uno:SpinButton"/> +</toolbar:toolbar> diff --git a/basctl/uiconfig/basicide/toolbar/macrobar.xml b/basctl/uiconfig/basicide/toolbar/macrobar.xml new file mode 100644 index 0000000000..2959b2ad47 --- /dev/null +++ b/basctl/uiconfig/basicide/toolbar/macrobar.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE toolbar:toolbar PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "toolbar.dtd"> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink"> + <toolbar:toolbaritem xlink:href=".uno:LibSelector"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:CompileBasic"/> + <toolbar:toolbaritem xlink:href=".uno:RunBasic"/> + <toolbar:toolbaritem xlink:href=".uno:BasicStop"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:BasicStepOver"/> + <toolbar:toolbaritem xlink:href=".uno:BasicStepInto"/> + <toolbar:toolbaritem xlink:href=".uno:BasicStepOut"/> + <toolbar:toolbaritem xlink:href=".uno:ToggleBreakPoint"/> + <toolbar:toolbaritem xlink:href=".uno:ManageBreakPoints"/> + <toolbar:toolbaritem xlink:href=".uno:AddWatch"/> + <toolbar:toolbaritem xlink:href=".uno:MatchGroup"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:LoadBasic"/> + <toolbar:toolbaritem xlink:href=".uno:SaveBasicAs"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:ImportDialog"/> +</toolbar:toolbar> diff --git a/basctl/uiconfig/basicide/toolbar/standardbar.xml b/basctl/uiconfig/basicide/toolbar/standardbar.xml new file mode 100644 index 0000000000..f41df28ab6 --- /dev/null +++ b/basctl/uiconfig/basicide/toolbar/standardbar.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE toolbar:toolbar PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "toolbar.dtd"> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink"> + <toolbar:toolbaritem xlink:href=".uno:OpenUrl" toolbar:visible="false"/> + <toolbar:toolbaritem xlink:href=".uno:AddDirect"/> + <toolbar:toolbaritem xlink:href=".uno:Open"/> + <toolbar:toolbaritem xlink:href=".uno:Save"/> + <toolbar:toolbaritem xlink:href=".uno:SaveAs" toolbar:visible="false"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:PrintDefault" toolbar:visible="false"/> + <toolbar:toolbaritem xlink:href=".uno:Print"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:Cut"/> + <toolbar:toolbaritem xlink:href=".uno:Copy"/> + <toolbar:toolbaritem xlink:href=".uno:Paste"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:Undo"/> + <toolbar:toolbaritem xlink:href=".uno:Redo"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:ObjectCatalog"/> + <toolbar:toolbaritem xlink:href=".uno:WatchWindow"/> + <toolbar:toolbaritem xlink:href=".uno:StackWindow"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:ChooseMacro"/> + <toolbar:toolbaritem xlink:href=".uno:ModuleDialog"/> + <toolbar:toolbarseparator/> + <toolbar:toolbaritem xlink:href=".uno:HelpIndex"/> + <toolbar:toolbaritem xlink:href=".uno:ExtendedHelp" toolbar:visible="false"/> +</toolbar:toolbar> diff --git a/basctl/uiconfig/basicide/toolbar/translationbar.xml b/basctl/uiconfig/basicide/toolbar/translationbar.xml new file mode 100644 index 0000000000..99b5ed26fc --- /dev/null +++ b/basctl/uiconfig/basicide/toolbar/translationbar.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE toolbar:toolbar PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "toolbar.dtd"> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<toolbar:toolbar xmlns:toolbar="http://openoffice.org/2001/toolbar" xmlns:xlink="http://www.w3.org/1999/xlink"> + <toolbar:toolbaritem xlink:href=".uno:CurrentLanguage"/> + <toolbar:toolbaritem xlink:href=".uno:ManageLanguage"/> +</toolbar:toolbar>
\ No newline at end of file diff --git a/basctl/uiconfig/basicide/ui/basicmacrodialog.ui b/basctl/uiconfig/basicide/ui/basicmacrodialog.ui new file mode 100644 index 0000000000..bdece2cca4 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/basicmacrodialog.ui @@ -0,0 +1,503 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name expander --> + <column type="GdkPixbuf"/> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkTreeStore" id="liststore2"> + <columns> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkDialog" id="BasicMacroDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="title" translatable="yes" context="basicmacrodialog|BasicMacroDialog">BASIC Macros</property> + <property name="modal">True</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="homogeneous">True</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="ok"> + <property name="label" translatable="yes" context="basicmacrodialog|run">Run</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="ok-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|ok">Runs or saves the current macro.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="close"> + <property name="label" translatable="yes" context="stock">_Close</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">8</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkBox" id="box1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="spacing">12</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkFrame" id="frame3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <property name="margin-start">12</property> + <property name="margin-top">6</property> + <child> + <object class="GtkTreeView" id="macros"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore2</property> + <property name="headers_visible">False</property> + <property name="search_column">0</property> + <property name="show_expanders">False</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Tree List-selection1"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn1"> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="macros-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|macros">Lists the macros that are contained in the module selected in the Macro from list.</property> + </object> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="existingmacrosft"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="basicmacrodialog|existingmacrosft">Existing Macros In:</property> + <property name="ellipsize">end</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <property name="margin-start">12</property> + <property name="margin-top">6</property> + <child> + <object class="GtkTreeView" id="libraries"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="search_column">1</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Macro Library List-selection1"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn2"> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/> + <attributes> + <attribute name="pixbuf">0</attribute> + </attributes> + </child> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="libraries-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|libraries">Lists the libraries and the modules where you can open or save your macros. To save a macro with a particular document, open the document, and then open this dialog.</property> + </object> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkBox" id="box2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkLabel" id="macrofromft"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="basicmacrodialog|macrofromft">Macro From</property> + <property name="xalign">0</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="macrotoft"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="basicmacrodialog|macrotoft">Save Macro In</property> + <property name="xalign">0</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkEntry" id="macronameedit"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="activates_default">True</property> + <property name="margin-start">12</property> + <property name="margin-top">6</property> + <property name="truncate-multiline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="macronameedit-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|macronameedit">Displays the name of the selected macro. To create or to change the name of a macro, enter a name here.</property> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="libraryft1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="basicmacrodialog|libraryft1">Macro Name</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkButtonBox" id="buttonbox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">5</property> + <property name="homogeneous">True</property> + <property name="layout_style">start</property> + <child> + <object class="GtkButton" id="assign"> + <property name="label" translatable="yes" context="basicmacrodialog|assign">Assign...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="assign-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|assign">Opens the Customize dialog, where you can assign the selected macro to a menu command, a toolbar, or an event.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="edit"> + <property name="label" translatable="yes" context="basicmacrodialog|edit">Edit</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="edit-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|edit">Starts the Basic editor and opens the selected macro or dialog for editing.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="delete"> + <property name="label" translatable="yes" context="basicmacrodialog|delete">_Delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="delete-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|delete">Creates a new macro, creates a new module or deletes the selected macro or selected module.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="new"> + <property name="label" translatable="yes" context="basicmacrodialog|new">_New</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="no_show_all">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="new-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|new">Creates a new library.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkButton" id="organize"> + <property name="label" translatable="yes" context="basicmacrodialog|organize">Organizer...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="organize-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|organize">Opens the Macro Organizer dialog, where you can add, edit, or delete existing macro modules, dialogs, and libraries.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkButton" id="newlibrary"> + <property name="label" translatable="yes" context="basicmacrodialog|newlibrary">New Library</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="no_show_all">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="newlibrary-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|newlibrary">Saves the recorded macro in a new library.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">5</property> + </packing> + </child> + <child> + <object class="GtkButton" id="newmodule"> + <property name="label" translatable="yes" context="basicmacrodialog|newmodule">New Module</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="no_show_all">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="newmodule-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|newmodule">Saves the recorded macro in a new module.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">6</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-5">ok</action-widget> + <action-widget response="-7">close</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + <child type="titlebar"> + <placeholder/> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="BasicMacroDialog-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="basicmacrodialog|extended_tip|BasicMacroDialog">Opens a dialog to organize macros.</property> + </object> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/breakpointmenus.ui b/basctl/uiconfig/basicide/ui/breakpointmenus.ui new file mode 100644 index 0000000000..7ebbf88286 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/breakpointmenus.ui @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkMenu" id="breaklistmenu"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkMenuItem" id="manage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="breakpointmenus|manage">Manage Breakpoints...</property> + <child internal-child="accessible"> + <object class="AtkObject" id="manage-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="breakpointmenus|extended_tip|manage">Specifies the options for breakpoints.</property> + </object> + </child> + </object> + </child> + </object> + <object class="GtkMenu" id="breakmenu"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkCheckMenuItem" id="active"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="breakpointmenus|active">_Active</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="active-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="breakpointmenus|extended_tip|active">Activates or deactivates the current breakpoint.</property> + </object> + </child> + </object> + </child> + <child> + <object class="GtkSeparatorMenuItem" id="menuitem1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + </object> + </child> + <child> + <object class="GtkMenuItem" id="properties"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="breakpointmenus|properties">_Properties...</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="properties-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="breakpointmenus|extended_tip|properties">Specifies the options for breakpoints.</property> + </object> + </child> + </object> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/codecomplete.ui b/basctl/uiconfig/basicide/ui/codecomplete.ui new file mode 100644 index 0000000000..8dce431e07 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/codecomplete.ui @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkBox" id="CodeComplete"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="hscrollbar_policy">never</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> + <property name="enable_search">False</property> + <property name="search_column">1</property> + <property name="show_expanders">False</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn1"> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/combobox.ui b/basctl/uiconfig/basicide/ui/combobox.ui new file mode 100644 index 0000000000..d9d6efd650 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/combobox.ui @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkBox" id="ComboBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkComboBoxText" id="combobox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/defaultlanguage.ui b/basctl/uiconfig/basicide/ui/defaultlanguage.ui new file mode 100644 index 0000000000..eb11678d41 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/defaultlanguage.ui @@ -0,0 +1,316 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name check1 --> + <column type="gboolean"/> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + <!-- column-name checkvis1 --> + <column type="gboolean"/> + <!-- column-name checktri1 --> + <column type="gboolean"/> + </columns> + </object> + <object class="GtkTreeStore" id="liststore2"> + <columns> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkDialog" id="DefaultLanguageDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="title" translatable="yes" context="defaultlanguage|DefaultLanguageDialog">Set Default User Interface Language</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="type_hint">dialog</property> + <child> + <placeholder/> + </child> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="ok"> + <property name="label" translatable="yes" context="stock">_OK</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="cancel"> + <property name="label" translatable="yes" context="stock">_Cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">12</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkLabel" id="defaultlabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="defaultlanguage|defaultlabel">Default language:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">entries</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="entries"> + <property name="width_request">-1</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore2</property> + <property name="headers_visible">False</property> + <property name="search_column">1</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Macro Library List-selection1"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn3"> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="checkedentries"> + <property name="width_request">-1</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="search_column">1</property> + <property name="show_expanders">False</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Macro Library List-selection2"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn2"> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererToggle" id="cellrenderer5"/> + <attributes> + <attribute name="visible">3</attribute> + <attribute name="active">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn4"> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">3</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="checkedlabel"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes" context="defaultlanguage|checkedlabel">Available languages:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">checkedentries</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="hidden"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="has_entry">True</property> + <child internal-child="entry"> + <object class="GtkEntry"> + <property name="can_focus">False</property> + <property name="truncate-multiline">True</property> + <property name="activates_default">True</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">4</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="defined"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="defaultlanguage|defined">Select a language to define the default user interface language. All currently present strings will be assigned to the resources created for the selected language.</property> + <property name="wrap">True</property> + <property name="wrap_mode">word-char</property> + <property name="max_width_chars">72</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="added"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes" context="defaultlanguage|added">Select languages to be added. Resources for these languages will be created in the library. Strings of the current default user interface language will be copied to these new resources by default.</property> + <property name="wrap">True</property> + <property name="wrap_mode">word-char</property> + <property name="max_width_chars">72</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="alttitle"> + <property name="can_focus">False</property> + <property name="no_show_all">True</property> + <property name="label" translatable="yes" context="defaultlanguage|alttitle">Add User Interface Languages</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">3</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-5">ok</action-widget> + <action-widget response="-6">cancel</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/deletelangdialog.ui b/basctl/uiconfig/basicide/ui/deletelangdialog.ui new file mode 100644 index 0000000000..ff5b6c438c --- /dev/null +++ b/basctl/uiconfig/basicide/ui/deletelangdialog.ui @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.18.3 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkMessageDialog" id="DeleteLangDialog"> + <property name="can_focus">False</property> + <property name="title" translatable="yes" context="deletelangdialog|DeleteLangDialog">Delete Language Resources</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="type_hint">dialog</property> + <property name="skip_taskbar_hint">True</property> + <property name="message_type">question</property> + <property name="buttons">ok-cancel</property> + <property name="text" translatable="yes" context="deletelangdialog|DeleteLangDialog">Do you want to delete the resources of the selected language(s)?</property> + <property name="secondary_text" translatable="yes" context="deletelangdialog|DeleteLangDialog">You are about to delete the resources for the selected language(s). All user interface strings for this language(s) will be deleted.</property> + <child internal-child="vbox"> + <object class="GtkBox" id="messagedialog-vbox"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="messagedialog-action_area"> + <property name="can_focus">False</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/dialogpage.ui b/basctl/uiconfig/basicide/ui/dialogpage.ui new file mode 100644 index 0000000000..373fc2f4f8 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/dialogpage.ui @@ -0,0 +1,274 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name expander --> + <column type="GdkPixbuf"/> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="DialogPage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="column_spacing">12</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="dialogpage|label1">Dialog:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">library</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="library"> + <property name="width_request">-1</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="reorderable">True</property> + <property name="search_column">1</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Macro Library List-selection1"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn2"> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/> + <attributes> + <attribute name="pixbuf">0</attribute> + </attributes> + </child> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"> + <property name="editable">True</property> + </object> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="library-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="dialogpage|extended_tip|library">Deletes the selected element or elements after confirmation.</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkButtonBox" id="buttonbox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <property name="layout_style">start</property> + <child> + <object class="GtkButton" id="edit"> + <property name="label" translatable="yes" context="stock">_Edit</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="edit-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="dialogpage|extended_tip|edit">Opens the Basic editor so that you can modify the selected library.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="newmodule"> + <property name="label" translatable="yes" context="dialogpage|newmodule">_New...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="newmodule-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="dialogpage|extended_tip|newmodule">Opens the editor and creates a new module.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + <property name="secondary">True</property> + </packing> + </child> + <child> + <object class="GtkButton" id="newdialog"> + <property name="label" translatable="yes" context="dialogpage|newdialog">_New...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + <child> + <object class="GtkButton" id="delete"> + <property name="label" translatable="yes" context="stock">_Delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="delete-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="dialogpage|extended_tip|delete">Deletes the selected element or elements without requiring confirmation.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + <property name="secondary">True</property> + </packing> + </child> + <child> + <object class="GtkButton" id="password"> + <property name="label" translatable="yes" context="dialogpage|password">_Password...</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="no_show_all">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="password-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="dialogpage|extended_tip|password">Assigns or edits the password for the selected library.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkButton" id="import"> + <property name="label" translatable="yes" context="dialogpage|import">_Import...</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="no_show_all">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="import-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="dialogpage|extended_tip|import">Locate the Basic library that you want to add to the current list, and then click Open.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">5</property> + </packing> + </child> + <child> + <object class="GtkButton" id="export"> + <property name="label" translatable="yes" context="dialogpage|export">_Export...</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="no_show_all">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">6</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="DialogPage-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="dialogpage|extended_tip|DialogPage">Lists the existing modules or dialogs.</property> + </object> + </child> + </object> + <object class="GtkSizeGroup" id="sizegroup1"> + <widgets> + <widget name="edit"/> + <widget name="newmodule"/> + <widget name="newdialog"/> + <widget name="delete"/> + <widget name="password"/> + <widget name="import"/> + <widget name="export"/> + </widgets> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/dockingorganizer.ui b/basctl/uiconfig/basicide/ui/dockingorganizer.ui new file mode 100644 index 0000000000..f0e05055d1 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/dockingorganizer.ui @@ -0,0 +1,82 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name expander --> + <column type="GdkPixbuf"/> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="DockingOrganizer"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="libraries"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="search_column">1</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn2"> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/> + <attributes> + <attribute name="pixbuf">0</attribute> + </attributes> + </child> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="title"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">libraries</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/dockingstack.ui b/basctl/uiconfig/basicide/ui/dockingstack.ui new file mode 100644 index 0000000000..90d7146940 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/dockingstack.ui @@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="DockingStack"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="stack"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="search_column">1</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn2"> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="title"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">stack</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/dockingwatch.ui b/basctl/uiconfig/basicide/ui/dockingwatch.ui new file mode 100644 index 0000000000..d6d35f8b0e --- /dev/null +++ b/basctl/uiconfig/basicide/ui/dockingwatch.ui @@ -0,0 +1,164 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkImage" id="image1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="icon_name">res/baswatr.png</property> + <property name="icon_size">2</property> + </object> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name text1 --> + <column type="gchararray"/> + <!-- column-name text2 --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="DockingWatch"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="titlearea"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="column_spacing">6</property> + <child> + <object class="GtkButton" id="remove"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="image">image1</property> + <property name="use_underline">True</property> + <property name="always_show_image">True</property> + </object> + <packing> + <property name="left_attach">2</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="edit"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="valign">center</property> + <property name="truncate-multiline">True</property> + <property name="vexpand">False</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="title"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">edit</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkBox"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="search_column">1</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn1"> + <property name="resizable">True</property> + <property name="title" translatable="yes" context="dockingwatch|RID_STR_WATCHVARIABLE">Variable</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn2"> + <property name="resizable">True</property> + <property name="title" translatable="yes" context="dockingwatch|RID_STR_WATCHVALUE">Value</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"> + <property name="editable">True</property> + </object> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn3"> + <property name="resizable">True</property> + <property name="title" translatable="yes" context="dockingwatch|RID_STR_WATCHTYPE">Type</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext3"/> + <attributes> + <attribute name="text">2</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/exportdialog.ui b/basctl/uiconfig/basicide/ui/exportdialog.ui new file mode 100644 index 0000000000..05f624eccd --- /dev/null +++ b/basctl/uiconfig/basicide/ui/exportdialog.ui @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkDialog" id="ExportDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="title" translatable="yes" context="exportdialog|ExportDialog">Export Basic library</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="default_width">0</property> + <property name="default_height">0</property> + <property name="type_hint">dialog</property> + <child> + <placeholder/> + </child> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="ok"> + <property name="label" translatable="yes" context="stock">_OK</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="cancel"> + <property name="label" translatable="yes" context="stock">_Cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="margin-end">6</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">2</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="halign">center</property> + <property name="hexpand">True</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkRadioButton" id="extension"> + <property name="label" translatable="yes" context="exportdialog|extension">Export as _extension</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="active">True</property> + <property name="draw_indicator">True</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="basic"> + <property name="label" translatable="yes" context="exportdialog|basic">Export as BASIC library</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + <property name="group">extension</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-5">ok</action-widget> + <action-widget response="-6">cancel</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/gotolinedialog.ui b/basctl/uiconfig/basicide/ui/gotolinedialog.ui new file mode 100644 index 0000000000..e5b5e13ab0 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/gotolinedialog.ui @@ -0,0 +1,129 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.20.4 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkDialog" id="GotoLineDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="title" translatable="yes" context="gotolinedialog|GotoLineDialog">Go to Line</property> + <property name="modal">True</property> + <property name="default_width">0</property> + <property name="default_height">0</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="ok"> + <property name="label" translatable="yes" context="stock">_OK</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="cancel"> + <property name="label" translatable="yes" context="stock">_Cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="margin-end">6</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">2</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="area"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="gotolinedialog|area">_Line number:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">entry</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="truncate-multiline">True</property> + <property name="activates_default">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-5">ok</action-widget> + <action-widget response="-6">cancel</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + <child> + <placeholder/> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/importlibdialog.ui b/basctl/uiconfig/basicide/ui/importlibdialog.ui new file mode 100644 index 0000000000..98066ca827 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/importlibdialog.ui @@ -0,0 +1,267 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name check1 --> + <column type="gboolean"/> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + <!-- column-name checkvis1 --> + <column type="gboolean"/> + <!-- column-name checktri1 --> + <column type="gboolean"/> + </columns> + </object> + <object class="GtkDialog" id="ImportLibDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="title" translatable="yes" context="importlibdialog|ImportLibDialog">Import Libraries</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="default_width">0</property> + <property name="default_height">0</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="ok"> + <property name="label" translatable="yes" context="stock">_OK</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="cancel"> + <property name="label" translatable="yes" context="stock">_Cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">12</property> + <child> + <object class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="row_spacing">6</property> + <property name="margin-start">12</property> + <property name="margin-top">6</property> + <child> + <object class="GtkCheckButton" id="ref"> + <property name="label" translatable="yes" context="importlibdialog|ref">Insert as reference (read-only)</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="ref-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="importlibdialog|extended_tip|ref">Adds the selected library as a read-only file. The library is reloaded each time you start the office suite.</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="replace"> + <property name="label" translatable="yes" context="importlibdialog|replace">Replace existing libraries</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="replace-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="importlibdialog|extended_tip|replace">Replaces a library that has the same name with the current library.</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="importlibdialog|label1">Options</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="storageframe"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <property name="margin-start">12</property> + <property name="margin-top">6</property> + <child> + <object class="GtkTreeView" id="entries"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="search_column">0</property> + <property name="show_expanders">False</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Macro Library List-selection2"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn4"> + <property name="resizable">True</property> + <property name="spacing">6</property> + <property name="alignment">0.5</property> + <child> + <object class="GtkCellRendererToggle" id="cellrenderer5"/> + <attributes> + <attribute name="visible">3</attribute> + <attribute name="active">0</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn5"> + <property name="resizable">True</property> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererText" id="cellrenderer4"/> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-5">ok</action-widget> + <action-widget response="-6">cancel</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + <child type="titlebar"> + <placeholder/> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="ImportLibDialog-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="importlibdialog|extended_tip|ImportLibDialog">Enter a name or the path to the library that you want to append. You can also select a library from the list.</property> + </object> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/libpage.ui b/basctl/uiconfig/basicide/ui/libpage.ui new file mode 100644 index 0000000000..6047b0c906 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/libpage.ui @@ -0,0 +1,309 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name expander --> + <column type="GdkPixbuf"/> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name text1 --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="LibPage"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="row_spacing">12</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">12</property> + <property name="column_spacing">12</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="libpage|label1">L_ocation:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">location</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkComboBoxText" id="location"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="location-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="libpage|extended_tip|location">Select the application or the document containing the macro libraries that you want to organize.</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="lingudictsft"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="libpage|lingudictsft">_Library:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">library</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="library"> + <property name="width_request">-1</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="search_column">1</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Macro Library List-selection1"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn2"> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/> + <attributes> + <attribute name="pixbuf">0</attribute> + </attributes> + </child> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"> + <property name="editable">True</property> + </object> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn3"> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererText" id="cellrenderertext3"/> + <attributes> + <attribute name="text">2</attribute> + </attributes> + </child> + </object> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="library-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="libpage|extended_tip|library">Deletes the selected element or elements after confirmation.</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkButtonBox" id="buttonbox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <property name="layout_style">start</property> + <child> + <object class="GtkButton" id="edit"> + <property name="label" translatable="yes" context="stock">_Edit</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="edit-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="libpage|extended_tip|edit">Opens the Basic editor so that you can modify the selected library.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="password"> + <property name="label" translatable="yes" context="libpage|password">_Password...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="password-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="libpage|extended_tip|password">Assigns or edits the password for the selected library.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="new"> + <property name="label" translatable="yes" context="libpage|new">_New...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="new-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="libpage|extended_tip|new">Creates a new library.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + <child> + <object class="GtkButton" id="import"> + <property name="label" translatable="yes" context="libpage|import">_Import...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="import-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="libpage|extended_tip|import">Locate the Basic library that you want to add to the current list, and then click Open.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + <property name="secondary">True</property> + </packing> + </child> + <child> + <object class="GtkButton" id="export"> + <property name="label" translatable="yes" context="libpage|export">_Export...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + <property name="secondary">True</property> + </packing> + </child> + <child> + <object class="GtkButton" id="delete"> + <property name="label" translatable="yes" context="stock">_Delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="delete-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="libpage|extended_tip|delete">Deletes the selected element or elements without requiring confirmation.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">5</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + <property name="height">2</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="LibPage-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="libpage|extended_tip|LibPage">Select the application or the document containing the macro libraries that you want to organize.</property> + </object> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/managebreakpoints.ui b/basctl/uiconfig/basicide/ui/managebreakpoints.ui new file mode 100644 index 0000000000..d0910a0763 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/managebreakpoints.ui @@ -0,0 +1,310 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkDialog" id="ManageBreakpointsDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="title" translatable="yes" context="managebreakpoints|ManageBreakpointsDialog">Manage Breakpoints</property> + <property name="modal">True</property> + <property name="default_width">0</property> + <property name="default_height">0</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="new"> + <property name="label" translatable="yes" context="stock">_New</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="new-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="managebreakpoints|extended_tip|new">Creates a breakpoint on the line number specified.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="delete"> + <property name="label" translatable="yes" context="stock">_Delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="delete-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="managebreakpoints|extended_tip|delete">Deletes the selected breakpoint.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="ok"> + <property name="label" translatable="yes" context="stock">_OK</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkButton" id="cancel"> + <property name="label" translatable="yes" context="stock">_Cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="margin-end">6</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">2</property> + </packing> + </child> + <child> + <object class="GtkFrame" id="frame1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <property name="margin-start">12</property> + <property name="margin-top">6</property> + <child> + <object class="GtkCheckButton" id="active"> + <property name="label" translatable="yes" context="managebreakpoints|active">Active</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="active-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="managebreakpoints|extended_tip|active">Activates or deactivates the current breakpoint.</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="entriesgrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">3</property> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="entrieslist"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="headers_clickable">False</property> + <property name="search_column">0</property> + <property name="show_expanders">False</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="treeview-selection1"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn1"> + <child> + <object class="GtkCellRendererText" id="cellrenderertext1"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entries"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="activates_default">True</property> + <property name="truncate-multiline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="entries-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="managebreakpoints|extended_tip|entries">Enter the line number for a new breakpoint, then click New.</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkSpinButton" id="pass"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="activates_default">True</property> + <property name="truncate-multiline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="pass-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="managebreakpoints|extended_tip|pass">Specify the number of loops to perform before the breakpoint takes effect.</property> + </object> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="managebreakpoints|label2">Pass count:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">pass</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="managebreakpoints|label1">Breakpoints</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="101">new</action-widget> + <action-widget response="102">delete</action-widget> + <action-widget response="-5">ok</action-widget> + <action-widget response="-6">cancel</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + <child type="titlebar"> + <placeholder/> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="ManageBreakpointsDialog-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="managebreakpoints|extended_tip|ManageBreakpointsDialog">Specifies the options for breakpoints.</property> + </object> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/managelanguages.ui b/basctl/uiconfig/basicide/ui/managelanguages.ui new file mode 100644 index 0000000000..1b18eed23f --- /dev/null +++ b/basctl/uiconfig/basicide/ui/managelanguages.ui @@ -0,0 +1,232 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkDialog" id="ManageLanguagesDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="title" translatable="yes" context="managelanguages|ManageLanguagesDialog">Manage User Interface Languages [$1]</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="type_hint">normal</property> + <child> + <placeholder/> + </child> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="close"> + <property name="label" translatable="yes" context="stock">_Close</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="managelanguages|label1">Present languages:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">treeview</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="label2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="managelanguages|label2">The default language is used if no localization for a user interface locale is present. Furthermore all strings from the default language are copied to resources of newly added languages.</property> + <property name="wrap">True</property> + <property name="max_width_chars">68</property> + <property name="xalign">0</property> + <attributes> + <attribute name="scale" value="0.9"/> + </attributes> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkButtonBox" id="buttonbox1"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <property name="layout_style">start</property> + <child> + <object class="GtkButton" id="add"> + <property name="label" translatable="yes" context="managelanguages|add">Add...</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="delete"> + <property name="label" translatable="yes" context="stock">_Delete</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="default"> + <property name="label" translatable="yes" context="managelanguages|default">Default</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use_underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow_type">in</property> + <child> + <object class="GtkTreeView" id="treeview"> + <property name="width_request">-1</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers_visible">False</property> + <property name="search_column">1</property> + <property name="enable_tree_lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Macro Library List-selection1"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn3"> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"/> + <attributes> + <attribute name="text">0</attribute> + </attributes> + </child> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-7">close</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/modulepage.ui b/basctl/uiconfig/basicide/ui/modulepage.ui new file mode 100644 index 0000000000..328add73b6 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/modulepage.ui @@ -0,0 +1,279 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.38.2 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name expander --> + <column type="GdkPixbuf"/> + <!-- column-name text --> + <column type="gchararray"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="ModulePage"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="border-width">6</property> + <property name="row-spacing">12</property> + <child> + <!-- n-columns=2 n-rows=1 --> + <object class="GtkGrid" id="grid2"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="column-spacing">12</property> + <child> + <!-- n-columns=1 n-rows=2 --> + <object class="GtkGrid" id="grid3"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="row-spacing">6</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes" context="modulepage|label1">M_odule:</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">library</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow-type">in</property> + <child> + <object class="GtkTreeView" id="library"> + <property name="width-request">-1</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="headers-visible">False</property> + <property name="reorderable">True</property> + <property name="search-column">1</property> + <property name="enable-tree-lines">True</property> + <child internal-child="selection"> + <object class="GtkTreeSelection" id="Macro Library List-selection1"/> + </child> + <child> + <object class="GtkTreeViewColumn" id="treeviewcolumn2"> + <property name="spacing">6</property> + <child> + <object class="GtkCellRendererPixbuf" id="cellrenderertext4"/> + <attributes> + <attribute name="pixbuf">0</attribute> + </attributes> + </child> + <child> + <object class="GtkCellRendererText" id="cellrenderertext2"> + <property name="editable">True</property> + </object> + <attributes> + <attribute name="text">1</attribute> + </attributes> + </child> + </object> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="library-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="modulepage|extended_tip|library">Lists the existing macro libraries for the current application and any open documents.</property> + </object> + </child> + </object> + </child> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">1</property> + </packing> + </child> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">0</property> + </packing> + </child> + <child> + <object class="GtkButtonBox" id="buttonbox1"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <property name="layout-style">start</property> + <child> + <object class="GtkButton" id="edit"> + <property name="label" translatable="yes" context="stock">_Edit</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="edit-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="modulepage|extended_tip|edit">Opens the Basic editor so that you can modify the selected library.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="newmodule"> + <property name="label" translatable="yes" context="modulepage|newmodule">_New...</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="newmodule-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="modulepage|extended_tip|newmodule">Opens the editor and creates a new module.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + <property name="secondary">True</property> + </packing> + </child> + <child> + <object class="GtkButton" id="newdialog"> + <property name="label" translatable="yes" context="modulepage|newdialog">_New...</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="newdialog-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="modulepage|extended_tip|newdialog">Lets you manage the macro libraries.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + <child> + <object class="GtkButton" id="delete"> + <property name="label" translatable="yes" context="stock">_Delete</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="delete-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="modulepage|extended_tip|delete">Creates a new macro, or deletes the selected macro.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">3</property> + <property name="secondary">True</property> + </packing> + </child> + <child> + <object class="GtkButton" id="password"> + <property name="label" translatable="yes" context="modulepage|password">_Password...</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="no-show-all">True</property> + <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="password-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="modulepage|extended_tip|password">Assigns or edits the password for the selected library.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">4</property> + </packing> + </child> + <child> + <object class="GtkButton" id="import"> + <property name="label" translatable="yes" context="modulepage|import">_Import...</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="no-show-all">True</property> + <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="import-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="modulepage|extended_tip|import">Locate the Basic library that you want to add to the current list, and then click Open.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">5</property> + </packing> + </child> + <child> + <object class="GtkButton" id="export"> + <property name="label" translatable="yes" context="modulepage|export">_Export...</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="no-show-all">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">6</property> + </packing> + </child> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">0</property> + </packing> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="ModulePage-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="modulepage|extended_tip|ModulePage">Lists the existing modules or dialogs.</property> + </object> + </child> + </object> + <object class="GtkSizeGroup" id="sizegroup1"> + <widgets> + <widget name="edit"/> + <widget name="newmodule"/> + <widget name="newdialog"/> + <widget name="delete"/> + <widget name="password"/> + <widget name="import"/> + <widget name="export"/> + </widgets> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/newlibdialog.ui b/basctl/uiconfig/basicide/ui/newlibdialog.ui new file mode 100644 index 0000000000..77f9785105 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/newlibdialog.ui @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.36.0 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkDialog" id="NewLibDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="modal">True</property> + <property name="default_width">0</property> + <property name="default_height">0</property> + <property name="type_hint">dialog</property> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="ok"> + <property name="label" translatable="yes" context="stock">_OK</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="ok-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="newlibdialog|extended_tip|ok">Runs or saves the current macro.</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkButton" id="cancel"> + <property name="label" translatable="yes" context="stock">_Cancel</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="margin-end">6</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">2</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid" id="grid3"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="hexpand">True</property> + <property name="row_spacing">6</property> + <property name="column_spacing">12</property> + <child> + <object class="GtkLabel" id="area"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="newlibdialog|area">_Name:</property> + <property name="use_underline">True</property> + <property name="mnemonic_widget">entry</property> + <property name="xalign">0</property> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkEntry" id="entry"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="truncate-multiline">True</property> + <property name="activates_default">True</property> + </object> + <packing> + <property name="left_attach">1</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-6">cancel</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + <child type="titlebar"> + <placeholder/> + </child> + <child internal-child="accessible"> + <object class="AtkObject" id="NewLibDialog-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="newlibdialog|extended_tip|NewLibDialog">Enter a name for the new library or module.</property> + </object> + </child> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/organizedialog.ui b/basctl/uiconfig/basicide/ui/organizedialog.ui new file mode 100644 index 0000000000..fdad0a3d43 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/organizedialog.ui @@ -0,0 +1,227 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.22.1 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkDialog" id="OrganizeDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="title" translatable="yes" context="organizedialog|OrganizeDialog">Basic Macro Organizer</property> + <property name="resizable">False</property> + <property name="modal">True</property> + <property name="default_width">0</property> + <property name="default_height">0</property> + <property name="type_hint">dialog</property> + <child> + <placeholder/> + </child> + <child internal-child="vbox"> + <object class="GtkBox" id="dialog-vbox1"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="dialog-action_area1"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + <child> + <object class="GtkButton" id="close"> + <property name="label" translatable="yes" context="stock">_Close</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + <child> + <object class="GtkButton" id="help"> + <property name="label" translatable="yes" context="stock">_Help</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">True</property> + <property name="use-underline">True</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">2</property> + <property name="secondary">True</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkNotebook" id="tabcontrol"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="scrollable">True</property> + <property name="enable_popup">True</property> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + </child> + <child type="tab"> + <object class="GtkLabel" id="modules"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="organizedialog|modules">Modules</property> + </object> + <packing> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="position">1</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="dialogs"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="organizedialog|dialogs">Dialogs</property> + </object> + <packing> + <property name="position">1</property> + <property name="tab_fill">False</property> + </packing> + </child> + <child> + <!-- n-columns=1 n-rows=1 --> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> + </object> + <packing> + <property name="position">2</property> + </packing> + </child> + <child type="tab"> + <object class="GtkLabel" id="libraries"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="organizedialog|libraries">Libraries</property> + </object> + <packing> + <property name="position">2</property> + <property name="tab_fill">False</property> + </packing> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + </child> + <action-widgets> + <action-widget response="-7">close</action-widget> + <action-widget response="-11">help</action-widget> + </action-widgets> + </object> +</interface> diff --git a/basctl/uiconfig/basicide/ui/sortmenu.ui b/basctl/uiconfig/basicide/ui/sortmenu.ui new file mode 100644 index 0000000000..bc490f0b20 --- /dev/null +++ b/basctl/uiconfig/basicide/ui/sortmenu.ui @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.20.0 --> +<interface domain="basctl"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkMenu" id="sortmenu"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkMenuItem"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="sortmenu|macrosort">_Sorting</property> + <property name="use_underline">True</property> + <child type="submenu"> + <object class="GtkMenu" id="sortsubmenu"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkRadioMenuItem" id="alphabetically"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="sortmenu|alphabetically">_Alphabetically</property> + <property name="use_underline">True</property> + <property name="draw_as_radio">True</property> + <property name="group">properorder</property> + </object> + </child> + <child> + <object class="GtkRadioMenuItem" id="properorder"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes" context="sortmenu|properorder">_Proper order</property> + <property name="draw_as_radio">True</property> + <property name="use_underline">True</property> + </object> + </child> + </object> + </child> + </object> + </child> + </object> +</interface> diff --git a/basctl/util/basctl.component b/basctl/util/basctl.component new file mode 100644 index 0000000000..3b1c169e73 --- /dev/null +++ b/basctl/util/basctl.component @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.basic.BasicIDE" + constructor="com_sun_star_comp_basic_BasicID_get_implementation"> + <service name="com.sun.star.script.BasicIDE"/> + </implementation> +</component> |